From 57763b70c44804ec856f8bff9dbcae18bc33c345 Mon Sep 17 00:00:00 2001 From: Ramakrishnan Muthukrishnan <vu3rdd@gmail.com> Date: Sun, 19 May 2013 23:40:48 +0530 Subject: [PATCH] submodulized .emacs.d setup --- .gitmodules | 12 + emacs/ac-python.el | 72 + emacs/basic-mode.el | 669 + emacs/cldoc.el | 1538 +++ emacs/espresso.el | 869 ++ emacs/flyspell.el | 2458 ++++ emacs/gambit.el | 649 + emacs/gist.el | 346 + emacs/graphviz-dot-mode.el | 919 ++ emacs/highlight-parentheses.el | 157 + emacs/javascript.el | 707 ++ emacs/lacarte.el | 605 + emacs/ll-debug.el | 634 + emacs/malyon.el | 3211 +++++ emacs/maxframe.el | 110 + emacs/moz.el | 282 + emacs/my-c-mode.el | 29 + emacs/my-erc.el | 77 + emacs/my-generic-stuff.el | 44 + emacs/my-haskell.el | 24 + emacs/my-org-mode.el | 33 + emacs/my-python.el | 19 + emacs/my-search.el | 4 + emacs/my-slime.el | 43 + emacs/my-swank-js.el | 3 + emacs/my-twitter.el | 4 + emacs/naquadah-theme.el | 185 + emacs/notify.el | 99 + emacs/nxhtml/README.txt | 46 + emacs/nxhtml/alts/find-recursive-orig.el | 137 + emacs/nxhtml/alts/javascript-mozlab.el | 712 ++ emacs/nxhtml/alts/smarty-mode-vdebout.el | 2715 +++++ emacs/nxhtml/autostart.el | 194 + emacs/nxhtml/autostart22.el | 71 + emacs/nxhtml/emacs22.cmd | 1 + emacs/nxhtml/etc/img/pause/pause.jpg | Bin 0 -> 25849 bytes emacs/nxhtml/etc/img/pause/pause2.jpg | Bin 0 -> 26756 bytes .../etc/schema/FDA-2009-N-0392-0396.1.doc | Bin 0 -> 47104 bytes emacs/nxhtml/etc/schema/genshi-old.rnc | 27 + emacs/nxhtml/etc/schema/genshi-schemas.xml | 3 + emacs/nxhtml/etc/schema/genshi.rnc | 84 + emacs/nxhtml/etc/schema/mjt.rnc | 74 + emacs/nxhtml/etc/schema/nxml-erb.patch | 37 + emacs/nxhtml/etc/schema/old-genshi.rnc | 31 + emacs/nxhtml/etc/schema/old-qtmstr-xhtml.rnc | 61 + emacs/nxhtml/etc/schema/old-xinclude.rnc | 11 + emacs/nxhtml/etc/schema/qtmstr-xhtml-old.rnc | 58 + emacs/nxhtml/etc/schema/qtmstr-xhtml.rnc | 66 + emacs/nxhtml/etc/schema/schema-path-patch.el | 95 + emacs/nxhtml/etc/schema/xinclude.rnc | 35 + emacs/nxhtml/etc/templates/rollover-2v.css | 25 + emacs/nxhtml/etc/uts39/idnchars.txt | 894 ++ emacs/nxhtml/etc/viper-tut/0intro | 59 + emacs/nxhtml/etc/viper-tut/1basics | 187 + emacs/nxhtml/etc/viper-tut/2moving | 269 + emacs/nxhtml/etc/viper-tut/3cutpaste | 318 + emacs/nxhtml/etc/viper-tut/4inserting | 180 + emacs/nxhtml/etc/viper-tut/5tricks | 229 + emacs/nxhtml/etc/viper-tut/README | 49 + emacs/nxhtml/etc/viper-tut/outline | 131 + emacs/nxhtml/nxhtml-base.el | 150 + emacs/nxhtml/nxhtml-loaddefs.el | 4490 +++++++ emacs/nxhtml/nxhtml-web-vcs.el | 689 ++ emacs/nxhtml/nxhtml/ChangeLog | 17 + emacs/nxhtml/nxhtml/doc/demo.html | 71 + emacs/nxhtml/nxhtml/doc/html2xhtml.html | 39 + .../nxhtml/doc/htmlfontify-example.html | 424 + emacs/nxhtml/nxhtml/doc/img/Las_Medulas.jpg | Bin 0 -> 40927 bytes emacs/nxhtml/nxhtml/doc/img/Toco_toucan.jpg | Bin 0 -> 17430 bytes emacs/nxhtml/nxhtml/doc/img/bacchante2.jpg | Bin 0 -> 67205 bytes emacs/nxhtml/nxhtml/doc/img/butterflies.jpg | Bin 0 -> 14954 bytes emacs/nxhtml/nxhtml/doc/img/butterflies.png | Bin 0 -> 65893 bytes emacs/nxhtml/nxhtml/doc/img/butterflies.xcf | Bin 0 -> 87456 bytes emacs/nxhtml/nxhtml/doc/img/continue-play.jpg | Bin 0 -> 44390 bytes emacs/nxhtml/nxhtml/doc/img/divine2.jpg | Bin 0 -> 69985 bytes emacs/nxhtml/nxhtml/doc/img/edit-part.png | Bin 0 -> 23263 bytes .../nxhtml/doc/img/editing-web-files.png | Bin 0 -> 7237 bytes .../nxhtml/doc/img/editing-web-files.xcf | Bin 0 -> 15415 bytes .../nxhtml/doc/img/emacs-style-completion.png | Bin 0 -> 23199 bytes emacs/nxhtml/nxhtml/doc/img/emacsP.png | Bin 0 -> 1882 bytes emacs/nxhtml/nxhtml/doc/img/emacsP16.png | Bin 0 -> 694 bytes emacs/nxhtml/nxhtml/doc/img/embedded-css.png | Bin 0 -> 14019 bytes .../nxhtml/nxhtml/doc/img/embedded-xhtml.png | Bin 0 -> 17326 bytes emacs/nxhtml/nxhtml/doc/img/foldit-closed.png | Bin 0 -> 7894 bytes .../nxhtml/doc/img/foldit-temp-opened.png | Bin 0 -> 17590 bytes emacs/nxhtml/nxhtml/doc/img/fun-brain-2.png | Bin 0 -> 40042 bytes .../nxhtml/nxhtml/doc/img/getitbuttons-1.png | Bin 0 -> 1931 bytes .../nxhtml/nxhtml/doc/img/getitbuttons-1.xcf | Bin 0 -> 5446 bytes .../nxhtml/nxhtml/doc/img/getitbuttons-2.png | Bin 0 -> 1276 bytes emacs/nxhtml/nxhtml/doc/img/getitbuttons.png | Bin 0 -> 1324 bytes emacs/nxhtml/nxhtml/doc/img/getitbuttons.xcf | Bin 0 -> 5988 bytes emacs/nxhtml/nxhtml/doc/img/giraffe.jpg | Bin 0 -> 20966 bytes emacs/nxhtml/nxhtml/doc/img/healthy_feet2.jpg | Bin 0 -> 24042 bytes .../nxhtml/nxhtml/doc/img/itsalltext-pref.png | Bin 0 -> 14720 bytes emacs/nxhtml/nxhtml/doc/img/links-appmenu.png | Bin 0 -> 7124 bytes emacs/nxhtml/nxhtml/doc/img/nxml-where.png | Bin 0 -> 17217 bytes .../nxhtml/nxhtml/doc/img/php-in-nxhtml-2.png | Bin 0 -> 23203 bytes emacs/nxhtml/nxhtml/doc/img/php-in-nxhtml.png | Bin 0 -> 22179 bytes emacs/nxhtml/nxhtml/doc/img/php-in-php.png | Bin 0 -> 21113 bytes emacs/nxhtml/nxhtml/doc/img/php-in-xhtml.png | Bin 0 -> 21510 bytes emacs/nxhtml/nxhtml/doc/img/popup-compl.png | Bin 0 -> 8709 bytes emacs/nxhtml/nxhtml/doc/img/raindrops2.jpg | Bin 0 -> 36480 bytes .../nxhtml/doc/img/region-selected-after.png | Bin 0 -> 3122 bytes .../doc/img/region-selected-completion.png | Bin 0 -> 27193 bytes .../nxhtml/nxhtml/doc/img/region-selected.png | Bin 0 -> 3662 bytes .../doc/img/rembrandt-self-portrait.jpg | Bin 0 -> 52583 bytes .../nxhtml/nxhtml/doc/img/style-in-nxhtml.png | Bin 0 -> 19275 bytes .../nxhtml/doc/img/use-nXhtml-trans.png | Bin 0 -> 1485 bytes .../nxhtml/doc/img/use-nXhtml-trans2.png | Bin 0 -> 1520 bytes emacs/nxhtml/nxhtml/doc/img/use-nXhtml.png | Bin 0 -> 1347 bytes emacs/nxhtml/nxhtml/doc/img/use-nXhtml.xcf | Bin 0 -> 3484 bytes .../nxhtml/doc/img/validation-error.png | Bin 0 -> 2293 bytes emacs/nxhtml/nxhtml/doc/img/volga.jpg | Bin 0 -> 34027 bytes .../nxhtml/doc/img/xml-validation-header.png | Bin 0 -> 23172 bytes .../doc/js/smoothgallery/css/img/carrow1.gif | Bin 0 -> 243 bytes .../doc/js/smoothgallery/css/img/carrow2.gif | Bin 0 -> 241 bytes .../doc/js/smoothgallery/css/img/fleche1.gif | Bin 0 -> 1035 bytes .../doc/js/smoothgallery/css/img/fleche1.png | Bin 0 -> 2626 bytes .../doc/js/smoothgallery/css/img/fleche2.gif | Bin 0 -> 974 bytes .../doc/js/smoothgallery/css/img/fleche2.png | Bin 0 -> 2889 bytes .../css/img/loading-bar-black.gif | Bin 0 -> 10814 bytes .../doc/js/smoothgallery/css/img/open.gif | Bin 0 -> 489 bytes .../doc/js/smoothgallery/css/img/open.png | Bin 0 -> 1258 bytes .../doc/js/smoothgallery/css/jd.gallery.css | 238 + .../doc/js/smoothgallery/css/layout.css | 91 + .../js/smoothgallery/scripts/jd.gallery.js | 449 + .../doc/js/smoothgallery/scripts/mootools.js | 2 + .../scripts/mootools.uncompressed.js | 4078 +++++++ emacs/nxhtml/nxhtml/doc/nxhtml-changes.html | 3395 ++++++ emacs/nxhtml/nxhtml/doc/nxhtml.css | 171 + emacs/nxhtml/nxhtml/doc/nxhtml.html | 987 ++ emacs/nxhtml/nxhtml/doc/wd/grapes/grapes.css | 107 + .../nxhtml/doc/wd/grapes/images/bkgrnd.gif | Bin 0 -> 974 bytes .../nxhtml/doc/wd/grapes/images/grapes.jpg | Bin 0 -> 24419 bytes .../nxhtml/doc/wd/grapes/images/quote.gif | Bin 0 -> 643 bytes emacs/nxhtml/nxhtml/doc/wd/grapes/index.html | 76 + .../nxhtml/doc/wd/grapes/nxhtml-grapes.css | 252 + emacs/nxhtml/nxhtml/doc/working-demo.html | 60 + emacs/nxhtml/nxhtml/html-chklnk.el | 168 + .../html-chklnk/PerlLib/HTML/LinkWalker.pm | 774 ++ .../html-chklnk/PerlLib/HTML/ParserTagEnd.pm | 448 + .../html-chklnk/PerlLib/HTML/datadir.txt | 1 + .../nxhtml/html-chklnk/PerlLib/PathSubs.pm | 207 + .../nxhtml/nxhtml/html-chklnk/link_checker.pl | 328 + emacs/nxhtml/nxhtml/html-imenu.el | 101 + emacs/nxhtml/nxhtml/html-move.el | 251 + emacs/nxhtml/nxhtml/html-pagetoc.el | 336 + emacs/nxhtml/nxhtml/html-quote.el | 71 + emacs/nxhtml/nxhtml/html-site.el | 801 ++ emacs/nxhtml/nxhtml/html-toc.el | 363 + .../nxhtml/html-toc/html-toc-template.html | 83 + .../html-toc/html-toc/html-toc-template.css | 141 + .../nxhtml/html-toc/html-toc/html-toc.css | 84 + .../nxhtml/html-toc/html-toc/html-toc.js | 361 + .../nxhtml/html-toc/html-toc/img/blank12.gif | Bin 0 -> 825 bytes .../nxhtml/html-toc/html-toc/img/down.gif | Bin 0 -> 853 bytes .../nxhtml/html-toc/html-toc/img/freeCont.gif | Bin 0 -> 913 bytes .../html-toc/html-toc/img/gnu-m-x-160.png | Bin 0 -> 1957 bytes .../html-toc/html-toc/img/gnu-m-x-160.xcf | Bin 0 -> 22466 bytes .../nxhtml/html-toc/html-toc/img/hideCont.gif | Bin 0 -> 917 bytes .../nxhtml/html-toc/html-toc/img/nailCont.gif | Bin 0 -> 917 bytes .../nxhtml/html-toc/html-toc/img/nosearch.gif | Bin 0 -> 1100 bytes .../nxhtml/html-toc/html-toc/img/right.gif | Bin 0 -> 857 bytes .../nxhtml/html-toc/html-toc/img/search.gif | Bin 0 -> 1118 bytes .../nxhtml/html-toc/html-toc/img/showCont.gif | Bin 0 -> 909 bytes emacs/nxhtml/nxhtml/html-upl.el | 329 + emacs/nxhtml/nxhtml/html-upl/COPYING | 340 + emacs/nxhtml/nxhtml/html-upl/Changes | 115 + emacs/nxhtml/nxhtml/html-upl/README | 111 + emacs/nxhtml/nxhtml/html-upl/TODO | 2 + emacs/nxhtml/nxhtml/html-upl/ftpsync.pl | 700 ++ emacs/nxhtml/nxhtml/html-wtoc.el | 200 + .../nxhtml/html-wtoc/PerlLib/PathSubs.pm | 207 + .../nxhtml/html-wtoc/PerlLib/html_tags.pm | 127 + .../nxhtml/html-wtoc/html-wtoc-template.css | 141 + .../nxhtml/html-wtoc/html-wtoc-template.html | 143 + emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.css | 84 + emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.js | 361 + emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.pl | 1395 +++ emacs/nxhtml/nxhtml/html-wtoc/img/blank12.gif | Bin 0 -> 825 bytes emacs/nxhtml/nxhtml/html-wtoc/img/down.gif | Bin 0 -> 853 bytes .../nxhtml/nxhtml/html-wtoc/img/freeCont.gif | Bin 0 -> 913 bytes .../nxhtml/html-wtoc/img/gnu-m-x-160.png | Bin 0 -> 1957 bytes .../nxhtml/html-wtoc/img/gnu-m-x-160.xcf | Bin 0 -> 22466 bytes .../nxhtml/nxhtml/html-wtoc/img/hideCont.gif | Bin 0 -> 917 bytes .../nxhtml/nxhtml/html-wtoc/img/nailCont.gif | Bin 0 -> 917 bytes .../nxhtml/nxhtml/html-wtoc/img/nosearch.gif | Bin 0 -> 1100 bytes .../html-wtoc/img/other/CompFaceLogoTemp4.gif | Bin 0 -> 3202 bytes .../html-wtoc/img/other/CompFaceLogoTemp4.png | Bin 0 -> 6710 bytes .../html-wtoc/img/other/blue_left_top.png | Bin 0 -> 381 bytes .../html-wtoc/img/other/close-cross.gif | Bin 0 -> 866 bytes .../html-wtoc/img/other/lbiinfo_and_blue.png | Bin 0 -> 3763 bytes .../html-wtoc/img/other/lbiinfo_and_blue1.png | Bin 0 -> 4012 bytes .../html-wtoc/img/other/lbinfo_col1.gif | Bin 0 -> 3732 bytes .../html-wtoc/img/other/lbinfo_col1_30.gif | Bin 0 -> 1299 bytes .../nxhtml/nxhtml/html-wtoc/img/other/up.gif | Bin 0 -> 851 bytes emacs/nxhtml/nxhtml/html-wtoc/img/right.gif | Bin 0 -> 857 bytes emacs/nxhtml/nxhtml/html-wtoc/img/search.gif | Bin 0 -> 1118 bytes .../nxhtml/nxhtml/html-wtoc/img/showCont.gif | Bin 0 -> 909 bytes emacs/nxhtml/nxhtml/nxhtml-autoload.el | 147 + emacs/nxhtml/nxhtml/nxhtml-bug.el | 332 + emacs/nxhtml/nxhtml/nxhtml-menu.el | 1658 +++ emacs/nxhtml/nxhtml/nxhtml-mode.el | 2796 +++++ emacs/nxhtml/nxhtml/nxhtml-mumamo.el | 365 + emacs/nxhtml/nxhtml/nxhtml-strval.el | 210 + emacs/nxhtml/nxhtml/nxhtml.el | 339 + emacs/nxhtml/nxhtml/nxhtmljs.el | 240 + emacs/nxhtml/nxhtml/nxml-where.el | 734 ++ emacs/nxhtml/nxhtml/outline-magic.el | 588 + emacs/nxhtml/nxhtml/rngalt.el | 828 ++ emacs/nxhtml/nxhtml/tidy-xhtml.el | 2921 +++++ emacs/nxhtml/nxhtml/wtest.el | 56 + emacs/nxhtml/nxhtml/xhtml-help.el | 373 + emacs/nxhtml/nxhtmlmaint.el | 439 + emacs/nxhtml/related/blank.html | 6 + emacs/nxhtml/related/csharp-mode.el | 1977 +++ emacs/nxhtml/related/django.el | 203 + emacs/nxhtml/related/env.js | 695 ++ emacs/nxhtml/related/flymake-css.el | 161 + emacs/nxhtml/related/flymake-helpers.el | 78 + emacs/nxhtml/related/flymake-java-1.el | 109 + emacs/nxhtml/related/flymake-js.el | 234 + emacs/nxhtml/related/flymakemsg.el | 144 + emacs/nxhtml/related/flymu.el | 157 + emacs/nxhtml/related/iss-mode.el | 205 + emacs/nxhtml/related/iss-mumamo.el | 70 + emacs/nxhtml/related/js_temp.js | 4 + emacs/nxhtml/related/jslint.js | 523 + emacs/nxhtml/related/moz.el | 289 + emacs/nxhtml/related/mozadd.el | 369 + emacs/nxhtml/related/php-imenu.el | 174 + emacs/nxhtml/related/php-mode.el | 1231 ++ emacs/nxhtml/related/readme.txt | 7 + emacs/nxhtml/related/rhino.js | 14 + emacs/nxhtml/related/smarty-mode.el | 2753 +++++ emacs/nxhtml/related/tt-mode.el | 124 + emacs/nxhtml/related/visual-basic-mode.el | 1263 ++ emacs/nxhtml/related/wikipedia-mode.el | 2296 ++++ emacs/nxhtml/tests/angus77-setup-jde.el | 90 + emacs/nxhtml/tests/emacstest-suites.el | 102 + emacs/nxhtml/tests/ert.el | 2418 ++++ emacs/nxhtml/tests/ert2.el | 268 + emacs/nxhtml/tests/hfy-test.el | 102 + emacs/nxhtml/tests/in/3-heights.html | 42 + emacs/nxhtml/tests/in/400415-index.phtml | 43 + emacs/nxhtml/tests/in/asp.asp | 40 + emacs/nxhtml/tests/in/bastien-test.mm | 38 + .../tests/in/bigfile-stringerr-64000.html | 1850 +++ emacs/nxhtml/tests/in/blorgit.rb | 313 + emacs/nxhtml/tests/in/bug-080609.html | 9 + emacs/nxhtml/tests/in/bug-1908494.php | 6 + .../nxhtml/tests/in/bug-2010-02-17-delgado.mm | 10 + .../tests/in/bug-2010-02-17-delgado.org | 3 + emacs/nxhtml/tests/in/bug-290364.php | 66 + emacs/nxhtml/tests/in/bug-300946-index.html | 24 + emacs/nxhtml/tests/in/bug-311640-index.html | 24 + emacs/nxhtml/tests/in/bug-311641.php | 7 + .../nxhtml/tests/in/bug-373106-flipbook.html | 160 + emacs/nxhtml/tests/in/bug-381191-dh-test.el | 23 + emacs/nxhtml/tests/in/bug-381191-dh-test.php | 6 + .../tests/in/bug-johan-2010-02-12.rhtml | 22 + .../tests/in/bug-johan-2010-02-16.html.haml | 34 + .../tests/in/bug-johan-2010-02-17-2.erb | 14 + .../nxhtml/tests/in/bug-johan-2010-02-17.erb | 4 + emacs/nxhtml/tests/in/bug261792.ghtml | 7 + emacs/nxhtml/tests/in/bug271497.el | 14 + emacs/nxhtml/tests/in/bug271497.txt | 7 + emacs/nxhtml/tests/in/bug272871.php | 7 + emacs/nxhtml/tests/in/bug290364-messages.txt | 97 + emacs/nxhtml/tests/in/bug354363-index.php | 38 + emacs/nxhtml/tests/in/bug354363-test.php | 3 + .../tests/in/bug369800-load-history.txt | 9483 +++++++++++++++ emacs/nxhtml/tests/in/bug370417.php | 10 + .../tests/in/bug381979-2-bad-traceb.txt | 24 + emacs/nxhtml/tests/in/bug381979-2.php | 6 + emacs/nxhtml/tests/in/bug381979-svnlib.inc | 744 ++ emacs/nxhtml/tests/in/bug384115-bt2.txt | 11 + emacs/nxhtml/tests/in/bug388729-messages.txt | 292 + .../nxhtml/tests/in/bug388729-nxhtml_test.php | 2 + emacs/nxhtml/tests/in/bug393137-new.html.erb | 18 + emacs/nxhtml/tests/in/bug400415-foo.php | 9 + emacs/nxhtml/tests/in/bug400415-foo2.php | 9 + emacs/nxhtml/tests/in/bug409183.html | 14 + emacs/nxhtml/tests/in/bug416505-Body.mxml | 85 + emacs/nxhtml/tests/in/bug416505-nxhtml.el | 45 + emacs/nxhtml/tests/in/bug452676.php | 12 + emacs/nxhtml/tests/in/bug463136.php | 5 + emacs/nxhtml/tests/in/bug492366-test.php | 21 + .../nxhtml/tests/in/bug495770-heredoc_demo.pl | 95 + .../in/bug505554-nxhtml-download-messages.txt | 98 + .../nxhtml/tests/in/bug505554-sample.html.erb | 11 + emacs/nxhtml/tests/in/bug505726-foo.html | 10 + emacs/nxhtml/tests/in/bug509586.ghtml | 16 + emacs/nxhtml/tests/in/bug523065.jsp | 9 + emacs/nxhtml/tests/in/bug523065.php | 6 + .../nxhtml/tests/in/bug529133-statemachine.py | 1491 +++ emacs/nxhtml/tests/in/bug531328.rhtml | 1 + emacs/nxhtml/tests/in/bug532500.rhtml | 7 + emacs/nxhtml/tests/in/bug532759.djhtml | 17 + emacs/nxhtml/tests/in/bug546027.html | 17 + .../nxhtml/tests/in/bug552789-loremipsum.php | 10 + emacs/nxhtml/tests/in/bug552789.php | 20 + emacs/nxhtml/tests/in/bug556832-error-test.py | 23 + emacs/nxhtml/tests/in/bug557700-2.erb | 5 + emacs/nxhtml/tests/in/bug557700-3.erb | 3 + emacs/nxhtml/tests/in/bug557700-4.erb | 11 + emacs/nxhtml/tests/in/bug557700-5.erb | 4 + emacs/nxhtml/tests/in/bug557700-6.erb | 11 + emacs/nxhtml/tests/in/bug557700.erb | 3 + .../nxhtml/tests/in/bug559772-TextHelper.php | 205 + emacs/nxhtml/tests/in/bug565595.mako | 12 + emacs/nxhtml/tests/in/bug568178.pl | 4 + emacs/nxhtml/tests/in/bug568178.sh | 9 + .../nxhtml/tests/in/bug569742-master-end.html | 37 + .../tests/in/ch-2008-07-25-test.html.erb | 37 + emacs/nxhtml/tests/in/chunks-in-chunks1.php | 19 + emacs/nxhtml/tests/in/chunks.html | 63 + emacs/nxhtml/tests/in/cr-lf.el | 2 + emacs/nxhtml/tests/in/csr-080710-2.html | 23 + emacs/nxhtml/tests/in/csr-080710.html | 24 + emacs/nxhtml/tests/in/cvd-080805-ac.php | 21 + emacs/nxhtml/tests/in/cvd-080805-cc.php | 18 + .../tests/in/drechsler-080517-simple.xml | 3 + emacs/nxhtml/tests/in/el-070424-duh.xml | 6 + emacs/nxhtml/tests/in/el-070511-simple.html | 102 + emacs/nxhtml/tests/in/el-070602-index.php | 54 + emacs/nxhtml/tests/in/el-070604.html | 11 + emacs/nxhtml/tests/in/el-070604.php | 11 + .../tests/in/el-070722-comment-error.php | 6 + emacs/nxhtml/tests/in/el-070722-index-2.el | 7 + emacs/nxhtml/tests/in/el-070722-index-2.php | 48 + .../tests/in/el-070722-index-noheader.php | 48 + emacs/nxhtml/tests/in/el-070722-index.php | 55 + emacs/nxhtml/tests/in/el-071217-foo.html | 13 + emacs/nxhtml/tests/in/emacswiki-080119.php | 15 + emacs/nxhtml/tests/in/emacswiki-erb-bug.el | 36 + emacs/nxhtml/tests/in/err-line38.html | 768 ++ emacs/nxhtml/tests/in/eval-in-html.el | Bin 0 -> 22420 bytes emacs/nxhtml/tests/in/fontif-err.html | 339 + emacs/nxhtml/tests/in/fontif-err.php | 339 + .../tests/in/genshi-HelloWorldPage.ghtml | 10 + emacs/nxhtml/tests/in/genshi-auto-mode.html | 10 + emacs/nxhtml/tests/in/genshi.ghtml | 23 + .../tests/in/goesele-091110-testnote-orig.mm | 16 + .../tests/in/goesele-091110-testnote-temp.mm | 16 + .../tests/in/goesele-091110-testnote.mm | 16 + .../tests/in/goesele-091110-testnote.mm.org | 5 + .../in/goesele-091110-testnote.mm.org.mm | 16 + emacs/nxhtml/tests/in/haml1.haml | 132 + emacs/nxhtml/tests/in/heredoc.php | 61 + emacs/nxhtml/tests/in/heredoc.pl | 11 + emacs/nxhtml/tests/in/heredoc.py | 11 + emacs/nxhtml/tests/in/heredoc.rb | 8 + emacs/nxhtml/tests/in/heredoc.sh | 4 + .../nxhtml/tests/in/hg-2008-03-22-ajax.xhtml | 38 + emacs/nxhtml/tests/in/hq-070510-test.php | 12 + emacs/nxhtml/tests/in/hq-070510-test.php.html | 44 + emacs/nxhtml/tests/in/hq-070524-bug.php | 10 + emacs/nxhtml/tests/in/hq-071006-index.php | 38 + .../tests/in/html-syntactic-err-l164.html | 1474 +++ emacs/nxhtml/tests/in/ind-0-error.php | 28 + .../nxhtml/tests/in/indent-bug-html-mode.html | 18 + emacs/nxhtml/tests/in/java.java | 13 + .../nxhtml/tests/in/jcl-080802-index.html.erb | 16 + .../in/jcl-080802-messages_controller.rb | 57 + emacs/nxhtml/tests/in/jj-081226.html | 26 + .../tests/in/josh-091115-cancer_summary.xsl | 490 + emacs/nxhtml/tests/in/jump-parse.html | 7 + emacs/nxhtml/tests/in/jump-parse.rhtml | 9 + emacs/nxhtml/tests/in/kp-080604.php | 4 + .../tests/in/kubica-080516-freezing-1.html | 13 + .../tests/in/kubica-080516-freezing-2.html | 174 + .../tests/in/kubica-080516-freezing-2j.html | 174 + .../tests/in/kubica-080516-freezing-3.html | 61 + .../tests/in/kubica-080516-freezing-4.html | 58 + .../tests/in/kubica-080516-freezing-5.html | 20 + .../tests/in/kubica-080516-freezing-6.html | 58 + .../tests/in/kubica-080516-freezing-7.html | 56 + .../tests/in/kubica-080516-freezing-8.html | 57 + .../tests/in/kubica-080516-freezing-9.html | 57 + .../in/kubica-080516-freezing-a-notabs.html | 57 + .../tests/in/kubica-080516-freezing-a.html | 57 + .../tests/in/kubica-080516-freezing-b.html | 55 + .../tests/in/kubica-080516-freezing-c.html | 52 + .../tests/in/kubica-080516-freezing-d.html | 51 + .../tests/in/kubica-080516-freezing-e.html | 50 + .../tests/in/kubica-080516-freezing-f.html | 49 + .../tests/in/kubica-080516-freezing-g.html | 39 + .../tests/in/kubica-080516-freezing-h.html | 27 + .../tests/in/kubica-080516-freezing-i.html | 19 + .../tests/in/kubica-080516-freezing-j.html | 19 + .../tests/in/kubica-080516-freezing-k.html | 19 + .../tests/in/kubica-080516-freezing.css | 36 + .../tests/in/kubica-080516-freezing.html | 174 + .../tests/in/kubica-080516-freezing.txt | 10 + emacs/nxhtml/tests/in/kwalo-080930.php | 23 + .../tests/in/latex-clojre-mumamo-test.lclj | 17 + emacs/nxhtml/tests/in/lg-080813-div.html | 16 + emacs/nxhtml/tests/in/lg-080813-label.html | 15 + emacs/nxhtml/tests/in/long-lines.txt | 1 + emacs/nxhtml/tests/in/markdown.markdown | 16 + emacs/nxhtml/tests/in/mason.mason | 46 + emacs/nxhtml/tests/in/menu-err.txt | 10 + emacs/nxhtml/tests/in/mjt-feed.html | 86 + emacs/nxhtml/tests/in/mjt-imagesearch.html | 46 + emacs/nxhtml/tests/in/mjt-minimal.html | 11 + emacs/nxhtml/tests/in/mumamo-and-org.org | 20 + emacs/nxhtml/tests/in/mumamo-and-org.org.mm | 45 + emacs/nxhtml/tests/in/ng-080309-read-url.html | 11 + emacs/nxhtml/tests/in/no-php-end-2.php | 18 + .../nxhtml/tests/in/no-php-end-2.php-log.txt | 312 + .../nxhtml/tests/in/no-php-end-2.php-log2.txt | 238 + emacs/nxhtml/tests/in/no-php-end-3.php | 18 + emacs/nxhtml/tests/in/no-php-end-4.php | 18 + emacs/nxhtml/tests/in/no-php-end.php | 4 + emacs/nxhtml/tests/in/nojump-parse.html | 9 + emacs/nxhtml/tests/in/noweb1.now | 38 + emacs/nxhtml/tests/in/nutshell.mako | 27 + emacs/nxhtml/tests/in/nxml-bug.html | 11 + emacs/nxhtml/tests/in/nxml-indent-2.html | 134 + emacs/nxhtml/tests/in/nxml-indent-3.html | 134 + emacs/nxhtml/tests/in/nxml-indent-noerr1.html | 192 + emacs/nxhtml/tests/in/nxml-indent.el | 1 + emacs/nxhtml/tests/in/nxml-indent.html | 192 + emacs/nxhtml/tests/in/only-html.html | 11 + emacs/nxhtml/tests/in/only-php.php | 10 + emacs/nxhtml/tests/in/pavel-071116.djhtml | 31 + emacs/nxhtml/tests/in/php-parseable.php | 11 + emacs/nxhtml/tests/in/question43320.html | 35 + .../tests/in/question44504-folding.html | 28 + emacs/nxhtml/tests/in/question49234.sh | 41 + .../nxhtml/tests/in/rgr-030809-indexbody.php | 57 + emacs/nxhtml/tests/in/rgr-080307.php | 2 + emacs/nxhtml/tests/in/rgr-080308-header-2.php | 56 + emacs/nxhtml/tests/in/rgr-080308-header.php | 56 + .../nxhtml/tests/in/rgr-080308-indexbody.php | 57 + emacs/nxhtml/tests/in/rr-090524-header.php | 76 + emacs/nxhtml/tests/in/rr-090923-header.php | 101 + emacs/nxhtml/tests/in/rr-address-090304.php | 4 + emacs/nxhtml/tests/in/rr-address-nxhtml.err | Bin 0 -> 6647 bytes emacs/nxhtml/tests/in/rr-min8.php | 6 + emacs/nxhtml/tests/in/ryan-091104-literal.tpl | 148 + .../tests/in/ryan-091111-wrong-side.tpl | 18 + emacs/nxhtml/tests/in/schemas.xml | 3 + emacs/nxhtml/tests/in/sd-080803-test.php | 14 + emacs/nxhtml/tests/in/senny-091118.htm | 247 + emacs/nxhtml/tests/in/sheit-2007-12-26.php | 9 + emacs/nxhtml/tests/in/short-tags.php | 3 + .../nxhtml/tests/in/single-question-sign.html | 11 + emacs/nxhtml/tests/in/ssjs.ssjs | 9 + emacs/nxhtml/tests/in/string-bug.php | 1 + emacs/nxhtml/tests/in/style=.html | 12 + emacs/nxhtml/tests/in/style=string-font.html | 18 + emacs/nxhtml/tests/in/svg.svg | 1 + emacs/nxhtml/tests/in/temp2.php | 48 + emacs/nxhtml/tests/in/temp3.html | 44 + emacs/nxhtml/tests/in/test-only-nxml.my-xhtml | 38 + emacs/nxhtml/tests/in/test.tt | 11 + emacs/nxhtml/tests/in/tut1.jsp | 5 + emacs/nxhtml/tests/in/utf8-problem.el | 7 + emacs/nxhtml/tests/in/wiki-080606-indent.php | 18 + .../tests/in/wiki-080708-ind-problem.rhtml | 5 + emacs/nxhtml/tests/in/wiki-090804-js.html | 32 + emacs/nxhtml/tests/in/wiki-2008-01-30.rhtml | 1 + emacs/nxhtml/tests/in/wiki-comments.php | 20 + .../tests/in/wiki-strange-hili-080629.html | 5 + emacs/nxhtml/tests/in/xml-as-string.php | 54 + .../in/ygne-2008-02-07-hotproperty.html.php | 1967 +++ emacs/nxhtml/tests/in/zero-pi.html | 11 + .../nxhtml/tests/in/zn-090529-doxysample.php | 37 + emacs/nxhtml/tests/inemacs/bug1013.el | 35 + emacs/nxhtml/tests/mumamo-test.el | 299 + emacs/nxhtml/tests/nxhtmltest-Q.el | 114 + emacs/nxhtml/tests/nxhtmltest-helpers.el | 156 + emacs/nxhtml/tests/nxhtmltest-suites.el | 632 + emacs/nxhtml/util/anchored-transpose.el | 305 + emacs/nxhtml/util/appmenu-fold.el | 79 + emacs/nxhtml/util/appmenu.el | 523 + emacs/nxhtml/util/as-external.el | 310 + emacs/nxhtml/util/buffer-bg.el | 89 + emacs/nxhtml/util/chartg.el | 844 ++ emacs/nxhtml/util/css-color.el | 983 ++ emacs/nxhtml/util/css-palette.el | 471 + emacs/nxhtml/util/css-simple-completion.el | 238 + emacs/nxhtml/util/cus-new-user.el | 803 ++ emacs/nxhtml/util/custsets.el | 83 + emacs/nxhtml/util/ecb-batch-compile.el | 65 + emacs/nxhtml/util/ediff-url.el | 188 + emacs/nxhtml/util/ffip.el | 304 + emacs/nxhtml/util/fold-dwim.el | 466 + emacs/nxhtml/util/foldit.el | 357 + emacs/nxhtml/util/fupd.el | 127 + emacs/nxhtml/util/gimpedit.el | 172 + emacs/nxhtml/util/gpl.el | 213 + emacs/nxhtml/util/hfyview.el | 651 + emacs/nxhtml/util/hl-needed.el | 402 + emacs/nxhtml/util/html-write.el | 455 + emacs/nxhtml/util/idn.el | 151 + emacs/nxhtml/util/inlimg.el | 429 + emacs/nxhtml/util/key-cat.el | 329 + emacs/nxhtml/util/majmodpri.el | 448 + emacs/nxhtml/util/markchars.el | 151 + emacs/nxhtml/util/mlinks.el | 1367 +++ emacs/nxhtml/util/mumamo-aspnet.el | 227 + emacs/nxhtml/util/mumamo-fun.el | 3333 +++++ emacs/nxhtml/util/mumamo-regions.el | 311 + emacs/nxhtml/util/mumamo-trace.el | 6 + emacs/nxhtml/util/mumamo.el | 9100 ++++++++++++++ emacs/nxhtml/util/n-back.el | 1296 ++ emacs/nxhtml/util/new-key-seq-widget.el | 312 + emacs/nxhtml/util/nxml-mode-os-additions.el | 99 + emacs/nxhtml/util/ocr-user.el | 86 + emacs/nxhtml/util/org-panel.el | 745 ++ emacs/nxhtml/util/ourcomments-util.el | 2427 ++++ emacs/nxhtml/util/ourcomments-widgets.el | 141 + emacs/nxhtml/util/pause.el | 794 ++ emacs/nxhtml/util/pointback.el | 93 + emacs/nxhtml/util/popcmp.el | 472 + emacs/nxhtml/util/readme.txt | 3 + emacs/nxhtml/util/rebind.el | 240 + emacs/nxhtml/util/rnc-mode.el | 265 + emacs/nxhtml/util/rxi.el | 148 + emacs/nxhtml/util/search-form.el | 473 + emacs/nxhtml/util/sex-mode.el | 463 + emacs/nxhtml/util/sml-modeline.el | 192 + emacs/nxhtml/util/tabkey2.el | 1701 +++ emacs/nxhtml/util/tyda.el | 94 + emacs/nxhtml/util/udev-ecb.el | 229 + emacs/nxhtml/util/udev-rinari.el | 204 + emacs/nxhtml/util/udev.el | 456 + emacs/nxhtml/util/useful-commands.el | 63 + emacs/nxhtml/util/viper-tut.el | 1009 ++ emacs/nxhtml/util/vline.el | 350 + emacs/nxhtml/util/web-vcs-revision.txt | 1 + emacs/nxhtml/util/whelp.el | 988 ++ emacs/nxhtml/util/winsav.el | 1585 +++ emacs/nxhtml/util/winsize.el | 1173 ++ emacs/nxhtml/util/wrap-to-fill.el | 364 + emacs/nxhtml/util/zencoding-mode.el | 801 ++ emacs/nxhtml/web-autoload.el | 262 + emacs/nxhtml/web-vcs.el | 2069 ++++ emacs/paredit.el | 2149 ++++ emacs/pastebin.el | 190 + emacs/pbook.el | 932 ++ emacs/quack.el | 4742 ++++++++ emacs/rainbow-mode.el | 207 + emacs/redo.el | 203 + emacs/scheme-complete.el | 4115 +++++++ emacs/scheme48.el | 397 + emacs/screencast.el | 778 ++ emacs/sml-mode.el | 1901 +++ emacs/solarized-theme.el | 4 + emacs/solarized.el | 1096 ++ emacs/sql-complete.el | 105 + emacs/sunrise-commander.el | 4247 +++++++ emacs/twittering-mode | 1 + emacs/verilog-mode.el | 10137 ++++++++++++++++ emacs/xcscope.el | 2463 ++++ emacs/xml-rpc.el | 865 ++ init.el | 35 +- themes/solarized | 1 + themes/solarized-dark-theme.el | 7 + themes/solarized-light-theme.el | 7 + themes/zenburn | 1 + themes/zenburn-theme.el | 811 ++ vendor/haskell-mode | 1 + vendor/swank-js | 1 + 567 files changed, 180489 insertions(+), 30 deletions(-) create mode 100644 emacs/ac-python.el create mode 100644 emacs/basic-mode.el create mode 100644 emacs/cldoc.el create mode 100644 emacs/espresso.el create mode 100644 emacs/flyspell.el create mode 100644 emacs/gambit.el create mode 100644 emacs/gist.el create mode 100644 emacs/graphviz-dot-mode.el create mode 100644 emacs/highlight-parentheses.el create mode 100644 emacs/javascript.el create mode 100644 emacs/lacarte.el create mode 100644 emacs/ll-debug.el create mode 100644 emacs/malyon.el create mode 100644 emacs/maxframe.el create mode 100644 emacs/moz.el create mode 100644 emacs/my-c-mode.el create mode 100644 emacs/my-erc.el create mode 100644 emacs/my-generic-stuff.el create mode 100644 emacs/my-haskell.el create mode 100644 emacs/my-org-mode.el create mode 100644 emacs/my-python.el create mode 100644 emacs/my-search.el create mode 100644 emacs/my-slime.el create mode 100644 emacs/my-swank-js.el create mode 100644 emacs/my-twitter.el create mode 100644 emacs/naquadah-theme.el create mode 100644 emacs/notify.el create mode 100644 emacs/nxhtml/README.txt create mode 100644 emacs/nxhtml/alts/find-recursive-orig.el create mode 100644 emacs/nxhtml/alts/javascript-mozlab.el create mode 100644 emacs/nxhtml/alts/smarty-mode-vdebout.el create mode 100644 emacs/nxhtml/autostart.el create mode 100644 emacs/nxhtml/autostart22.el create mode 100644 emacs/nxhtml/emacs22.cmd create mode 100644 emacs/nxhtml/etc/img/pause/pause.jpg create mode 100644 emacs/nxhtml/etc/img/pause/pause2.jpg create mode 100644 emacs/nxhtml/etc/schema/FDA-2009-N-0392-0396.1.doc create mode 100644 emacs/nxhtml/etc/schema/genshi-old.rnc create mode 100644 emacs/nxhtml/etc/schema/genshi-schemas.xml create mode 100644 emacs/nxhtml/etc/schema/genshi.rnc create mode 100644 emacs/nxhtml/etc/schema/mjt.rnc create mode 100644 emacs/nxhtml/etc/schema/nxml-erb.patch create mode 100644 emacs/nxhtml/etc/schema/old-genshi.rnc create mode 100644 emacs/nxhtml/etc/schema/old-qtmstr-xhtml.rnc create mode 100644 emacs/nxhtml/etc/schema/old-xinclude.rnc create mode 100644 emacs/nxhtml/etc/schema/qtmstr-xhtml-old.rnc create mode 100644 emacs/nxhtml/etc/schema/qtmstr-xhtml.rnc create mode 100644 emacs/nxhtml/etc/schema/schema-path-patch.el create mode 100644 emacs/nxhtml/etc/schema/xinclude.rnc create mode 100644 emacs/nxhtml/etc/templates/rollover-2v.css create mode 100644 emacs/nxhtml/etc/uts39/idnchars.txt create mode 100644 emacs/nxhtml/etc/viper-tut/0intro create mode 100644 emacs/nxhtml/etc/viper-tut/1basics create mode 100644 emacs/nxhtml/etc/viper-tut/2moving create mode 100644 emacs/nxhtml/etc/viper-tut/3cutpaste create mode 100644 emacs/nxhtml/etc/viper-tut/4inserting create mode 100644 emacs/nxhtml/etc/viper-tut/5tricks create mode 100644 emacs/nxhtml/etc/viper-tut/README create mode 100644 emacs/nxhtml/etc/viper-tut/outline create mode 100644 emacs/nxhtml/nxhtml-base.el create mode 100644 emacs/nxhtml/nxhtml-loaddefs.el create mode 100644 emacs/nxhtml/nxhtml-web-vcs.el create mode 100644 emacs/nxhtml/nxhtml/ChangeLog create mode 100644 emacs/nxhtml/nxhtml/doc/demo.html create mode 100644 emacs/nxhtml/nxhtml/doc/html2xhtml.html create mode 100644 emacs/nxhtml/nxhtml/doc/htmlfontify-example.html create mode 100644 emacs/nxhtml/nxhtml/doc/img/Las_Medulas.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/Toco_toucan.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/bacchante2.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/butterflies.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/butterflies.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/butterflies.xcf create mode 100644 emacs/nxhtml/nxhtml/doc/img/continue-play.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/divine2.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/edit-part.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/editing-web-files.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/editing-web-files.xcf create mode 100644 emacs/nxhtml/nxhtml/doc/img/emacs-style-completion.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/emacsP.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/emacsP16.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/embedded-css.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/embedded-xhtml.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/foldit-closed.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/foldit-temp-opened.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/fun-brain-2.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/getitbuttons-1.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/getitbuttons-1.xcf create mode 100644 emacs/nxhtml/nxhtml/doc/img/getitbuttons-2.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/getitbuttons.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/getitbuttons.xcf create mode 100644 emacs/nxhtml/nxhtml/doc/img/giraffe.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/healthy_feet2.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/itsalltext-pref.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/links-appmenu.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/nxml-where.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/php-in-nxhtml-2.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/php-in-nxhtml.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/php-in-php.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/php-in-xhtml.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/popup-compl.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/raindrops2.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/region-selected-after.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/region-selected-completion.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/region-selected.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/rembrandt-self-portrait.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/style-in-nxhtml.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/use-nXhtml-trans.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/use-nXhtml-trans2.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/use-nXhtml.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/use-nXhtml.xcf create mode 100644 emacs/nxhtml/nxhtml/doc/img/validation-error.png create mode 100644 emacs/nxhtml/nxhtml/doc/img/volga.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/img/xml-validation-header.png create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/carrow1.gif create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/carrow2.gif create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche1.gif create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche1.png create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche2.gif create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche2.png create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/loading-bar-black.gif create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/open.gif create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/open.png create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/jd.gallery.css create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/layout.css create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/jd.gallery.js create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.js create mode 100644 emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.uncompressed.js create mode 100644 emacs/nxhtml/nxhtml/doc/nxhtml-changes.html create mode 100644 emacs/nxhtml/nxhtml/doc/nxhtml.css create mode 100644 emacs/nxhtml/nxhtml/doc/nxhtml.html create mode 100644 emacs/nxhtml/nxhtml/doc/wd/grapes/grapes.css create mode 100644 emacs/nxhtml/nxhtml/doc/wd/grapes/images/bkgrnd.gif create mode 100644 emacs/nxhtml/nxhtml/doc/wd/grapes/images/grapes.jpg create mode 100644 emacs/nxhtml/nxhtml/doc/wd/grapes/images/quote.gif create mode 100644 emacs/nxhtml/nxhtml/doc/wd/grapes/index.html create mode 100644 emacs/nxhtml/nxhtml/doc/wd/grapes/nxhtml-grapes.css create mode 100644 emacs/nxhtml/nxhtml/doc/working-demo.html create mode 100644 emacs/nxhtml/nxhtml/html-chklnk.el create mode 100644 emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/LinkWalker.pm create mode 100644 emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/ParserTagEnd.pm create mode 100644 emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/datadir.txt create mode 100644 emacs/nxhtml/nxhtml/html-chklnk/PerlLib/PathSubs.pm create mode 100644 emacs/nxhtml/nxhtml/html-chklnk/link_checker.pl create mode 100644 emacs/nxhtml/nxhtml/html-imenu.el create mode 100644 emacs/nxhtml/nxhtml/html-move.el create mode 100644 emacs/nxhtml/nxhtml/html-pagetoc.el create mode 100644 emacs/nxhtml/nxhtml/html-quote.el create mode 100644 emacs/nxhtml/nxhtml/html-site.el create mode 100644 emacs/nxhtml/nxhtml/html-toc.el create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc-template.html create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc-template.css create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.css create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.js create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/blank12.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/down.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/freeCont.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/gnu-m-x-160.png create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/gnu-m-x-160.xcf create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/hideCont.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/nailCont.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/nosearch.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/right.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/search.gif create mode 100644 emacs/nxhtml/nxhtml/html-toc/html-toc/img/showCont.gif create mode 100644 emacs/nxhtml/nxhtml/html-upl.el create mode 100644 emacs/nxhtml/nxhtml/html-upl/COPYING create mode 100644 emacs/nxhtml/nxhtml/html-upl/Changes create mode 100644 emacs/nxhtml/nxhtml/html-upl/README create mode 100644 emacs/nxhtml/nxhtml/html-upl/TODO create mode 100644 emacs/nxhtml/nxhtml/html-upl/ftpsync.pl create mode 100644 emacs/nxhtml/nxhtml/html-wtoc.el create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/PerlLib/PathSubs.pm create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/PerlLib/html_tags.pm create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.css create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.html create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.css create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.js create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.pl create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/blank12.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/down.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/freeCont.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/gnu-m-x-160.png create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/gnu-m-x-160.xcf create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/hideCont.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/nailCont.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/nosearch.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/CompFaceLogoTemp4.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/CompFaceLogoTemp4.png create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/blue_left_top.png create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/close-cross.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/lbiinfo_and_blue.png create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/lbiinfo_and_blue1.png create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/lbinfo_col1.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/lbinfo_col1_30.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/other/up.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/right.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/search.gif create mode 100644 emacs/nxhtml/nxhtml/html-wtoc/img/showCont.gif create mode 100644 emacs/nxhtml/nxhtml/nxhtml-autoload.el create mode 100644 emacs/nxhtml/nxhtml/nxhtml-bug.el create mode 100644 emacs/nxhtml/nxhtml/nxhtml-menu.el create mode 100644 emacs/nxhtml/nxhtml/nxhtml-mode.el create mode 100644 emacs/nxhtml/nxhtml/nxhtml-mumamo.el create mode 100644 emacs/nxhtml/nxhtml/nxhtml-strval.el create mode 100644 emacs/nxhtml/nxhtml/nxhtml.el create mode 100644 emacs/nxhtml/nxhtml/nxhtmljs.el create mode 100644 emacs/nxhtml/nxhtml/nxml-where.el create mode 100644 emacs/nxhtml/nxhtml/outline-magic.el create mode 100644 emacs/nxhtml/nxhtml/rngalt.el create mode 100644 emacs/nxhtml/nxhtml/tidy-xhtml.el create mode 100644 emacs/nxhtml/nxhtml/wtest.el create mode 100644 emacs/nxhtml/nxhtml/xhtml-help.el create mode 100644 emacs/nxhtml/nxhtmlmaint.el create mode 100644 emacs/nxhtml/related/blank.html create mode 100644 emacs/nxhtml/related/csharp-mode.el create mode 100644 emacs/nxhtml/related/django.el create mode 100644 emacs/nxhtml/related/env.js create mode 100644 emacs/nxhtml/related/flymake-css.el create mode 100644 emacs/nxhtml/related/flymake-helpers.el create mode 100644 emacs/nxhtml/related/flymake-java-1.el create mode 100644 emacs/nxhtml/related/flymake-js.el create mode 100644 emacs/nxhtml/related/flymakemsg.el create mode 100644 emacs/nxhtml/related/flymu.el create mode 100644 emacs/nxhtml/related/iss-mode.el create mode 100644 emacs/nxhtml/related/iss-mumamo.el create mode 100644 emacs/nxhtml/related/js_temp.js create mode 100644 emacs/nxhtml/related/jslint.js create mode 100644 emacs/nxhtml/related/moz.el create mode 100644 emacs/nxhtml/related/mozadd.el create mode 100644 emacs/nxhtml/related/php-imenu.el create mode 100644 emacs/nxhtml/related/php-mode.el create mode 100644 emacs/nxhtml/related/readme.txt create mode 100644 emacs/nxhtml/related/rhino.js create mode 100644 emacs/nxhtml/related/smarty-mode.el create mode 100644 emacs/nxhtml/related/tt-mode.el create mode 100644 emacs/nxhtml/related/visual-basic-mode.el create mode 100644 emacs/nxhtml/related/wikipedia-mode.el create mode 100644 emacs/nxhtml/tests/angus77-setup-jde.el create mode 100644 emacs/nxhtml/tests/emacstest-suites.el create mode 100644 emacs/nxhtml/tests/ert.el create mode 100644 emacs/nxhtml/tests/ert2.el create mode 100644 emacs/nxhtml/tests/hfy-test.el create mode 100644 emacs/nxhtml/tests/in/3-heights.html create mode 100644 emacs/nxhtml/tests/in/400415-index.phtml create mode 100644 emacs/nxhtml/tests/in/asp.asp create mode 100644 emacs/nxhtml/tests/in/bastien-test.mm create mode 100644 emacs/nxhtml/tests/in/bigfile-stringerr-64000.html create mode 100644 emacs/nxhtml/tests/in/blorgit.rb create mode 100644 emacs/nxhtml/tests/in/bug-080609.html create mode 100644 emacs/nxhtml/tests/in/bug-1908494.php create mode 100644 emacs/nxhtml/tests/in/bug-2010-02-17-delgado.mm create mode 100644 emacs/nxhtml/tests/in/bug-2010-02-17-delgado.org create mode 100644 emacs/nxhtml/tests/in/bug-290364.php create mode 100644 emacs/nxhtml/tests/in/bug-300946-index.html create mode 100644 emacs/nxhtml/tests/in/bug-311640-index.html create mode 100644 emacs/nxhtml/tests/in/bug-311641.php create mode 100644 emacs/nxhtml/tests/in/bug-373106-flipbook.html create mode 100644 emacs/nxhtml/tests/in/bug-381191-dh-test.el create mode 100644 emacs/nxhtml/tests/in/bug-381191-dh-test.php create mode 100644 emacs/nxhtml/tests/in/bug-johan-2010-02-12.rhtml create mode 100644 emacs/nxhtml/tests/in/bug-johan-2010-02-16.html.haml create mode 100644 emacs/nxhtml/tests/in/bug-johan-2010-02-17-2.erb create mode 100644 emacs/nxhtml/tests/in/bug-johan-2010-02-17.erb create mode 100644 emacs/nxhtml/tests/in/bug261792.ghtml create mode 100644 emacs/nxhtml/tests/in/bug271497.el create mode 100644 emacs/nxhtml/tests/in/bug271497.txt create mode 100644 emacs/nxhtml/tests/in/bug272871.php create mode 100644 emacs/nxhtml/tests/in/bug290364-messages.txt create mode 100644 emacs/nxhtml/tests/in/bug354363-index.php create mode 100644 emacs/nxhtml/tests/in/bug354363-test.php create mode 100644 emacs/nxhtml/tests/in/bug369800-load-history.txt create mode 100644 emacs/nxhtml/tests/in/bug370417.php create mode 100644 emacs/nxhtml/tests/in/bug381979-2-bad-traceb.txt create mode 100644 emacs/nxhtml/tests/in/bug381979-2.php create mode 100644 emacs/nxhtml/tests/in/bug381979-svnlib.inc create mode 100644 emacs/nxhtml/tests/in/bug384115-bt2.txt create mode 100644 emacs/nxhtml/tests/in/bug388729-messages.txt create mode 100644 emacs/nxhtml/tests/in/bug388729-nxhtml_test.php create mode 100644 emacs/nxhtml/tests/in/bug393137-new.html.erb create mode 100644 emacs/nxhtml/tests/in/bug400415-foo.php create mode 100644 emacs/nxhtml/tests/in/bug400415-foo2.php create mode 100644 emacs/nxhtml/tests/in/bug409183.html create mode 100644 emacs/nxhtml/tests/in/bug416505-Body.mxml create mode 100644 emacs/nxhtml/tests/in/bug416505-nxhtml.el create mode 100644 emacs/nxhtml/tests/in/bug452676.php create mode 100644 emacs/nxhtml/tests/in/bug463136.php create mode 100644 emacs/nxhtml/tests/in/bug492366-test.php create mode 100644 emacs/nxhtml/tests/in/bug495770-heredoc_demo.pl create mode 100644 emacs/nxhtml/tests/in/bug505554-nxhtml-download-messages.txt create mode 100644 emacs/nxhtml/tests/in/bug505554-sample.html.erb create mode 100644 emacs/nxhtml/tests/in/bug505726-foo.html create mode 100644 emacs/nxhtml/tests/in/bug509586.ghtml create mode 100644 emacs/nxhtml/tests/in/bug523065.jsp create mode 100644 emacs/nxhtml/tests/in/bug523065.php create mode 100644 emacs/nxhtml/tests/in/bug529133-statemachine.py create mode 100644 emacs/nxhtml/tests/in/bug531328.rhtml create mode 100644 emacs/nxhtml/tests/in/bug532500.rhtml create mode 100644 emacs/nxhtml/tests/in/bug532759.djhtml create mode 100644 emacs/nxhtml/tests/in/bug546027.html create mode 100644 emacs/nxhtml/tests/in/bug552789-loremipsum.php create mode 100644 emacs/nxhtml/tests/in/bug552789.php create mode 100644 emacs/nxhtml/tests/in/bug556832-error-test.py create mode 100644 emacs/nxhtml/tests/in/bug557700-2.erb create mode 100644 emacs/nxhtml/tests/in/bug557700-3.erb create mode 100644 emacs/nxhtml/tests/in/bug557700-4.erb create mode 100644 emacs/nxhtml/tests/in/bug557700-5.erb create mode 100644 emacs/nxhtml/tests/in/bug557700-6.erb create mode 100644 emacs/nxhtml/tests/in/bug557700.erb create mode 100644 emacs/nxhtml/tests/in/bug559772-TextHelper.php create mode 100644 emacs/nxhtml/tests/in/bug565595.mako create mode 100644 emacs/nxhtml/tests/in/bug568178.pl create mode 100644 emacs/nxhtml/tests/in/bug568178.sh create mode 100644 emacs/nxhtml/tests/in/bug569742-master-end.html create mode 100644 emacs/nxhtml/tests/in/ch-2008-07-25-test.html.erb create mode 100644 emacs/nxhtml/tests/in/chunks-in-chunks1.php create mode 100644 emacs/nxhtml/tests/in/chunks.html create mode 100644 emacs/nxhtml/tests/in/cr-lf.el create mode 100644 emacs/nxhtml/tests/in/csr-080710-2.html create mode 100644 emacs/nxhtml/tests/in/csr-080710.html create mode 100644 emacs/nxhtml/tests/in/cvd-080805-ac.php create mode 100644 emacs/nxhtml/tests/in/cvd-080805-cc.php create mode 100644 emacs/nxhtml/tests/in/drechsler-080517-simple.xml create mode 100644 emacs/nxhtml/tests/in/el-070424-duh.xml create mode 100644 emacs/nxhtml/tests/in/el-070511-simple.html create mode 100644 emacs/nxhtml/tests/in/el-070602-index.php create mode 100644 emacs/nxhtml/tests/in/el-070604.html create mode 100644 emacs/nxhtml/tests/in/el-070604.php create mode 100644 emacs/nxhtml/tests/in/el-070722-comment-error.php create mode 100644 emacs/nxhtml/tests/in/el-070722-index-2.el create mode 100644 emacs/nxhtml/tests/in/el-070722-index-2.php create mode 100644 emacs/nxhtml/tests/in/el-070722-index-noheader.php create mode 100644 emacs/nxhtml/tests/in/el-070722-index.php create mode 100644 emacs/nxhtml/tests/in/el-071217-foo.html create mode 100644 emacs/nxhtml/tests/in/emacswiki-080119.php create mode 100644 emacs/nxhtml/tests/in/emacswiki-erb-bug.el create mode 100644 emacs/nxhtml/tests/in/err-line38.html create mode 100644 emacs/nxhtml/tests/in/eval-in-html.el create mode 100644 emacs/nxhtml/tests/in/fontif-err.html create mode 100644 emacs/nxhtml/tests/in/fontif-err.php create mode 100644 emacs/nxhtml/tests/in/genshi-HelloWorldPage.ghtml create mode 100644 emacs/nxhtml/tests/in/genshi-auto-mode.html create mode 100644 emacs/nxhtml/tests/in/genshi.ghtml create mode 100644 emacs/nxhtml/tests/in/goesele-091110-testnote-orig.mm create mode 100644 emacs/nxhtml/tests/in/goesele-091110-testnote-temp.mm create mode 100644 emacs/nxhtml/tests/in/goesele-091110-testnote.mm create mode 100644 emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org create mode 100644 emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org.mm create mode 100644 emacs/nxhtml/tests/in/haml1.haml create mode 100644 emacs/nxhtml/tests/in/heredoc.php create mode 100644 emacs/nxhtml/tests/in/heredoc.pl create mode 100644 emacs/nxhtml/tests/in/heredoc.py create mode 100644 emacs/nxhtml/tests/in/heredoc.rb create mode 100644 emacs/nxhtml/tests/in/heredoc.sh create mode 100644 emacs/nxhtml/tests/in/hg-2008-03-22-ajax.xhtml create mode 100644 emacs/nxhtml/tests/in/hq-070510-test.php create mode 100644 emacs/nxhtml/tests/in/hq-070510-test.php.html create mode 100644 emacs/nxhtml/tests/in/hq-070524-bug.php create mode 100644 emacs/nxhtml/tests/in/hq-071006-index.php create mode 100644 emacs/nxhtml/tests/in/html-syntactic-err-l164.html create mode 100644 emacs/nxhtml/tests/in/ind-0-error.php create mode 100644 emacs/nxhtml/tests/in/indent-bug-html-mode.html create mode 100644 emacs/nxhtml/tests/in/java.java create mode 100644 emacs/nxhtml/tests/in/jcl-080802-index.html.erb create mode 100644 emacs/nxhtml/tests/in/jcl-080802-messages_controller.rb create mode 100644 emacs/nxhtml/tests/in/jj-081226.html create mode 100644 emacs/nxhtml/tests/in/josh-091115-cancer_summary.xsl create mode 100644 emacs/nxhtml/tests/in/jump-parse.html create mode 100644 emacs/nxhtml/tests/in/jump-parse.rhtml create mode 100644 emacs/nxhtml/tests/in/kp-080604.php create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-1.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-2.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-2j.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-3.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-4.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-5.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-6.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-7.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-8.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-9.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-a-notabs.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-a.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-b.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-c.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-d.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-e.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-f.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-g.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-h.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-i.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-j.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing-k.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing.css create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing.html create mode 100644 emacs/nxhtml/tests/in/kubica-080516-freezing.txt create mode 100644 emacs/nxhtml/tests/in/kwalo-080930.php create mode 100644 emacs/nxhtml/tests/in/latex-clojre-mumamo-test.lclj create mode 100644 emacs/nxhtml/tests/in/lg-080813-div.html create mode 100644 emacs/nxhtml/tests/in/lg-080813-label.html create mode 100644 emacs/nxhtml/tests/in/long-lines.txt create mode 100644 emacs/nxhtml/tests/in/markdown.markdown create mode 100644 emacs/nxhtml/tests/in/mason.mason create mode 100644 emacs/nxhtml/tests/in/menu-err.txt create mode 100644 emacs/nxhtml/tests/in/mjt-feed.html create mode 100644 emacs/nxhtml/tests/in/mjt-imagesearch.html create mode 100644 emacs/nxhtml/tests/in/mjt-minimal.html create mode 100644 emacs/nxhtml/tests/in/mumamo-and-org.org create mode 100644 emacs/nxhtml/tests/in/mumamo-and-org.org.mm create mode 100644 emacs/nxhtml/tests/in/ng-080309-read-url.html create mode 100644 emacs/nxhtml/tests/in/no-php-end-2.php create mode 100644 emacs/nxhtml/tests/in/no-php-end-2.php-log.txt create mode 100644 emacs/nxhtml/tests/in/no-php-end-2.php-log2.txt create mode 100644 emacs/nxhtml/tests/in/no-php-end-3.php create mode 100644 emacs/nxhtml/tests/in/no-php-end-4.php create mode 100644 emacs/nxhtml/tests/in/no-php-end.php create mode 100644 emacs/nxhtml/tests/in/nojump-parse.html create mode 100644 emacs/nxhtml/tests/in/noweb1.now create mode 100644 emacs/nxhtml/tests/in/nutshell.mako create mode 100644 emacs/nxhtml/tests/in/nxml-bug.html create mode 100644 emacs/nxhtml/tests/in/nxml-indent-2.html create mode 100644 emacs/nxhtml/tests/in/nxml-indent-3.html create mode 100644 emacs/nxhtml/tests/in/nxml-indent-noerr1.html create mode 100644 emacs/nxhtml/tests/in/nxml-indent.el create mode 100644 emacs/nxhtml/tests/in/nxml-indent.html create mode 100644 emacs/nxhtml/tests/in/only-html.html create mode 100644 emacs/nxhtml/tests/in/only-php.php create mode 100644 emacs/nxhtml/tests/in/pavel-071116.djhtml create mode 100644 emacs/nxhtml/tests/in/php-parseable.php create mode 100644 emacs/nxhtml/tests/in/question43320.html create mode 100644 emacs/nxhtml/tests/in/question44504-folding.html create mode 100644 emacs/nxhtml/tests/in/question49234.sh create mode 100644 emacs/nxhtml/tests/in/rgr-030809-indexbody.php create mode 100644 emacs/nxhtml/tests/in/rgr-080307.php create mode 100644 emacs/nxhtml/tests/in/rgr-080308-header-2.php create mode 100644 emacs/nxhtml/tests/in/rgr-080308-header.php create mode 100644 emacs/nxhtml/tests/in/rgr-080308-indexbody.php create mode 100644 emacs/nxhtml/tests/in/rr-090524-header.php create mode 100644 emacs/nxhtml/tests/in/rr-090923-header.php create mode 100644 emacs/nxhtml/tests/in/rr-address-090304.php create mode 100644 emacs/nxhtml/tests/in/rr-address-nxhtml.err create mode 100644 emacs/nxhtml/tests/in/rr-min8.php create mode 100644 emacs/nxhtml/tests/in/ryan-091104-literal.tpl create mode 100644 emacs/nxhtml/tests/in/ryan-091111-wrong-side.tpl create mode 100644 emacs/nxhtml/tests/in/schemas.xml create mode 100644 emacs/nxhtml/tests/in/sd-080803-test.php create mode 100644 emacs/nxhtml/tests/in/senny-091118.htm create mode 100644 emacs/nxhtml/tests/in/sheit-2007-12-26.php create mode 100644 emacs/nxhtml/tests/in/short-tags.php create mode 100644 emacs/nxhtml/tests/in/single-question-sign.html create mode 100644 emacs/nxhtml/tests/in/ssjs.ssjs create mode 100644 emacs/nxhtml/tests/in/string-bug.php create mode 100644 emacs/nxhtml/tests/in/style=.html create mode 100644 emacs/nxhtml/tests/in/style=string-font.html create mode 100644 emacs/nxhtml/tests/in/svg.svg create mode 100644 emacs/nxhtml/tests/in/temp2.php create mode 100644 emacs/nxhtml/tests/in/temp3.html create mode 100644 emacs/nxhtml/tests/in/test-only-nxml.my-xhtml create mode 100644 emacs/nxhtml/tests/in/test.tt create mode 100644 emacs/nxhtml/tests/in/tut1.jsp create mode 100644 emacs/nxhtml/tests/in/utf8-problem.el create mode 100644 emacs/nxhtml/tests/in/wiki-080606-indent.php create mode 100644 emacs/nxhtml/tests/in/wiki-080708-ind-problem.rhtml create mode 100644 emacs/nxhtml/tests/in/wiki-090804-js.html create mode 100644 emacs/nxhtml/tests/in/wiki-2008-01-30.rhtml create mode 100644 emacs/nxhtml/tests/in/wiki-comments.php create mode 100644 emacs/nxhtml/tests/in/wiki-strange-hili-080629.html create mode 100644 emacs/nxhtml/tests/in/xml-as-string.php create mode 100644 emacs/nxhtml/tests/in/ygne-2008-02-07-hotproperty.html.php create mode 100644 emacs/nxhtml/tests/in/zero-pi.html create mode 100644 emacs/nxhtml/tests/in/zn-090529-doxysample.php create mode 100644 emacs/nxhtml/tests/inemacs/bug1013.el create mode 100644 emacs/nxhtml/tests/mumamo-test.el create mode 100644 emacs/nxhtml/tests/nxhtmltest-Q.el create mode 100644 emacs/nxhtml/tests/nxhtmltest-helpers.el create mode 100644 emacs/nxhtml/tests/nxhtmltest-suites.el create mode 100644 emacs/nxhtml/util/anchored-transpose.el create mode 100644 emacs/nxhtml/util/appmenu-fold.el create mode 100644 emacs/nxhtml/util/appmenu.el create mode 100644 emacs/nxhtml/util/as-external.el create mode 100644 emacs/nxhtml/util/buffer-bg.el create mode 100644 emacs/nxhtml/util/chartg.el create mode 100644 emacs/nxhtml/util/css-color.el create mode 100644 emacs/nxhtml/util/css-palette.el create mode 100644 emacs/nxhtml/util/css-simple-completion.el create mode 100644 emacs/nxhtml/util/cus-new-user.el create mode 100644 emacs/nxhtml/util/custsets.el create mode 100644 emacs/nxhtml/util/ecb-batch-compile.el create mode 100644 emacs/nxhtml/util/ediff-url.el create mode 100644 emacs/nxhtml/util/ffip.el create mode 100644 emacs/nxhtml/util/fold-dwim.el create mode 100644 emacs/nxhtml/util/foldit.el create mode 100644 emacs/nxhtml/util/fupd.el create mode 100644 emacs/nxhtml/util/gimpedit.el create mode 100644 emacs/nxhtml/util/gpl.el create mode 100644 emacs/nxhtml/util/hfyview.el create mode 100644 emacs/nxhtml/util/hl-needed.el create mode 100644 emacs/nxhtml/util/html-write.el create mode 100644 emacs/nxhtml/util/idn.el create mode 100644 emacs/nxhtml/util/inlimg.el create mode 100644 emacs/nxhtml/util/key-cat.el create mode 100644 emacs/nxhtml/util/majmodpri.el create mode 100644 emacs/nxhtml/util/markchars.el create mode 100644 emacs/nxhtml/util/mlinks.el create mode 100644 emacs/nxhtml/util/mumamo-aspnet.el create mode 100644 emacs/nxhtml/util/mumamo-fun.el create mode 100644 emacs/nxhtml/util/mumamo-regions.el create mode 100644 emacs/nxhtml/util/mumamo-trace.el create mode 100644 emacs/nxhtml/util/mumamo.el create mode 100644 emacs/nxhtml/util/n-back.el create mode 100644 emacs/nxhtml/util/new-key-seq-widget.el create mode 100644 emacs/nxhtml/util/nxml-mode-os-additions.el create mode 100644 emacs/nxhtml/util/ocr-user.el create mode 100644 emacs/nxhtml/util/org-panel.el create mode 100644 emacs/nxhtml/util/ourcomments-util.el create mode 100644 emacs/nxhtml/util/ourcomments-widgets.el create mode 100644 emacs/nxhtml/util/pause.el create mode 100644 emacs/nxhtml/util/pointback.el create mode 100644 emacs/nxhtml/util/popcmp.el create mode 100644 emacs/nxhtml/util/readme.txt create mode 100644 emacs/nxhtml/util/rebind.el create mode 100644 emacs/nxhtml/util/rnc-mode.el create mode 100644 emacs/nxhtml/util/rxi.el create mode 100644 emacs/nxhtml/util/search-form.el create mode 100644 emacs/nxhtml/util/sex-mode.el create mode 100644 emacs/nxhtml/util/sml-modeline.el create mode 100644 emacs/nxhtml/util/tabkey2.el create mode 100644 emacs/nxhtml/util/tyda.el create mode 100644 emacs/nxhtml/util/udev-ecb.el create mode 100644 emacs/nxhtml/util/udev-rinari.el create mode 100644 emacs/nxhtml/util/udev.el create mode 100644 emacs/nxhtml/util/useful-commands.el create mode 100644 emacs/nxhtml/util/viper-tut.el create mode 100644 emacs/nxhtml/util/vline.el create mode 100644 emacs/nxhtml/util/web-vcs-revision.txt create mode 100644 emacs/nxhtml/util/whelp.el create mode 100644 emacs/nxhtml/util/winsav.el create mode 100644 emacs/nxhtml/util/winsize.el create mode 100644 emacs/nxhtml/util/wrap-to-fill.el create mode 100644 emacs/nxhtml/util/zencoding-mode.el create mode 100644 emacs/nxhtml/web-autoload.el create mode 100644 emacs/nxhtml/web-vcs.el create mode 100644 emacs/paredit.el create mode 100644 emacs/pastebin.el create mode 100644 emacs/pbook.el create mode 100644 emacs/quack.el create mode 100644 emacs/rainbow-mode.el create mode 100644 emacs/redo.el create mode 100644 emacs/scheme-complete.el create mode 100644 emacs/scheme48.el create mode 100644 emacs/screencast.el create mode 100644 emacs/sml-mode.el create mode 100644 emacs/solarized-theme.el create mode 100644 emacs/solarized.el create mode 100644 emacs/sql-complete.el create mode 100644 emacs/sunrise-commander.el create mode 160000 emacs/twittering-mode create mode 100644 emacs/verilog-mode.el create mode 100644 emacs/xcscope.el create mode 100644 emacs/xml-rpc.el create mode 160000 themes/solarized create mode 100644 themes/solarized-dark-theme.el create mode 100644 themes/solarized-light-theme.el create mode 160000 themes/zenburn create mode 100644 themes/zenburn-theme.el create mode 160000 vendor/haskell-mode create mode 160000 vendor/swank-js diff --git a/.gitmodules b/.gitmodules index 9a65b06..421b435 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,3 +17,15 @@ [submodule "vendor/company-mode"] path = vendor/company-mode url = https://github.com/company-mode/company-mode.git +[submodule "vendor/haskell-mode"] + path = vendor/haskell-mode + url = https://github.com/haskell/haskell-mode.git +[submodule "vendor/swank-js"] + path = vendor/swank-js + url = https://github.com/swank-js/swank-js.git +[submodule "themes/solarized"] + path = themes/solarized + url = https://github.com/bbatsov/solarized-emacs.git +[submodule "themes/zenburn"] + path = themes/zenburn + url = https://github.com/bbatsov/zenburn-emacs.git diff --git a/emacs/ac-python.el b/emacs/ac-python.el new file mode 100644 index 0000000..cb35e4e --- /dev/null +++ b/emacs/ac-python.el @@ -0,0 +1,72 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;; Simple Python Completion Source for Auto-Complete +;;;;; ================================================= +;;;;; +;;;;; This file provides a completion source for Auto-Complete: +;;;;; http://www.emacswiki.org/emacs/AutoComplete +;;;;; +;;;;; Installation +;;;;; ------------ +;;;;; +;;;;; Setup Auto-Complete in the usual fashion, and make sure it gets loaded for +;;;;; python buffers. Then, place this file in your load-path, and add +;;;;; +;;;;; (require 'ac-python) +;;;;; +;;;;; to your .emacs file (after loading Auto-Complete). +;;;;; +;;;;; Usage +;;;;; ----- +;;;;; +;;;;; Python symbols will be completed by Auto-Complete, once Emacs learns about +;;;;; these symbols. This is the short-coming of the plugin, but it's a small +;;;;; price to pay. +;;;;; +;;;;; To teach Emacs about symbols in imported modules, Emacs needs to execute +;;;;; the Python source. This can be accomplished with `python-send-buffer` for +;;;;; example, often bound to `C-c C-c`. If a python process is already running, +;;;;; this is essentially instantaneous. +;;;;; +;;;;; --- +;;;;; +;;;;; Version: 20110519 +;;;;; License: MIT +;;;;; Author: Chris Poole <chris@chrispoole.com> +;;;;; More information: http://chrispoole.com/project/ac-python +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +(defun ac-get-python-symbol-at-point () + "Return python symbol at point. + +Assumes symbol can be alphanumeric, `.' or `_'." + (let ((end (point)) + (start (ac-python-start-of-expression))) + (buffer-substring-no-properties start end))) + +(defun ac-python-completion-at-point () + "Returns a possibly empty list of completions for the symbol at +point." + (python-symbol-completions (ac-get-python-symbol-at-point))) + +(defun ac-python-start-of-expression () + "Return point of the start of python expression at point. + +Assumes symbol can be alphanumeric, `.' or `_'." + (save-excursion + (and (re-search-backward + (rx (or buffer-start (regexp "[^[:alnum:]._]")) + (group (1+ (regexp "[[:alnum:]._]"))) point) + nil t) + (match-beginning 1)))) + +(defvar ac-source-python + '((candidates . ac-python-completion-at-point) + (prefix . ac-python-start-of-expression) + (symbol . "f") + (requires . 2)) + "Source for python completion.") + +(add-hook 'python-mode-hook (lambda () (add-to-list 'ac-sources 'ac-source-python))) + +(provide 'ac-python) \ No newline at end of file diff --git a/emacs/basic-mode.el b/emacs/basic-mode.el new file mode 100644 index 0000000..70f58c6 --- /dev/null +++ b/emacs/basic-mode.el @@ -0,0 +1,669 @@ +;; basic-mode.el --- A mode for editing Visual Basic programs. + +;; Copyright (C) 1996, Fred White <fwhite@world.std.com> + +;; Author: Fred White <fwhite@world.std.com> +;; Version: 1.0 (April 18, 1996) +;; Keywords: languages basic + +;; LCD Archive Entry: +;; basic-mode|Fred White|fwhite@world.std.com| +;; A mode for editing Visual Basic programs.| +;; 18-Apr-96|1.0|~/modes/basic-mode.el.Z| + +;; This file is NOT part of GNU Emacs but the same permissions apply. +;; +;; 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, 675 Mass Ave, Cambridge, MA 02139, USA. +;; 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. + + +;; Purpose of this package: +;; This is a mode for editing programs written in The World's Most +;; Successful Programming Language. It features automatic +;; indentation, font locking, keyword capitalization, and some minor +;; convenience functions. + +;; Installation instructions +;; Put basic-mode.el somewhere in your path, compile it, and add the +;; following to your init file: + +;; (autoload 'basic-mode "basic-mode" "Basic mode." t) +;; (setq auto-mode-alist (append '(("\\.\\(frm\\|bas\\|cls\\)$" . +;; basic-mode)) auto-mode-alist)) + +;; Of course, under Windows 3.1, you'll have to name this file +;; something shorter than basic-mode.el + + + +;; Known bugs: +;; Doesn't know about ":" separated stmts +;; Doesn't know about single-line IF stmts + + +;; todo: +;; fwd/back-compound-statement +;; completion over OCX methods and properties. +;; ensure Then at the end of IF statements. +;; IDE integration +;; etc. + + +(provide 'basic-mode) + +(defvar basic-xemacs-p (string-match "XEmacs\\|Lucid" (emacs-version))) +(defvar basic-winemacs-p (string-match "Win-Emacs" (emacs-version))) + +;; Variables you may want to customize. +(defvar basic-mode-indent 2 "*Default indentation per nesting level") +(defvar basic-fontify-p t "*Whether to fontify Basic buffers.") +(defvar basic-capitalize-keywords-p t + "*Whether to capitalize BASIC keywords.") +(defvar basic-wild-files "*.frm *.bas *.cls" + "*Wildcard pattern for BASIC source files") +(defvar basic-ide-pathname nil + "*The full pathname of your Visual Basic exe file, if any.") + + +(defvar basic-keywords-to-highlight + '("Dim" "If" "Then" "Else" "ElseIf" "End If") + "*A list of keywords to highlight in Basic mode, or T, meaning all keywords") + +(defvar basic-defn-templates + (list "Public Sub ()\nEnd Sub\n\n" + "Public Function () As Variant\nEnd Function\n\n" + "Public Property Get ()\nEnd Property\n\n") + "*List of function templates though which basic-new-sub cycles.") + + + +(defvar basic-mode-syntax-table nil) +(if basic-mode-syntax-table + () + (setq basic-mode-syntax-table (make-syntax-table)) + (modify-syntax-entry ?\' "\<" basic-mode-syntax-table) ; Comment starter + (modify-syntax-entry ?\n ">" basic-mode-syntax-table) + (modify-syntax-entry ?\\ "w" basic-mode-syntax-table) + (modify-syntax-entry ?_ "w" basic-mode-syntax-table)) + + +(defvar basic-mode-map nil) +(if basic-mode-map + () + (setq basic-mode-map (make-sparse-keymap)) + (define-key basic-mode-map "\t" 'basic-indent-line) + (define-key basic-mode-map "\r" 'basic-newline-and-indent) + (define-key basic-mode-map "\M-\C-a" 'basic-beginning-of-defun) + (define-key basic-mode-map "\M-\C-e" 'basic-end-of-defun) + (define-key basic-mode-map "\M-\C-h" 'basic-mark-defun) + (define-key basic-mode-map "\M-\C-\\" 'basic-indent-region) + (define-key basic-mode-map "\M-q" 'basic-fill-or-indent) + (if basic-xemacs-p + (progn + (if basic-winemacs-p + (define-key basic-mode-map '(control C) 'basic-start-ide)) + (define-key basic-mode-map "\M-G" 'basic-grep) + (define-key basic-mode-map '(meta backspace) 'backward-kill-word) + (define-key basic-mode-map '(control meta /) 'basic-new-sub)))) + + +;; These abbrevs are valid only in a code context. +(defvar basic-mode-abbrev-table nil) + +(defvar basic-mode-hook ()) + + +;; Is there a way to case-fold all regexp matches? + +(defconst basic-defun-start-regexp + (concat + "^[ \t]*\\([Pp]ublic \\|[Pp]rivate \\|[Ss]tatic \\)*" + "\\([Ss]ub\\|[Ff]unction\\|[Pp]roperty +[GgSsLl]et\\|[Tt]ype\\)" + "[ \t]+\\(\\w+\\)[ \t]*(?")) + +(defconst basic-defun-end-regexp + "^[ \t]*[Ee]nd \\([Ss]ub\\|[Ff]unction\\|[Pp]roperty\\|[Tt]ype\\)") + + +;; Includes the compile-time #if variation. +(defconst basic-if-regexp "^[ \t]*#?[Ii]f") +(defconst basic-else-regexp "^[ \t]*#?[Ee]lse\\([Ii]f\\)?") +(defconst basic-endif-regexp "[ \t]*#?[Ee]nd[ \t]*[Ii]f") + +(defconst basic-continuation-regexp "^.*\\_[ \t]*$") +(defconst basic-label-regexp "^[ \t]*[a-zA-Z0-9_]+:$") + +(defconst basic-select-regexp "^[ \t]*[Ss]elect[ \t]+[Cc]ase") +(defconst basic-case-regexp "^[ \t]*[Cc]ase") +(defconst basic-select-end-regexp "^[ \t]*[Ee]nd[ \t]+[Ss]elect") + +(defconst basic-for-regexp "^[ \t]*[Ff]or") +(defconst basic-next-regexp "^[ \t]*[Nn]ext") + +(defconst basic-do-regexp "^[ \t]*[Dd]o") +(defconst basic-loop-regexp "^[ \t]*[Ll]oop") + +(defconst basic-while-regexp "^[ \t]*[Ww]hile") +(defconst basic-wend-regexp "^[ \t]*[Ww]end") + +(defconst basic-with-regexp "^[ \t]*[Ww]ith") +(defconst basic-end-with-regexp "^[ \t]*[Ee]nd[ \t]+[Ww]ith") + +(defconst basic-blank-regexp "^[ \t]*$") +(defconst basic-comment-regexp "^[ \t]*\\s<.*$") + + +;; This is some approximation of the set of reserved words in Visual Basic. +(defconst basic-all-keywords + '("Aggregate" "And" "App" "AppActivate" "Application" "Array" "As" + "Asc" "AscB" "Atn" "Beep" "BeginTrans" "ByVal" "CBool" "CByte" "CCur" + "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr" "CVErr" "CVar" "Call" + "Case" "ChDir" "ChDrive" "Character" "Choose" "Chr" "ChrB" + "ClassModule" "Clipboard" "Close" "Collection" "Column" "Columns" + "Command" "CommitTrans" "CompactDatabase" "Component" "Components" + "Const" "Container" "Containers" "Cos" "CreateDatabase" "CreateObject" + "CurDir" "Currency" "DBEngine" "DDB" "Data" "Database" "Databases" + "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue" "Day" + "Debug" "Declare" "Deftype" "DeleteSetting" "Dim" "Dir" "Do" "Domain" + "Double" "Dynaset" "EOF" "Each" "Else" "End" "Environ" "Erase" "Err" + "Error" "Exit" "Exp" "FV" "False" "Field" "Fields" "FileAttr" + "FileCopy" "FileDateTime" "FileLen" "Fix" "Font" "For" "Form" + "FormTemplate" "Format" "Forms" "FreeFile" "FreeLocks" "Function" + "Get" "GetAllSettings" "GetAttr" "GetObject" "GetSetting" "GoSub" + "GoTo" "Group" "Groups" "Hex" "Hour" "IIf" "IMEStatus" "IPmt" "IRR" + "If" "InStr" "Input" "Int" "Integer" "Is" "IsArray" "IsDate" "IsEmpty" + "IsError" "IsMissing" "IsNull" "IsNumeric" "IsObject" "Kill" "LBound" + "LCase" "LOF" "LSet" "LTrim" "Left" "Len" "Let" "Like" "Line" "Load" + "LoadPicture" "LoadResData" "LoadResPicture" "LoadResString" "Loc" + "Lock" "Log" "Long" "Loop" "MDIForm" "MIRR" "Me" "MenuItems" + "MenuLine" "Mid" "Minute" "MkDir" "Month" "MsgBox" "NPV" "NPer" "Name" + "New" "Next" "Now" "Oct" "On" "Open" "OpenDatabase" "Operator" + "Option" "PPmt" "PV" "Parameter" "Parameters" "Partition" "Picture" + "Pmt" "Print" "Printer" "Printers" "Private" "ProjectTemplate" + "Properties" "Public" "Put" "QBColor" "QueryDef" "QueryDefs" "RGB" + "RSet" "RTrim" "Randomize" "Rate" "ReDim" "Recordset" "Recordsets" + "RegisterDatabase" "Relation" "Relations" "Rem" "RepairDatabase" + "Reset" "Resume" "Return" "Right" "RmDir" "Rnd" "Rollback" "RowBuffer" + "SLN" "SYD" "SavePicture" "SaveSetting" "Screen" "Second" "Seek" + "SelBookmarks" "Select" "SelectedComponents" "SendKeys" "Set" + "SetAttr" "SetDataAccessOption" "SetDefaultWorkspace" "Sgn" "Shell" + "Sin" "Single" "Snapshot" "Space" "Spc" "Sqr" "Static" "Stop" "Str" + "StrComp" "StrConv" "String" "Sub" "SubMenu" "Switch" "Tab" "Table" + "TableDef" "TableDefs" "Tan" "Then" "Time" "TimeSerial" "TimeValue" + "Timer" "To" "Trim" "True" "Type" "TypeName" "UBound" "UCase" "Unload" + "Unlock" "Val" "VarType" "Verb" "Weekday" "Wend" + "While" "Width" "With" "Workspace" "Workspaces" "Write" "Year")) + + +(defun basic-word-list-regexp (keys) + (let ((re "\\b\\(") + (key nil)) + (while keys + (setq key (car keys) + keys (cdr keys)) + (setq re (concat re key (if keys "\\|" "")))) + (concat re "\\)\\b"))) + +(defun basic-keywords-to-highlight () + (if (eq basic-keywords-to-highlight t) + basic-all-keywords + basic-keywords-to-highlight)) + + +(defvar basic-font-lock-keywords + (list + ;; Names of functions. + (list basic-defun-start-regexp 3 'font-lock-function-name-face) + + ;; Statement labels + (cons basic-label-regexp 'font-lock-keyword-face) + + ;; Case values + ;; String-valued cases get font-lock-string-face regardless. + (list "^[ \t]*[Cc]ase[ \t]+\\([^'\n]+\\)" 1 'font-lock-keyword-face t) + + ;; Any keywords you like. + (cons (basic-word-list-regexp (basic-keywords-to-highlight)) + 'font-lock-keyword-face))) + + + +(defun basic-mode () + "A mode for editing Microsoft Visual Basic programs. +Features automatic indentation, font locking, keyword capitalization, +and some minor convenience functions. +Commands: +\\{basic-mode-map}" + (interactive) + (kill-all-local-variables) + (use-local-map basic-mode-map) + (setq major-mode 'basic-mode) + (setq mode-name "Basic") + (set-syntax-table basic-mode-syntax-table) + + (add-hook 'write-file-hooks 'basic-untabify) + + (setq local-abbrev-table basic-mode-abbrev-table) + (if basic-capitalize-keywords-p + (progn + (make-local-variable 'pre-abbrev-expand-hook) + (add-hook 'pre-abbrev-expand-hook 'basic-pre-abbrev-expand-hook) + (abbrev-mode 1))) + + + (make-local-variable 'comment-start) + (setq comment-start "' ") + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "'+ *") + (make-local-variable 'comment-column) + (setq comment-column 40) + (make-local-variable 'comment-end) + (setq comment-end "") + + (make-local-variable 'indent-line-function) + (setq indent-line-function 'basic-indent-line) + + (make-local-variable 'font-lock-keywords) + (setq font-lock-keywords basic-font-lock-keywords) + + (if basic-fontify-p + (font-lock-mode 1)) + + (run-hooks 'basic-mode-hook)) + + +(defun basic-construct-keyword-abbrev-table () + (if basic-mode-abbrev-table + nil + (let ((words basic-all-keywords) + (word nil) + (list nil)) + (while words + (setq word (car words) + words (cdr words)) + (setq list (cons (list (downcase word) word) list))) + + (define-abbrev-table 'basic-mode-abbrev-table list)))) + +(basic-construct-keyword-abbrev-table) + + +(defun basic-in-code-context-p () + (if (fboundp 'buffer-syntactic-context) ; XEmacs function. + (null (buffer-syntactic-context)) + ;; Attempt to simulate buffer-syntactic-context + ;; I don't know how reliable this is. + (let* ((beg (save-excursion + (beginning-of-line) + (point))) + (list + (parse-partial-sexp beg (point)))) + (and (null (nth 3 list)) ; inside string. + (null (nth 4 list)))))) ; inside cocmment + +(defun basic-pre-abbrev-expand-hook () + ;; Allow our abbrevs only in a code context. + (setq local-abbrev-table + (if (basic-in-code-context-p) + basic-mode-abbrev-table))) + + + +(defun basic-newline-and-indent (&optional count) + "Insert a newline, updating indentation." + (interactive) + (expand-abbrev) + (basic-indent-line) + (call-interactively 'newline-and-indent)) + +(defun basic-beginning-of-defun () + (interactive) + (re-search-backward basic-defun-start-regexp)) + +(defun basic-end-of-defun () + (interactive) + (re-search-forward basic-defun-end-regexp)) + +(defun basic-mark-defun () + (interactive) + (beginning-of-line) + (basic-end-of-defun) + (set-mark (point)) + (basic-beginning-of-defun) + (if basic-xemacs-p + (zmacs-activate-region))) + +(defun basic-indent-defun () + (interactive) + (save-excursion + (basic-mark-defun) + (call-interactively 'basic-indent-region))) + + +(defun basic-fill-long-comment () + "Fills block of comment lines around point." + ;; Derived from code in ilisp-ext.el. + (interactive) + (save-excursion + (beginning-of-line) + (let ((comment-re "^[ \t]*\\s<+[ \t]*")) + (if (looking-at comment-re) + (let ((fill-prefix + (buffer-substring + (progn (beginning-of-line) (point)) + (match-end 0)))) + + (while (and (not (bobp)) + (looking-at basic-comment-regexp)) + (forward-line -1)) + (if (not (bobp)) (forward-line 1)) + + (let ((start (point))) + + ;; Make all the line prefixes the same. + (while (and (not (eobp)) + (looking-at comment-re)) + (replace-match fill-prefix) + (forward-line 1)) + + (if (not (eobp)) + (beginning-of-line)) + + ;; Fill using fill-prefix + (fill-region-as-paragraph start (point)))))))) + + +(defun basic-fill-or-indent () + "Fill long comment around point, if any, else indent current definition." + (interactive) + (cond ((save-excursion + (beginning-of-line) + (looking-at basic-comment-regexp)) + (basic-fill-long-comment)) + (t + (basic-indent-defun)))) + + +(defun basic-new-sub () + "Insert template for a new subroutine. Repeat to cycle through alternatives." + (interactive) + (beginning-of-line) + (let ((templates (cons basic-blank-regexp + basic-defn-templates)) + (tem nil) + (bound (point))) + (while templates + (setq tem (car templates) + templates (cdr templates)) + (cond ((looking-at tem) + (replace-match (or (car templates) + "")) + (setq templates nil)))) + + (search-backward "()" bound t))) + + +(defun basic-untabify () + "Do not allow any tabs into the file" + (if (eq major-mode 'basic-mode) + (untabify (point-min) (point-max))) + nil) + +(defun basic-default-tag () + (if (and (not (bobp)) + (save-excursion + (backward-char 1) + (looking-at "\\w"))) + (backward-word 1)) + (let ((s (point)) + (e (save-excursion + (forward-word 1) + (point)))) + (buffer-substring s e))) + +(defun basic-grep (tag) + "Search BASIC source files in current directory for tag." + (interactive + (list (let* ((def (basic-default-tag)) + (tag (read-string + (format "Grep for [%s]: " def)))) + (if (string= tag "") def tag)))) + + (grep (format "grep -n %s %s" tag basic-wild-files))) + + + +(defun basic-start-ide () + "Start Visual Basic (or your favorite IDE, (after Emacs, of course)) +on the project file in the current directory. +Note: it's not a good idea to leave Visual Basic running while you +are editing in emacs, since Visual Basic has no provision for reloading +changed files." + (interactive) + (let (file) + (cond ((not (fboundp 'win-exec)) + (error "Not available")) + ((null basic-ide-pathname) + (error "No pathname set for Visual Basic. See basic-ide-pathname")) + ((setq file (car (directory-files (pwd) t "\\.vbp"))) + (iconify-emacs) + (win-exec basic-ide-pathname 'win-show-normal file)) + (t + (error "No project file found."))))) + + + +;;; Indentation-related stuff. + +(defun basic-indent-region (start end) + "Perform basic-indent-line on each line in region." + (interactive "r") + (save-excursion + (goto-char start) + (beginning-of-line) + (while (and (not (eobp)) + (< (point) end)) + (if (not (looking-at basic-blank-regexp)) + (basic-indent-line)) + (forward-line 1))) + + (cond ((fboundp 'zmacs-deactivate-region) + (zmacs-deactivate-region)) + ((fboundp 'deactivate-mark) + (deactivate-mark)))) + + + +(defun basic-previous-line-of-code () + (if (not (bobp)) + (forward-line -1)) ; previous-line depends on goal column + (while (and (not (bobp)) + (or (looking-at basic-blank-regexp) + (looking-at basic-comment-regexp))) + (forward-line -1))) + + +(defun basic-find-original-statement () + ;; If the current line is a continuation from the previous, move + ;; back to the original stmt. + (let ((here (point))) + (basic-previous-line-of-code) + (while (and (not (bobp)) + (looking-at basic-continuation-regexp)) + (setq here (point)) + (basic-previous-line-of-code)) + (goto-char here))) + +(defun basic-find-matching-stmt (open-regexp close-regexp) + ;; Searching backwards + (let ((level 0)) + (while (and (>= level 0) (not (bobp))) + (basic-previous-line-of-code) + (basic-find-original-statement) + (cond ((looking-at close-regexp) + (setq level (+ level 1))) + ((looking-at open-regexp) + (setq level (- level 1))))))) + +(defun basic-find-matching-if () + (basic-find-matching-stmt basic-if-regexp basic-endif-regexp)) + +(defun basic-find-matching-select () + (basic-find-matching-stmt basic-select-regexp basic-select-end-regexp)) + +(defun basic-find-matching-for () + (basic-find-matching-stmt basic-for-regexp basic-next-regexp)) + +(defun basic-find-matching-do () + (basic-find-matching-stmt basic-do-regexp basic-loop-regexp)) + +(defun basic-find-matching-while () + (basic-find-matching-stmt basic-while-regexp basic-wend-regexp)) + +(defun basic-find-matching-with () + (basic-find-matching-stmt basic-with-regexp basic-end-with-regexp)) + + +(defun basic-calculate-indent () + (let ((original-point (point))) + (save-excursion + (beginning-of-line) + ;; Some cases depend only on where we are now. + (cond ((or (looking-at basic-defun-start-regexp) + (looking-at basic-label-regexp) + (looking-at basic-defun-end-regexp)) + 0) + + ;; The outdenting stmts, which simply match their original. + ((or (looking-at basic-else-regexp) + (looking-at basic-endif-regexp)) + (basic-find-matching-if) + (current-indentation)) + + ;; All the other matching pairs act alike. + ((looking-at basic-next-regexp) ; for/next + (basic-find-matching-for) + (current-indentation)) + + ((looking-at basic-loop-regexp) ; do/loop + (basic-find-matching-do) + (current-indentation)) + + ((looking-at basic-wend-regexp) ; while/wend + (basic-find-matching-while) + (current-indentation)) + + ((looking-at basic-with-regexp) ; with/end with + (basic-find-matching-with) + (current-indentation)) + + ((looking-at basic-select-end-regexp) ; select case/end select + (basic-find-matching-select) + (current-indentation)) + + ;; A case of a select is somewhat special. + ((looking-at basic-case-regexp) + (basic-find-matching-select) + (+ (current-indentation) basic-mode-indent)) + + (t + ;; Other cases which depend on the previous line. + (basic-previous-line-of-code) + + ;; Skip over label lines, which always have 0 indent. + (while (looking-at basic-label-regexp) + (basic-previous-line-of-code)) + + (cond + ((looking-at basic-continuation-regexp) + (basic-find-original-statement) + ;; Indent continuation line under matching open paren, + ;; or else one word in. + (let* ((orig-stmt (point)) + (matching-open-paren + (condition-case () + (save-excursion + (goto-char original-point) + (beginning-of-line) + (backward-up-list 1) + ;; Only if point is now w/in cont. block. + (if (<= orig-stmt (point)) + (current-column))) + (error nil)))) + (cond (matching-open-paren + (1+ matching-open-paren)) + (t + ;; Else, after first word on original line. + (back-to-indentation) + (forward-word 1) + (while (looking-at "[ \t]") + (forward-char 1)) + (current-column))))) + (t + (basic-find-original-statement) + (let ((indent (current-indentation))) + ;; All the various +indent regexps. + (cond ((looking-at basic-defun-start-regexp) + (+ indent basic-mode-indent)) + + ((or (looking-at basic-if-regexp) + (looking-at basic-else-regexp)) + (+ indent basic-mode-indent)) + + ((or (looking-at basic-select-regexp) + (looking-at basic-case-regexp)) + (+ indent basic-mode-indent)) + + ((or (looking-at basic-do-regexp) + (looking-at basic-for-regexp) + (looking-at basic-while-regexp) + (looking-at basic-with-regexp)) + (+ indent basic-mode-indent)) + + (t + ;; By default, just copy indent from prev line. + indent)))))))))) + +(defun basic-indent-to-column (col) + (let* ((bol (save-excursion + (beginning-of-line) + (point))) + (point-in-whitespace + (<= (point) (+ bol (current-indentation)))) + (blank-line-p + (save-excursion + (beginning-of-line) + (looking-at basic-blank-regexp)))) + + (cond ((/= col (current-indentation)) + (save-excursion + (beginning-of-line) + (back-to-indentation) + (delete-region bol (point)) + (indent-to col)))) + + ;; If point was in the whitespace, move back-to-indentation. + (cond (blank-line-p + (end-of-line)) + (point-in-whitespace + (back-to-indentation))))) + +(defun basic-indent-line () + "Indent current line for BASIC" + (interactive) + (basic-indent-to-column (basic-calculate-indent))) diff --git a/emacs/cldoc.el b/emacs/cldoc.el new file mode 100644 index 0000000..9e4086f --- /dev/null +++ b/emacs/cldoc.el @@ -0,0 +1,1538 @@ +;;; cldoc.el --- show Common Lisp operators and variables information in echo area + +;; Copyright (C) 1996, 97, 98, 99, 2000 Free Software Foundation, Inc. +;; Copyright (C) 2004 Yuji Minejima + +;; This program (cldoc.el) is based on eldoc.el. +;; Eldoc Author: Noah Friedman <friedman@splode.com> +;; Keywords: extensions + +;; $Id: cldoc.el,v 1.16 2004/12/01 02:06:43 yuji Exp $ + +;; This file is not 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: + +;; cldoc.el is basically an eldoc clone for Common Lisp. +;; The following comment is from eldoc.el +;; > This program was inspired by the behavior of the "mouse documentation +;; > window" on many Lisp Machine systems; as you type a function's symbol +;; > name as part of a sexp, it will print the argument list for that +;; > function. Behavior is not identical; for example, you need not actually +;; > type the function name, you need only move point around in a sexp that +;; > calls it. Also, if point is over a documented variable, it will print +;; > the one-line documentation for that variable instead, to remind you of +;; > that variable's meaning. +;; +;; cldoc.el has a database of parameters and results of Common Lisp's standard +;; functions, and syntax rules of standard macros and special operators. +;; cldoc.el automatically uses SLIME's autodoc facility if available to display +;; parameters of user defined functions and macros, and the values of global +;; variables. + + +;; One useful way to enable this minor mode is to put the following in your +;; .emacs: +;; +;; ;; all users +;; (autoload 'turn-on-cldoc-mode "cldoc" nil t) +;; (add-hook 'lisp-mode-hook 'turn-on-cldoc-mode) +;; +;; ;; ilisp users +;; (add-hook 'ilisp-mode-hook 'turn-on-cldoc-mode) +;; (setq ilisp-bindings-*bind-space-p* nil) +;; +;; ;; slime users +;; (add-hook 'slime-repl-mode-hook +;; #'(lambda () +;; (turn-on-cldoc-mode) +;; (define-key slime-repl-mode-map " " nil))) +;; (add-hook 'slime-mode-hook +;; #'(lambda () (define-key slime-mode-map " " nil))) +;; (setq slime-use-autodoc-mode nil) + +;; todo +;; * handling of operators with multiple syntax rules (e.g. file-position). +;; * handling of operators which implementations are allowed to extend +;; (e.g. directory) + + +;;; Code: +(require 'cl) + +;; Use idle timers if available in the version of emacs running. +;; Please don't change this to use `require'; this package works +;; as-is in XEmacs 19.14 and later and I am striving to maintain +;; compatibility between emacs variants. +(or (featurep 'timer) + (load "timer" t)) + +(defgroup cldoc nil + "Show function arglist or variable docstring in echo area." + :group 'lisp + :group 'extensions) + +;;;###autoload +(defcustom cldoc-mode nil + "*If non-nil, show the defined parameters for the elisp function near point. + +For the emacs lisp function at the beginning of the sexp which point is +within, show the defined parameters for the function in the echo area. +This information is extracted directly from the function or macro if it is +in pure lisp. If the emacs function is a subr, the parameters are obtained +from the documentation string if possible. + +If point is over a documented variable, print that variable's docstring +instead. + +This variable is buffer-local." + :type 'boolean + :group 'cldoc) +(make-variable-buffer-local 'cldoc-mode) + +(defcustom cldoc-idle-delay 0.50 + "*Number of seconds of idle time to wait before printing. +If user input arrives before this interval of time has elapsed after the +last input, no documentation will be printed. + +If this variable is set to 0, no idle time is required." + :type 'number + :group 'cldoc) + +;;;###autoload +(defcustom cldoc-minor-mode-string " Cldoc" + "*String to display in mode line when Cldoc Mode is enabled." + :type 'string + :group 'cldoc) + +(defcustom cldoc-argument-case 'upcase + "Case to display argument names of functions, as a symbol. +This has two preferred values: `upcase' or `downcase'. +Actually, any name of a function which takes a string as an argument and +returns another string is acceptable." + :type '(radio (function-item upcase) + (function-item downcase) + function) + :group 'cldoc) + +(defcustom cldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit + "*Allow long cldoc messages to resize echo area display. +If value is `t', never attempt to truncate messages; complete symbol name +and function arglist or 1-line variable documentation will be displayed +even if echo area must be resized to fit. + +If value is any non-nil value other than `t', symbol name may be truncated +if it will enable the function arglist or documentation string to fit on a +single line without resizing window. Otherwise, behavior is just like +former case. + +If value is nil, messages are always truncated to fit in a single line of +display in the echo area. Function or variable symbol name may be +truncated to make more of the arglist or documentation string visible. + +Non-nil values for this variable have no effect unless +`cldoc-echo-area-multiline-supported-p' is non-nil." + :type '(radio (const :tag "Always" t) + (const :tag "Never" nil) + (const :tag "Yes, but truncate symbol names if it will\ + enable argument list to fit on one line" truncate-sym-name-if-fit)) + :group 'cldoc) + +;;; No user options below here. + +;; Non-nil if this version of emacs supports dynamically resizable echo areas. +(defvar cldoc-echo-area-multiline-supported-p + (and (string-lessp "21" emacs-version) + (save-match-data + (numberp (string-match "^GNU Emacs" (emacs-version)))))) + +;; Commands after which it is appropriate to print in the echo area. +;; Cldoc does not try to print function arglists, etc. after just any command, +;; because some commands print their own messages in the echo area and these +;; functions would instantly overwrite them. But self-insert-command as well +;; as most motion commands are good candidates. +;; This variable contains an obarray of symbols; do not manipulate it +;; directly. Instead, use `cldoc-add-command' and `cldoc-remove-command'. +(defvar cldoc-message-commands nil) + +;; This is used by cldoc-add-command to initialize cldoc-message-commands +;; as an obarray. +;; It should probably never be necessary to do so, but if you +;; choose to increase the number of buckets, you must do so before loading +;; this file since the obarray is initialized at load time. +;; Remember to keep it a prime number to improve hash performance. +(defvar cldoc-message-commands-table-size 31) + +;; Bookkeeping; elements are as follows: +;; 0 - contains the last symbol read from the buffer. +;; 1 - contains the string last displayed in the echo area for that +;; symbol, so it can be printed again if necessary without reconsing. +;; 2 - 'function if function args, 'variable if variable documentation. +(defvar cldoc-last-data (make-vector 3 nil)) +(defvar cldoc-last-message nil) + +;; Idle timers are supported in Emacs 19.31 and later. +(defvar cldoc-use-idle-timer-p (fboundp 'run-with-idle-timer)) + +;; cldoc's timer object, if using idle timers +(defvar cldoc-timer nil) + +;; idle time delay currently in use by timer. +;; This is used to determine if cldoc-idle-delay is changed by the user. +(defvar cldoc-current-idle-delay cldoc-idle-delay) + +;; Put minor mode string on the global minor-mode-alist. +;;;###autoload +(cond ((fboundp 'add-minor-mode) + (add-minor-mode 'cldoc-mode 'cldoc-minor-mode-string)) + ((assq 'cldoc-mode (default-value 'minor-mode-alist))) + (t + (setq-default minor-mode-alist + (append (default-value 'minor-mode-alist) + '((cldoc-mode cldoc-minor-mode-string)))))) + + +;;;###autoload +(defun cldoc-mode (&optional prefix) + "*Enable or disable cldoc mode. +See documentation for the variable of the same name for more details. + +If called interactively with no prefix argument, toggle current condition +of the mode. +If called with a positive or negative prefix argument, enable or disable +the mode, respectively." + (interactive "P") + (setq cldoc-last-message nil) + (cond (cldoc-use-idle-timer-p + (add-hook 'post-command-hook 'cldoc-schedule-timer) + (add-hook 'pre-command-hook 'cldoc-pre-command-refresh-echo-area)) + (t + ;; Use post-command-idle-hook if defined, otherwise use + ;; post-command-hook. The former is only proper to use in Emacs + ;; 19.30; that is the first version in which it appeared, but it + ;; was obsolesced by idle timers in Emacs 19.31. + (add-hook (if (boundp 'post-command-idle-hook) + 'post-command-idle-hook + 'post-command-hook) + 'cldoc-print-current-symbol-info t t) + ;; quick and dirty hack for seeing if this is XEmacs + (and (fboundp 'display-message) + (add-hook 'pre-command-hook + 'cldoc-pre-command-refresh-echo-area t t)))) + (setq cldoc-mode (if prefix + (>= (prefix-numeric-value prefix) 0) + (not cldoc-mode))) + (and (interactive-p) + (if cldoc-mode + (message "cldoc-mode is enabled") + (message "cldoc-mode is disabled"))) + (when (and cldoc-mode (and (boundp 'slime-autodoc-mode) slime-autodoc-mode)) + (slime-autodoc-mode -1)) + cldoc-mode) + +;;;###autoload +(defun turn-on-cldoc-mode () + "Unequivocally turn on cldoc-mode (see variable documentation)." + (interactive) + (cldoc-mode 1)) + + +;; Idle timers are part of Emacs 19.31 and later. +(defun cldoc-schedule-timer () + (or (and cldoc-timer + (memq cldoc-timer timer-idle-list)) + (setq cldoc-timer + (run-with-idle-timer cldoc-idle-delay t + 'cldoc-print-current-symbol-info))) + + ;; If user has changed the idle delay, update the timer. + (cond ((not (= cldoc-idle-delay cldoc-current-idle-delay)) + (setq cldoc-current-idle-delay cldoc-idle-delay) + (timer-set-idle-time cldoc-timer cldoc-idle-delay t)))) + +(defun cldoc-message (&rest args) + (let ((omessage cldoc-last-message)) + (cond ((eq (car args) cldoc-last-message)) + ((or (null args) + (null (car args))) + (setq cldoc-last-message nil)) + ;; If only one arg, no formatting to do so put it in + ;; cldoc-last-message so eq test above might succeed on + ;; subsequent calls. + ((null (cdr args)) + (setq cldoc-last-message (car args))) + (t + (setq cldoc-last-message (apply 'format args)))) + ;; In emacs 19.29 and later, and XEmacs 19.13 and later, all messages + ;; are recorded in a log. Do not put cldoc messages in that log since + ;; they are Legion. + (cond ((fboundp 'display-message) + ;; XEmacs 19.13 way of preventing log messages. + (cond (cldoc-last-message + (display-message 'no-log cldoc-last-message)) + (omessage + (clear-message 'no-log)))) + (t + ;; Emacs way of preventing log messages. + (let ((message-log-max nil)) + (cond (cldoc-last-message + (message "%s" cldoc-last-message)) + (omessage + (message nil))))))) + cldoc-last-message) + +;; This function goes on pre-command-hook for XEmacs or when using idle +;; timers in Emacs. Motion commands clear the echo area for some reason, +;; which make cldoc messages flicker or disappear just before motion +;; begins. This function reprints the last cldoc message immediately +;; before the next command executes, which does away with the flicker. +;; This doesn't seem to be required for Emacs 19.28 and earlier. +(defun cldoc-pre-command-refresh-echo-area () + (and cldoc-last-message + (if (cldoc-display-message-no-interference-p) + (cldoc-message cldoc-last-message) + (setq cldoc-last-message nil)))) + +;; Decide whether now is a good time to display a message. +(defun cldoc-display-message-p () + (and (cldoc-display-message-no-interference-p) + (cond (cldoc-use-idle-timer-p + ;; If this-command is non-nil while running via an idle + ;; timer, we're still in the middle of executing a command, + ;; e.g. a query-replace where it would be annoying to + ;; overwrite the echo area. + (and (not this-command) + (symbolp last-command) + (intern-soft (symbol-name last-command) + cldoc-message-commands))) + (t + ;; If we don't have idle timers, this function is + ;; running on post-command-hook directly; that means the + ;; user's last command is still on `this-command', and we + ;; must wait briefly for input to see whether to do display. + (and (symbolp this-command) + (intern-soft (symbol-name this-command) + cldoc-message-commands) + (sit-for cldoc-idle-delay)))))) + +;; Check various conditions about the current environment that might make +;; it undesirable to print cldoc messages right this instant. +(defun cldoc-display-message-no-interference-p () + (and cldoc-mode + (not executing-kbd-macro) + (not (and (boundp 'edebug-active) edebug-active)) + ;; Having this mode operate in an active minibuffer/echo area causes + ;; interference with what's going on there. + (not cursor-in-echo-area) + (not (eq (selected-window) (minibuffer-window))))) + + +(defun cldoc-print-current-symbol-info () + (and (cldoc-display-message-p) + (let* ((current-symbol (cldoc-current-symbol)) + (current-fnsym (cldoc-fnsym-in-current-sexp)) + (doc (cond ((eq current-symbol current-fnsym) + (or (cldoc-get-fnsym-args-string current-fnsym) + (cldoc-get-var-value current-symbol))) + (t + (or (cldoc-get-var-value current-symbol) + (cldoc-get-fnsym-args-string current-fnsym)))))) + (cldoc-message doc)))) + + +(defun cldoc-get-fnsym-signature-from-lisp-process (sym) + (cond + ((fboundp 'slime-space) + ;; from slime.el + (when (and slime-space-information-p + (slime-connected-p) + (or (not (slime-busy-p)))) + (let ((result (slime-eval + `(swank:arglist-for-echo-area '(,(symbol-name sym)))))) + (when (stringp result) (cdar (read-from-string result)))))) + ;;((fboundp 'ilisp-arglist-message-lisp-space) + ;; (cldoc-ilisp-signature)) + (t nil))) + +;; Return a string containing the function parameter list, or 1-line +;; docstring if function is a subr and no arglist is obtainable from the +;; docstring or elsewhere. +(defun cldoc-get-fnsym-args-string (sym) + (let* ((entry (intern-soft (downcase (symbol-name sym)) cl-operator-signatures)) + (signature (if (and entry (boundp entry)) + (symbol-value entry) + (cldoc-get-fnsym-signature-from-lisp-process sym)))) + (setq doc + (cond + ((null signature) nil) + ((stringp signature) + (cldoc-docstring-format-sym-doc sym signature)) + (t + (let* ((tail (member '=> signature)) + (result (cldoc-function-resultstring-format (cdr tail))) + (args (cldoc-function-argstring-format (ldiff signature tail))) + (args-and-result (if tail + (format "%s => %s" args result) + (format "%s" args)))) + (cldoc-docstring-format-sym-doc sym args-and-result))))))) + +(defun cldoc-function-resultstring-format (results) + (let (str) + (do* ((results results (cdr results)) + result) + ((endp results)) + (setq result (funcall cldoc-argument-case (symbol-name (car results)))) + (if str + (setq str (format "%s, %s" str result)) + (setq str (format "%s" result)))) + str)) + + +;; Return a string containing a brief (one-line) documentation string for +;; the variable. +(defun cldoc-get-var-value (sym) + (cond + ((fboundp 'slime-autodoc) ;; from slime.el + (let* ((name (slime-autodoc-global-at-point)) + (value (when (and name + slime-space-information-p + (slime-connected-p) + (or (not (slime-busy-p))) + (slime-global-variable-name-p name)) + (slime-eval `(swank:variable-desc-for-echo-area ,name))))) + value)) + (t nil))) + +(defun cldoc-last-data-store (symbol doc type) + (aset cldoc-last-data 0 symbol) + (aset cldoc-last-data 1 doc) + (aset cldoc-last-data 2 type)) + +;; Note that any leading `*' in the docstring (which indicates the variable +;; is a user option) is removed. +(defun cldoc-docstring-first-line (doc) + (and (stringp doc) + (substitute-command-keys + (save-match-data + (let ((start (if (string-match "^\\*" doc) (match-end 0) 0))) + (cond ((string-match "\n" doc) + (substring doc start (match-beginning 0))) + ((zerop start) doc) + (t (substring doc start)))))))) + +;; If the entire line cannot fit in the echo area, the symbol name may be +;; truncated or eliminated entirely from the output to make room for the +;; description. +(defun cldoc-docstring-format-sym-doc (sym doc) + (save-match-data + (let* ((name (symbol-name sym)) + (ea-multi (and cldoc-echo-area-multiline-supported-p + cldoc-echo-area-use-multiline-p)) + ;; Subtract 1 from window width since emacs will not write + ;; any chars to the last column, or in later versions, will + ;; cause a wraparound and resize of the echo area. + (ea-width (1- (window-width (minibuffer-window)))) + (strip (- (+ (length name) (length ": ") (length doc)) ea-width))) + (cond ((or (<= strip 0) + (eq ea-multi t) + (and ea-multi (> (length doc) ea-width))) + (format "%s: %s" sym doc)) + ((> (length doc) ea-width) + (substring (format "%s" doc) 0 ea-width)) + ((>= strip (length name)) + (format "%s" doc)) + (t + ;; Show the end of the partial symbol name, rather + ;; than the beginning, since the former is more likely + ;; to be unique given package namespace conventions. + (setq name (substring name strip)) + (format "%s: %s" name doc)))))) + + +(defun cldoc-fnsym-in-current-sexp () + (let ((p (point))) + (cldoc-beginning-of-sexp) + (prog1 + ;; Don't do anything if current word is inside a string. + (if (= (or (char-after (1- (point))) 0) ?\") + nil + (cldoc-current-symbol)) + (goto-char p)))) + +(defun cldoc-beginning-of-sexp () + (let ((parse-sexp-ignore-comments t)) + (condition-case err + (while (progn + (forward-sexp -1) + (or (= (or (char-after (1- (point)))) ?\") + (> (point) (point-min))))) + (error nil)))) + +(defun cldoc-current-symbol () + (let ((c (char-after (point)))) + (and c + (memq (char-syntax c) '(?w ?_)) + (intern (current-word))))) + +;; Do indirect function resolution if possible. +(defun cldoc-symbol-function (fsym) + (let ((defn (and (fboundp fsym) + (symbol-function fsym)))) + (and (symbolp defn) + (condition-case err + (setq defn (indirect-function fsym)) + (error (setq defn nil)))) + defn)) + +(defun cldoc-function-arglist (fn) + (let* ((prelim-def (cldoc-symbol-function fn)) + (def (if (eq (car-safe prelim-def) 'macro) + (cdr prelim-def) + prelim-def)) + (arglist (cond ((null def) nil) + ((byte-code-function-p def) + (cond ((fboundp 'compiled-function-arglist) + (funcall 'compiled-function-arglist def)) + (t + (aref def 0)))) + ((eq (car-safe def) 'lambda) + (nth 1 def)) + (t t)))) + arglist)) + +(defun cldoc-function-argstring (fn) + (cldoc-function-argstring-format (cldoc-function-arglist fn))) + +(defun cldoc-function-arg-format (arg) + (typecase arg + (symbol (if (memq arg '(&allow-other-keys &aux &body &environment &key &optional + &rest &whole)) + (symbol-name arg) + (funcall cldoc-argument-case (symbol-name arg)))) + (string (if (member arg '("&allow-other-keys" "&aux" "&body" "&environment" + "&key" "&optional" "&rest" "&whole")) + arg + (funcall cldoc-argument-case (symbol-name arg)))) + (cons (cldoc-function-argstring-format arg)) + (t (format "%s" arg)))) + +(defun cldoc-function-argstring-format (arglist) + (concat "(" (mapconcat #'cldoc-function-arg-format arglist " ") ")")) + + +;; Alist of predicate/action pairs. +;; Each member of the list is a sublist consisting of a predicate function +;; used to determine if the arglist for a function can be found using a +;; certain pattern, and a function which returns the actual arglist from +;; that docstring. +;; +;; The order in this table is significant, since later predicates may be +;; more general than earlier ones. +;; +;; Compiler note for Emacs/XEmacs versions which support dynamic loading: +;; these functions will be compiled to bytecode, but can't be lazy-loaded +;; even if you set byte-compile-dynamic; to do that would require making +;; them named top-level defuns, which is not particularly desirable either. +(defvar cldoc-function-argstring-from-docstring-method-table + (list + ;; Try first searching for args starting with symbol name. + ;; This is to avoid matching parenthetical remarks in e.g. sit-for. + (list (function (lambda (doc fn) + (string-match (format "^(%s[^\n)]*)$" fn) doc))) + (function (lambda (doc) + ;; end does not include trailing ")" sequence. + (let ((end (- (match-end 0) 1))) + (if (string-match " +" doc (match-beginning 0)) + (substring doc (match-end 0) end) + ""))))) + + ;; Try again not requiring this symbol name in the docstring. + ;; This will be the case when looking up aliases. + (list (function (lambda (doc fn) + ;; save-restriction has a pathological docstring in + ;; Emacs/XEmacs 19. + (and (not (eq fn 'save-restriction)) + (string-match "^([^\n)]+)$" doc)))) + (function (lambda (doc) + ;; end does not include trailing ")" sequence. + (let ((end (- (match-end 0) 1))) + (and (string-match " +" doc (match-beginning 0)) + (substring doc (match-end 0) end)))))) + + ;; Emacs subr docstring style: + ;; (fn arg1 arg2 ...): description... + (list (function (lambda (doc fn) + (string-match "^([^\n)]+):" doc))) + (function (lambda (doc) + ;; end does not include trailing "):" sequence. + (let ((end (- (match-end 0) 2))) + (and (string-match " +" doc (match-beginning 0)) + (substring doc (match-end 0) end)))))) + + ;; XEmacs subr docstring style: + ;; "arguments: (arg1 arg2 ...) + (list (function (lambda (doc fn) + (string-match "^arguments: (\\([^\n)]+\\))" doc))) + (function (lambda (doc) + ;; also skip leading paren, but the first word is + ;; actually an argument, not the function name. + (substring doc (match-beginning 1) (match-end 1))))) + + ;; This finds the argstring for `condition-case'. Any others? + (list (function (lambda (doc fn) + (string-match + (format "^Usage looks like \\((%s[^\n)]*)\\)\\.$" fn) + doc))) + (function (lambda (doc) + ;; end does not include trailing ")" sequence. + (let ((end (- (match-end 1) 1))) + (and (string-match " +" doc (match-beginning 1)) + (substring doc (match-end 0) end)))))) + + ;; This finds the argstring for `setq-default'. Any others? + (list (function (lambda (doc fn) + (string-match (format "^[ \t]+\\((%s[^\n)]*)\\)$" fn) + doc))) + (function (lambda (doc) + ;; end does not include trailing ")" sequence. + (let ((end (- (match-end 1) 1))) + (and (string-match " +" doc (match-beginning 1)) + (substring doc (match-end 0) end)))))) + + ;; This finds the argstring for `start-process'. Any others? + (list (function (lambda (doc fn) + (string-match "^Args are +\\([^\n]+\\)$" doc))) + (function (lambda (doc) + (substring doc (match-beginning 1) (match-end 1))))) + + ;; These common subrs don't have arglists in their docstrings. So cheat. + (list (function (lambda (doc fn) + (memq fn '(and or list + -)))) + (function (lambda (doc) + ;; The value nil is a placeholder; otherwise, the + ;; following string may be compiled as a docstring, + ;; and not a return value for the function. + ;; In interpreted lisp form they are + ;; indistinguishable; it only matters for compiled + ;; forms. + nil + "&rest args"))) + )) + +(defun cldoc-function-argstring-from-docstring (fn) + (let ((docstring (documentation fn 'raw)) + (table cldoc-function-argstring-from-docstring-method-table) + (doc nil) + (doclist nil)) + (save-match-data + (while table + (cond ((funcall (car (car table)) docstring fn) + (setq doc (funcall (car (cdr (car table))) docstring)) + (setq table nil)) + (t + (setq table (cdr table))))) + + (cond ((not (stringp doc)) + nil) + ((string-match "&" doc) + (let ((p 0) + (l (length doc))) + (while (< p l) + (cond ((string-match "[ \t\n]+" doc p) + (setq doclist + (cons (substring doc p (match-beginning 0)) + doclist)) + (setq p (match-end 0))) + (t + (setq doclist (cons (substring doc p) doclist)) + (setq p l)))) + (cldoc-function-argstring-format (nreverse doclist)))) + (t + (concat "(" (funcall cldoc-argument-case doc) ")")))))) + + +;; When point is in a sexp, the function args are not reprinted in the echo +;; area after every possible interactive command because some of them print +;; their own messages in the echo area; the cldoc functions would instantly +;; overwrite them unless it is more restrained. +;; These functions do display-command table management. + +(defun cldoc-add-command (&rest cmds) + (or cldoc-message-commands + (setq cldoc-message-commands + (make-vector cldoc-message-commands-table-size 0))) + + (let (name sym) + (while cmds + (setq name (car cmds)) + (setq cmds (cdr cmds)) + + (cond ((symbolp name) + (setq sym name) + (setq name (symbol-name sym))) + ((stringp name) + (setq sym (intern-soft name)))) + + (and (symbolp sym) + (fboundp sym) + (set (intern name cldoc-message-commands) t))))) + +(defun cldoc-add-command-completions (&rest names) + (while names + (apply 'cldoc-add-command + (all-completions (car names) obarray 'fboundp)) + (setq names (cdr names)))) + +(defun cldoc-remove-command (&rest cmds) + (let (name) + (while cmds + (setq name (car cmds)) + (setq cmds (cdr cmds)) + + (and (symbolp name) + (setq name (symbol-name name))) + + (if (fboundp 'unintern) + (unintern name cldoc-message-commands) + (let ((s (intern-soft name cldoc-message-commands))) + (and s + (makunbound s))))))) + +(defun cldoc-remove-command-completions (&rest names) + (while names + (apply 'cldoc-remove-command + (all-completions (car names) cldoc-message-commands)) + (setq names (cdr names)))) + + +;; Prime the command list. +(cldoc-add-command-completions + "backward-" "beginning-of-" "delete-other-windows" "delete-window" + "end-of-" "forward-" "indent-for-tab-command" "goto-" "mouse-set-point" + "next-" "other-window" "previous-" "recenter" "scroll-" + "self-insert-command" "split-window-" + "up-list" "down-list") + + +(defvar cl-operator-signatures (make-vector 67 0)) + +;; note +;; these symbols are used, => =>| +(mapcar (lambda (entry) + (let ((symbol (intern (symbol-name (car entry)) cl-operator-signatures))) + (set symbol (cdr entry)))) + + '(;; evaluation and compilation + (lambda . "lambda-list [[declaration* | documentation]] form* => function") + (compile function-name-or-nil &optional lambda-expression-or-function => function warnings-p failure-p) + (eval form => result*) + (eval-when . "(situation*) form* => result*") + (load-time-value . "form &optional read-only-p => object") + (quote object => object) + (compiler-macro-function name &optional (environment nil) => function) + (define-compiler-macro . "name lambda-list [[declaration* | documentation]] form* => name") + (defmacro . "name lambda-list [[declaration* | documentation]] form* => name") + (macro-function symbol &optional (environment nil) => macro-function-or-nil) + (macroexpand form &optional (environment nil) => expansion expanded-p) + (macroexpand-1 form &optional (environment nil) => expansion expanded-p) + (define-symbol-macro . "symbol expansion => symbol") + (symbol-macrolet . "((symbol expansion)*) declaration* form* => result*") + (proclaim declaration-specifier => implementation-dependent) + (declaim . "declaration-specifier* => implementation-dependent") + (locally declaration* form* => result*) + (the value-type form => result*) + (special-operator-p symbol => generalized-boolean) + (constantp form &optional (environment nil) => generalized-boolean) + + + ;; types and classes + (coerce object result-type => result) + (deftype . "name lambda-list [[declaration* | documentation]] form* => name") + (subtypep subtype type &optional (environment nil) => subtype-p valid-p) + (typep object type-specifier &optional (environment nil) => generalized-boolean) + (type-error-datum condition => datum) + (type-error-expected-type condition => expected-type) + + + ;; data and control flow + (apply function &rest args+ => result*) + (defun . "function-name lambda-list [[declaration* | documentation]] form* => function-name") + (fdefinition function-name => definition) + (fboundp function-name => generalized-boolean) + (fmakunbound function-name => function-name) + (flet . "((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form* => result*") + (labels . "((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form* => result*") + (macrolet . "((name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form* => result*") + + (funcall function &rest args => result*) + (function . "function-name-or-lambda-expression => function") + (function-lambda-expression function => lambda-expression closure-p name) + (functionp object => generalized-boolean) + (compiled-function-p object => generalized-boolean) + (defconstant . "name initial-value [documentation] => name") + (defparameter . "name initial-value [documentation] => name") + (defvar . "name [initial-value [documentation]] => name") + (destructuring-bind . "destructuring-lambda-list expression declaration* form* => result*") + (let . "({var | (var [init-form])}*) declaration* form* => result*") + (let* . "({var | (var [init-form])}*) declaration* form* => result*") + (progv . "symbols values form* => result*") + (setq . "{pair}* => result") + (psetq . "{pair}* => nil") + (block . "name-symbol form* => result*") + (catch . "tag-form form* => result*") + (go . "tag =>|") + (return-from . "name [result-form] =>|") + (return . "[result-form] =>|") + (tagbody . "{tag | statement}* => nil") + (throw . "tag-form result-form =>|") + (unwind-protect . "protected-form cleanup-form* => result*") + (not x => boolean) + (eq x y => generalized-boolean) + (eql x y => generalized-boolean) + (equal x y => generalized-boolean) + (equalp x y => generalized-boolean) + (identity object => object) + (complement function => complement-function) + (constantly value => function-constantly-returning-value) + (every predicate &rest sequences+ => generalized-boolean) + (some predicate &rest sequences+ => result) + (notevery predicate &rest sequences+ => generalized-boolean) + (notany predicate &rest sequences+ => generalized-boolean) + (and . "form* => result*") + (cond . "{(test-form form*)}* => result*") + (if . "test-form then-form [else-form] => result*") + (or . "form* => results*") + (when . "test-form form* => result*") + (unless . "test-form form* => result*") + (case . "keyform {(keys form*)}* [({otherwise | t} form*)] => result*") + (ccase . "keyplace {(keys form*)}* => result*") + (ecase . "keyform {(keys form*)}* => result*") + (typecase . "keyform {(type form*)}* [({otherwise | t} form*)] => result*") + (ctypecase . "keyplace {(type form*)}* => result*") + (etypecase . "keyform {(type form*)}* => result*") + (multiple-value-bind . "(var*) values-form declaration* form* => result*") + (multiple-value-call . "function-form form* => result*") + (multiple-value-list . "form => list") + (multiple-value-prog1 . "first-form form* => first-form-results") + (multiple-value-setq . "vars form => result") + (values &rest object => object*) + (values-list list => element*) + (nth-value . "n-form form => object") + (prog . "({var | (var [init-form])}*) declaration* {tag | statement}* => result*") + (prog* . "({var | (var [init-form])}*) declaration* {tag | statement}* => result*") + (prog1 . "first-form form* => primary-value-of-evaluated-first-form") + (prog2 . "first-form second-form form* => primary-value-of-evaluated-second-form") + (progn . "form* => result*") + (define-modify-macro . "name lambda-list function [documentation] => name") + ;;(defsetf . "access-fn update-fn [documentation] => access-fn") + ;;(defsetf . " access-fn lambda-list (store-variable*) [[declaration* | documentation]] form* => access-fn") + (define-setf-expander . "access-fn lambda-list [[declaration* | documentation]] form* => access-fn") + (get-setf-expansion place &optional (environment nil) => vars vals store-vars writer-form reader-form) + (setf . "{place newvalue}* => result*") + (psetf . "{place newvalue}* => nil") + (shiftf . "place+ newvalue => old-value-1") + (rotatef . "place* => nil") + + + ;; iteration + (do . "({var | (var [init-form [step-form]])}*) (end-test-form result-form*) declaration* {tag | statement}* => result*") + (do* . "({var | (var [init-form [step-form]])}*) (end-test-form result-form*) declaration* {tag | statement}* => result*") + (dotimes . "(var count-form [result-form]) declaration* {tag | statement}* => result*") + (dolist . "(var list-form [result-form]) declaration* {tag | statement}* => result*") + ;;(loop . "compound-form* => result*") + ;;(loop . "[name-clause] {variable-clause}* {main-clause}* => result*") + (loop-finish . " =>|") + + + ;; objects + (function-keywords method => keys allow-other-keys-p) + (ensure-generic-function function-name &key argument-precedence-order declare documentation environment generic-function-class lambda-list method-class method-combination => generic-function) + (allocate-instance class &rest initargs &key &allow-other-keys => new-instance) + (reinitialize-instance instance &rest initargs &key &allow-other-keys => instance) + (shared-initialize instance slot-names &rest initargs &key &allow-other-keys => instance) + (update-instance-for-different-class previous current &rest initargs &key &allow-other-keys => implementation-dependent) + (update-instance-for-redefined-class instance added-slots discarded-slots property-list &rest initargs &key &allow-other-keys => result*) + (change-class instance new-class &key &allow-other-keys => instance) + (slot-boundp instance slot-name => generalized-boolean) + (slot-exists-p object slot-name => generalized-boolean) + (slot-makunbound instance slot-name => instance) + (slot-missing class object slot-name operation &optional new-value => result*) + (slot-unbound class instance slot-name => result*) + (slot-value object slot-name => value) + (method-qualifiers method => qualifiers) + (no-applicable-method generic-function &rest function-arguments => result*) + (no-next-method generic-function method &rest args => result*) + (remove-method generic-function method => generic-function) + (make-instance class-designator &rest initargs &key &allow-other-keys => instance) + (make-instances-obsolete class-designator => class) + (make-load-form object &optional (environment nil) => creation-form \[initialization-form\]) + (make-load-form-saving-slots object &key slot-names (environment nil) => creation-form initialization-form) + (with-accessors . "(slot-entry*) instance-form declaration* form* => result*") + (with-slots . "({slot-name | (variable-name slot-name)}*) instance-form declaration* form* => result*") + (defclass . "class-name ({superclass-name}*) ({slot-specifier}*) [[class-option]] => new-class") + (defgeneric . "function-name gf-lambda-list [[option | {method-description}*]] => new-generic)") + (defmethod . "function-name {method-qualifier}* specialized-lambda-list [[declaration* | documentation]] form* => new-method") + (find-class symbol &optional (errorp t) environment => class) + (next-method-p => generalized-boolean) + (call-method method &optional next-method-list => result*) + (make-method form => method-object) + (call-next-method &rest args => result*) + (compute-applicable-methods generic-function function-arguments => methods) + ;;(define-method-combination . "name [[short-form-option]] => name") + ;;(define-method-combination . "name lambda-list (method-group-specifier*) [(:arguments . args-lambda-list)] [(:generic-function generic-function-symbol)] [[declaration* | documentation]] form* => name") + (find-method generic-function method-qualifiers specializers &optional (errorp t) => method) + (add-method generic-function method => generic-function) + (initialize-instance instance &rest initargs &key &allow-other-keys => instance) + (class-name class => name) + (class-of object => class) + (unbound-slot-instance condition => instance) + + ;; structures + (defstruct . "name-and-options [documentation] {slot-description}* => structure-name") + (copy-structure structure => copy) + + + ;; conditions + (cell-error-name condition => name) + (assert . "test-form [(place*) [datum-form argument-form*]] => nil") + (error datum &rest arguments =>|) + (cerror continue-format-control datum &rest arguments => nil) + (check-type . "place typespec [string] => nil") + (invalid-method-error method format-control &rest args => implementation-dependent) + (method-combination-error format-control &rest args => implementation-dependent) + (signal datum &rest arguments => nil) + (simple-condition-format-control condition => format-control) + (simple-condition-format-arguments condition => format-arguments) + (warn datum &rest arguments => nil) + (invoke-debugger condition =>|) + (break &optional (format-control *implementation-dependent-format-control*) &rest format-arguments => nil) + (handler-bind . "({(type handler)}*) form* => result*") + (handler-case . "expression [[{error-clause}* | no-error-clause]] => result* +clause::= error-clause | no-error-clause +error-clause::= (typespec ([var]) declaration* form*) +no-error-clause::= (:no-error lambda-list declaration* form*)") + (ignore-errors . "form* => result*") + (define-condition . "name (parent-type*) ({slot-spec}*) option* => name") + (make-condition type &rest slot-initializations => condition) + (compute-restarts &optional (condition nil) => restarts) + (find-restart identifier &optional (condition nil) => restart) + (invoke-restart restart-designator &rest arguments => result*) + (invoke-restart-interactively restart-designator => result*) + (restart-bind . "({(name function {key-val-pair}*)}) form* => result*") + (restart-case . "restartable-form {clause} => result*") + (restart-name restart => name) + (with-condition-restarts . "condition-form restarts-form form* => result*") + (with-simple-restart . "(name format-control format-argument*) form* => result*") + (abort &optional (condition nil) =>|) + (continue &optional (condition nil) => nil) + (muffle-warning &optional (condition nil) =>|) + (store-value value &optional (condition nil) => nil) + (use-value value &optional (condition nil) => nil) + + + ;; symbols + (symbolp object => generalized-boolean) + (keywordp object => generalized-boolean) + (make-symbol name-string => new-symbol) + (copy-symbol symbol &optional (copy-properties nil) => new-symbol) + (gensym &optional string-or-non-negative-integer => new-symbol) + (gentemp &optional (prefix "T") (package *package*) => new-symbol) + (symbol-function symbol => contents) + (symbol-name symbol => name) + (symbol-package symbol => package-or-nil) + (symbol-plist symbol => plist) + (symbol-value symbol => value) + (get symbol indicator &optional (default nil) => value) + (remprop symbol indicator => generalized-boolean) + (boundp symbol => generalized-boolean) + (makunbound symbol => symbol) + (set symbol value => value) + + + ;; packages + (export designator-for-a-list-of-symbols &optional (package *package*) => t) + (find-symbol string &optional (package *package*) => symbol status) + (find-package string-designator-or-package => package) + (find-all-symbols string-designator => symbols) + (import designator-for-a-list-of-symbols &optional (package *package*)) + (list-all-packages => packages) + (rename-package package new-name &optional (new-nicknames '()) => package-object) + (shadow symbol-names &optional (package *package*) => t) + (shadowing-import designator-for-a-list-of-symbols &optional (package *package*) => t) + (delete-package package-designator => generalized-boolean) + (make-package package-name &key (nicknames '()) (use *implementation-defined-use-list*) => package) + (with-package-iterator . "(name package-list-form &rest symbol-types) declaration* form* => result*") + (unexport designator-for-a-list-of-symbols &optional (package *package*) => t) + (unintern symbol &optional (package *package*) => generalized-boolean) + (in-package . "name => package") + (unuse-package packages-to-unuse &optional (package *package*) => t) + (use-package packages-to-use &optional (package *package*) => t) + (defpackage . "defined-package-name [[option]] => package +option::= (:nicknames nickname*)* | + (:documentation string) | + (:use package-name*)* | + (:shadow {symbol-name}*)* | + (:shadowing-import-from package-name {symbol-name}*)* | + (:import-from package-name {symbol-name}*)* | + (:export {symbol-name}*)* | + (:intern {symbol-name}*)* | + (:size integer) ") + (do-symbols . "(var [package [result-form]]) declaration* {tag | statement}* => result*") + (do-external-symbols . "(var [package [result-form]]) declaration* {tag | statement}* => result*") + (do-all-symbols . "(var [result-form]) declaration* {tag | statement}* => result*") + (intern string &optional (package *package*) => symbol status) + (package-name package-designator => name) + (package-nicknames package-designator => nicknames) + (package-shadowing-symbols package-designator => symbols) + (package-use-list package-designator => use-list) + (package-used-by-list package-designator => used-by-list) + (packagep object => generalized-boolean) + (package-error-package condition => package) + + + ;; numbers + (= &rest numbers+ => generalized-boolean) + (/= &rest numbers+ => generalized-boolean) + (< &rest numbers+ => generalized-boolean) + (> &rest numbers+ => generalized-boolean) + (<= &rest numbers+ => generalized-boolean) + (>= &rest numbers+ => generalized-boolean) + (max &rest reals+ => max-real) + (min &rest reals+ => min-real) + (minusp real => generalized-boolean) + (plusp real => generalized-boolean) + (zerop number => generalized-boolean) + (floor number &optional (divisor 1) => quotient remainder) + (ffloor number &optional (divisor 1) => quotient remainder) + (ceiling number &optional (divisor 1) => quotient remainder) + (fceiling number &optional (divisor 1) => quotient remainder) + (truncate number &optional (divisor 1) => quotient remainder) + (ftruncate number &optional (divisor 1) => quotient remainder) + (round number &optional (divisor 1) => quotient remainder) + (fround number &optional (divisor 1) => quotient remainder) + (sin radians => number) + (cos radians => number) + (tan radians => number) + (asin number => radians) + (acos number => radians) + (atan number1 &optional number2 => radians) + (sinh number => result) + (cosh number => result) + (tanh number => result) + (asinh number => result) + (acosh number => result) + (atanh number => result) + (* &rest numbers => product) + (+ &rest numbers => sum) + ;;(- number => negation) + ;;(- minuend &rest subtrahends+ => difference) + ;;(/ number => reciprocal) + ;;(/ numerator &rest denominators+ => quotient) + (1+ number => successor) + (1- number => predecessor) + (abs number => absolute-value) + (evenp integer => generalized-boolean) + (oddp integer => generalized-boolean) + (exp number => result) + (expt base-number power-number => result) + (gcd &rest integers => greatest-common-denominator) + (incf . "place [delta-form] => new-value") + (decf . "place [delta-form] => new-value") + (lcm &rest integers => least-common-multiple) + (log number &optional (base *E-base-of-the-natural-logarithms*) => logarithm) + (mod number divisor => modulus) + (rem number divisor => remainder) + (signum number => signed-prototype) + (sqrt number => root) + (isqrt natural => natural-root) + (make-random-state &optional (state nil) => new-state) + (random limit &optional (random-state *random-state*) => random-number) + (random-state-p object => generalized-boolean) + (numberp object => generalized-boolean) + (cis radians => number) + (complex realpart &optional (imagpart (coerce 0 (type-of realpart))) => complex) + (complexp object => generalized-boolean) + (conjugate number => conjugate) + (phase number => phase) + (realpart number => real) + (imagpart number => real) + (upgraded-complex-part-type typespec &optional (environment nil) => upgraded-typespec) + (realp object => generalized-boolean) + (numerator rational => numerator) + (denominator rational => denominator) + (rational number => rational) + (rationalize number => rational) + (rationalp object => generalized-boolean) + (ash integer count => shifted-integer) + (integer-length integer => number-of-bits) + (integerp object => generalized-boolean) + (parse-integer string &key (start 0) (end nil) (radix 10) junk-allowed => integer pos) + (boole op integer-1 integer-2 => result-integer) + (logand &rest integers => result-integer) + (logandc1 integer-1 integer-2 => result-integer) + (logandc2 integer-1 integer-2 => result-integer) + (logeqv &rest integers => result-integer) + (logior &rest integers => result-integer) + (lognand integer-1 integer-2 => result-integer) + (lognor integer-1 integer-2 => result-integer) + (lognot integer => result-integer) + (logorc1 integer-1 integer-2 => result-integer) + (logorc2 integer-1 integer-2 => result-integer) + (logxor &rest integers => result-integer) + (logbitp index integer => generalized-boolean) + (logcount integer => number-of-on-bits) + (logtest integer-1 integer-2 => generalized-boolean) + (byte size position => bytespec) + (byte-size bytespec => size) + (byte-position bytespec => position) + (deposit-field newbyte bytespec integer => result-integer) + (dpb newbyte bytespec integer => result-integer) + (ldb bytespec integer => byte) + (ldb-test bytespec integer => generalized-boolean) + (mask-field bytespec integer => masked-integer) + (decode-float float => significand exponent sign) + (scale-float float integer => scaled-float) + (float-radix float => float-radix) + (float-sign float-1 &optional (float-2 (float 1 float-1)) => signed-float) + (float-digits float => digits1) + (float-precision float => digits2) + (integer-decode-float float => significand exponent integer-sign) + (float number &optional prototype => float) + (floatp object) + (arithmetic-error-operands condition => operands) + (arithmetic-error-operation condition => operation) + + ;; characters + (char= &rest characters+ => generalized-boolean) + (char/= &rest characters+ => generalized-boolean) + (char< &rest characters+ => generalized-boolean) + (char> &rest characters+ => generalized-boolean) + (char<= &rest characters+ => generalized-boolean) + (char>= &rest characters+ => generalized-boolean) + (char-equal &rest characters+ => generalized-boolean) + (char-not-equal &rest characters+ => generalized-boolean) + (char-lessp &rest characters+ => generalized-boolean) + (char-greaterp &rest characters+ => generalized-boolean) + (char-not-greaterp &rest characters+ => generalized-boolean) + (char-not-lessp &rest characters+ => generalized-boolean) + (character character-designator => denoted-character) + (characterp object => generalized-boolean) + (alpha-char-p character => generalized-boolean) + (alphanumericp character => generalized-boolean) + (digit-char weight &optional (radix 10) => char) + (digit-char-p char &optional (radix 10) => weight) + (graphic-char-p char => generalized-boolean) + (standard-char-p character => generalized-boolean) + (char-upcase character => corresponding-character) + (char-downcase character => corresponding-character) + (upper-case-p character => generalized-boolean) + (lower-case-p character => generalized-boolean) + (both-case-p character => generalized-boolean) + (char-code character => code) + (char-int character => integer) + (code-char code => char-p) + (char-name character => name) + (name-char name => character-or-nil) + + + ;; conses + (cons car cdr => cons) + (consp object => generalized-boolean) + (atom object => generalized-boolean) + (rplaca cons object => cons) + (rplacd cons object => cons) + (car list => car-of-list) + (cdr list => cdr-of-list) + (copy-tree tree => new-tree) + (sublis alist tree &key key test test-not => new-tree) + (nsublis alist tree &key key test test-not => new-tree) + (subst new old tree &key key test test-not => new-tree) + (subst-if new predicate tree &key key => new-tree) + (subst-if-not new predicate tree &key key => new-tree) + (nsubst new old tree &key key test test-not => new-tree) + (nsubst-if new predicate tree &key key => new-tree) + (nsubst-if-not new predicate tree &key key => new-tree) + (tree-equal tree-1 tree-2 &key test test-not => generalized-boolean) + (copy-list list => copy) + (list &rest objects => list) + (list* &rest objects+ => result) + (list-length list => length) + (listp object => generalized-boolean) + (make-list size &key (initial-element nil) => list) + (push . "item place => new-place-value") + (pop . "place => element") + (nth n list => object) + (endp list => generalized-boolean) + (null object => boolean) + (nconc &rest lists => concatenated-list) + (append &rest lists => result) + (revappend list tail => result-list) + (nreconc list tail => result-list) + (butlast list &optional (n 1) => result-list) + (nbutlast list &optional (n 1) => result-list) + (last list &optional (n 1) => tail) + (ldiff list possible-tail => result-list) + (tailp possible-tail list => generalized-boolean) + (nthcdr n list => tail) + (rest list => tail) + (member item list &key key test test-not => tail) + (member-if predicate list &key key => tail) + (member-if-not predicate list &key key => tail) + (mapc function &rest lists+ => list-1) + (mapcar function &rest lists+ => result-list) + (mapcan function &rest lists+ => concatenated-results) + (mapl function &rest lists+ => list-1) + (maplist function &rest lists+ => result-list) + (mapcon function &rest lists+ => concatenated-results) + (acons key datum alist => new-alist) + (assoc item alist &key key test test-not => entry) + (assoc-if predicate alist &key key => entry) + (assoc-if-not predicate alist &key key => entry) + (copy-alist alist => new-alist) + (pairlis keys data &optional (alist '()) => new-alist) + (rassoc item alist &key key test test-not => entry) + (rassoc-if predicate alist &key key => entry) + (rassoc-if-not predicate alist &key key => entry) + (get-properties plist indicator-list => indicator value tail) + (getf plist indicator &optional (default nil) => value) + (remf place indicator => generalized-boolean) + (intersection list-1 list-2 &key key test test-not => result-list) + (nintersection list-1 list-2 &key key test test-not => result-list) + (adjoin item list &key key test test-not => new-list) + (pushnew item place &key key test test-not => new-place-value) + (set-difference list-1 list-2 &key key test test-not => result-list) + (nset-difference list-1 list-2 &key key test test-not => result-list) + (set-exclusive-or list-1 list-2 &key key test test-not => result-list) + (nset-exclusive-or list-1 list-2 &key key test test-not => result-list) + (subsetp list-1 list-2 &key key test test-not => generalized-boolean) + (union list-1 list-2 &key key test test-not => result-list) + (nunion list-1 list-2 &key key test test-not => result-list) + + ;; arrays + (make-array dimensions &key (element-type t) initial-element initial-contents (adjustable nil) (fill-pointer nil) (displaced-to nil) (displaced-index-offset 0) => new-array) + (adjust-array array new-dimensions &key element-type initial-element initial-contents (fill-pointer nil) displaced-to displaced-index-offset => adjusted-array) + (adjustable-array-p array => generalized-boolean) + (aref array &rest subscripts => element) + (array-dimension array axis-number => dimension) + (array-dimensions array => dimensions) + (array-element-type array => typespec) + (array-has-fill-pointer-p array => generalized-boolean) + (array-displacement array => displaced-to displaced-index-offset) + (array-in-bounds-p array &rest subscripts => generalized-boolean) + (array-rank array => rank) + (array-row-major-index array &rest subscripts => index) + (array-total-size array => size) + (arrayp object => generalized-boolean) + (fill-pointer vector => fill-pointer) + (row-major-aref array index => element) + (upgraded-array-element-type typespec &optional (environment nil) => upgraded-typespec) + (simple-vector-p object => generalized-boolean) + (svref simple-vector index => element) + (vector &rest objects => vector) + (vector-pop vector => element) + (vector-push new-element vector => new-index-p) + (vector-push-extend new-element vector &optional (extension *implementation-dependent-extension*) => new-index) + (vectorp object => generalized-boolean) + (bit bit-array &rest subscripts => bit) + (sbit bit-array &rest subscripts => bit) + (bit-and bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-andc1 bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-andc2 bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-eqv bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-ior bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-nand bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-nor bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-orc1 bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-orc2 bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-xor bit-array1 bit-array2 &optional (opt-arg nil) => resulting-bit-array) + (bit-not bit-array &optional (opt-arg nil) => resulting-bit-array) + (bit-vector-p object => generalized-boolean) + (simple-bit-vector-p object => generalized-boolean) + + + ;; strings + (simple-string-p object => generalized-boolean) + (char string index => character) + (schar simple-string index => character) + (string string-or-symbol-or-character => string) + (string-upcase string-designator &key (start 0) (end nil) => cased-string) + (string-downcase string-designator &key (start 0) (end nil) => cased-string) + (string-capitalize string-designator &key (start 0) (end nil) => cased-string) + (nstring-upcase string &key (start 0) (end nil) => modified-string) + (nstring-downcase string &key (start 0) (end nil) => modified-string) + (nstring-capitalize string &key (start 0) (end nil) => modified-string) + + (string-trim character-bag string => trimmed-string) + (string-left-trim character-bag string => trimmed-string) + (string-right-trim character-bag string => trimmed-string) + (string= string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => generalized-boolean) + (string/= string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string< string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string> string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string<= string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string>= string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string-equal string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => generalized-boolean) + (string-not-equal string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string-lessp string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string-greaterp string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string-not-greaterp string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (string-not-lessp string1 string2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => mismatch-index) + (stringp object => generalized-boolean) + (make-string size &key (initial-element *implementation-dependent-character*) (element-type 'character) => string) + + + ;; sequences + (copy-seq proper-sequence => copied-sequence) + (elt proper-sequence index => object) + (fill proper-sequence item &key (start 0) (end nil) => sequence) ; + (make-sequence result-type size &key (initial-element *implementation-dependent-element*) => sequence) + (subseq sequence start &optional (end nil) => subsequence) + (map result-sequence-type function &rest sequences+ => result) + (map-into result-sequence function &rest sequences => result-sequence) + (reduce function sequence &key key (from-end nil) (start 0) (end nil) initial-value => result) + (count item sequence &key (from-end nil) (start 0) (end nil) key test test-not => n) + (count-if predicate sequence &key (from-end nil) (start 0) (end nil) key => n) + (count-if-not predicate sequence &key (from-end nil) (start 0) (end nil) key => n) + (length sequence => n) + (reverse sequence => reversed-sequence) + (nreverse sequence => reversed-sequence) + (sort sequence predicate &key key => destructively-sorted-sequence) + (stable-sort sequence predicate &key key => destructively-sorted-sequence) + (find item sequence &key (from-end nil) test test-not (start 0) (end nil) key => element) + (find-if predicate sequence &key (from-end nil) (start 0) (end nil) key => element) + (find-if-not predicate sequence &key (from-end nil) (start 0) (end nil) key => element) + (position item sequence &key (from-end nil) test test-not (start 0) (end nil) key => position) + (position-if predicate sequence &key (from-end nil) (start 0) (end nil) key => position) + (position-if-not predicate sequence &key (from-end nil) (start 0) (end nil) key => position) + (search subsequence sequence &key (from-end nil) test test-not key (start1 0) (start2 0) (end1 nil) (end2 nil) => position) + (mismatch sequence-1 sequence-2 &key (from-end nil) test test-not key (start1 0) (start2 0) (end1 nil) (end2 nil) => position) + (replace sequence-1 sequence-2 &key (start1 0) (end1 nil) (start2 0) (end2 nil) => destructively-modified-sequence-1) + (substitute newitem olditem sequence &key (from-end nil) test test-not (start 0) (end nil) (count nil) key => result-sequence) + (substitute-if newitem predicate sequence &key (from-end nil) (start 0) (end nil) (count nil) key => result-sequence) + (substitute-if-not newitem predicate sequence &key (from-end nil) (start 0) (end nil) (count nil) key => result-sequence) + (nsubstitute newitem olditem sequence &key (from-end nil) test test-not (start 0) (end nil) (count nil) key => sequence) + (nsubstitute-if newitem predicate sequence &key (from-end nil) (start 0) (end nil) (count nil) key=> sequence) + (nsubstitute-if-not newitem predicate sequence &key (from-end nil) (start 0) (end nil) (count nil) key => sequence) + (concatenate result-type &rest sequences => result-sequence) + (merge result-type sequence-1 sequence-2 predicate &key key => result-sequence) + (remove item sequence &key (from-end nil) test test-not (start 0) (end nil) (count nil) key => result-sequence) + (remove-if test sequence &key (from-end nil) (start 0) (end nil) (count nil) key => result-sequence) + (remove-if-not test sequence &key (from-end nil) (start 0) (end nil) (count nil) key => result-sequence) + (delete item sequence &key (from-end nil) test test-not (start 0) (end nil) (count nil) key => result-sequence) + (delete-if test sequence &key (from-end nil) (start 0) (end nil) (count nil) key => result-sequence) + (delete-if-not test sequence &key (from-end nil) (start 0) (end nil) (count nil) key => result-sequence) + (remove-duplicates sequence &key (from-end nil) test test-not (start 0) (end nil) key => result-sequence) + (delete-duplicates sequence &key (from-end nil) test test-not (start 0) (end nil) key => result-sequence) + + + ;; hash tables + (make-hash-table &key (test #'eql) (size *implementation-dependent-size*) (rehash-size *implementation-dependent-rehash-size*) (rehash-threshold *implementation-dependent-threshold) => hash-table) + (hash-table-p object => generalized-boolean) + (hash-table-count hash-table => count) + (hash-table-rehash-size hash-table => rehash-size) + (hash-table-rehash-threshold hash-table => rehash-threshold) + (hash-table-size hash-table => size) + (hash-table-test hash-table => test) + (gethash key hash-table &optional (default nil) => value present-p) + (remhash key hash-table => generalized-boolean) + (maphash function hash-table => nil) + (with-hash-table-iterator . "(name hash-table) declaration* form* => result*") + (clrhash hash-table => hash-table) + (sxhash object => hash-code) + + ;; filenames + (pathname pathspec => pathname) + (make-pathname &key host device directory name type version defaults case => pathname) + (pathnamep object => generalized-boolean) + (pathname-host pathname-designator &key (case :local) => host) + (pathname-device pathname-designator &key (case :local) => device) + (pathname-directory pathname-designator &key (case :local) => directory) + (pathname-name pathname-designator &key (case :local) => name) + (pathname-type pathname-designator &key (case :local) => type) + (pathname-version pathname-designator => version) + (load-logical-pathname-translations host => just-loaded) + (logical-pathname-translations host => translations) + (logical-pathname pathspec => logical-pathname) + (namestring pathname-designator => namestring) + (file-namestring pathname-designator => namestring) + (directory-namestring pathname-designator => namestring) + (host-namestring pathname-designator => namestring) + (enough-namestring pathname-designator &optional (defaults *default-pathname-defaults*) => namestring) + (parse-namestring thing &optional host (default-pathname *default-pathname-defaults*) &key (start 0) (end nil) (junk-allowed nil) => pathname position) + (wild-pathname-p pathname &optional (field-key nil) => generalized-boolean) + (pathname-match-p pathname wildcard => generalized-boolean) + (translate-logical-pathname pathname &key => physical-pathname) + (translate-pathname source from-wildcard to-wildcard &key => translated-pathname) + (merge-pathnames pathname &optional (default-pathname *default-pathname-defaults*) (default-version :newest) => merged-pathname) + + ;; files + (directory pathspec &key => pathnames) + (probe-file pathspec => truename) + (ensure-directories-exist pathspec &key verbose => pathspec created) + (truename filespec => truename) + (file-author pathspec => author) + (file-write-date pathspec => date) + (rename-file filespec new-name => defaulted-new-name old-truename new-truename) + (delete-file filespec => t) + (file-error-pathname condition => pathspec) + + ;; streams + (input-stream-p stream => generalized-boolean) + (output-stream-p stream => generalized-boolean) + (interactive-stream-p stream => generalized-boolean) + (open-stream-p stream => generalized-boolean) + (stream-element-type stream => typespec) + (streamp object => generalized-boolean) + (read-byte stream &optional (eof-error-p t) (eof-value nil) => byte) + (write-byte byte stream => byte) + (peek-char &optional (peek-type nil) (input-stream *standard-input*) (eof-error-p t) (eof-value nil) (recursive-p nil) => char) + (read-char &optional (input-stream *standard-input*) (eof-error-p t) (eof-value nil) (recursive-p nil) => char) + (read-char-no-hang &optional (input-stream *standard-input*) (eof-error-p t) (eof-value nil) (recursive-p nil) => char) + (terpri &optional (output-stream *standard-output*) => nil) + (fresh-line &optional (output-stream *standard-output*) => generalized-boolean) + (unread-char character &optional (input-stream *standard-input*) => nil) + (write-char character &optional (output-stream *standard-output*) => character) + (read-line &optional (input-stream *standard-input*) (eof-error-p t) (eof-value nil) (recursive-p nil) => line missing-newline-p) + (write-string string &optional (output-stream *standard-output*) &key (start 0) (end nil) => string) + (write-line string &optional (output-stream *standard-output*) &key (start 0) (end nil) => string) + (read-sequence sequence stream &key (start 0) (end nil) => position) + (write-sequence sequence stream &key (start 0) (end nil) => sequence) + (file-length stream => length) + ;;(file-position stream => position) + ;;(file-position stream position-spec => success-p) + (file-string-length stream object => length) + (open filespec &key (direction :input) (element-type 'character) if-exists if-does-not-exist external-format => stream) + (stream-external-format stream => format) + (with-open-file . "(stream filespec options*) declaration* form* => results") + (close stream &key (abort nil) => result) + (with-open-stream . "(var stream) declaration* form* => result*") + (listen &optional (input-stream *standard-input*) => generalized-boolean) + (clear-input &optional (input-stream *standard-input*) => nil) + (finish-output &optional (output-stream *standard-output*) => nil) + (force-output &optional (output-stream *standard-output*) => nil) + (clear-output &optional (output-stream *standard-output*) => nil) + (y-or-n-p &optional control &rest arguments => generalized-boolean) + (yes-or-no-p &optional control &rest arguments => generalized-boolean) + (make-synonym-stream symbol => synonym-stream) + (synonym-stream-symbol synonym-stream => symbol) + (broadcast-stream-streams broadcast-stream => streams) + (make-broadcast-stream &rest streams => broadcast-stream) + (make-two-way-stream input-stream output-stream => two-way-stream) + (two-way-stream-input-stream two-way-stream => input-stream) + (two-way-stream-output-stream two-way-stream => output-stream) + (echo-stream-input-stream echo-stream => input-stream) + (echo-stream-output-stream echo-stream => output-stream) + (make-echo-stream input-stream output-stream => echo-stream) + (concatenated-stream-streams concatenated-stream => streams) + (make-concatenated-stream &rest input-streams => concatenated-stream) + (get-output-stream-string string-output-stream => string) + (make-string-input-stream string &optional (start 0) (end nil) => string-stream) + (make-string-output-stream &key (element-type 'character) => string-stream) + (with-input-from-string . "(var string &key index start end) declaration* form* => result*") + (with-output-to-string . "(var &optional string-form &key element-type) declaration* form* => result*") + (stream-error-stream condition => stream) + + ;; printer + (copy-pprint-dispatch &optional (table *print-pprint-dispatch*) => new-table) + (formatter control-string => function) + (pprint-dispatch object &optional (table *print-pprint-dispatch*) => function found-p) + (pprint-exit-if-list-exhausted => nil) + (pprint-fill stream object &optional (colon-p t) (at-sign-p *implementation-dependent-at-sign-p*) => nil) + (pprint-linear stream object &optional (colon-p t) (at-sign-p *implementation-dependent-at-sign-p*) => nil) + (pprint-tabular stream object &optional (colon-p t) (at-sign-p *implementation-dependent-at-sign-p*) (tabsize 16) => nil) + (pprint-indent relative-to n &optional (stream *standard-output*) => nil) + (pprint-logical-block . "(stream-symbol object &key prefix per-line-prefix suffix) declaration* form* => nil") + (pprint-newline kind &optional (stream *standard-output*) => nil) + (pprint-pop => object) + (pprint-tab kind colnum colinc &optional stream => nil) + (print-object object stream => object) + (print-unreadable-object . "(object stream &key type identity) form* => nil") + (set-pprint-dispatch type-specifier function &optional (priority 0) (table *print-pprint-dispatch*) => nil) + (write object &key array base case circle escape gensym length level lines miser-width pprint-dispatch pretty radix readably right-margin (stream *standard-output*) => object) + (prin1 object &optional (output-stream *standard-output*) => object) + (princ object &optional (output-stream *standard-output*) => object) + (print object &optional (output-stream *standard-output*) => object) + (pprint object &optional (output-stream *standard-output*) => <no values>) + (write-to-string object &key array base case circle escape gensym length level lines miser-width pprint-dispatch pretty radix readably right-margin => string) + (prin1-to-string object => string) + (princ-to-string object => string) + (print-not-readable-object condition => object) + (format destination control-string &rest args => result) + + ;; reader + (copy-readtable &optional (from-readtable *readtable*) (to-readtable nil) => readtable) + (make-dispatch-macro-character char &optional (non-terminating-p nil) (readtable *readtable*) => t) + (read &optional input-stream (eof-error-p t) (eof-value nil) (recursive-p nil) => object) + (read-preserving-whitespace &optional input-stream (eof-error-p t) (eof-value nil) (recursive-p nil) => object) + (read-delimited-list char &optional (input-stream *standard-input*) (recursive-p nil) => list) + (read-from-string string &optional (eof-error-p t) (eof-value nil) &key (start 0) (end nil) (preserve-whitespace nil) => object position) + (readtable-case readtable => case-sensitivity-mode) + (readtablep object => generalized-boolean) + (get-dispatch-macro-character disp-char sub-char &optional (readtable *readtable*) => function) + (set-dispatch-macro-character disp-char sub-char new-function &optional (readtable *readtable*) => t) + (get-macro-character char &optional (readtable *readtable*) => function non-terminating-p) + (set-macro-character char new-function &optional (non-terminating-p nil) (readtable *readtable*) => t) + (set-syntax-from-char to-char from-char &optional (to-readtable *readtable*) (from-readtable +standard-readtable+) => t) + (with-standard-io-syntax . "form* => result*") + + ;; system construction + (compile-file input-file &key (output-file *implementation-defined-output-file*) (verbose *compile-verbose*) (print *compile-print*) (external-format :default) => output-truename warnings-p failure-p) + (compile-file-pathname input-file &key (output-file *implementation-defined-output-file*) &allow-other-keys => pathname) + (load filespec &key (verbose *load-verbose*) (print *load-print*) (if-does-not-exist t) (external-format :default) => generalized-boolean) + (with-compilation-unit . "([[:override override-form]]) form* => result*") + (provide module-name => implementation-dependent) + (require module-name &optional pathname-list => implementation-dependent) + + ;; environment + (decode-universal-time universal-time &optional time-zone => second minute hour date month year day daylight-p zone) + (encode-universal-time second minute hour date month year &optional time-zone => universal-time) + (get-universal-time => universal-time) + (get-decoded-time => second minute hour date month year day daylight-p zone) + (sleep seconds => nil) + (apropos string &optional (package nil) => <no values>) + (apropos-list string &optional (package nil) => symbols) + (describe object &optional (stream *standard-output*) => <no values>) + (describe-object object stream => implementation-dependent) + (trace . "function-name* => trace-result") + (untrace . "function-name* => untrace-result") + (step . "form => result*") + (time . "form => result*") + (get-internal-real-time => internal-time) + (get-internal-run-time => internal-time) + (disassemble extended-function-designator-or-lambda-expression => nil) + (documentation x doc-type => documentation) + (room &optional x => implementation-dependent) + (ed &optional x => implementation-dependent) + (inspect object => implementation-dependent) + (dribble &optional pathname => implementation-dependent) + (lisp-implementation-type => description) + (lisp-implementation-version => description) + (short-site-name => description) + (long-site-name => description) + (machine-instance => description) + (machine-type => description) + (machine-version => description) + (software-type => description) + (software-version => description) + (user-homedir-pathname &optional host => pathname) + )) + + +(provide 'cldoc) + +;;; cldoc.el ends here diff --git a/emacs/espresso.el b/emacs/espresso.el new file mode 100644 index 0000000..1e6f3a9 --- /dev/null +++ b/emacs/espresso.el @@ -0,0 +1,869 @@ +;;; espresso.el --- Major mode for editing JavaScript source text +;; Copyright (C) 2008 Free Software Foundation, Inc. +;; Copyright (C) 2009 Daniel Colascione <dan.colascione@gmail.com> +;; Author: Karl Landstrom <karl.landstrom@brgeight.se> +;; Author: Daniel Colascione <dan.colascione@gmail.com> +;; Maintainer: Daniel Colascione <dan.colascione@gmail.com> +;; Version: 4 +;; Date: 2009-01-06 +;; Keywords: languages, oop, javascript + +;; 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 3, 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary + +;; This is based on Karl Landstrom's barebones javascript-mode. This +;; is much more robust and works with cc-mode's comment filling +;; (mostly). +;; +;; The main features of this JavaScript mode are syntactic +;; highlighting (enabled with `font-lock-mode' or +;; `global-font-lock-mode'), automatic indentation and filling of +;; comments, and C preprocessor fontification. +;; +;; This package has (only) been tested with GNU Emacs 22 (the latest +;; stable release). +;; +;; Installation: +;; +;; Put this file in a directory where Emacs can find it (`C-h v +;; load-path' for more info). Then add the following lines to your +;; Emacs initialization file: +;; +;; (add-to-list 'auto-mode-alist '("\\.js\\'" . espresso-mode)) +;; (autoload 'espresso-mode "espresso" nil t) +;; +;; General Remarks: +;; +;; XXX: This mode assumes that block comments are not nested inside block +;; XXX: comments and that strings do not contain line breaks. +;; +;; Exported names start with "espresso-" whereas private names start +;; with "espresso--". +;; +;; Code: + +;;; Code + +(require 'cc-mode) +(require 'font-lock) +(require 'newcomment) + +(eval-when-compile + (require 'cl)) + +;;; User customization + +(defgroup espresso nil + "Customization variables for `espresso-mode'." + :tag "JavaScript - Espresso-Mode" + :group 'languages) + +(defcustom espresso-indent-level 4 + "Number of spaces for each indentation step." + :type 'integer + :group 'espresso) + +(defcustom espresso-expr-indent-offset 0 + "Number of additional spaces used for indentation of continued +expressions. The value must be no less than minus +`espresso-indent-level'." + :type 'integer + :group 'espresso) + +(defcustom espresso-auto-indent-flag t + "Automatic indentation with punctuation characters. If non-nil, the +current line is indented when certain punctuations are inserted." + :type 'boolean + :group 'espresso) + +;;; KeyMap + +(defvar espresso-mode-map nil + "Keymap used in Espresso mode.") + +(unless espresso-mode-map + (setq espresso-mode-map (make-sparse-keymap))) + +(when espresso-auto-indent-flag + (mapc (lambda (key) + (define-key espresso-mode-map key 'espresso-insert-and-indent)) + '("{" "}" "(" ")" ":" ";" ","))) + +(defun espresso-insert-and-indent (key) + "Runs the command bound to KEY in the global keymap, and if +we're not in a string or comment, indents the current line." + (interactive (list (this-command-keys))) + (call-interactively (lookup-key (current-global-map) key)) + (let ((syntax (save-restriction (widen) (syntax-ppss)))) + (unless (nth 8 syntax) + (indent-according-to-mode)))) + +;;; Syntax table and parsing + +(defvar espresso-mode-syntax-table + (let ((table (make-syntax-table))) + (c-populate-syntax-table table) + (modify-syntax-entry ?$ "_" table) + table) + "Syntax table used in Espresso mode.") + +(defconst espresso--name-start-re "[a-zA-Z_$]" + "Matches the first character of a Espresso identifier. No grouping") + +(defconst espresso--stmt-delim-chars "^;{}?:") + +(defconst espresso--name-re (concat espresso--name-start-re + "\\(?:\\s_\\|\\sw\\)*") + "Matches a Javascript name. No grouping.") + +(defconst espresso--dotted-name-re + (concat espresso--name-re "\\(?:\\." espresso--name-re "\\)*") + "Matches a dot-separated sequence of Javascript names") + +(defconst espresso--cpp-name-re espresso--name-re + "Matches a C preprocessor name") + +(defconst espresso--opt-cpp-start "^\\s-*#\\s-*\\([[:alnum:]]+\\)" + " Regexp matching the prefix of a cpp directive including the directive +name, or nil in languages without preprocessor support. The first +submatch surrounds the directive name.") + + +(defconst espresso--class-decls + `(; var NewClass = BaseClass.extend( + ,(concat "^\\s-*\\_<var\\_>\\s-+" + "\\(" espresso--dotted-name-re "\\)" + "\\s-*=" "\\s-*" + "\\(" espresso--dotted-name-re + "\\)\\.extend\\(?:Final\\)?\\s-*(") + + ; NewClass: BaseClass.extend( ; for nested classes + ,(concat "^\\s-*" + "\\(" espresso--dotted-name-re "\\):" + "\\s-*\\(" espresso--dotted-name-re + "\\)\\.extend\\(?:Finak\\)?\\s-*(")) + "List of regular expressions that can match class definitions. +Each one must set match group 1 to the name of the class being +defined, and optionally, group 2 to the name of the base class.") + +(defun espresso--regexp-opt-symbol (list) + "Like regexp-opt, but surround the optimized regular expression +with `\\\\_<' and `\\\\_>'." + (concat "\\_<" (regexp-opt list t) "\\_>")) + +(defun espresso--re-search-forward-inner (regexp &optional bound count) + "Auxiliary function for `espresso--re-search-forward'." + (let ((parse) + (orig-macro-end (save-excursion + (when (espresso--beginning-of-macro) + (c-end-of-macro) + (point)))) + (saved-point (point-min))) + (while (> count 0) + (re-search-forward regexp bound) + (setq parse (parse-partial-sexp saved-point (point))) + (cond ((nth 3 parse) + (re-search-forward + (concat "\\([^\\]\\|^\\)" (string (nth 3 parse))) + (save-excursion (end-of-line) (point)) t)) + ((nth 7 parse) + (forward-line)) + ((or (nth 4 parse) + (and (eq (char-before) ?\/) (eq (char-after) ?\*))) + (re-search-forward "\\*/")) + ((and (not (and orig-macro-end + (<= (point) orig-macro-end))) + (espresso--beginning-of-macro)) + (c-end-of-macro)) + (t + (setq count (1- count)))) + (setq saved-point (point)))) + (point)) + + +(defun espresso--re-search-forward (regexp &optional bound noerror count) + "Search forward but ignore strings, cpp macros, and comments. +Invokes `re-search-forward' but treats the buffer as if strings, +cpp macros, and comments have been removed. + +If invoked while inside a macro, treat the contents of the macro +as normal text. + +" + (let ((saved-point (point)) + (search-expr + (cond ((null count) + '(espresso--re-search-forward-inner regexp bound 1)) + ((< count 0) + '(espresso--re-search-backward-inner regexp bound (- count))) + ((> count 0) + '(espresso--re-search-forward-inner regexp bound count))))) + (condition-case err + (eval search-expr) + (search-failed + (goto-char saved-point) + (unless noerror + (error (error-message-string err))))))) + + +(defun espresso--re-search-backward-inner (regexp &optional bound count) + "Auxiliary function for `espresso--re-search-backward'." + (let ((parse) + (orig-macro-start + (save-excursion + (and (espresso--beginning-of-macro) + (point)))) + (saved-point (point-min))) + (while (> count 0) + (re-search-backward regexp bound) + (when (and (> (point) (point-min)) + (save-excursion (backward-char) (looking-at "/[/*]"))) + (forward-char)) + (setq parse (parse-partial-sexp saved-point (point))) + (cond ((nth 3 parse) + (re-search-backward + (concat "\\([^\\]\\|^\\)" (string (nth 3 parse))) + (save-excursion (beginning-of-line) (point)) t)) + ((nth 7 parse) + (goto-char (nth 8 parse))) + ((or (nth 4 parse) + (and (eq (char-before) ?/) (eq (char-after) ?*))) + (re-search-backward "/\\*")) + ((and (not (and orig-macro-start + (>= (point) orig-macro-start))) + (espresso--beginning-of-macro))) + (t + (setq count (1- count)))))) + (point)) + + +(defun espresso--re-search-backward (regexp &optional bound noerror count) + "Search backward but ignore strings, preprocessor macros, and +comments. Invokes `re-search-backward' but treats the buffer as +if strings, preprocessor macros, and comments have been removed. + +If inside a macro when called, treat the macro as normal text. +" + (let ((saved-point (point)) + (search-expr + (cond ((null count) + '(espresso--re-search-backward-inner regexp bound 1)) + ((< count 0) + '(espresso--re-search-forward-inner regexp bound (- count))) + ((> count 0) + '(espresso--re-search-backward-inner regexp bound count))))) + (condition-case err + (eval search-expr) + (search-failed + (goto-char saved-point) + (unless noerror + (error (error-message-string err))))))) + + +(defun espresso--forward-function-decl () + (assert (looking-at "\\_<function\\_>")) + (forward-word) + (forward-comment most-positive-fixnum) + (skip-chars-forward "^(") + (unless (eobp) + (forward-list) + (forward-comment most-positive-fixnum) + (skip-chars-forward "^{")) + t) + +(defun espresso--beginning-of-defun () + (cond ((espresso--re-search-backward "\\_<function\\_>" (point-min) t) + (let ((pos (point))) + (save-excursion + (forward-line 0) + (when (looking-at espresso--function-heading-2-re) + (setq pos (match-beginning 1)))) + (goto-char pos))) + + (t + (goto-char (point-min))))) + +(defun espresso--end-of-defun () + ;; look for function backward. if we're inside it, go to that + ;; function's end. otherwise, search for the next function's end and + ;; go there + (unless (looking-at "\\_<") + (skip-syntax-backward "w_")) + + (let ((orig-point (point)) pos) + (when (or (looking-at "\\_<function\\_>") + (espresso--re-search-backward "\\_<function\\_>" (point-min) t)) + (goto-char (match-beginning 0)) + (let* ((func-loc (point)) + (opening-brace-loc (progn (espresso--forward-function-decl) + (point)))) + + (cond ((and (<= func-loc orig-point) + (<= orig-point opening-brace-loc)) + (setq pos opening-brace-loc)) + + ((/= 0 (nth 0 (parse-partial-sexp + opening-brace-loc orig-point 0))) + (setq pos opening-brace-loc))))) + + (cond + (pos (goto-char pos) + (forward-list)) + + ((espresso--re-search-forward "\\_<function\\_>" (point-max) t) + (espresso--end-of-defun)) + + (t (goto-char (point-max)))))) + +(defun espresso--beginning-of-macro (&optional lim) + (let ((here (point))) + (save-restriction + (if lim (narrow-to-region lim (point-max))) + (beginning-of-line) + (while (eq (char-before (1- (point))) ?\\) + (forward-line -1)) + (back-to-indentation) + (if (and (<= (point) here) + (looking-at espresso--opt-cpp-start)) + t + (goto-char here) + nil)))) + +(defun espresso--backward-syntactic-ws (&optional lim) + "Simple implementation of c-backward-syntactic-ws" + (save-restriction + (when lim (narrow-to-region lim (point-max))) + + (let ((in-macro (save-excursion (espresso--beginning-of-macro))) + (pos (point))) + + (while (progn (unless in-macro (espresso--beginning-of-macro)) + (forward-comment most-negative-fixnum) + (/= (point) + (prog1 + pos + (setq pos (point))))))))) + +(defun espresso--forward-syntactic-ws (&optional lim) + "Simple implementation of c-forward-syntactic-ws" + (save-restriction + (when lim (narrow-to-region (point-min) min)) + (let ((pos (point))) + (while (progn + (forward-comment most-positive-fixnum) + (when (eq (char-after) ?#) + (c-end-of-macro)) + (/= (point) + (prog1 + pos + (setq pos (point))))))))) + +;;; Font Lock + +(defun espresso--inside-param-list-p () + "Return non-nil iff point is inside a function parameter list." + (condition-case err + (save-excursion + (up-list -1) + (and (looking-at "(") + (progn (forward-symbol -1) + (or (looking-at "function") + (progn (forward-symbol -1) (looking-at "function")))))) + (error nil))) + +(defconst espresso--function-heading-1-re + (concat + "^\\s-*function\\s-+\\(" espresso--name-re "\\)") + "Regular expression matching the start of a function header. Match group 1 +is the name of the function.") + +(defconst espresso--function-heading-2-re + (concat + "^\\s-*\\(" espresso--name-re "\\)\\s-*:\\s-*function\\_>") + "Regular expression matching the start of a function entry in + an associative array. Match group 1 is the name of the function.") + +(defconst espresso--macro-decl-re + (concat "^\\s-*#\\s-*define\\s-+\\(" espresso--cpp-name-re "\\)\\s-*(") + "Regular expression matching a CPP macro definition up to the opening +parenthesis. Match group 1 is the name of the function.") + +(defconst espresso--keyword-re + (espresso--regexp-opt-symbol + '("abstract" "break" "case" "catch" "class" "const" + "continue" "debugger" "default" "delete" "do" "else" + "enum" "export" "extends" "final" "finally" "for" + "function" "goto" "if" "implements" "import" "in" + "instanceof" "interface" "native" "new" "package" + "private" "protected" "public" "return" "static" + "super" "switch" "synchronized" "throw" + "throws" "transient" "try" "typeof" "var" "void" + "volatile" "while" "with" "let")) + "Regular expression matching any JavaScript keyword.") + +(defconst espresso--basic-type-re + (espresso--regexp-opt-symbol + '("boolean" "byte" "char" "double" "float" "int" "long" + "short" "void")) + "Regular expression matching any predefined type in JavaScript.") + +(defconst espresso--constant-re + (espresso--regexp-opt-symbol '("false" "null" "undefined" + "true" "arguments" "this")) + "Regular expression matching any future reserved words in JavaScript.") + + +(defconst espresso--font-lock-keywords-1 + (list + "\\_<import\\_>" + (list espresso--function-heading-1-re 1 font-lock-function-name-face) + (list espresso--function-heading-2-re 1 font-lock-function-name-face)) + "Level one font lock.") + +(defconst espresso--font-lock-keywords-2 + (append espresso--font-lock-keywords-1 + (list (list espresso--keyword-re 1 font-lock-keyword-face) + (cons espresso--basic-type-re font-lock-type-face) + (cons espresso--constant-re font-lock-constant-face))) + "Level two font lock.") + + +;; Limitations with variable declarations: There seems to be no +;; sensible way to highlight variables occuring after an initialized +;; variable in a variable list. For instance, in +;; +;; var x, y = f(a, b), z +;; +;; z will not be highlighted. Also, in variable declaration lists +;; spanning several lines only variables on the first line will be +;; highlighted. To get correct fontification, every line with variable +;; declarations must contain a `var' keyword. + +(defconst espresso--font-lock-keywords-3 + `( + ;; This goes before keywords-2 so it gets used preferentially + ;; instead of the keywords in keywords-2. Don't use override + ;; because that will override syntactic fontification too, which + ;; will fontify commented-out directives as if they weren't + ;; commented out. + ,@cpp-font-lock-keywords ; from font-lock.el + + ,@espresso--font-lock-keywords-2 + + ;; variable declarations + ,(list + (concat "\\_<\\(const\\|var\\)\\_>\\|" espresso--basic-type-re) + (list (concat "\\(" espresso--name-re "\\)" + "\\s-*\\([=;].*\\|\\_<in\\_>.*\\|,\\|/[/*]\\|$\\)") + nil + nil + '(1 font-lock-variable-name-face))) + + ;; class instantiation + ,(list + (concat "\\_<new\\_>\\s-+\\(" espresso--dotted-name-re "\\)") + (list 1 'font-lock-type-face)) + + ;; instanceof + ,(list + (concat "\\_<instanceof\\_>\\s-+\\(" espresso--dotted-name-re "\\)") + (list 1 'font-lock-type-face)) + + ;; formal parameters + ,(list + (concat + "\\_<function\\_>\\(\\s-+" espresso--name-re "\\)?\\s-*(\\s-*" + espresso--name-start-re) + (list (concat "\\(" espresso--name-re "\\)\\(\\s-*).*\\)?") + '(backward-char) + '(end-of-line) + '(1 font-lock-variable-name-face))) + + ;; continued formal parameter list + ,(list + (concat + "^\\s-*" espresso--name-re "\\s-*[,)]") + (list espresso--name-re + '(if (save-excursion (backward-char) + (espresso--inside-param-list-p)) + (forward-symbol -1) + (end-of-line)) + '(end-of-line) + '(0 font-lock-variable-name-face))) + + ;; class declarations + ,@(mapcar #'(lambda (x) + `(,x + (1 font-lock-type-face t t) + (2 font-lock-type-face t t))) + + espresso--class-decls)) + "Level three font lock.") + + +(defconst espresso--font-lock-keywords + '(espresso--font-lock-keywords-3 espresso--font-lock-keywords-1 + espresso--font-lock-keywords-2 + espresso--font-lock-keywords-3) + "See `font-lock-keywords'.") + +;; Note: Javascript cannot continue a regular expression literal +;; across lines +(defconst espresso--regexp-literal + "[=(,]\\(?:\\s-\\|\n\\)*\\(/\\)[^/*]\\(?:.*?[^\\]\\)?\\(/\\)" + "Match a regular expression literal. Match groups 1 and 2 are +the characters forming the beginning and end of the literal") + +;; we want to match regular expressions only at the beginning of +;; expressions +(defconst espresso--font-lock-syntactic-keywords + `((,espresso--regexp-literal (1 "|") (2 "|"))) + "Highlighting of regular expressions. See also the variable + `font-lock-keywords'.") + +;;; Indentation + +(defconst espresso--possibly-braceless-keyword-re + (espresso--regexp-opt-symbol + '("catch" "do" "else" "finally" "for" "if" "try" "while" "with" "let")) + "Regular expression matching keywords that are optionally + followed by an opening brace.") + +(defconst espresso--indent-operator-re + (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|" + (espresso--regexp-opt-symbol '("in" "instanceof"))) + "Regular expression matching operators that affect indentation + of continued expressions.") + + +(defun espresso--looking-at-operator-p () + "Return non-nil if text after point is an operator (that is not +a comma)." + (save-match-data + (and (looking-at espresso--indent-operator-re) + (or (not (looking-at ":")) + (save-excursion + (and (espresso--re-search-backward "[?:{]\\|\\_<case\\_>" nil t) + (looking-at "?"))))))) + + +(defun espresso--continued-expression-p () + "Returns non-nil if the current line continues an expression." + (save-excursion + (back-to-indentation) + (or (espresso--looking-at-operator-p) + (and (espresso--re-search-backward "\n" nil t) + (progn + (skip-chars-backward " \t") + (or (bobp) (backward-char)) + (and (> (point) (point-min)) + (save-excursion (backward-char) (not (looking-at "[/*]/"))) + (espresso--looking-at-operator-p) + (and (progn (backward-char) + (not (looking-at "++\\|--\\|/[/*]")))))))))) + + +(defun espresso--end-of-do-while-loop-p () + "Returns non-nil if word after point is `while' of a do-while +statement, else returns nil. A braceless do-while statement +spanning several lines requires that the start of the loop is +indented to the same column as the current line." + (interactive) + (save-excursion + (save-match-data + (when (looking-at "\\s-*\\_<while\\_>") + (if (save-excursion + (skip-chars-backward "[ \t\n]*}") + (looking-at "[ \t\n]*}")) + (save-excursion + (backward-list) (forward-symbol -1) (looking-at "\\_<do\\_>")) + (espresso--re-search-backward "\\_<do\\_>" (point-at-bol) t) + (or (looking-at "\\_<do\\_>") + (let ((saved-indent (current-indentation))) + (while (and (espresso--re-search-backward "^\\s-*\\_<" nil t) + (/= (current-indentation) saved-indent))) + (and (looking-at "\\s-*\\_<do\\_>") + (not (espresso--re-search-forward + "\\_<while\\_>" (point-at-eol) t)) + (= (current-indentation) saved-indent))))))))) + + +(defun espresso--ctrl-statement-indentation () + "Returns the proper indentation of the current line if it +starts the body of a control statement without braces, else +returns nil." + (save-excursion + (back-to-indentation) + (when (save-excursion + (and (not (looking-at "[{]")) + (progn + (espresso--re-search-backward "[[:graph:]]" nil t) + (or (eobp) (forward-char)) + (when (= (char-before) ?\)) (backward-list)) + (skip-syntax-backward " ") + (skip-syntax-backward "w_") + (looking-at espresso--possibly-braceless-keyword-re)) + (not (espresso--end-of-do-while-loop-p)))) + (save-excursion + (goto-char (match-beginning 0)) + (+ (current-indentation) espresso-indent-level))))) + + +(defun espresso--proper-indentation (parse-status) + "Return the proper indentation for the current line." + (save-excursion + (back-to-indentation) + (let ((ctrl-stmt-indent (espresso--ctrl-statement-indentation)) + (same-indent-p (looking-at "[]})]\\|\\_<case\\_>\\|\\_<default\\_>")) + (continued-expr-p (espresso--continued-expression-p))) + (cond (ctrl-stmt-indent) + ((eq (char-after) ?#) 0) + ((save-excursion (espresso--beginning-of-macro)) + 4) + ((nth 1 parse-status) + (goto-char (nth 1 parse-status)) + (if (looking-at "[({[]\\s-*\\(/[/*]\\|$\\)") + (progn + (skip-syntax-backward " ") + (when (= (char-before) ?\)) (backward-list)) + (back-to-indentation) + (cond (same-indent-p + (current-column)) + (continued-expr-p + (+ (current-column) (* 2 espresso-indent-level) + espresso-expr-indent-offset)) + (t + (+ (current-column) espresso-indent-level)))) + (unless same-indent-p + (forward-char) + (skip-chars-forward " \t")) + (current-column))) + (continued-expr-p (+ espresso-indent-level + espresso-expr-indent-offset)) + (t 0))))) + + +(defun espresso-indent-line () + "Indent the current line as JavaScript source text." + (interactive) + (save-restriction + (widen) + (let* ((parse-status + (save-excursion (syntax-ppss (point-at-bol)))) + (offset (- (current-column) (current-indentation)))) + + (if (nth 8 parse-status) + (indent-relative-maybe) + (indent-line-to (espresso--proper-indentation parse-status)) + (when (> offset 0) (forward-char offset)))))) + +;;; Filling + +(defun espresso-c-fill-paragraph (&optional justify) + "Fill the paragraph with c-fill-paragraph" + (interactive "*P") + + ;; FIXME: filling a single-line C-style comment into multiple lines + ;; does something horrible to the undo list + + (flet ((c-forward-sws + (&optional limit) + (espresso--forward-syntactic-ws limit)) + + (c-backward-sws + (&optional limit) + (espresso--backward-syntactic-ws limit)) + + (c-beginning-of-macro + (&optional limit) + (espresso--beginning-of-macro limit))) + + (let ((fill-paragraph-function 'c-fill-paragraph)) + (c-fill-paragraph justify)))) + +;;; Imenu + +(defun espresso--imenu-create-index () + (let ((search-re (mapconcat (lambda (x) + (concat "\\(" x "\\)")) + (list espresso--function-heading-1-re + espresso--function-heading-2-re + (concat "\\(?:" + (mapconcat + #'identity + espresso--class-decls "\\|") + "\\)") + espresso--macro-decl-re) + "\\|")) + entries parent-entries ends tmp syntax) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + + (while (re-search-forward search-re (point-max) t) + (goto-char (match-beginning 0)) + (setq syntax (syntax-ppss)) + (unless (or (nth 3 syntax) (nth 4 syntax)) + (while (and ends (>= (point) (car ends))) + (setq tmp (nreverse entries) + entries (pop parent-entries)) + + (unless tmp + (setq tmp (list + (cons "[empty]" (set-marker (make-marker) + (car ends)))))) + + (pop ends) + + (setcdr (car entries) tmp)) + + (cond ((and (not parent-entries) ; regular function or macro + (or (looking-at espresso--function-heading-1-re) + (looking-at espresso--macro-decl-re))) + + (push (cons (match-string-no-properties 1) + (set-marker (make-marker) (match-beginning 1))) + entries)) + + ;; does one of the espresso--class-decls regexps match? + ((let ((r espresso--class-decls)) + (while (and r (not (looking-at (car r) ))) + (setq r (cdr r))) + r) + + (push (cons + (match-string-no-properties 1) + nil) + entries) + (push entries parent-entries) + (setq entries nil) + (goto-char (match-end 1)) + (condition-case err + (forward-list) + (error nil)) + (push (point) ends)) + + + ((and parent-entries + (looking-at espresso--function-heading-2-re)) + (push (cons (match-string-no-properties 1) + (set-marker (make-marker) (match-beginning 1))) + entries)))) + + (goto-char (match-end 0))) + + (while parent-entries + (setq tmp (nreverse entries) + entries (pop parent-entries)) + (setcdr (car entries) tmp)))) + + (nreverse entries))) + +(defun espresso--which-func-joiner (parts) + (mapconcat #'identity parts ".")) + +;;; Main Function + +;;;###autoload +(defun espresso-mode () + "Major mode for editing JavaScript source text. + +Key bindings: + +\\{espresso-mode-map}" + (interactive) + (kill-all-local-variables) + + (use-local-map espresso-mode-map) + (set-syntax-table espresso-mode-syntax-table) + (set (make-local-variable 'indent-line-function) 'espresso-indent-line) + (set (make-local-variable 'beginning-of-defun-function) + 'espresso--beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) + 'espresso--end-of-defun) + + (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil) + + (set (make-local-variable 'font-lock-defaults) + (list espresso--font-lock-keywords + nil nil nil nil + '(font-lock-syntactic-keywords + . espresso--font-lock-syntactic-keywords))) + + (set (make-local-variable 'parse-sexp-ignore-comments) t) + (set (make-local-variable 'parse-sexp-lookup-properties) t) + (set (make-local-variable 'which-func-imenu-joiner-function) + #'espresso--which-func-joiner) + + ;; Comments + (setq comment-start "// ") + (setq comment-end "") + (set (make-local-variable 'fill-paragraph-function) + 'espresso-c-fill-paragraph) + + ;; Imenu + (setq imenu-case-fold-search nil) + (set (make-local-variable 'imenu-create-index-function) + #'espresso--imenu-create-index) + + (setq major-mode 'espresso-mode) + (setq mode-name "Espresso") + + ;; for filling, pretend we're cc-mode + (setq c-comment-prefix-regexp "//+\\|\\**" + c-paragraph-start "$" + c-paragraph-separate "$" + c-block-comment-prefix "* " + c-line-comment-starter "//" + c-comment-start-regexp "/[*/]\\|\\s!" + comment-start-skip "\\(//+\\|/\\*+\\)\\s *") + + (let ((c-buffer-is-cc-mode t)) + (c-setup-paragraph-variables)) + + ;; Important to fontify the whole buffer syntactically! If we don't, + ;; then we might have regular expression literals that aren't marked + ;; as strings, which will screw up parse-partial-sexp, scan-lists, etc. + ;; and and produce maddening "unbalanced parenthesis" errors. When we attempt + ;; to find the error and scroll to the portion of the buffer containing the problem, + ;; JIT-lock will apply the correct syntax to the regular expresion literal and + ;; the problem will mysteriously disappear. + (font-lock-set-defaults) + + (let (font-lock-keywords) ; leaves syntactic keywords intact + (font-lock-fontify-buffer)) + + (run-mode-hooks 'espresso-mode-hook)) + + +(eval-after-load "hideshow" + '(add-to-list 'hs-special-modes-alist + '(espresso-mode "{" "}" "/[*/]" + nil hs-c-like-adjust-block-beginning))) + +(eval-after-load "folding" + (when (fboundp 'folding-add-to-marks-list) + (folding-add-to-marks-list 'espresso-mode "// {{{" "// }}}" ))) + + +;;; Emacs +(provide 'espresso-mode) +;; Local Variables: +;; outline-regexp: ";;; " +;; End: +;; espresso.el ends here diff --git a/emacs/flyspell.el b/emacs/flyspell.el new file mode 100644 index 0000000..aeaceee --- /dev/null +++ b/emacs/flyspell.el @@ -0,0 +1,2458 @@ +;;; <pre> +;;; flyspell.el --- on-the-fly spell checker + +;; Copyright (C) 1998, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +;; Author: Manuel Serrano <Manuel.Serrano@sophia.inria.fr> +;; Version: 1.7o +;; Keywords: convenience + +;; 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: +;; +;; Flyspell is a minor Emacs mode performing on-the-fly spelling +;; checking. +;; +;; To enable Flyspell minor mode, type M-x flyspell-mode. +;; This applies only to the current buffer. +;; +;; To enable Flyspell in text representing computer programs, type +;; M-x flyspell-prog-mode. +;; In that mode only text inside comments is checked. +;; +;; Note: consider setting the variable ispell-parser to `tex' to +;; avoid TeX command checking; use `(setq ispell-parser 'tex)'. +;; +;; Some user variables control the behavior of flyspell. They are +;; those defined under the `User variables' comment. + +;;; Code: +(require 'ispell) + +;*---------------------------------------------------------------------*/ +;* Group ... */ +;*---------------------------------------------------------------------*/ +(defgroup flyspell nil + "Spell checking on the fly." + :tag "FlySpell" + :prefix "flyspell-" + :group 'ispell + :group 'processes) + +;*---------------------------------------------------------------------*/ +;* Which emacs are we currently running */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-emacs + (cond + ((string-match "XEmacs" emacs-version) + 'xemacs) + (t + 'emacs)) + "The type of Emacs we are currently running.") + +(defvar flyspell-use-local-map + (or (eq flyspell-emacs 'xemacs) + (not (string< emacs-version "20")))) + +;*---------------------------------------------------------------------*/ +;* User configuration ... */ +;*---------------------------------------------------------------------*/ +(defcustom flyspell-highlight-flag t + "*How Flyspell should indicate misspelled words. +Non-nil means use highlight, nil means use minibuffer messages." + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-mark-duplications-flag t + "*Non-nil means Flyspell reports a repeated word as an error." + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-sort-corrections nil + "*Non-nil means, sort the corrections alphabetically before popping them." + :group 'flyspell + :version "21.1" + :type 'boolean) + +(defcustom flyspell-duplicate-distance -1 + "*The maximum distance for finding duplicates of unrecognized words. +This applies to the feature that when a word is not found in the dictionary, +if the same spelling occurs elsewhere in the buffer, +Flyspell uses a different face (`flyspell-duplicate-face') to highlight it. +This variable specifies how far to search to find such a duplicate. +-1 means no limit (search the whole buffer). +0 means do not search for duplicate unrecognized spellings." + :group 'flyspell + :version "21.1" + :type 'number) + +(defcustom flyspell-delay 3 + "*The number of seconds to wait before checking, after a \"delayed\" command." + :group 'flyspell + :type 'number) + +(defcustom flyspell-persistent-highlight t + "*Non-nil means misspelled words remain highlighted until corrected. +If this variable is nil, only the most recently detected misspelled word +is highlighted." + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-highlight-properties t + "*Non-nil means highlight incorrect words even if a property exists for this word." + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-default-delayed-commands + '(self-insert-command + delete-backward-char + backward-or-forward-delete-char + delete-char + scrollbar-vertical-drag + backward-delete-char-untabify) + "The standard list of delayed commands for Flyspell. +See `flyspell-delayed-commands'." + :group 'flyspell + :version "21.1" + :type '(repeat (symbol))) + +(defcustom flyspell-delayed-commands nil + "List of commands that are \"delayed\" for Flyspell mode. +After these commands, Flyspell checking is delayed for a short time, +whose length is specified by `flyspell-delay'." + :group 'flyspell + :type '(repeat (symbol))) + +(defcustom flyspell-default-deplacement-commands + '(next-line + previous-line + scroll-up + scroll-down) + "The standard list of deplacement commands for Flyspell. +See `flyspell-deplacement-commands'." + :group 'flyspell + :version "21.1" + :type '(repeat (symbol))) + +(defcustom flyspell-default-ignored-commands + '(fill-paragraph) + "The standard list of ignored commands for Flyspell. + See `flyspell-delayed-commands'." + :group 'flyspell + :version "21.3" + :type '(repeat (symbol))) + + (defcustom flyspell-ignored-commands nil + "List of commands that are \"ignored\" for Flyspell mode. + The changes in the text made by these commands are ignored. This list is meant for commands that change text in a way that does not affect individual words, such as `fill-paragraph'." + :group 'flyspell + :version "21.3" + :type '(repeat (symbol))) + +(defcustom flyspell-deplacement-commands nil + "List of commands that are \"deplacement\" for Flyspell mode. +After these commands, Flyspell checking is performed only if the previous +command was not the very same command." + :group 'flyspell + :version "21.1" + :type '(repeat (symbol))) + +(defcustom flyspell-issue-welcome-flag t + "*Non-nil means that Flyspell should display a welcome message when started." + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-issue-message-flag t + "*Non-nil means that Flyspell emits messages when checking words." + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-incorrect-hook nil + "*List of functions to be called when incorrect words are encountered. +Each function is given three arguments: the beginning and the end +of the incorrect region. The third is either the symbol 'doublon' or the list +of possible corrections as returned by 'ispell-parse-output'. + +If any of the functions return non-Nil, the word is not highlighted as +incorrect." + :group 'flyspell + :version "21.1" + :type 'hook) + +(defcustom flyspell-default-dictionary nil + "A string that is the name of the default dictionary. +This is passed to the `ispell-change-dictionary' when flyspell is started. +If the variable `ispell-local-dictionary' or `ispell-dictionary' is non-nil +when flyspell is started, the value of that variable is used instead +of `flyspell-default-dictionary' to select the default dictionary. +Otherwise, if `flyspell-default-dictionary' is nil, it means to use +Ispell's ultimate default dictionary." + :group 'flyspell + :version "21.1" + :type '(choice string (const :tag "Default" nil))) + +(defcustom flyspell-tex-command-regexp + "\\(\\(begin\\|end\\)[ \t]*{\\|\\(cite[a-z*]*\\|label\\|ref\\|eqref\\|usepackage\\|documentclass\\)[ \t]*\\(\\[[^]]*\\]\\)?{[^{}]*\\)" + "A string that is the regular expression that matches TeX commands." + :group 'flyspell + :version "21.1" + :type 'string) + +(defcustom flyspell-check-tex-math-command nil + "*Non nil means check even inside TeX math environment. +TeX math environments are discovered by the TEXMATHP that implemented +inside the texmathp.el Emacs package. That package may be found at: +http://strw.leidenuniv.nl/~dominik/Tools" + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-dictionaries-that-consider-dash-as-word-delimiter + '("francais" "deutsch8" "norsk") + "List of dictionary names that consider `-' as word delimiter." + :group 'flyspell + :version "21.1" + :type '(repeat (string))) + +(defcustom flyspell-abbrev-p + nil + "*If non-nil, add correction to abbreviation table." + :group 'flyspell + :version "21.1" + :type 'boolean) + +(defcustom flyspell-use-global-abbrev-table-p + nil + "*If non-nil, prefer global abbrev table to local abbrev table." + :group 'flyspell + :version "21.1" + :type 'boolean) + +;;;###autoload +(defcustom flyspell-mode-line-string " Fly" + "*String displayed on the modeline when flyspell is active. +Set this to nil if you don't want a modeline indicator." + :group 'flyspell + :type '(choice string (const :tag "None" nil))) + +(defcustom flyspell-large-region 1000 + "*The threshold that determines if a region is small. +The `flyspell-region' function is invoked if the region is small, the +word are checked one after the other using regular flyspell check +means. If the region is large, a new Ispell process is spawned to get +speed. + +if flyspell-large-region is nil, regions are treated as small." + :group 'flyspell + :version "21.1" + :type '(choice number boolean)) + +(defcustom flyspell-insert-function (function insert) + "*Function for inserting word by flyspell upon correction." + :group 'flyspell + :type 'function) + +(defcustom flyspell-before-incorrect-word-string nil + "String used to indicate an incorrect word starting." + :group 'flyspell + :type '(choice string (const nil))) + +(defcustom flyspell-after-incorrect-word-string nil + "String used to indicate an incorrect word ending." + :group 'flyspell + :type '(choice string (const nil))) + +(defcustom flyspell-use-meta-tab t + "*Non-nil means that flyspell uses META-TAB to correct word." + :group 'flyspell + :type 'boolean) + +(defcustom flyspell-auto-correct-binding + (cond + ((eq flyspell-emacs 'xemacs) + [(control \;)]) + (t + [?\C-\;])) + "The key binding for flyspell auto correction." + :group 'flyspell) + +;*---------------------------------------------------------------------*/ +;* Mode specific options */ +;* ------------------------------------------------------------- */ +;* Mode specific options enable users to disable flyspell on */ +;* certain word depending of the emacs mode. For instance, when */ +;* using flyspell with mail-mode add the following expression */ +;* in your .emacs file: */ +;* (add-hook 'mail-mode */ +;* '(lambda () (setq flyspell-generic-check-word-p */ +;* 'mail-mode-flyspell-verify))) */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-generic-check-word-p nil + "Function providing per-mode customization over which words are flyspelled. +Returns t to continue checking, nil otherwise. +Flyspell mode sets this variable to whatever is the `flyspell-mode-predicate' +property of the major mode name.") +(make-variable-buffer-local 'flyspell-generic-check-word-p) + +;*--- mail mode -------------------------------------------------------*/ +(put 'mail-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify) +(put 'message-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify) +(defun mail-mode-flyspell-verify () + "This function is used for `flyspell-generic-check-word-p' in Mail mode." + (let ((header-end (save-excursion + (goto-char (point-min)) + (re-search-forward + (concat "^" + (regexp-quote mail-header-separator) + "$") + nil t) + (point))) + (signature-begin (save-excursion + (goto-char (point-max)) + (re-search-backward message-signature-separator + nil t) + (point)))) + (cond ((< (point) header-end) + (and (save-excursion (beginning-of-line) + (looking-at "^Subject:")) + (> (point) (match-end 0)))) + ((> (point) signature-begin) + nil) + (t + (save-excursion + (beginning-of-line) + (not (looking-at "[>}|]\\|To:"))))))) + +;*--- texinfo mode ----------------------------------------------------*/ +(put 'texinfo-mode 'flyspell-mode-predicate 'texinfo-mode-flyspell-verify) +(defun texinfo-mode-flyspell-verify () + "This function is used for `flyspell-generic-check-word-p' in Texinfo mode." + (save-excursion + (forward-word -1) + (not (looking-at "@")))) + +;*--- tex mode --------------------------------------------------------*/ +(put 'tex-mode 'flyspell-mode-predicate 'tex-mode-flyspell-verify) +(defun tex-mode-flyspell-verify () + "This function is used for `flyspell-generic-check-word-p' in LaTeX mode." + (and + (not (save-excursion + (re-search-backward "^[ \t]*%%%[ \t]+Local" (point-min) t))) + (not (save-excursion + (let ((this (point-marker)) + (e (progn (end-of-line) (point-marker)))) + (beginning-of-line) + (if (re-search-forward "\\\\\\(cite\\|label\\|ref\\){[^}]*}" e t) + (and (>= this (match-beginning 0)) + (<= this (match-end 0)) ))))))) + +;*--- sgml mode -------------------------------------------------------*/ +(put 'sgml-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify) +(put 'html-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify) + +(defun sgml-mode-flyspell-verify () + "This function is used for `flyspell-generic-check-word-p' in SGML mode." + (not (save-excursion + (let ((this (point-marker)) + (s (progn (beginning-of-line) (point-marker))) + (e (progn (end-of-line) (point-marker)))) + (or (progn + (goto-char this) + (and (re-search-forward "[^<]*>" e t) + (= (match-beginning 0) this))) + (progn + (goto-char this) + (and (re-search-backward "<[^>]*" s t) + (= (match-end 0) this))) + (and (progn + (goto-char this) + (and (re-search-forward "[^&]*;" e t) + (= (match-beginning 0) this))) + (progn + (goto-char this) + (and (re-search-backward "&[^;]*" s t) + (= (match-end 0) this))))))))) + +;*---------------------------------------------------------------------*/ +;* Programming mode */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-prog-text-faces + '(font-lock-string-face font-lock-comment-face font-lock-doc-face) + "Faces corresponding to text in programming-mode buffers.") + +(defun flyspell-generic-progmode-verify () + "Used for `flyspell-generic-check-word-p' in programming modes." + (let ((f (get-text-property (point) 'face))) + (memq f flyspell-prog-text-faces))) + +;;;###autoload +(defun flyspell-prog-mode () + "Turn on `flyspell-mode' for comments and strings." + (interactive) + (setq flyspell-generic-check-word-p 'flyspell-generic-progmode-verify) + (flyspell-mode 1) + (run-hooks 'flyspell-prog-mode-hook)) + +;*---------------------------------------------------------------------*/ +;* Overlay compatibility */ +;*---------------------------------------------------------------------*/ +(autoload 'make-overlay "overlay" "Overlay compatibility kit." t) +(autoload 'overlayp "overlay" "Overlay compatibility kit." t) +(autoload 'overlays-in "overlay" "Overlay compatibility kit." t) +(autoload 'delete-overlay "overlay" "Overlay compatibility kit." t) +(autoload 'overlays-at "overlay" "Overlay compatibility kit." t) +(autoload 'overlay-put "overlay" "Overlay compatibility kit." t) +(autoload 'overlay-get "overlay" "Overlay compatibility kit." t) +(autoload 'previous-overlay-change "overlay" "Overlay compatibility kit." t) + +;*---------------------------------------------------------------------*/ +;* The minor mode declaration. */ +;*---------------------------------------------------------------------*/ +(eval-when-compile (defvar flyspell-local-mouse-map)) + +;;;###autoload +(defvar flyspell-mode nil) +(make-variable-buffer-local 'flyspell-mode) + +(defvar flyspell-mouse-map + (let ((map (make-sparse-keymap))) + (if flyspell-use-meta-tab + (define-key map "\M-\t" #'flyspell-auto-correct-word)) + (define-key map (if (featurep 'xemacs) [button2] [down-mouse-2]) + #'flyspell-correct-word) + (if (not (featurep 'xemacs)) + (define-key map [(shift down-mouse-2)] #'flyspell-correct-word)) + (define-key map flyspell-auto-correct-binding 'flyspell-auto-correct-previous-word) + (define-key map [(control \,)] 'flyspell-goto-next-error) + (define-key map [(control \.)] 'flyspell-auto-correct-word) + map)) + +;;;###autoload +(defvar flyspell-mode-map (make-sparse-keymap)) + +;; mouse, keyboard bindings and misc definition +(when (or (assoc 'flyspell-mode minor-mode-map-alist) + (setq minor-mode-map-alist + (cons (cons 'flyspell-mode flyspell-mode-map) + minor-mode-map-alist))) + (if flyspell-use-meta-tab + (define-key flyspell-mode-map "\M-\t" 'flyspell-auto-correct-word)) + (cond + ((eq flyspell-emacs 'xemacs) + (define-key flyspell-mode-map flyspell-auto-correct-binding 'flyspell-auto-correct-previous-word) + (define-key flyspell-mode-map [(control \,)] 'flyspell-goto-next-error) + (define-key flyspell-mode-map [(control \.)] 'flyspell-auto-correct-word)) + (flyspell-use-local-map + (define-key flyspell-mode-map flyspell-auto-correct-binding 'flyspell-auto-correct-previous-word) + (define-key flyspell-mode-map [?\C-\,] 'flyspell-goto-next-error) + (define-key flyspell-mode-map [?\C-\.] 'flyspell-auto-correct-word)))) + + +;; the name of the overlay property that defines the keymap +(defvar flyspell-overlay-keymap-property-name 'keymap) + +;; dash character machinery +(defvar flyspell-consider-dash-as-word-delimiter-flag nil + "*Non-nil means that the `-' char is considered as a word delimiter.") +(make-variable-buffer-local 'flyspell-consider-dash-as-word-delimiter-flag) +(defvar flyspell-dash-dictionary nil) +(make-variable-buffer-local 'flyspell-dash-dictionary) +(defvar flyspell-dash-local-dictionary nil) +(make-variable-buffer-local 'flyspell-dash-local-dictionary) + +;*---------------------------------------------------------------------*/ +;* Highlighting */ +;*---------------------------------------------------------------------*/ +(defface flyspell-incorrect-face + (if (eq flyspell-emacs 'xemacs) + '((((class color)) (:foreground "OrangeRed" :bold t :underline t)) + (t (:bold t))) + '((((class color)) (:foreground "OrangeRed" :weight bold :underline t)) + (t (:weight bold)))) + "Face used for marking a misspelled word in Flyspell." + :group 'flyspell) + +(defface flyspell-duplicate-face + (if (eq flyspell-emacs 'xemacs) + '((((class color)) (:foreground "Gold3" :bold t :underline t)) + (t (:bold t))) + '((((class color)) (:foreground "Gold3" :weight bold :underline t)) + (t (:weight bold)))) + "Face used for marking a misspelled word that appears twice in the buffer. +See also `flyspell-duplicate-distance'." + :group 'flyspell) + +(defvar flyspell-overlay nil) + +;*---------------------------------------------------------------------*/ +;* flyspell-mode ... */ +;*---------------------------------------------------------------------*/ +;;;###autoload +(defun flyspell-mode (&optional arg) + "Minor mode performing on-the-fly spelling checking. +Ispell is automatically spawned on background for each entered words. +The default flyspell behavior is to highlight incorrect words. +With no argument, this command toggles Flyspell mode. +With a prefix argument ARG, turn Flyspell minor mode on iff ARG is positive. + +Bindings: +\\[ispell-word]: correct words (using Ispell). +\\[flyspell-auto-correct-word]: automatically correct word. +\\[flyspell-auto-correct-previous-word]: automatically correct the last misspelled word. +\\[flyspell-correct-word] (or down-mouse-2): popup correct words. + +Hooks: +This runs `flyspell-mode-hook' after flyspell is entered. + +Remark: +`flyspell-mode' uses `ispell-mode'. Thus all Ispell options are +valid. For instance, a personal dictionary can be used by +invoking `ispell-change-dictionary'. + +Consider using the `ispell-parser' to check your text. For instance +consider adding: +\(add-hook 'tex-mode-hook (function (lambda () (setq ispell-parser 'tex)))) +in your .emacs file. + +\\[flyspell-region] checks all words inside a region. +\\[flyspell-buffer] checks the whole buffer." + (interactive "P") + (let ((old-flyspell-mode flyspell-mode)) + ;; Mark the mode as on or off. + (setq flyspell-mode (not (or (and (null arg) flyspell-mode) + (<= (prefix-numeric-value arg) 0)))) + ;; Do the real work. + (unless (eq flyspell-mode old-flyspell-mode) + (if flyspell-mode + (flyspell-mode-on) + (flyspell-mode-off)) + ;; Force modeline redisplay. + (set-buffer-modified-p (buffer-modified-p))))) + +;*---------------------------------------------------------------------*/ +;* Autoloading */ +;*---------------------------------------------------------------------*/ +;;;###autoload +(if (fboundp 'add-minor-mode) + (add-minor-mode 'flyspell-mode + 'flyspell-mode-line-string + flyspell-mode-map + nil + 'flyspell-mode) + (or (assoc 'flyspell-mode minor-mode-alist) + (setq minor-mode-alist + (cons '(flyspell-mode flyspell-mode-line-string) + minor-mode-alist))) + + (or (assoc 'flyspell-mode minor-mode-map-alist) + (setq minor-mode-map-alist + (cons (cons 'flyspell-mode flyspell-mode-map) + minor-mode-map-alist)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-buffers ... */ +;* ------------------------------------------------------------- */ +;* For remembering buffers running flyspell */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-buffers nil) + +;*---------------------------------------------------------------------*/ +;* flyspell-minibuffer-p ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-minibuffer-p (buffer) + "Is BUFFER a minibuffer?" + (let ((ws (get-buffer-window-list buffer t))) + (and (consp ws) (window-minibuffer-p (car ws))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-version ... */ +;*---------------------------------------------------------------------*/ +;;;###autoload +(defun flyspell-version () + "The flyspell version" + (interactive) + "1.7o") + +;*---------------------------------------------------------------------*/ +;* flyspell-accept-buffer-local-defs ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-accept-buffer-local-defs () + ;; strange problem. If buffer in current window has font-lock turned on, + ;; but SET-BUFFER was called to point to an invisible buffer, this ispell + ;; call will reset the buffer to the buffer in the current window. However, + ;; it only happens at startup (fix by Albert L. Ting). + (let ((buf (current-buffer))) + (ispell-accept-buffer-local-defs) + (set-buffer buf)) + (if (not (and (eq flyspell-dash-dictionary ispell-dictionary) + (eq flyspell-dash-local-dictionary ispell-local-dictionary))) + ;; the dictionary has changed + (progn + (setq flyspell-dash-dictionary ispell-dictionary) + (setq flyspell-dash-local-dictionary ispell-local-dictionary) + (if (member (or ispell-local-dictionary ispell-dictionary) + flyspell-dictionaries-that-consider-dash-as-word-delimiter) + (setq flyspell-consider-dash-as-word-delimiter-flag t) + (setq flyspell-consider-dash-as-word-delimiter-flag nil))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-mode-on ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-mode-on () + "Turn Flyspell mode on. Do not use this; use `flyspell-mode' instead." + (setq ispell-highlight-face 'flyspell-incorrect-face) + ;; local dictionaries setup + (ispell-change-dictionary + (or ispell-local-dictionary ispell-dictionary flyspell-default-dictionary)) + ;; we have to force ispell to accept the local definition or + ;; otherwise it could be too late, the local dictionary may + ;; be forgotten! + (flyspell-accept-buffer-local-defs) + ;; we put the `flyspell-delayed' property on some commands + (flyspell-delay-commands) + ;; we put the `flyspell-deplacement' property on some commands + (flyspell-deplacement-commands) + ;; we put the `flyspell-ignored' property on some commands + (flyspell-ignore-commands) + ;; we bound flyspell action to post-command hook + (if (eq flyspell-emacs 'xemacs) + (make-local-hook 'post-command-hook)) + (add-hook 'post-command-hook (function flyspell-post-command-hook) t t) + ;; we bound flyspell action to pre-command hook + (if (eq flyspell-emacs 'xemacs) + (make-local-hook 'pre-command-hook)) + (add-hook 'pre-command-hook (function flyspell-pre-command-hook) t t) + ;; we bound flyspell action to after-change hook + (make-local-variable 'after-change-functions) + (setq after-change-functions + (cons 'flyspell-after-change-function after-change-functions)) + ;; set flyspell-generic-check-word-p based on the major mode + (let ((mode-predicate (get major-mode 'flyspell-mode-predicate))) + (if mode-predicate + (setq flyspell-generic-check-word-p mode-predicate))) + ;; work around the fact that the `local-map' text-property replaces the + ;; buffer's local map rather than shadowing it. + (set (make-local-variable 'flyspell-mouse-map) + (let ((map (copy-keymap flyspell-mouse-map))) + (set-keymap-parent map (current-local-map)) + (if (and (eq flyspell-emacs 'emacs) + (not (string< emacs-version "20"))) + (define-key map '[tool-bar] nil)) + map)) + (set (make-local-variable 'flyspell-mode-map) + (let ((map (copy-keymap flyspell-mode-map))) + (set-keymap-parent map (current-local-map)) + (if (and (eq flyspell-emacs 'emacs) + (not (string< emacs-version "20"))) + (define-key map '[tool-bar] nil)) + map)) + ;; the welcome message + (if (and flyspell-issue-message-flag + flyspell-issue-welcome-flag + (interactive-p)) + (let ((binding (where-is-internal 'flyspell-auto-correct-word + nil 'non-ascii))) + (message + (if binding + (format "Welcome to flyspell. Use %s or Mouse-2 to correct words." + (key-description binding)) + "Welcome to flyspell. Use Mouse-2 to correct words.")))) + ;; we end with the flyspell hooks + (run-hooks 'flyspell-mode-hook)) + +;*---------------------------------------------------------------------*/ +;* flyspell-delay-commands ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-delay-commands () + "Install the standard set of Flyspell delayed commands." + (mapcar 'flyspell-delay-command flyspell-default-delayed-commands) + (mapcar 'flyspell-delay-command flyspell-delayed-commands)) + +;*---------------------------------------------------------------------*/ +;* flyspell-delay-command ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-delay-command (command) + "Set COMMAND to be delayed, for Flyspell. +When flyspell `post-command-hook' is invoked because a delayed command +as been used the current word is not immediately checked. +It will be checked only after `flyspell-delay' seconds." + (interactive "SDelay Flyspell after Command: ") + (put command 'flyspell-delayed t)) + +;*---------------------------------------------------------------------*/ +;* flyspell-deplacement-commands ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-deplacement-commands () + "Install the standard set of Flyspell deplacement commands." + (mapcar 'flyspell-deplacement-command flyspell-default-deplacement-commands) + (mapcar 'flyspell-deplacement-command flyspell-deplacement-commands)) + +;*---------------------------------------------------------------------*/ +;* flyspell-deplacement-command ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-deplacement-command (command) + "Set COMMAND that implement cursor movements, for Flyspell. +When flyspell `post-command-hook' is invoked because of a deplacement command +as been used the current word is checked only if the previous command was +not the very same deplacement command." + (interactive "SDeplacement Flyspell after Command: ") + (put command 'flyspell-deplacement t)) + +;*---------------------------------------------------------------------*/ +;* flyspell-ignore-commands ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-ignore-commands () + "Install the standard set of Flyspell ignored commands." + (mapcar 'flyspell-ignore-command flyspell-default-ignored-commands) + (mapcar 'flyspell-ignore-command flyspell-ignored-commands)) + +;*---------------------------------------------------------------------*/ +;* flyspell-ignore-command ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-ignore-command (command) + "Set COMMAND to be ignored, for Flyspell. +When flyspell `post-command-hook' is invoked because of an +ignored command having been used, the changes in the text made by +that command are ignored. This feature is meant for commands that +change text in a way that does not affect individual words, such +as `fill-paragraph'." + (interactive "SMake Flyspell ignore changes made by Command: ") + (put command 'flyspell-ignored t)) + +;*---------------------------------------------------------------------*/ +;* flyspell-word-cache ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-word-cache-start nil) +(defvar flyspell-word-cache-end nil) +(defvar flyspell-word-cache-word nil) +(defvar flyspell-word-cache-result '_) +(make-variable-buffer-local 'flyspell-word-cache-start) +(make-variable-buffer-local 'flyspell-word-cache-end) +(make-variable-buffer-local 'flyspell-word-cache-word) +(make-variable-buffer-local 'flyspell-word-cache-result) + +;*---------------------------------------------------------------------*/ +;* The flyspell pre-hook, store the current position. In the */ +;* post command hook, we will check, if the word at this position */ +;* has to be spell checked. */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-pre-buffer nil) +(defvar flyspell-pre-point nil) +(defvar flyspell-pre-column nil) +(defvar flyspell-pre-pre-buffer nil) +(defvar flyspell-pre-pre-point nil) + +;*---------------------------------------------------------------------*/ +;* flyspell-previous-command ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-previous-command nil + "The last interactive command checked by Flyspell.") + +;*---------------------------------------------------------------------*/ +;* flyspell-pre-command-hook ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-pre-command-hook () + "Save the current buffer and point for Flyspell's post-command hook." + (interactive) + (setq flyspell-pre-buffer (current-buffer)) + (setq flyspell-pre-point (point)) + (setq flyspell-pre-column (current-column))) + +;*---------------------------------------------------------------------*/ +;* flyspell-mode-off ... */ +;*---------------------------------------------------------------------*/ +;;;###autoload +(defun flyspell-mode-off () + "Turn Flyspell mode off." + ;; we remove the hooks + (remove-hook 'post-command-hook (function flyspell-post-command-hook) t) + (remove-hook 'pre-command-hook (function flyspell-pre-command-hook) t) + (setq after-change-functions (delq 'flyspell-after-change-function + after-change-functions)) + ;; we remove all the flyspell hilightings + (flyspell-delete-all-overlays) + ;; we have to erase pre cache variables + (setq flyspell-pre-buffer nil) + (setq flyspell-pre-point nil) + ;; we mark the mode as killed + (setq flyspell-mode nil)) + +;*---------------------------------------------------------------------*/ +;* flyspell-check-pre-word-p ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-check-pre-word-p () + "Return non-nil if we should check the word before point. +More precisely, it applies to the word that was before point +before the current command." + (cond + ((or (not (numberp flyspell-pre-point)) + (not (bufferp flyspell-pre-buffer)) + (not (buffer-live-p flyspell-pre-buffer))) + nil) + ((and (eq flyspell-pre-pre-point flyspell-pre-point) + (eq flyspell-pre-pre-buffer flyspell-pre-buffer)) + nil) + ((or (and (= flyspell-pre-point (- (point) 1)) + (eq (char-syntax (char-after flyspell-pre-point)) ?w)) + (= flyspell-pre-point (point)) + (= flyspell-pre-point (+ (point) 1))) + nil) + ((and (symbolp this-command) + (not executing-kbd-macro) + (or (get this-command 'flyspell-delayed) + (and (get this-command 'flyspell-deplacement) + (eq flyspell-previous-command this-command))) + (or (= (current-column) 0) + (= (current-column) flyspell-pre-column) + (eq (char-syntax (char-after flyspell-pre-point)) ?w))) + nil) + ((not (eq (current-buffer) flyspell-pre-buffer)) + t) + ((not (and (numberp flyspell-word-cache-start) + (numberp flyspell-word-cache-end))) + t) + (t + (or (< flyspell-pre-point flyspell-word-cache-start) + (> flyspell-pre-point flyspell-word-cache-end))))) + +;*---------------------------------------------------------------------*/ +;* The flyspell after-change-hook, store the change position. In */ +;* the post command hook, we will check, if the word at this */ +;* position has to be spell checked. */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-changes nil) + +;*---------------------------------------------------------------------*/ +;* flyspell-after-change-function ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-after-change-function (start stop len) + "Save the current buffer and point for Flyspell's post-command hook." + (interactive) + (unless (and (symbolp this-command) (get this-command 'flyspell-ignored)) + (setq flyspell-changes (cons (cons start stop) flyspell-changes)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-check-changed-word-p ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-check-changed-word-p (start stop) + "Return t when the changed word has to be checked. +The answer depends of several criteria. +Mostly we check word delimiters." + (cond + ((and (memq (char-after start) '(?\n ? )) (> stop start)) + t) + ((not (numberp flyspell-pre-point)) + t) + ((and (>= flyspell-pre-point start) (<= flyspell-pre-point stop)) + nil) + ((let ((pos (point))) + (or (>= pos start) (<= pos stop) (= pos (1+ stop)))) + nil) + (t + t))) + +;*---------------------------------------------------------------------*/ +;* flyspell-check-word-p ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-check-word-p () + "Return t when the word at `point' has to be checked. +The answer depends of several criteria. +Mostly we check word delimiters." + (cond + ((<= (- (point-max) 1) (point-min)) + ;; the buffer is not filled enough + nil) + ((and (and (> (current-column) 0) + (not (eq (current-column) flyspell-pre-column))) + (save-excursion + (backward-char 1) + (and (looking-at (flyspell-get-not-casechars)) + (or flyspell-consider-dash-as-word-delimiter-flag + (not (looking-at "\\-")))))) + ;; yes because we have reached or typed a word delimiter. + t) + ((symbolp this-command) + (cond + ((get this-command 'flyspell-deplacement) + (not (eq flyspell-previous-command this-command))) + ((get this-command 'flyspell-delayed) + ;; the current command is not delayed, that + ;; is that we must check the word now + (if (or (fboundp 'about-xemacs) (featurep 'xemacs)) + (sit-for flyspell-delay nil) + (sit-for flyspell-delay 0 nil))) + (t t))) + (t t))) + +;*---------------------------------------------------------------------*/ +;* flyspell-debug-signal-no-check ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-debug-signal-no-check (msg obj) + (setq debug-on-error t) + (save-excursion + (let ((buffer (get-buffer-create "*flyspell-debug*"))) + (set-buffer buffer) + (erase-buffer) + (insert "NO-CHECK:\n") + (insert (format " %S : %S\n" msg obj))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-debug-signal-pre-word-checked ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-debug-signal-pre-word-checked () + (setq debug-on-error t) + (save-excursion + (let ((buffer (get-buffer-create "*flyspell-debug*"))) + (set-buffer buffer) + (insert "PRE-WORD:\n") + (insert (format " pre-point : %S\n" flyspell-pre-point)) + (insert (format " pre-buffer : %S\n" flyspell-pre-buffer)) + (insert (format " cache-start: %S\n" flyspell-word-cache-start)) + (insert (format " cache-end : %S\n" flyspell-word-cache-end)) + (goto-char (point-max))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-debug-signal-word-checked ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-debug-signal-word-checked () + (setq debug-on-error t) + (save-excursion + (let ((oldbuf (current-buffer)) + (buffer (get-buffer-create "*flyspell-debug*")) + (point (point))) + (set-buffer buffer) + (insert "WORD:\n") + (insert (format " this-cmd : %S\n" this-command)) + (insert (format " delayed : %S\n" (and (symbolp this-command) + (get this-command 'flyspell-delayed)))) + (insert (format " ignored : %S\n" (and (symbolp this-command) + (get this-command 'flyspell-ignored)))) + (insert (format " point : %S\n" point)) + (insert (format " prev-char : [%c] %S\n" + (progn + (set-buffer oldbuf) + (let ((c (if (> (point) (point-min)) + (save-excursion + (backward-char 1) + (char-after (point))) + ? ))) + (set-buffer buffer) + c)) + (progn + (set-buffer oldbuf) + (let ((c (if (> (point) (point-min)) + (save-excursion + (backward-char 1) + (and (and (looking-at (flyspell-get-not-casechars)) 1) + (and (or flyspell-consider-dash-as-word-delimiter-flag + (not (looking-at "\\-"))) 2)))))) + (set-buffer buffer) + c)))) + (insert (format " because : %S\n" + (cond + ((not (and (symbolp this-command) + (get this-command 'flyspell-delayed))) + ;; the current command is not delayed, that + ;; is that we must check the word now + 'not-delayed) + ((progn + (set-buffer oldbuf) + (let ((c (if (> (point) (point-min)) + (save-excursion + (backward-char 1) + (and (looking-at (flyspell-get-not-casechars)) + (or flyspell-consider-dash-as-word-delimiter-flag + (not (looking-at "\\-")))))))) + (set-buffer buffer) + c)) + ;; yes because we have reached or typed a word delimiter. + 'separator) + ((not (integerp flyspell-delay)) + ;; yes because the user had set up a no-delay configuration. + 'no-delay) + (t + 'sit-for)))) + (goto-char (point-max))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-debug-signal-changed-checked ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-debug-signal-changed-checked () + (setq debug-on-error t) + (save-excursion + (let ((buffer (get-buffer-create "*flyspell-debug*")) + (point (point))) + (set-buffer buffer) + (insert "CHANGED WORD:\n") + (insert (format " point : %S\n" point)) + (goto-char (point-max))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-post-command-hook ... */ +;* ------------------------------------------------------------- */ +;* It is possible that we check several words: */ +;* 1- the current word is checked if the predicate */ +;* FLYSPELL-CHECK-WORD-P is true */ +;* 2- the word that used to be the current word before the */ +;* THIS-COMMAND is checked if: */ +;* a- the previous word is different from the current word */ +;* b- the previous word as not just been checked by the */ +;* previous FLYSPELL-POST-COMMAND-HOOK */ +;* 3- the words changed by the THIS-COMMAND that are neither the */ +;* previous word nor the current word */ +;*---------------------------------------------------------------------*/ +(defun flyspell-post-command-hook () + "The `post-command-hook' used by flyspell to check a word in-the-fly." + (interactive) + (let ((command this-command)) + (if (flyspell-check-pre-word-p) + (save-excursion + '(flyspell-debug-signal-pre-word-checked) + (set-buffer flyspell-pre-buffer) + (save-excursion + (goto-char flyspell-pre-point) + (flyspell-word)))) + (if (flyspell-check-word-p) + (progn + '(flyspell-debug-signal-word-checked) + (flyspell-word) + ;; we remember which word we have just checked. + ;; this will be used next time we will check a word + ;; to compare the next current word with the word + ;; that as been registered in the pre-command-hook + ;; that is these variables are used within the predicate + ;; FLYSPELL-CHECK-PRE-WORD-P + (setq flyspell-pre-pre-buffer (current-buffer)) + (setq flyspell-pre-pre-point (point))) + (progn + (setq flyspell-pre-pre-buffer nil) + (setq flyspell-pre-pre-point nil) + ;; when a word is not checked because of a delayed command + ;; we do not disable the ispell cache. + (if (and (symbolp this-command) (get this-command 'flyspell-delayed)) + (progn + (setq flyspell-word-cache-end -1) + (setq flyspell-word-cache-result '_))))) + (while (consp flyspell-changes) + (let ((start (car (car flyspell-changes))) + (stop (cdr (car flyspell-changes)))) + (if (flyspell-check-changed-word-p start stop) + (save-excursion + '(flyspell-debug-signal-changed-checked) + (goto-char start) + (flyspell-word))) + (setq flyspell-changes (cdr flyspell-changes)))) + (setq flyspell-previous-command command))) + +;*---------------------------------------------------------------------*/ +;* flyspell-notify-misspell ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-notify-misspell (start end word poss) + (let ((replacements (if (stringp poss) + poss + (if flyspell-sort-corrections + (sort (car (cdr (cdr poss))) 'string<) + (car (cdr (cdr poss))))))) + (if flyspell-issue-message-flag + (message (format "mispelling `%s' %S" word replacements))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-word-search-backward ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-word-search-backward (word bound) + (save-excursion + (let ((r '()) + p) + (while (and (not r) (setq p (search-backward word bound t))) + (let ((lw (flyspell-get-word '()))) + (if (and (consp lw) (string-equal (car lw) word)) + (setq r p) + (goto-char p)))) + r))) + +;*---------------------------------------------------------------------*/ +;* flyspell-word-search-forward ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-word-search-forward (word bound) + (save-excursion + (let ((r '()) + p) + (while (and (not r) (setq p (search-forward word bound t))) + (let ((lw (flyspell-get-word '()))) + (if (and (consp lw) (string-equal (car lw) word)) + (setq r p) + (goto-char (1+ p))))) + r))) + +;*---------------------------------------------------------------------*/ +;* flyspell-word ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-word (&optional following) + "Spell check a word." + (interactive (list current-prefix-arg)) + (if (interactive-p) + (setq following ispell-following-word)) + (save-excursion + ;; use the correct dictionary + (flyspell-accept-buffer-local-defs) + (let* ((cursor-location (point)) + (flyspell-word (flyspell-get-word following)) + start end poss word) + (if (or (eq flyspell-word nil) + (and (fboundp flyspell-generic-check-word-p) + (not (funcall flyspell-generic-check-word-p)))) + t + (progn + ;; destructure return flyspell-word info list. + (setq start (car (cdr flyspell-word)) + end (car (cdr (cdr flyspell-word))) + word (car flyspell-word)) + ;; before checking in the directory, we check for doublons. + (cond + ((and (or (not (eq ispell-parser 'tex)) + (and (> start (point-min)) + (not (eq (char-after (1- start)) ?})) + (not (eq (char-after (1- start)) ?\\)))) + flyspell-mark-duplications-flag + (save-excursion + (goto-char (1- start)) + (let ((p (flyspell-word-search-backward + word + (- start (1+ (- end start)))))) + (and p (/= p (1- start)))))) + ;; yes, this is a doublon + (flyspell-highlight-incorrect-region start end 'doublon) + nil) + ((and (eq flyspell-word-cache-start start) + (eq flyspell-word-cache-end end) + (string-equal flyspell-word-cache-word word)) + ;; this word had been already checked, we skip + flyspell-word-cache-result) + ((and (eq ispell-parser 'tex) + (flyspell-tex-command-p flyspell-word)) + ;; this is a correct word (because a tex command) + (flyspell-unhighlight-at start) + (if (> end start) + (flyspell-unhighlight-at (- end 1))) + t) + (t + ;; we setup the cache + (setq flyspell-word-cache-start start) + (setq flyspell-word-cache-end end) + (setq flyspell-word-cache-word word) + ;; now check spelling of word. + (process-send-string ispell-process "%\n") + ;; put in verbose mode + (process-send-string ispell-process + (concat "^" word "\n")) + ;; we mark the ispell process so it can be killed + ;; when emacs is exited without query + (if (fboundp 'process-kill-without-query) + (process-kill-without-query ispell-process)) + ;; wait until ispell has processed word + (while (progn + (accept-process-output ispell-process) + (not (string= "" (car ispell-filter))))) + ;; (process-send-string ispell-process "!\n") + ;; back to terse mode. + (setq ispell-filter (cdr ispell-filter)) + (if (consp ispell-filter) + (setq poss (ispell-parse-output (car ispell-filter)))) + (let ((res (cond ((eq poss t) + ;; correct + (setq flyspell-word-cache-result t) + (flyspell-unhighlight-at start) + (if (> end start) + (flyspell-unhighlight-at (- end 1))) + t) + ((and (stringp poss) flyspell-highlight-flag) + ;; correct + (setq flyspell-word-cache-result t) + (flyspell-unhighlight-at start) + (if (> end start) + (flyspell-unhighlight-at (- end 1))) + t) + ((null poss) + (setq flyspell-word-cache-result t) + (flyspell-unhighlight-at start) + (if (> end start) + (flyspell-unhighlight-at (- end 1))) + t) + ((or (and (< flyspell-duplicate-distance 0) + (or (save-excursion + (goto-char start) + (flyspell-word-search-backward + word + (point-min))) + (save-excursion + (goto-char end) + (flyspell-word-search-forward + word + (point-max))))) + (and (> flyspell-duplicate-distance 0) + (or (save-excursion + (goto-char start) + (flyspell-word-search-backward + word + (- start + flyspell-duplicate-distance))) + (save-excursion + (goto-char end) + (flyspell-word-search-forward + word + (+ end + flyspell-duplicate-distance)))))) + (setq flyspell-word-cache-result nil) + (if flyspell-highlight-flag + (flyspell-highlight-duplicate-region + start end) + (message (format "duplicate `%s'" word))) + nil) + (t + (setq flyspell-word-cache-result nil) + ;; incorrect highlight the location + (if flyspell-highlight-flag + (flyspell-highlight-incorrect-region + start end poss) + (flyspell-notify-misspell start end word poss)) + nil)))) + ;; return to original location + (goto-char cursor-location) + (if ispell-quit (setq ispell-quit nil)) + res)))))))) + +;* {*---------------------------------------------------------------------*} */ +;* {* flyspell-tex-math-initialized ... *} */ +;* {*---------------------------------------------------------------------*} */ +;* (defvar flyspell-tex-math-initialized nil) */ +;* */ +;* {*---------------------------------------------------------------------*} */ +;* {* flyspell-math-tex-command-p ... *} */ +;* {* ------------------------------------------------------------- *} */ +;* {* This function uses the texmathp package to check if (point) *} */ +;* {* is within a tex command. In order to avoid using *} */ +;* {* condition-case each time we use the variable *} */ +;* {* flyspell-tex-math-initialized to make a special case the first *} */ +;* {* time that function is called. *} */ +;* {*---------------------------------------------------------------------*} */ +;* (defun flyspell-math-tex-command-p () */ +;* (cond */ +;* (flyspell-check-tex-math-command */ +;* nil) */ +;* ((eq flyspell-tex-math-initialized t) */ +;* (texmathp)) */ +;* ((eq flyspell-tex-math-initialized 'error) */ +;* nil) */ +;* (t */ +;* (setq flyspell-tex-math-initialized t) */ +;* (condition-case nil */ +;* (texmathp) */ +;* (error (progn */ +;* (setq flyspell-tex-math-initialized 'error) */ +;* nil)))))) */ + +;*---------------------------------------------------------------------*/ +;* flyspell-math-tex-command-p ... */ +;* ------------------------------------------------------------- */ +;* This function uses the texmathp package to check if point */ +;* is within a TeX math environment. `texmathp' can yield errors */ +;* if the document is currently not valid TeX syntax. */ +;*---------------------------------------------------------------------*/ +(defun flyspell-math-tex-command-p () + (when (fboundp 'texmathp) + (if flyspell-check-tex-math-command + nil + (condition-case nil + (texmathp) + (error nil))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-tex-command-p ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-tex-command-p (word) + "Return t if WORD is a TeX command." + (or (save-excursion + (let ((b (car (cdr word)))) + (and (re-search-backward "\\\\" (- (point) 100) t) + (or (= (match-end 0) b) + (and (goto-char (match-end 0)) + (looking-at flyspell-tex-command-regexp) + (>= (match-end 0) b)))))) + (flyspell-math-tex-command-p))) + +;*---------------------------------------------------------------------*/ +;* flyspell-casechars-cache ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-casechars-cache nil) +(defvar flyspell-ispell-casechars-cache nil) +(make-variable-buffer-local 'flyspell-casechars-cache) +(make-variable-buffer-local 'flyspell-ispell-casechars-cache) + +;*---------------------------------------------------------------------*/ +;* flyspell-get-casechars ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-get-casechars () + "This function builds a string that is the regexp of word chars. +In order to avoid one useless string construction, +this function changes the last char of the `ispell-casechars' string." + (let ((ispell-casechars (ispell-get-casechars))) + (cond + ((eq ispell-parser 'tex) + (setq flyspell-ispell-casechars-cache ispell-casechars) + (setq flyspell-casechars-cache + (concat (substring ispell-casechars + 0 + (- (length ispell-casechars) 1)) + "]")) + flyspell-casechars-cache) + (t + (setq flyspell-ispell-casechars-cache ispell-casechars) + (setq flyspell-casechars-cache ispell-casechars) + flyspell-casechars-cache)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-get-not-casechars-cache ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-not-casechars-cache nil) +(defvar flyspell-ispell-not-casechars-cache nil) +(make-variable-buffer-local 'flyspell-not-casechars-cache) +(make-variable-buffer-local 'flyspell-ispell-not-casechars-cache) + +;*---------------------------------------------------------------------*/ +;* flyspell-get-not-casechars ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-get-not-casechars () + "This function builds a string that is the regexp of non-word chars." + (let ((ispell-not-casechars (ispell-get-not-casechars))) + (cond + ((eq ispell-parser 'tex) + (setq flyspell-ispell-not-casechars-cache ispell-not-casechars) + (setq flyspell-not-casechars-cache + (concat (substring ispell-not-casechars + 0 + (- (length ispell-not-casechars) 1)) + "]")) + flyspell-not-casechars-cache) + (t + (setq flyspell-ispell-not-casechars-cache ispell-not-casechars) + (setq flyspell-not-casechars-cache ispell-not-casechars) + flyspell-not-casechars-cache)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-get-word ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-get-word (following &optional extra-otherchars) + "Return the word for spell-checking according to Ispell syntax. +If optional argument FOLLOWING is non-nil or if `flyspell-following-word' +is non-nil when called interactively, then the following word +\(rather than preceding\) is checked when the cursor is not over a word. +Optional second argument contains otherchars that can be included in word +many times. + +Word syntax described by `flyspell-dictionary-alist' (which see)." + (let* ((flyspell-casechars (flyspell-get-casechars)) + (flyspell-not-casechars (flyspell-get-not-casechars)) + (ispell-otherchars (ispell-get-otherchars)) + (ispell-many-otherchars-p (ispell-get-many-otherchars-p)) + (word-regexp (concat flyspell-casechars + "+\\(" + (if (not (string= "" ispell-otherchars)) + (concat ispell-otherchars "?")) + (if extra-otherchars + (concat extra-otherchars "?")) + flyspell-casechars + "+\\)" + (if (or ispell-many-otherchars-p + extra-otherchars) + "*" "?"))) + did-it-once prevpt + start end word) + ;; find the word + (if (not (looking-at flyspell-casechars)) + (if following + (re-search-forward flyspell-casechars (point-max) t) + (re-search-backward flyspell-casechars (point-min) t))) + ;; move to front of word + (re-search-backward flyspell-not-casechars (point-min) 'start) + (while (and (or (and (not (string= "" ispell-otherchars)) + (looking-at ispell-otherchars)) + (and extra-otherchars (looking-at extra-otherchars))) + (not (bobp)) + (or (not did-it-once) + ispell-many-otherchars-p) + (not (eq prevpt (point)))) + (if (and extra-otherchars (looking-at extra-otherchars)) + (progn + (backward-char 1) + (if (looking-at flyspell-casechars) + (re-search-backward flyspell-not-casechars (point-min) 'move))) + (setq did-it-once t + prevpt (point)) + (backward-char 1) + (if (looking-at flyspell-casechars) + (re-search-backward flyspell-not-casechars (point-min) 'move) + (backward-char -1)))) + ;; Now mark the word and save to string. + (if (not (re-search-forward word-regexp (point-max) t)) + nil + (progn + (setq start (match-beginning 0) + end (point) + word (buffer-substring-no-properties start end)) + (list word start end))))) + +(defun flyspell-get-word.old (following) + "Return the word for spell-checking according to Ispell syntax. +If argument FOLLOWING is non-nil or if `ispell-following-word' +is non-nil when called interactively, then the following word +\(rather than preceding\) is checked when the cursor is not over a word. +Optional second argument contains other chars that can be included in word +many times. + +Word syntax described by `ispell-dictionary-alist' (which see)." + (let* ((flyspell-casechars (flyspell-get-casechars)) + (flyspell-not-casechars (flyspell-get-not-casechars)) + (ispell-otherchars (ispell-get-otherchars)) + (ispell-many-otherchars-p (ispell-get-many-otherchars-p)) + (word-regexp (if (string< "" ispell-otherchars) + (concat flyspell-casechars + "+\\(" + ispell-otherchars + (if (> (length ispell-otherchars) 0) "?") + flyspell-casechars + "+\\)" + (if ispell-many-otherchars-p + "*" "?")) + (concat flyspell-casechars "+"))) + did-it-once + start end word) + ;; find the word + (if (not (looking-at flyspell-casechars)) + (if following + (re-search-forward flyspell-casechars (point-max) t) + (re-search-backward flyspell-casechars (point-min) t))) + ;; move to front of word + (re-search-backward flyspell-not-casechars (point-min) 'start) + (let ((pos nil)) + (if (string< "" ispell-otherchars) + (while (and (looking-at ispell-otherchars) + (not (bobp)) + (or (not did-it-once) + ispell-many-otherchars-p) + (not (eq pos (point)))) + (setq pos (point)) + (setq did-it-once t) + (backward-char 1) + (if (looking-at flyspell-casechars) + (re-search-backward flyspell-not-casechars (point-min) 'move) + (backward-char -1))))) + ;; Now mark the word and save to string. + (if (eq (re-search-forward word-regexp (point-max) t) nil) + nil + (progn + (setq start (match-beginning 0) + end (point) + word (buffer-substring-no-properties start end)) + (list word start end))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-small-region ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-small-region (beg end) + "Flyspell text between BEG and END." + (save-excursion + (if (> beg end) + (let ((old beg)) + (setq beg end) + (setq end old))) + (goto-char beg) + (let ((count 0)) + (while (< (point) end) + (if (and flyspell-issue-message-flag (= count 100)) + (progn + (message "Spell Checking...%d%%" + (* 100 (/ (float (- (point) beg)) (- end beg)))) + (setq count 0)) + (setq count (+ 1 count))) + (flyspell-word) + (sit-for 0) + (let ((cur (point))) + (forward-word 1) + (if (and (< (point) end) (> (point) (+ cur 1))) + (backward-char 1))))) + (backward-char 1) + (if flyspell-issue-message-flag (message "Spell Checking completed.")) + (flyspell-word))) + +;*---------------------------------------------------------------------*/ +;* flyspell-external-ispell-process ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-external-ispell-process '() + "The external Flyspell Ispell process.") + +;*---------------------------------------------------------------------*/ +;* flyspell-external-ispell-buffer ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-external-ispell-buffer '()) +(defvar flyspell-large-region-buffer '()) +(defvar flyspell-large-region-beg (point-min)) +(defvar flyspell-large-region-end (point-max)) + +;*---------------------------------------------------------------------*/ +;* flyspell-external-point-words ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-external-point-words () + (let ((buffer flyspell-external-ispell-buffer)) + (set-buffer buffer) + (beginning-of-buffer) + (let ((size (- flyspell-large-region-end flyspell-large-region-beg)) + (start flyspell-large-region-beg) + (pword "") + (pcount 1)) + ;; now we are done with ispell, we have to find the word in + ;; the initial buffer + (while (< (point) (- (point-max) 1)) + ;; we have to fetch the incorrect word + (if (re-search-forward "\\([^\n]+\\)\n" (point-max) t) + (let ((word (match-string 1))) + (if (string= word pword) + (setq pcount (1+ pcount)) + (progn + (setq pword word) + (setq pcount 1))) + (goto-char (match-end 0)) + (if flyspell-issue-message-flag + (message "Spell Checking...%d%% [%s]" + (* 100 (/ (float (point)) (point-max))) + word)) + (set-buffer flyspell-large-region-buffer) + (goto-char flyspell-large-region-beg) + (let ((keep t) + (n 0)) + (while (and (or (< n pcount) keep) + (search-forward word flyspell-large-region-end t)) + (progn + (goto-char (- (point) 1)) + (setq n (1+ n)) + (setq keep (flyspell-word)))) + (if (= n pcount) + (setq flyspell-large-region-beg (point)))) + (set-buffer buffer)) + (goto-char (point-max))))) + ;; we are done + (if flyspell-issue-message-flag (message "Spell Checking completed.")) + ;; ok, we are done with pointing out incorrect words, we just + ;; have to kill the temporary buffer + (kill-buffer flyspell-external-ispell-buffer) + (setq flyspell-external-ispell-buffer nil))) + +;*---------------------------------------------------------------------*/ +;* flyspell-process-localwords ... */ +;* ------------------------------------------------------------- */ +;* This function is used to prevent checking words declared */ +;* explictitly correct on large regions. */ +;*---------------------------------------------------------------------*/ +(defun flyspell-process-localwords () + "Parse Localwords in the buffer and remove them from the mispellings +buffer before flyspell attempts to check them." + (let (localwords + (current-buffer curbuf) + (mispellings-buffer buffer) + (ispell-casechars (ispell-get-casechars))) + ;; Get localwords from the original buffer + (save-excursion + (set-buffer current-buffer) +;* (flyspell-delete-all-overlays) */ + (beginning-of-buffer) + ;; Localwords parsing stolen form ispell.el + (while (search-forward ispell-words-keyword nil t) + (let ((end (save-excursion (end-of-line) (point))) + string) + ;; buffer-local words separated by a space, and can contain + ;; any character other than a space. Not rigorous enough. + (while (re-search-forward " *\\([^ ]+\\)" end t) + (setq string (buffer-substring-no-properties (match-beginning 1) + (match-end 1))) + ;; This can fail when string contains a word with illegal chars. + ;; Error handling needs to be added between ispell and emacs. + (if (and (< 1 (length string)) + (equal 0 (string-match ispell-casechars string))) + (setq localwords (add-to-list 'localwords string))))))) + ;; Remove localwords matches + (set-buffer mispellings-buffer) + (while localwords + (beginning-of-buffer) + (delete-matching-lines (concat "^" (car localwords) "$")) + (setq localwords (cdr localwords))) + (end-of-buffer))) + +;*---------------------------------------------------------------------*/ +;* flyspell-large-region ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-large-region (beg end) + (let* ((curbuf (current-buffer)) + (buffer (get-buffer-create "*flyspell-region*"))) + (setq flyspell-external-ispell-buffer buffer) + (setq flyspell-large-region-buffer curbuf) + (setq flyspell-large-region-beg beg) + (setq flyspell-large-region-end end) + (set-buffer buffer) + (erase-buffer) + ;; this is done, we can start checking... + (if flyspell-issue-message-flag (message "Checking region...")) + (set-buffer curbuf) + (let ((c (apply 'call-process-region beg + end + ispell-program-name + nil + buffer + nil + (if (boundp 'ispell-list-command) + ispell-list-command + "-l") + (let (args) + ;; Local dictionary becomes the global dictionary in use. + (if ispell-local-dictionary + (setq ispell-dictionary ispell-local-dictionary)) + (setq args (ispell-get-ispell-args)) + (if ispell-dictionary ; use specified dictionary + (setq args + (append (list "-d" ispell-dictionary) args))) + (if ispell-personal-dictionary ; use specified pers dict + (setq args + (append args + (list "-p" + (expand-file-name + ispell-personal-dictionary))))) + (setq args (append args ispell-extra-args)) + args)))) + (if (= c 0) + (progn + (flyspell-process-localwords) + (with-current-buffer curbuf + (flyspell-delete-region-overlays beg end)) + (flyspell-external-point-words)) + (error "Can't check region..."))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-region ... */ +;* ------------------------------------------------------------- */ +;* Because `ispell -a' is too slow, it is not possible to use */ +;* it on large region. Then, when ispell is invoked on a large */ +;* text region, a new `ispell -l' process is spawned. The */ +;* pointed out words are then searched in the region a checked with */ +;* regular flyspell means. */ +;*---------------------------------------------------------------------*/ +;;;###autoload +(defun flyspell-region (beg end) + "Flyspell text between BEG and END." + (interactive "r") + (if (= beg end) + () + (save-excursion + (if (> beg end) + (let ((old beg)) + (setq beg end) + (setq end old))) + (if (and flyspell-large-region (> (- end beg) flyspell-large-region)) + (flyspell-large-region beg end) + (flyspell-small-region beg end))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-buffer ... */ +;*---------------------------------------------------------------------*/ +;;;###autoload +(defun flyspell-buffer () + "Flyspell whole buffer." + (interactive) + (flyspell-region (point-min) (point-max))) + +;*---------------------------------------------------------------------*/ +;* old next error position ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-old-buffer-error nil) +(defvar flyspell-old-pos-error nil) + +;*---------------------------------------------------------------------*/ +;* flyspell-goto-next-error ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-goto-next-error () + "Go to the next previously detected error. +In general FLYSPELL-GOTO-NEXT-ERROR must be used after +FLYSPELL-BUFFER." + (interactive) + (let ((pos (point)) + (max (point-max))) + (if (and (eq (current-buffer) flyspell-old-buffer-error) + (eq pos flyspell-old-pos-error)) + (progn + (if (= flyspell-old-pos-error max) + ;; goto beginning of buffer + (progn + (message "Restarting from beginning of buffer") + (goto-char (point-min))) + (forward-word 1)) + (setq pos (point)))) + ;; seek the next error + (while (and (< pos max) + (let ((ovs (overlays-at pos)) + (r '())) + (while (and (not r) (consp ovs)) + (if (flyspell-overlay-p (car ovs)) + (setq r t) + (setq ovs (cdr ovs)))) + (not r))) + (setq pos (1+ pos))) + ;; save the current location for next invocation + (setq flyspell-old-pos-error pos) + (setq flyspell-old-buffer-error (current-buffer)) + (goto-char pos) + (if (= pos max) + (message "No more miss-spelled word!")))) + +;*---------------------------------------------------------------------*/ +;* flyspell-overlay-p ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-overlay-p (o) + "A predicate that return true iff O is an overlay used by flyspell." + (and (overlayp o) (overlay-get o 'flyspell-overlay))) + +;*---------------------------------------------------------------------*/ +;* flyspell-delete-region-overlays ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-delete-region-overlays (beg end) + "Delete overlays used by flyspell in a given region." + (let ((l (overlays-in beg end))) + (while (consp l) + (progn + (if (flyspell-overlay-p (car l)) + (delete-overlay (car l))) + (setq l (cdr l)))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-delete-all-overlays ... */ +;* ------------------------------------------------------------- */ +;* Remove all the overlays introduced by flyspell. */ +;*---------------------------------------------------------------------*/ +(defun flyspell-delete-all-overlays () + "Delete all the overlays used by flyspell." + (flyspell-delete-region-overlays (point-min) (point-max))) + +;*---------------------------------------------------------------------*/ +;* flyspell-unhighlight-at ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-unhighlight-at (pos) + "Remove the flyspell overlay that are located at POS." + (if flyspell-persistent-highlight + (let ((overlays (overlays-at pos))) + (while (consp overlays) + (if (flyspell-overlay-p (car overlays)) + (delete-overlay (car overlays))) + (setq overlays (cdr overlays)))) + (if (flyspell-overlay-p flyspell-overlay) + (delete-overlay flyspell-overlay)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-properties-at-p ... */ +;* ------------------------------------------------------------- */ +;* Is there an highlight properties at position pos? */ +;*---------------------------------------------------------------------*/ +(defun flyspell-properties-at-p (pos) + "Return t if there is a text property at POS, not counting `local-map'. +If variable `flyspell-highlight-properties' is set to nil, +text with properties are not checked. This function is used to discover +if the character at POS has any other property." + (let ((prop (text-properties-at pos)) + (keep t)) + (while (and keep (consp prop)) + (if (and (eq (car prop) 'local-map) (consp (cdr prop))) + (setq prop (cdr (cdr prop))) + (setq keep nil))) + (consp prop))) + +;*---------------------------------------------------------------------*/ +;* make-flyspell-overlay ... */ +;*---------------------------------------------------------------------*/ +(defun make-flyspell-overlay (beg end face mouse-face) + "Allocate an overlay to highlight an incorrect word. +BEG and END specify the range in the buffer of that word. +FACE and MOUSE-FACE specify the `face' and `mouse-face' properties +for the overlay." + (let ((flyspell-overlay (make-overlay beg end nil t nil))) + (overlay-put flyspell-overlay 'face face) + (overlay-put flyspell-overlay 'mouse-face mouse-face) + (overlay-put flyspell-overlay 'flyspell-overlay t) + (overlay-put flyspell-overlay 'evaporate t) + (overlay-put flyspell-overlay 'help-echo "mouse-2: correct word at point") + (if flyspell-use-local-map + (overlay-put flyspell-overlay + flyspell-overlay-keymap-property-name + flyspell-mouse-map)) + (when (eq face 'flyspell-incorrect-face) + (and (stringp flyspell-before-incorrect-word-string) + (overlay-put flyspell-overlay 'before-string + flyspell-before-incorrect-word-string)) + (and (stringp flyspell-after-incorrect-word-string) + (overlay-put flyspell-overlay 'after-string + flyspell-after-incorrect-word-string))) + flyspell-overlay)) + +;*---------------------------------------------------------------------*/ +;* flyspell-highlight-incorrect-region ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-highlight-incorrect-region (beg end poss) + "Set up an overlay on a misspelled word, in the buffer from BEG to END." + (unless (run-hook-with-args-until-success + 'flyspell-incorrect-hook beg end poss) + (if (or flyspell-highlight-properties (not (flyspell-properties-at-p beg))) + (progn + ;; we cleanup all the overlay that are in the region, not + ;; beginning at the word start position + (if (< (1+ beg) end) + (let ((os (overlays-in (1+ beg) end))) + (while (consp os) + (if (flyspell-overlay-p (car os)) + (delete-overlay (car os))) + (setq os (cdr os))))) + ;; we cleanup current overlay at the same position + (if (and (not flyspell-persistent-highlight) + (overlayp flyspell-overlay)) + (delete-overlay flyspell-overlay) + (let ((os (overlays-at beg))) + (while (consp os) + (if (flyspell-overlay-p (car os)) + (delete-overlay (car os))) + (setq os (cdr os))))) + ;; now we can use a new overlay + (setq flyspell-overlay + (make-flyspell-overlay beg end + 'flyspell-incorrect-face + 'highlight)))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-highlight-duplicate-region ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-highlight-duplicate-region (beg end) + "Set up an overlay on a duplicated word, in the buffer from BEG to END." + (if (or flyspell-highlight-properties (not (flyspell-properties-at-p beg))) + (progn + ;; we cleanup current overlay at the same position + (if (and (not flyspell-persistent-highlight) + (overlayp flyspell-overlay)) + (delete-overlay flyspell-overlay) + (let ((overlays (overlays-at beg))) + (while (consp overlays) + (if (flyspell-overlay-p (car overlays)) + (delete-overlay (car overlays))) + (setq overlays (cdr overlays))))) + ;; now we can use a new overlay + (setq flyspell-overlay + (make-flyspell-overlay beg end + 'flyspell-duplicate-face + 'highlight))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-auto-correct-cache ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-auto-correct-pos nil) +(defvar flyspell-auto-correct-region nil) +(defvar flyspell-auto-correct-ring nil) +(defvar flyspell-auto-correct-word nil) +(make-variable-buffer-local 'flyspell-auto-correct-pos) +(make-variable-buffer-local 'flyspell-auto-correct-region) +(make-variable-buffer-local 'flyspell-auto-correct-ring) +(make-variable-buffer-local 'flyspell-auto-correct-word) + +;*---------------------------------------------------------------------*/ +;* flyspell-check-previous-highlighted-word ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-check-previous-highlighted-word (&optional arg) + "Correct the closer misspelled word. +This function scans a mis-spelled word before the cursor. If it finds one +it proposes replacement for that word. With prefix arg, count that many +misspelled words backwards." + (interactive) + (let ((pos1 (point)) + (pos (point)) + (arg (if (or (not (numberp arg)) (< arg 1)) 1 arg)) + ov ovs) + (if (catch 'exit + (while (and (setq pos (previous-overlay-change pos)) + (not (= pos pos1))) + (setq pos1 pos) + (if (> pos (point-min)) + (progn + (setq ovs (overlays-at (1- pos))) + (while (consp ovs) + (setq ov (car ovs)) + (setq ovs (cdr ovs)) + (if (and (overlay-get ov 'flyspell-overlay) + (= 0 (setq arg (1- arg)))) + (throw 'exit t))))))) + (save-excursion + (goto-char pos) + (ispell-word)) + (error "No word to correct before point")))) + +;*---------------------------------------------------------------------*/ +;* flyspell-display-next-corrections ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-display-next-corrections (corrections) + (let ((string "Corrections:") + (l corrections) + (pos '())) + (while (< (length string) 80) + (if (equal (car l) flyspell-auto-correct-word) + (setq pos (cons (+ 1 (length string)) pos))) + (setq string (concat string " " (car l))) + (setq l (cdr l))) + (while (consp pos) + (let ((num (car pos))) + (put-text-property num + (+ num (length flyspell-auto-correct-word)) + 'face + 'flyspell-incorrect-face + string)) + (setq pos (cdr pos))) + (if (fboundp 'display-message) + (display-message 'no-log string) + (message string)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-abbrev-table ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-abbrev-table () + (if flyspell-use-global-abbrev-table-p + global-abbrev-table + local-abbrev-table)) + +;*---------------------------------------------------------------------*/ +;* flyspell-define-abbrev ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-define-abbrev (name expansion) + (let ((table (flyspell-abbrev-table))) + (when table + (define-abbrev table name expansion)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-auto-correct-word ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-auto-correct-word () + "Correct the current word. +This command proposes various successive corrections for the current word." + (interactive) + (let ((pos (point)) + (old-max (point-max))) + ;; use the correct dictionary + (flyspell-accept-buffer-local-defs) + (if (and (eq flyspell-auto-correct-pos pos) + (consp flyspell-auto-correct-region)) + ;; we have already been using the function at the same location + (let* ((start (car flyspell-auto-correct-region)) + (len (cdr flyspell-auto-correct-region))) + (flyspell-unhighlight-at start) + (delete-region start (+ start len)) + (setq flyspell-auto-correct-ring (cdr flyspell-auto-correct-ring)) + (let* ((word (car flyspell-auto-correct-ring)) + (len (length word))) + (rplacd flyspell-auto-correct-region len) + (goto-char start) + (if flyspell-abbrev-p + (if (flyspell-already-abbrevp (flyspell-abbrev-table) + flyspell-auto-correct-word) + (flyspell-change-abbrev (flyspell-abbrev-table) + flyspell-auto-correct-word + word) + (flyspell-define-abbrev flyspell-auto-correct-word word))) + (funcall flyspell-insert-function word) + (flyspell-word) + (flyspell-display-next-corrections flyspell-auto-correct-ring)) + (flyspell-ajust-cursor-point pos (point) old-max) + (setq flyspell-auto-correct-pos (point))) + ;; fetch the word to be checked + (let ((word (flyspell-get-word nil))) + (setq flyspell-auto-correct-region nil) + (if (consp word) + (let ((start (car (cdr word))) + (end (car (cdr (cdr word)))) + (word (car word)) + poss) + (setq flyspell-auto-correct-word word) + ;; now check spelling of word. + (process-send-string ispell-process "%\n") ;put in verbose mode + (process-send-string ispell-process (concat "^" word "\n")) + ;; wait until ispell has processed word + (while (progn + (accept-process-output ispell-process) + (not (string= "" (car ispell-filter))))) + (setq ispell-filter (cdr ispell-filter)) + (if (consp ispell-filter) + (setq poss (ispell-parse-output (car ispell-filter)))) + (cond + ((or (eq poss t) (stringp poss)) + ;; don't correct word + t) + ((null poss) + ;; ispell error + (error "Ispell: error in Ispell process")) + (t + ;; the word is incorrect, we have to propose a replacement + (let ((replacements (if flyspell-sort-corrections + (sort (car (cdr (cdr poss))) 'string<) + (car (cdr (cdr poss)))))) + (if (consp replacements) + (progn + (let ((replace (car replacements))) + (let ((new-word replace)) + (if (not (equal new-word (car poss))) + (progn + ;; the save the current replacements + (setq flyspell-auto-correct-region + (cons start (length new-word))) + (let ((l replacements)) + (while (consp (cdr l)) + (setq l (cdr l))) + (rplacd l (cons (car poss) replacements))) + (setq flyspell-auto-correct-ring + replacements) + (flyspell-unhighlight-at start) + (delete-region start end) + (funcall flyspell-insert-function new-word) + (if flyspell-abbrev-p + (if (flyspell-already-abbrevp + (flyspell-abbrev-table) word) + (flyspell-change-abbrev + (flyspell-abbrev-table) + word + new-word) + (flyspell-define-abbrev word + new-word))) + (flyspell-word) + (flyspell-display-next-corrections + (cons new-word flyspell-auto-correct-ring)) + (flyspell-ajust-cursor-point pos + (point) + old-max)))))))))) + (ispell-pdict-save t))) + (setq flyspell-auto-correct-pos (point)))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-auto-correct-previous-pos ... */ +;*---------------------------------------------------------------------*/ +(defvar flyspell-auto-correct-previous-pos nil + "Holds the start of the first incorrect word before point.") + +;*---------------------------------------------------------------------*/ +;* flyspell-auto-correct-previous-hook ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-auto-correct-previous-hook () + "Hook to track successive calls to `flyspell-auto-correct-previous-word'. +Sets flyspell-auto-correct-previous-pos to nil" + (interactive) + (remove-hook 'pre-command-hook (function flyspell-auto-correct-previous-hook) t) + (unless (eq this-command (function flyspell-auto-correct-previous-word)) + (setq flyspell-auto-correct-previous-pos nil))) + +;*---------------------------------------------------------------------*/ +;* flyspell-auto-correct-previous-word ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-auto-correct-previous-word (position) + "*Auto correct the first mispelled word that occurs before point." + (interactive "d") + + (add-hook 'pre-command-hook + (function flyspell-auto-correct-previous-hook) t t) + + (save-excursion + (unless flyspell-auto-correct-previous-pos + ;; only reset if a new overlay exists + (setq flyspell-auto-correct-previous-pos nil) + + (let ((overlay-list (overlays-in (point-min) position)) + (new-overlay 'dummy-value)) + + ;; search for previous (new) flyspell overlay + (while (and new-overlay + (or (not (flyspell-overlay-p new-overlay)) + ;; check if its face has changed + (not (eq (get-char-property + (overlay-start new-overlay) 'face) + 'flyspell-incorrect-face)))) + (setq new-overlay (car-safe overlay-list)) + (setq overlay-list (cdr-safe overlay-list))) + + ;; if nothing new exits new-overlay should be nil + (if new-overlay;; the length of the word may change so go to the start + (setq flyspell-auto-correct-previous-pos + (overlay-start new-overlay))))) + + (when flyspell-auto-correct-previous-pos + (save-excursion + (goto-char flyspell-auto-correct-previous-pos) + (let ((ispell-following-word t));; point is at start + (if (numberp flyspell-auto-correct-previous-pos) + (goto-char flyspell-auto-correct-previous-pos)) + (flyspell-auto-correct-word)) + ;; the point may have moved so reset this + (setq flyspell-auto-correct-previous-pos (point)))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-correct-word ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-correct-word (event) + "Pop up a menu of possible corrections for a misspelled word. +The word checked is the word at the mouse position." + (interactive "e") + ;; use the correct dictionary + (flyspell-accept-buffer-local-defs) + ;; retain cursor location (I don't know why but save-excursion here fails). + (let ((save (point))) + (mouse-set-point event) + (let ((cursor-location (point)) + (word (flyspell-get-word nil)) + (case-fold-search nil)) + (if (consp word) + (let ((start (car (cdr word))) + (end (car (cdr (cdr word)))) + (word (car word)) + poss replace) + ;; now check spelling of word. + (process-send-string ispell-process "%\n") ;put in verbose mode + (process-send-string ispell-process (concat "^" word "\n")) + ;; wait until ispell has processed word + (while (progn + (accept-process-output ispell-process) + (not (string= "" (car ispell-filter))))) + (setq ispell-filter (cdr ispell-filter)) + (if (consp ispell-filter) + (setq poss (ispell-parse-output (car ispell-filter)))) + (cond + ((or (eq poss t) (stringp poss)) + ;; don't correct word + t) + ((null poss) + ;; ispell error + (error "Ispell: error in Ispell process")) + ((string-match "GNU" (emacs-version)) + ;; the word is incorrect, we have to propose a replacement + (setq replace (flyspell-emacs-popup event poss word)) + (cond ((eq replace 'ignore) + (goto-char save) + nil) + ((eq replace 'save) + (goto-char save) + (process-send-string ispell-process + (concat "*" word "\n")) + (flyspell-unhighlight-at cursor-location) + (setq ispell-pdict-modified-p '(t))) + ((or (eq replace 'buffer) (eq replace 'session)) + (process-send-string ispell-process + (concat "@" word "\n")) + (if (null ispell-pdict-modified-p) + (setq ispell-pdict-modified-p + (list ispell-pdict-modified-p))) + (flyspell-unhighlight-at cursor-location) + (goto-char save) + (if (eq replace 'buffer) + (ispell-add-per-file-word-list word))) + (replace + (flyspell-unhighlight-at cursor-location) + (let ((new-word (if (atom replace) + replace + (car replace))) + (cursor-location + (+ (- (length word) (- end start)) + cursor-location))) + (if (not (equal new-word (car poss))) + (let ((old-max (point-max))) + (delete-region start end) + (funcall flyspell-insert-function new-word) + (if flyspell-abbrev-p + (flyspell-define-abbrev word new-word)) + (flyspell-ajust-cursor-point save + cursor-location + old-max))))) + (t + (goto-char save) + nil))) + ((eq flyspell-emacs 'xemacs) + (flyspell-xemacs-popup + event poss word cursor-location start end save) + (goto-char save))) + (ispell-pdict-save t)))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-xemacs-correct ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-xemacs-correct (replace poss word cursor-location start end save) + "The xemacs popup menu callback." + (cond ((eq replace 'ignore) + nil) + ((eq replace 'save) + (process-send-string ispell-process (concat "*" word "\n")) + (process-send-string ispell-process "#\n") + (flyspell-unhighlight-at cursor-location) + (setq ispell-pdict-modified-p '(t))) + ((or (eq replace 'buffer) (eq replace 'session)) + (process-send-string ispell-process (concat "@" word "\n")) + (flyspell-unhighlight-at cursor-location) + (if (null ispell-pdict-modified-p) + (setq ispell-pdict-modified-p + (list ispell-pdict-modified-p))) + (if (eq replace 'buffer) + (ispell-add-per-file-word-list word))) + (replace + (let ((old-max (point-max)) + (new-word (if (atom replace) + replace + (car replace))) + (cursor-location (+ (- (length word) (- end start)) + cursor-location))) + (if (not (equal new-word (car poss))) + (progn + (delete-region start end) + (goto-char start) + (funcall flyspell-insert-function new-word) + (if flyspell-abbrev-p + (flyspell-define-abbrev word new-word)))) + (flyspell-ajust-cursor-point save cursor-location old-max))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-ajust-cursor-point ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-ajust-cursor-point (save cursor-location old-max) + (if (>= save cursor-location) + (let ((new-pos (+ save (- (point-max) old-max)))) + (goto-char (cond + ((< new-pos (point-min)) + (point-min)) + ((> new-pos (point-max)) + (point-max)) + (t new-pos)))) + (goto-char save))) + +;*---------------------------------------------------------------------*/ +;* flyspell-emacs-popup ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-emacs-popup (event poss word) + "The Emacs popup menu." + (if (not event) + (let* ((mouse-pos (mouse-position)) + (mouse-pos (if (nth 1 mouse-pos) + mouse-pos + (set-mouse-position (car mouse-pos) + (/ (frame-width) 2) 2) + (unfocus-frame) + (mouse-position)))) + (setq event (list (list (car (cdr mouse-pos)) + (1+ (cdr (cdr mouse-pos)))) + (car mouse-pos))))) + (let* ((corrects (if flyspell-sort-corrections + (sort (car (cdr (cdr poss))) 'string<) + (car (cdr (cdr poss))))) + (cor-menu (if (consp corrects) + (mapcar (lambda (correct) + (list correct correct)) + corrects) + '())) + (affix (car (cdr (cdr (cdr poss))))) + (base-menu (let ((save (if (consp affix) + (list + (list (concat "Save affix: " (car affix)) + 'save) + '("Accept (session)" session) + '("Accept (buffer)" buffer)) + '(("Save word" save) + ("Accept (session)" session) + ("Accept (buffer)" buffer))))) + (if (consp cor-menu) + (append cor-menu (cons "" save)) + save))) + (menu (cons "flyspell correction menu" base-menu))) + (car (x-popup-menu event + (list (format "%s [%s]" word (or ispell-local-dictionary + ispell-dictionary)) + menu))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-xemacs-popup ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-xemacs-popup (event poss word cursor-location start end save) + "The XEmacs popup menu." + (let* ((corrects (if flyspell-sort-corrections + (sort (car (cdr (cdr poss))) 'string<) + (car (cdr (cdr poss))))) + (cor-menu (if (consp corrects) + (mapcar (lambda (correct) + (vector correct + (list 'flyspell-xemacs-correct + correct + (list 'quote poss) + word + cursor-location + start + end + save) + t)) + corrects) + '())) + (affix (car (cdr (cdr (cdr poss))))) + (menu (let ((save (if (consp affix) + (vector + (concat "Save affix: " (car affix)) + (list 'flyspell-xemacs-correct + ''save + (list 'quote poss) + word + cursor-location + start + end + save) + t) + (vector + "Save word" + (list 'flyspell-xemacs-correct + ''save + (list 'quote poss) + word + cursor-location + start + end + save) + t))) + (session (vector "Accept (session)" + (list 'flyspell-xemacs-correct + ''session + (list 'quote poss) + word + cursor-location + start + end + save) + t)) + (buffer (vector "Accept (buffer)" + (list 'flyspell-xemacs-correct + ''buffer + (list 'quote poss) + word + cursor-location + start + end + save) + t))) + (if (consp cor-menu) + (append cor-menu (list "-" save session buffer)) + (list save session buffer))))) + (popup-menu (cons (format "%s [%s]" word (or ispell-local-dictionary + ispell-dictionary)) + menu)))) + +;*---------------------------------------------------------------------*/ +;* Some example functions for real autocorrecting */ +;*---------------------------------------------------------------------*/ +(defun flyspell-maybe-correct-transposition (beg end poss) + "Check replacements for transposed characters. + +If the text between BEG and END is equal to a correction suggested by +Ispell, after transposing two adjacent characters, correct the text, +and return t. + +The third arg POSS is either the symbol 'doublon' or a list of +possible corrections as returned by 'ispell-parse-output'. + +This function is meant to be added to 'flyspell-incorrect-hook'." + (when (consp poss) + (catch 'done + (save-excursion + (goto-char (1+ beg)) + (while (< (point) end) + (transpose-chars 1) + (when (member (buffer-substring beg end) (car (cdr (cdr poss)))) + (throw 'done t)) + (transpose-chars -1) + (forward-char)) + nil)))) + +(defun flyspell-maybe-correct-doubling (beg end poss) + "Check replacements for doubled characters. + +If the text between BEG and END is equal to a correction suggested by +Ispell, after removing a pair of doubled characters, correct the text, +and return t. + +The third arg POSS is either the symbol 'doublon' or a list of +possible corrections as returned by 'ispell-parse-output'. + +This function is meant to be added to 'flyspell-incorrect-hook'." + (when (consp poss) + (catch 'done + (save-excursion + (let ((last (char-after beg)) + this) + (goto-char (1+ beg)) + (while (< (point) end) + (setq this (char-after)) + (if (not (char-equal this last)) + (forward-char) + (delete-char 1) + (when (member (buffer-substring beg (1- end)) (car (cdr (cdr poss)))) + (throw 'done t)) + ;; undo + (insert-char this 1)) + (setq last this)) + nil))))) + +;*---------------------------------------------------------------------*/ +;* flyspell-already-abbrevp ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-already-abbrevp (table word) + (let ((sym (abbrev-symbol word table))) + (and sym (symbolp sym)))) + +;*---------------------------------------------------------------------*/ +;* flyspell-change-abbrev ... */ +;*---------------------------------------------------------------------*/ +(defun flyspell-change-abbrev (table old new) + (set (abbrev-symbol old table) new)) + +;*---------------------------------------------------------------------*/ +;* flyspell-auto-correct-previous-word advice ... */ +;*---------------------------------------------------------------------*/ +(defadvice flyspell-auto-correct-previous-word + (around easymacs-flyspell-auto-correct) + "Correct current word if misspelled, else previous + misspelling. Protect against accidentally changing a word + that cannot be seen, because it is somewhere off the screen." + (let ((top) (bot)) + (save-excursion + (move-to-window-line 0) + (setq top (point)) + (move-to-window-line -1) + (setq bot (point))) + (save-restriction + (narrow-to-region top bot) + (save-excursion + (re-search-forward "\\s \\|\\'" nil t) + (overlay-recenter (point)) + ad-do-it)))) + +(ad-activate 'flyspell-auto-correct-previous-word) + +(provide 'flyspell) +;;; flyspell.el ends here +;;; </pre> diff --git a/emacs/gambit.el b/emacs/gambit.el new file mode 100644 index 0000000..404d160 --- /dev/null +++ b/emacs/gambit.el @@ -0,0 +1,649 @@ +;;; -*- Mode:Emacs-Lisp -*- +;;; gambit.el --- Run Gambit in an [X]Emacs buffer + +;; Copyright (c) 1997-2004 Marc Feeley & Michael Sperber + +;; Authors: Marc Feeley <feeley@iro.umontreal.ca> +;; Mike Sperber <sperber@informatik.uni-tuebingen.de> +;; Keywords: processes, lisp + +;; To use this package, make sure this file is accessible from your +;; load-path and that the following lines are in your ".emacs" file: +;; +;; (autoload 'gambit-inferior-mode "gambit" "Hook Gambit mode into cmuscheme.") +;; (autoload 'gambit-mode "gambit" "Hook Gambit mode into scheme.") +;; (add-hook 'inferior-scheme-mode-hook (function gambit-inferior-mode)) +;; (add-hook 'scheme-mode-hook (function gambit-mode)) +;; (setq scheme-program-name "gsi -:t") +;; +;; Alternatively, if you don't mind always loading this package, +;; you can simply add this line to your ".emacs" file: +;; +;; (require 'gambit) +;; +;; You can then start Gambit with "M-x run-scheme". +;; +;; When Gambit signals an error, Emacs will intercept the location +;; information in the error message and automatically open a buffer +;; highlighting the error. +;; +;; The continuation of the error can be inspected with the "C-c [" +;; (crawl towards older frames) and "C-c ]" (crawl towards newer +;; frames). For each new frame visited, Emacs will highlight the +;; expression associated with the frame. +;; +;; "C-c c", "C-c s" and "C-c l" can be used to send the commands +;; ",c", ",s" and ",l" respectively to Gambit. This is convenient for +;; single-stepping a program. +;; +;; "C-c _" can be used to delete the last popup window that was +;; created to highlight a Scheme expression. + +;;;---------------------------------------------------------------------------- + +;; User overridable parameters. + +(defvar scheme-program-name "gsi -:d-") + +(defvar gambit-repl-command-prefix "\C-c" + "Emacs keybinding prefix for Gambit REPL's commands.") + +(defvar gambit-highlight-color "gold" + "Color of the overlay for highlighting Scheme expressions.") + +(defvar gambit-highlight-face + (let ((face 'gambit-highlight-face)) + (condition-case nil + (progn + (make-face face) + (if (x-display-color-p) + (set-face-background face gambit-highlight-color) + (progn + ;(make-face-bold face) + (set-face-underline-p face t)))) + (error (setq face nil))) + face) + "Face of overlay for highlighting Scheme expressions.") + +(defvar gambit-new-window-height 6 + "Height of a window opened to highlight a Scheme expression.") + +(defvar gambit-move-to-highlighted (not gambit-highlight-face) + "Flag to move to window opened to highlight a Scheme expression.") + +;;;---------------------------------------------------------------------------- + +;; These must be loaded first because we redefine some of the +;; functions they contain. + +(require 'scheme) +(require 'cmuscheme) + +;;;---------------------------------------------------------------------------- + +(defun gambit-indent-function (indent-point state) + (let ((normal-indent (current-column))) + (goto-char (1+ (elt state 1))) + (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t) + (if (and (elt state 2) + (not (looking-at "\\sw\\|\\s_"))) + ;; car of form doesn't seem to be a a symbol + (progn + (if (not (> (save-excursion (forward-line 1) (point)) + calculate-lisp-indent-last-sexp)) + (progn (goto-char calculate-lisp-indent-last-sexp) + (beginning-of-line) + (parse-partial-sexp (point) + calculate-lisp-indent-last-sexp 0 t))) + ;; Indent under the list or under the first sexp on the same + ;; line as calculate-lisp-indent-last-sexp. Note that first + ;; thing on that line has to be complete sexp since we are + ;; inside the innermost containing sexp. + (backward-prefix-chars) + (current-column)) + (let ((function (buffer-substring (point) + (progn (forward-sexp 1) (point)))) + method) + (setq method (or (gambit-indent-method function) + (get (intern-soft function) 'scheme-indent-function) + (get (intern-soft function) 'scheme-indent-hook))) + (cond ((or (eq method 'defun) + (and (null method) + (> (length function) 3) + (string-match "\\`def" function))) + (lisp-indent-defform state indent-point)) + ((integerp method) + (lisp-indent-specform method state + indent-point normal-indent)) + (method + (funcall method state indent-point normal-indent))))))) + +(defun gambit-indent-method (function) + (let ((method nil) + (alist gambit-indent-regexp-alist)) + (while (and (not method) (not (null alist))) + (let* ((regexp (car alist)) + (x (string-match (car regexp) function))) + (if x + (setq method (cdr regexp))) + (setq alist (cdr alist)))) + method)) + +(set lisp-indent-function 'gambit-indent-function) + +(defvar gambit-indent-regexp-alist + '( + ("^declare$" . defun) + ("^##declare$" . defun) + ("^##define" . defun) + ("^macro-check" . defun) + ("^macro-force-vars$" . defun) + ("^macro-number-dispatch$" . defun) + )) + +;;;---------------------------------------------------------------------------- + +;; Portable functions for FSF Emacs and Xemacs. + +(defun window-top-edge (window) + (if (fboundp 'window-edges) + (car (cdr (window-edges window))) + (car (cdr (window-pixel-edges window))))) + +;; Xemacs calls its overlays "extents", so we have to use them to emulate +;; overlays on Xemacs. Some versions of Xemacs have the portability package +;; "overlays.el" for this, so we could simply do: +;; +;; (condition-case nil ; load "overlay.el" if we have it +;; (require 'overlay) +;; (error nil)) +;; +;; Unfortunately some versions of Xemacs don't have this package so +;; we explicitly define an interface to extents. + +(if (not (fboundp 'make-overlay)) + (defun make-overlay (start end) + (make-extent start end))) + +(if (not (fboundp 'overlay-put)) + (defun overlay-put (overlay prop val) + (set-extent-property overlay prop val))) + +(if (not (fboundp 'move-overlay)) + (defun move-overlay (overlay start end buffer) + (set-extent-endpoints overlay start end buffer))) + +;;;---------------------------------------------------------------------------- + +;; Redefine the function scheme-send-region from `cmuscheme' so +;; that we can keep track of all text sent to Gambit's stdin. + +(defun scheme-send-region (start end) + "Send the current region to the inferior Scheme process." + (interactive "r") + (scheme-send-string (buffer-substring start end))) + +(defun scheme-send-string (str) + "Send a string to the inferior Scheme process." + (let* ((clean-str (gambit-string-terminate-with-newline str)) + (proc (scheme-proc)) + (pmark (process-mark proc)) + (buffer (get-buffer scheme-buffer)) + (old-buffer (current-buffer))) + (set-buffer buffer) + (goto-char pmark) + (set-marker comint-last-input-start (point)) + (insert clean-str) + (set-marker pmark (point)) + (gambit-input-sender proc clean-str) + (set-buffer old-buffer))) + +(defun gambit-input-sender (proc str) + (let ((clean-str (gambit-string-terminate-with-newline str))) + (gambit-register-input clean-str) + (gambit-make-read-only (current-buffer) (point-max)) + (gambit-unhighlight) + (comint-send-string proc clean-str))) + +(defun gambit-register-input (str) + (let ((marker (make-marker))) + (set-marker marker comint-last-input-start) + (setq gambit-input-line-marker-alist + (cons (cons gambit-input-line-count + marker) + gambit-input-line-marker-alist)) + (setq gambit-input-line-count + (+ gambit-input-line-count + (gambit-string-count-lines str))))) + +(defun gambit-make-read-only (buffer end) + ' ; disable read-only interaction, cause it doesn't work! + (progn + (put-text-property 1 end 'front-sticky '(read-only) buffer) + (put-text-property 1 end 'rear-nonsticky '(read-only) buffer) + (put-text-property 1 end 'read-only t buffer))) + +;;;---------------------------------------------------------------------------- + +(defun gambit-load-file (file-name) + "Load a Scheme file FILE-NAME into the inferior Scheme process." + (interactive (comint-get-source "Load Scheme file: " scheme-prev-l/c-dir/file + scheme-source-modes t)) ; T because LOAD + ; needs an exact name + (comint-check-source file-name) ; Check to see if buffer needs saved. + (setq scheme-prev-l/c-dir/file (cons (file-name-directory file-name) + (file-name-nondirectory file-name))) + (scheme-send-string (concat "(load \"" file-name "\"\)\n"))) + +(defun gambit-compile-file (file-name) + "Compile a Scheme file FILE-NAME in the inferior Scheme process." + (interactive (comint-get-source "Compile Scheme file: " + scheme-prev-l/c-dir/file + scheme-source-modes + nil)) ; NIL because COMPILE doesn't + ; need an exact name. + (comint-check-source file-name) ; Check to see if buffer needs saved. + (setq scheme-prev-l/c-dir/file (cons (file-name-directory file-name) + (file-name-nondirectory file-name))) + (scheme-send-string (concat "(compile-file \"" file-name "\"\)\n"))) + +;;;---------------------------------------------------------------------------- + +;; Buffer local variables of the Gambit inferior process(es). + +(defvar gambit-input-line-count nil + "Line number as seen by the Gambit process.") + +(defvar gambit-input-line-marker-alist nil + "Alist of line numbers of input blocks and markers.") + +(defvar gambit-last-output-marker nil + "Points to the last character output by the Gambit process.") + +;;;---------------------------------------------------------------------------- + +;; Utilities + +(defun gambit-string-count-lines (str) + "Returns number of complete lines in string." + (let ((n 0) + (start 0)) + (while (string-match "\n" str start) + (setq n (+ n 1)) + (setq start (match-end 0))) + n)) + +(defun gambit-string-terminate-with-newline (str) + "Adds a newline at end of string if it doesn't already have one." + (let ((len (length str))) + (if (or (= len 0) + (not (equal (aref str (- len 1)) ?\n))) + (concat str "\n") + str))) + +;;;---------------------------------------------------------------------------- + +;; Define keys for single stepping and continuation crawling. + +(defun gambit-step-continuation () + (interactive) + (scheme-send-string "#||#,s;")) + +(defun gambit-leap-continuation () + (interactive) + (scheme-send-string "#||#,l;")) + +(defun gambit-continue () + (interactive) + (scheme-send-string "#||#,c;")) + +(defun gambit-environment () + (interactive) + (scheme-send-string "#||#,e;")) + +(defun gambit-backtrace () + (interactive) + (scheme-send-string "#||#,b;")) + +(defun gambit-crawl-backtrace-newer () + (interactive) + (scheme-send-string "#||#,-;")) + +(defun gambit-crawl-backtrace-older () + (interactive) + (scheme-send-string "#||#,+;")) + +(defun gambit-kill-last-popup () + (interactive) + (let ((windows gambit-popups)) + (while (not (null windows)) + (let ((window (car windows))) + (setq windows (cdr windows)) + (if (and window + (window-live-p window)) + (progn + (setq gambit-popups windows) + (setq windows nil) + (delete-window window))))))) + +(defun gambit-add-popup (popup) + (setq gambit-popups + (cons popup (gambit-gc-popups gambit-popups)))) + +(defun gambit-gc-popups (popups) + (cond ((null popups) + '()) + ((window-live-p (car popups)) + (cons (car popups) (gambit-gc-popups (cdr popups)))) + (t + (gambit-gc-popups (cdr popups))))) + +(defvar gambit-popups nil) + +;;;---------------------------------------------------------------------------- + +;; Procedures to intercept and process the location information output +;; by Gambit. + +(defun gambit-output-filter (str) + (let* ((buffer + (current-buffer)) + (output-marker + (process-mark (get-buffer-process buffer))) + (locat + (if (string-match "\n" str) ; match only after end of line is seen + (let* ((end + (save-excursion + (goto-char output-marker) + (beginning-of-line) + (point))) + (start + (save-excursion + (goto-char (+ gambit-last-output-marker 1)) + (beginning-of-line) + (point)))) + (gambit-extract-location + (buffer-substring start end))) + nil))) + (gambit-make-read-only buffer output-marker) + (set-marker gambit-last-output-marker (- output-marker 1)) + (let* ((windows + (gambit-windows-displaying-buffer buffer)) + (initially-selected-window + (selected-window))) + (if (not (null windows)) + (save-excursion + (set-buffer buffer) + (select-window (car windows)) + (goto-char output-marker) + (if (not (pos-visible-in-window-p)) + (recenter -1)) + (select-window initially-selected-window)))) + (if locat + (gambit-highlight-location locat)))) + +(defun gambit-extract-location (str) + (let ((location nil) + (alist gambit-location-regexp-alist)) + (while (and (not location) (not (null alist))) + (let* ((regexp (car alist)) + (x (string-match (car regexp) str))) + (if x + (let* ((pos1 (nth 1 regexp)) + (pos2 (nth 2 regexp)) + (pos3 (nth 3 regexp)) + (name (substring str + (match-beginning pos1) + (match-end pos1))) + (line (substring str + (match-beginning pos2) + (match-end pos2))) + (column (substring str + (match-beginning pos3) + (match-end pos3)))) + (setq location (list (read name) (read line) (read column))))) + (setq alist (cdr alist)))) + location)) + +(defvar gambit-location-regexp-alist + '(("\\(\\\"\\(\\\\\\\\\\|\\\\\"\\|[^\\\"\n]\\)+\\\"\\)@\\([0-9]+\\)\\.\\([0-9]+\\)[^0-9]" 1 3 4) + ("\\((console)\\)@\\([0-9]+\\)\\.\\([0-9]+\\)[^0-9]" 1 2 3) + ("\\((stdin)\\)@\\([0-9]+\\)\\.\\([0-9]+\\)[^0-9]" 1 2 3))) + +(defun gambit-closest-non-following (line alist) + (let ((closest nil)) + (while (not (null alist)) + (let ((x (car alist))) + (if (and (<= (car x) line) + (or (not closest) + (> (car x) (car closest)))) + (setq closest x)) + (setq alist (cdr alist)))) + closest)) + +(defun gambit-highlight-location (locat) + + ; invariant: the current buffer is the Scheme buffer + + (let ((name (car locat)) + (line (car (cdr locat))) + (column (car (cdr (cdr locat))))) + (cond ((or (equal name '(console)) + (equal name '(stdin))) + (let ((closest + (gambit-closest-non-following + line + gambit-input-line-marker-alist))) + (if closest + (let ((n (- line (car closest)))) + (gambit-highlight-expression + (current-buffer) + (save-excursion + (goto-char (cdr closest)) + (if (> n 0) (forward-line n)) + (forward-char (- column 1)) + (point))))))) + ((stringp name) + (let ((buffer (find-file-noselect name))) + (if buffer + (gambit-highlight-expression + buffer + (save-excursion + (set-buffer buffer) + (goto-line line) + (forward-char (- column 1)) + (point))))))))) + +(defun gambit-highlight-expression (location-buffer pos) + +"Highlight the expression at a specific location in a buffer. + +The location buffer is the one that contains the location to +highlight and `pos' points to the first character of the +expression in the buffer. If the location buffer is not visible +then we must display it in a window. We also have to make sure +the highlighted expression is visible, which may require the +window to be scrolled. + +Our approach is simple: if the location buffer is not visible or +it is the Scheme buffer and it is only displayed in the selected +window, then we split one of the windows in 2 and use the bottom +window to display the location buffer. The window chosen is +preferentially the topmost window displaying the Scheme buffer, +otherwise it is the selected window. Before we do the split, we +enlarge the window if it is too small." + + (let* ((location-windows + (gambit-windows-displaying-buffer location-buffer)) + (initially-selected-window + (selected-window))) + + ; "location-windows" is the list of windows containing + ; the location buffer. + + (if (or (null location-windows) + (and (eq location-buffer (get-buffer scheme-buffer)) + (eq initially-selected-window (car location-windows)) + (null (cdr location-windows)))) + + (let* ((scheme-windows + (gambit-windows-displaying-buffer (get-buffer scheme-buffer))) + (window-to-split + (if (null scheme-windows) + initially-selected-window + (car scheme-windows))) + (height + (window-height window-to-split))) + (select-window window-to-split) + (if (< height (* 2 gambit-new-window-height)) + (enlarge-window + (- (* 2 gambit-new-window-height) + height))) + (let ((bottom-window + (split-window + window-to-split + (- (window-height window-to-split) + gambit-new-window-height)))) + (gambit-add-popup bottom-window) + (select-window bottom-window) + (switch-to-buffer location-buffer))) + + (select-window (car (reverse location-windows)))) + + ; Highlight the expression in the location buffer. + + (save-excursion + (set-buffer (window-buffer (selected-window))) + (goto-char pos) + (if (not (pos-visible-in-window-p)) + (recenter (- (/ (window-height) 2) 1))) + (gambit-highlight-region + location-buffer + pos + (progn + (condition-case nil + (forward-sexp) ; we assume this uses the same syntax as Gambit + (error ; if forward-sexp fails with this condition name + (forward-char 1))) + (point))) + (goto-char pos)) + + (if (not (eq initially-selected-window (selected-window))) + (progn + (goto-char pos) + (if (not gambit-move-to-highlighted) + (select-window initially-selected-window)))))) + +(defun gambit-windows-displaying-buffer (buffer) + (let ((windows '())) + (walk-windows (function + (lambda (w) + (if (eq buffer (window-buffer w)) + (setq windows (cons w windows))))) + t + 'visible) + (sort windows + (function + (lambda (w1 w2) + (< (window-top-edge w1) + (window-top-edge w2))))))) + +(defvar gambit-highlight-overlay + (let ((ovl (make-overlay (point-min) (point-min)))) + (overlay-put ovl 'face gambit-highlight-face) + ovl) + "Overlay for highlighting Scheme expressions.") + +(defun gambit-highlight-region (buffer start end) + (if gambit-highlight-overlay + (move-overlay gambit-highlight-overlay start end buffer))) + +(defun gambit-unhighlight () + (gambit-highlight-region (get-buffer scheme-buffer) 1 1)) + +;;;---------------------------------------------------------------------------- + +(defun gambit-install-comment-syntax () + "Configure #| ... |# comments." + ;; XEmacs 19 and beyond use 8-bit modify-syntax-entry flags. + ;; Emacs 19 uses a 1-bit flag. We will have to set up our + ;; syntax tables differently to handle this. + ;; Stolen from CC Mode. + (let ((table (copy-syntax-table)) + entry) + (modify-syntax-entry ?a ". 12345678" table) + (cond + ;; XEmacs 19, and beyond Emacs 19.34 + ((arrayp table) + (setq entry (aref table ?a)) + ;; In Emacs, table entries are cons cells + (if (consp entry) (setq entry (car entry)))) + ;; XEmacs 20 + ((fboundp 'get-char-table) (setq entry (get-char-table ?a table))) + ;; before and including Emacs 19.34 + ((and (fboundp 'char-table-p) + (char-table-p table)) + (setq entry (car (char-table-range table [?a])))) + ;; incompatible + (t (error "Gambit mode is incompatible with this version of Emacs"))) + (if (= (logand (lsh entry -16) 255) 255) + (progn + ;; XEmacs 19 & 20 + (modify-syntax-entry ?# "(#58" scheme-mode-syntax-table) + (modify-syntax-entry ?| ". 67" scheme-mode-syntax-table)) + ;; Emacs 19 & 20 + (modify-syntax-entry ?# "_ 14" scheme-mode-syntax-table) + (modify-syntax-entry ?| "\" 23" scheme-mode-syntax-table)))) + +(defun gambit-extend-mode-map (map) + (define-key map [(f8)] 'gambit-continue) + (define-key map [(f9)] 'gambit-crawl-backtrace-newer) + (define-key map [(f10)] 'gambit-crawl-backtrace-older) + (define-key map [(f11)] 'gambit-step-continuation) + (define-key map [(f12)] 'gambit-leap-continuation) + + (define-key map "\C-c\C-l" 'gambit-load-file) + (define-key map "\C-c\C-k" 'gambit-compile-file) + + (let ((prefix gambit-repl-command-prefix)) + (define-key map (concat prefix "c") 'gambit-continue) + (define-key map (concat prefix "]") 'gambit-crawl-backtrace-newer) + (define-key map (concat prefix "[") 'gambit-crawl-backtrace-older) + (define-key map (concat prefix "s") 'gambit-step-continuation) + (define-key map (concat prefix "l") 'gambit-leap-continuation) + (define-key map (concat prefix "_") 'gambit-kill-last-popup))) + +(defun gambit-inferior-mode () + + (gambit-install-comment-syntax) + (gambit-extend-mode-map inferior-scheme-mode-map) + + (make-local-variable 'gambit-input-line-count) + (setq gambit-input-line-count 1) + + (make-local-variable 'gambit-input-line-marker-alist) + (setq gambit-input-line-marker-alist '()) + + (make-local-variable 'gambit-last-output-marker) + (setq gambit-last-output-marker (make-marker)) + (set-marker gambit-last-output-marker 0) + + (setq comint-input-sender (function gambit-input-sender)) + + (add-hook 'comint-output-filter-functions + (function gambit-output-filter) + t + t)) ; hook is buffer-local + +(defun gambit-mode () + (gambit-install-comment-syntax) + (gambit-extend-mode-map scheme-mode-map)) + +;;(autoload 'gambit-inferior-mode "gambit" "Hook Gambit mode into cmuscheme.") +;;(autoload 'gambit-mode "gambit" "Hook Gambit mode into scheme.") +(add-hook 'inferior-scheme-mode-hook (function gambit-inferior-mode)) +(add-hook 'scheme-mode-hook (function gambit-mode)) + +(provide 'gambit) + +;;;---------------------------------------------------------------------------- diff --git a/emacs/gist.el b/emacs/gist.el new file mode 100644 index 0000000..163e9af --- /dev/null +++ b/emacs/gist.el @@ -0,0 +1,346 @@ +;; gist.el --- Emacs integration for gist.github.com + +;; Author: Christian Neukirchen <purl.org/net/chneukirchen> +;; Maintainer: Chris Wanstrath <chris@ozmm.org> +;; Contributors: +;; Will Farrington <wcfarrington@gmail.com> +;; Michael Ivey +;; Phil Hagelberg +;; Dan McKinley +;; Version: 0.4 +;; Created: 21 Jul 2008 +;; Keywords: gist git github paste pastie pastebin + +;; This file is NOT part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + +;;; Commentary: + +;; Uses your local GitHub config if it can find it. +;; See http://github.com/blog/180-local-github-config + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'xml) + +(defvar github-user nil + "If non-nil, will be used as your GitHub username without checking +git-config(1).") +(defvar github-token nil + "If non-nil, will be used as your GitHub token without checking +git-config(1).") + +(defvar gist-view-gist nil + "If non-nil, automatically use `browse-url' to view gists after they're +posted.") + +(defvar gist-supported-modes-alist '((action-script-mode . "as") + (c-mode . "c") + (c++-mode . "cpp") + (clojure-mode . "clj") + (common-lisp-mode . "lisp") + (css-mode . "css") + (diff-mode . "diff") + (emacs-lisp-mode . "el") + (erlang-mode . "erl") + (haskell-mode . "hs") + (html-mode . "html") + (io-mode . "io") + (java-mode . "java") + (javascript-mode . "js") + (jde-mode . "java") + (js2-mode . "js") + (lua-mode . "lua") + (ocaml-mode . "ml") + (objective-c-mode . "m") + (perl-mode . "pl") + (php-mode . "php") + (python-mode . "py") + (ruby-mode . "rb") + (text-mode . "txt") + (scala-mode . "scala") + (sql-mode . "sql") + (scheme-mode . "scm") + (smalltalk-mode . "st") + (sh-mode . "sh") + (tcl-mode . "tcl") + (tex-mode . "tex") + (xml-mode . "xml"))) + + + +(defun* gist-request (url callback &optional params) + "Makes a request to `url' asynchronously, notifying `callback' when +complete. The github parameters are included in the request. Optionally +accepts additional POST `params' as a list of (key . value) conses." + (github-with-auth-info login token + (let ((url-request-data (gist-make-query-string + `(("login" . ,login) + ("token" . ,token) ,@params))) + (url-max-redirecton 5) + (url-request-method "POST")) + (url-retrieve url callback)))) + +;;;###autoload +(defun gist-region (begin end &optional private &optional callback) + "Post the current region as a new paste at gist.github.com +Copies the URL into the kill ring. + +With a prefix argument, makes a private paste." + (interactive "r\nP") + (let* ((file (or (buffer-file-name) (buffer-name))) + (name (file-name-nondirectory file)) + (ext (or (cdr (assoc major-mode gist-supported-modes-alist)) + (file-name-extension file) + "txt"))) + (gist-request + "http://gist.github.com/gists" + (or callback 'gist-created-callback) + `(,@(if private '(("action_button" . "private"))) + ("file_ext[gistfile1]" . ,(concat "." ext)) + ("file_name[gistfile1]" . ,name) + ("file_contents[gistfile1]" . ,(buffer-substring begin end)))))) + +(defun gist-created-callback (status) + (let ((location (cadr status))) + (message "Paste created: %s" location) + (when gist-view-gist + (browse-url location)) + (kill-new location) + (kill-buffer (current-buffer)))) + +(defun gist-make-query-string (params) + "Returns a query string constructed from PARAMS, which should be +a list with elements of the form (KEY . VALUE). KEY and VALUE +should both be strings." + (mapconcat + (lambda (param) + (concat (url-hexify-string (car param)) "=" + (url-hexify-string (cdr param)))) + params "&")) + +;;;###autoload +(defun gist-region-private (begin end) + "Post the current region as a new private paste at gist.github.com +Copies the URL into the kill ring." + (interactive "r") + (gist-region begin end t)) + +(defun github-config (key) + "Returns a GitHub specific value from the global Git config." + (let ((strip (lambda (string) + (if (> (length string) 0) + (substring string 0 (- (length string) 1))))) + (git (executable-find "git"))) + (funcall strip (shell-command-to-string + (concat git " config --global github." key))))) + +(defun github-set-config (key value) + "Sets a GitHub specific value to the global Git config." + (let ((git (executable-find "git"))) + (shell-command-to-string + (format git " config --global github.%s %s" key value)))) + +(defun github-auth-info () + "Returns the user's GitHub authorization information. +Searches for a GitHub username and token in the global git config, +and returns (USERNAME . TOKEN). If nothing is found, prompts +for the info then sets it to the git config." + (interactive) + + ;; If we've been called within a scope that already has this + ;; defined, don't take the time to get it again. + (if (boundp '*github-auth-info*) + *github-auth-info* + + (let* ((user (or github-user (github-config "user"))) + (token (or github-token (github-config "token")))) + + (when (not user) + (setq user (read-string "GitHub username: ")) + (github-set-config "user" user)) + + (when (not token) + (setq token (read-string "GitHub API token: ")) + (github-set-config "token" token)) + + (cons user token)))) + +(defmacro github-with-auth-info (login token &rest body) + "Binds the github authentication credentials to `login' and `token'. +The credentials are retrieved at most once within the body of this macro." + (declare (indent 2)) + `(let ((*github-auth-info* (github-auth-info))) + (destructuring-bind (,login . ,token) *github-auth-info* + ,@body))) + +;;;###autoload +(defun gist-buffer (&optional private) + "Post the current buffer as a new paste at gist.github.com. +Copies the URL into the kill ring. + +With a prefix argument, makes a private paste." + (interactive "P") + (gist-region (point-min) (point-max) private)) + +;;;###autoload +(defun gist-buffer-private () + "Post the current buffer as a new private paste at gist.github.com. +Copies the URL into the kill ring." + (interactive) + (gist-region-private (point-min) (point-max))) + +;;;###autoload +(defun gist-region-or-buffer (&optional private) + "Post either the current region, or if mark is not set, the current buffer as a new paste at gist.github.com +Copies the URL into the kill ring. + +With a prefix argument, makes a private paste." + (interactive "P") + (condition-case nil + (gist-region (point) (mark) private) + (mark-inactive (gist-buffer private)))) + +;;;###autoload +(defun gist-region-or-buffer-private () + "Post either the current region, or if mark is not set, the current buffer as a new private paste at gist.github.com +Copies the URL into the kill ring." + (interactive) + (condition-case nil + (gist-region-private (point) (mark)) + (mark-inactive (gist-buffer-private)))) + +(defvar gist-fetch-url "http://gist.github.com/%d.txt" + "Raw Gist content URL format") + +;;;###autoload +(defun gist-list () + "Displays a list of all of the current user's gists in a new buffer." + (interactive) + (message "Retrieving list of your gists...") + (github-with-auth-info login token + (gist-request + (format "http://gist.github.com/api/v1/xml/gists/%s" login) + 'gist-lists-retrieved-callback))) + +(defun gist-lists-retrieved-callback (status) + "Called when the list of gists has been retrieved. Parses the result +and displays the list." + (goto-char (point-min)) + (search-forward "<?xml") + (let ((gists (gist-xml-cleanup + (xml-parse-region (match-beginning 0) (point-max))))) + (kill-buffer (current-buffer)) + (with-current-buffer (get-buffer-create "*gists*") + (goto-char (point-min)) + (save-excursion + (kill-region (point-min) (point-max)) + (gist-insert-list-header) + (mapc 'gist-insert-gist-link (xml-node-children (car gists))) + + ;; remove the extra newline at the end + (delete-backward-char 1)) + + ;; skip header + (forward-line) + (toggle-read-only t) + (set-window-buffer nil (current-buffer))))) + +(defun gist-insert-list-header () + "Creates the header line in the gist list buffer." + (save-excursion + (insert " ID Created " + "Visibility Description \n")) + (let ((ov (make-overlay (line-beginning-position) (line-end-position)))) + (overlay-put ov 'face 'header-line)) + (forward-line)) + +(defun gist-insert-gist-link (gist) + "Inserts a button that will open the given gist when pressed." + (let* ((data (gist-parse-gist gist)) + (repo (string-to-number (car data)))) + (mapc '(lambda (x) (insert (format " %s " x))) data) + (make-text-button (line-beginning-position) (line-end-position) + 'repo repo + 'action 'gist-fetch-button + 'face 'default)) + (insert "\n")) + +(defun gist-fetch-button (button) + "Called when a gist button has been pressed. Fetches and displays the gist." + (gist-fetch (button-get button 'repo))) + +(defun gist-parse-gist (gist) + "Returns a list of the gist's attributes for display, given the xml list +for the gist." + (let ((repo (gist-child-text 'repo gist)) + (created-at (gist-child-text 'created-at gist)) + (description (gist-child-text 'description gist)) + (public (if (string= (gist-child-text 'public gist) "true") + "public" + "private"))) + (list repo created-at public description))) + +(defun gist-child-text (sym node) + "Retrieves the text content of a child of a <gist> element." + (let* ((children (xml-node-children node))) + (car (xml-node-children (assq sym children))))) + +(defun gist-xml-cleanup (xml-list) + "Removes empty strings or whitespace nodes from the `xml-list'. +Borrowed from rss.el." + (mapcar 'gist-xml-cleanup-node xml-list)) + +(defun gist-xml-cleanup-node (node) + "Recursively removes whitespace and empty strings from the given xml `node'. +Borrowed from rss.el." + (apply 'list + (xml-node-name node) + (xml-node-attributes node) + (let (new) + (dolist (child (xml-node-children node)) + (if (stringp child) + (or (string-match "\\`[ \t\n]+\\'" child) + (push child new)) + (push (gist-xml-cleanup-node child) new))) + (nreverse new)))) + +;;;###autoload +(defun gist-fetch (id) + "Fetches a Gist and inserts it into a new buffer +If the Gist already exists in a buffer, switches to it" + (interactive "nGist ID: ") + + (let* ((gist-buffer-name (format "*gist %d*" id)) + (gist-buffer (get-buffer gist-buffer-name))) + (if (bufferp gist-buffer) + (switch-to-buffer-other-window gist-buffer) + (progn + (message "Fetching Gist %d..." id) + (setq gist-buffer + (url-retrieve-synchronously (format gist-fetch-url id))) + (with-current-buffer gist-buffer + (rename-buffer gist-buffer-name t) + (goto-char (point-min)) + (search-forward-regexp "\n\n") + (delete-region (point-min) (point)) + (set-buffer-modified-p nil)) + (switch-to-buffer-other-window gist-buffer))))) + +(provide 'gist) +;;; gist.el ends here. \ No newline at end of file diff --git a/emacs/graphviz-dot-mode.el b/emacs/graphviz-dot-mode.el new file mode 100644 index 0000000..ebaa1aa --- /dev/null +++ b/emacs/graphviz-dot-mode.el @@ -0,0 +1,919 @@ +;;; graphviz-dot-mode.el --- Mode for the dot-language used by graphviz (att). + +;; Copyright (C) 2002 - 2005 Pieter Pareit <pieter.pareit@scarlet.be> + +;; 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., 59 Temple Place, Suite 330, Boston, +;; MA 02111-1307 USA + +;; Authors: Pieter Pareit <pieter.pareit@scarlet.be> +;; Rubens Ramos <rubensr AT users.sourceforge.net> +;; Maintainer: Pieter Pareit <pieter.pareit@planetinternet.be> +;; Homepage: http://users.skynet.be/ppareit/projects/graphviz-dot-mode/graphviz-dot-mode.html +;; Created: 28 Oct 2002 +;; Last modified: 24 Feb 2005 +;; Version: 0.3.4 +;; Keywords: mode dot dot-language dotlanguage graphviz graphs att + +;;; Commentary: +;; Use this mode for editing files in the dot-language (www.graphviz.org and +;; http://www.research.att.com/sw/tools/graphviz/). +;; +;; To use graphviz-dot-mode, add +;; (load-file "PATH_TO_FILE/graphviz-dot-mode.el") +;; to your ~/.emacs(.el) or ~/.xemacs/init.el +;; +;; The graphviz-dot-mode will do font locking, indentation, preview of graphs +;; and eases compilation/error location. There is support for both GNU Emacs +;; and XEmacs. +;; +;; Font locking is automatic, indentation uses the same commands as +;; other modes, tab, M-j and C-M-q. Insertion of comments uses the +;; same commands as other modes, M-; . You can compile a file using +;; M-x compile or C-c c, after that M-x next-error will also work. +;; There is support for viewing an generated image with C-c p. + +;;; Todo: +;; * cleanup the mess of graphviz-dot-compilation-parse-errors +;; * electric indentation is fundamentally broken, because +;; {...} are also used for record nodes. You could argue, I suppose, that +;; many diagrams don't need those, but it would be worth having a note (and +;; it makes sense that the default is now for electric indentation to be +;; off). + +;;; History: + +;; Version 0.3.4 bug fixes +;; 24/02/2005: * fixed a bug in graphviz-dot-preview +;; Version 0.3.3 bug fixes +;; 13/02/2005: Reuben Thomas <rrt AT sc3d.org> +;; * add graphviz-dot-indent-width +;; Version 0.3.2 bug fixes +;; 25/03/2004: Rubens Ramos <rubensr AT users.sourceforge.net> +;; * semi-colons and brackets are added when electric +;; behaviour is disabled. +;; * electric characters do not behave electrically inside +;; comments or strings. +;; * default for electric-braces is disabled now (makes more +;; sense I guess). +;; * using read-from-minibuffer instead of read-shell-command +;; for emacs. +;; * Fixed test for easymenu, so that it works on older +;; versions of XEmacs. +;; * Fixed indentation error when trying to indent last brace +;; of an empty graph. +;; * region-active-p does not exist in emacs (21.2 at least), +;; so removed from code +;; * Added uncomment menu option +;; Version 0.3.1 bug fixes +;; 03/03/2004: * backward-word needs argument for older emacs +;; Version 0.3 added features and fixed bugs +;; 10/01/2004: fixed a bug in graphviz-dot-indent-graph +;; 08/01/2004: Rubens Ramos <rubensr AT users.sourceforge.net> +;; * added customization support +;; * Now it works on XEmacs and Emacs +;; * Added support to use an external Viewer +;; * Now things do not break when dot mode is entered +;; when there is no buffer name, but the side effect is +;; that in this case, the compilation command is not +;; correct. +;; * Preview works on XEmacs and emacs. +;; * Electric indentation on newline +;; * Minor changes to indentation +;; * Added keyword completion (but could be A LOT better) +;; * There are still a couple of ugly hacks. Look for 'RR'. +;; Version 0.2 added features +;; 11/11/2002: added preview support. +;; 10/11/2002: indent a graph or subgraph at once with C-M-q. +;; 08/11/2002: relaxed rules for indentation, the may now be extra chars +;; after beginning of graph (comment's for example). +;; Version 0.1.2 bug fixes and naming issues +;; 06/11/2002: renamed dot-font-lock-defaults to dot-font-lock-keywords. +;; added some documentation to dot-colors. +;; provided a much better way to handle my max-specpdl-size +;; problem. +;; added an extra autoload cookie (hope this helps, as I don't +;; yet use autoload myself) +;; Version 0.1.1 bug fixes +;; 06/11/2002: added an missing attribute, for font-locking to work. +;; fixed the regex generating, so that it only recognizes +;; whole words +;; 05/11/2002: there can now be extra white space chars after an '{'. +;; 04/11/2002: Why I use max-specpdl-size is now documented, and old value +;; gets restored. +;; Version 0.1 initial release +;; 02/11/2002: implemented parser for *compilation* of a .dot file. +;; 01/11/2002: implemented compilation of an .dot file. +;; 31/10/2002: added syntax-table to the mode. +;; 30/10/2002: implemented indentation code. +;; 29/10/2002: implemented all of font-lock. +;; 28/10/2002: derived graphviz-dot-mode from fundamental-mode, started +;; implementing font-lock. + +;;; Code: + +(defconst graphviz-dot-mode-version "0.3.3" + "Version of `graphviz-dot-mode.el'.") + +(defgroup graphviz nil + "Major mode for editing Graphviz Dot files" + :group 'tools) + +(defun graphviz-dot-customize () + "Run \\[customize-group] for the `graphviz' group." + (interactive) + (customize-group 'graphviz)) + +(defvar graphviz-dot-mode-abbrev-table nil + "Abbrev table in use in Graphviz Dot mode buffers.") +(define-abbrev-table 'graphviz-dot-mode-abbrev-table ()) + +(defcustom graphviz-dot-dot-program "dot" + "*Location of the dot program. This is used by `compile'." + :type 'string + :group 'graphviz) + +(defcustom graphviz-dot-view-command "doted %s" + "*External program to run on the buffer. You can use `%s' in this string, +and it will be substituted by the buffer name." + :type 'string + :group 'graphviz) + +(defcustom graphviz-dot-view-edit-command nil + "*Whether to allow the user to edit the command to run an external +viewer." + :type 'boolean + :group 'graphviz) + +(defcustom graphviz-dot-save-before-view t + "*If not nil, M-x graphviz-dot-view saves the current buffer before running +the command." + :type 'boolean + :group 'graphviz) + +(defcustom graphviz-dot-auto-indent-on-newline t + "*If not nil, `electric-graphviz-dot-terminate-line' is executed in a line is terminated." + :type 'boolean + :group 'graphviz) + +(defcustom graphviz-dot-indent-width default-tab-width + "*Indentation width in Graphviz Dot mode buffers." + :type 'integer + :group 'graphviz) + +(defcustom graphviz-dot-auto-indent-on-braces nil + "*If not nil, `electric-graphviz-dot-open-brace' and `electric-graphviz-dot-close-brace' are executed when { or } are typed" + :type 'boolean + :group 'graphviz) + +(defcustom graphviz-dot-auto-indent-on-semi t + "*If not nil, `electric-graphviz-dot-semi' is executed when semicolon is typed" + :type 'boolean + :group 'graphviz) + +(defcustom graphviz-dot-preview-extension "png" + "*The extension to use for the compilation and preview commands. The format +for the compilation command is +`dot -T<extension> file.dot > file.<extension>'." + :type 'string + :group 'graphviz) + +(defcustom graphviz-dot-toggle-completions nil + "*Non-nil means that repeated use of \ +\\<graphviz-dot-mode-map>\\[graphviz-dot-complete-word] will toggle the possible +completions in the minibuffer. Normally, when there is more than one possible +completion, a buffer will display all completions." + :type 'boolean + :group 'graphviz) + +(defcustom graphviz-dot-delete-completions nil + "*Non-nil means that the completion buffer is automatically deleted when a +key is pressed." + :type 'boolean + :group 'graphviz) + +(defcustom graphviz-dot-attr-keywords + '("graph" "digraph" "subgraph" "node" "edge" "strict" "rankdir" + "size" "page" "Damping" "Epsilon" "URL" "arrowhead" "arrowsize" + "arrowtail" "bb" "bgcolor" "bottomlabel" "center" "clusterrank" + "color" "comment" "compound" "concentrate" "constraint" "decorate" + "dim" "dir" "distortion" "fillcolor" "fixedsize" "fontcolor" + "fontname" "fontpath" "fontsize" "group" "headURL" "headlabel" + "headport" "height" "label" "labelangle" "labeldistance" "labelfloat" + "labelfontcolor" "labelfontname" "labelfontsize" "labeljust" + "labelloc" "layer" "layers" "len" "lhead" "lp" "ltail" "margin" + "maxiter" "mclimit" "minlen" "model" "nodesep" "normalize" "nslimit" + "nslimit1" "ordering" "orientation" "overlap" "pack" "pagedir" + "pencolor" "peripheries" "pin" "pos" "quantum" "rank" "ranksep" + "ratio" "rects" "regular" "remincross" "rotate" "samehead" "sametail" + "samplepoint" "searchsize" "sep" "shape" "shapefile" "showboxes" + "sides" "skew" "splines" "start" "style" "stylesheet" "tailURL" + "taillabel" "tailport" "toplabel" "vertices" "voro_margin" "weight" + "z") + "*Keywords for attribute names in a graph. This is used by the auto +completion code. The actual completion tables are built when the mode +is loaded, so changes to this are not immediately visible." + :type '(repeat (string :tag "Keyword")) + :group 'graphviz) + +(defcustom graphviz-dot-value-keywords + '("true" "false" "normal" "inv" "dot" "invdot" "odot" "invodot" + "none" "tee" "empty" "invempty" "diamond" "odiamond" "box" "obox" + "open" "crow" "halfopen" "local" "global" "none" "forward" "back" + "both" "none" "BL" "BR" "TL" "TR" "RB" "RT" "LB" "LT" ":n" ":ne" ":e" + ":se" ":s" ":sw" ":w" ":nw" "same" "min" "source" "max" "sink" "LR" + "box" "polygon" "ellipse" "circle" "point" "egg" "triangle" + "plaintext" "diamond" "trapezium" "parallelogram" "house" "hexagon" + "octagon" "doublecircle" "doubleoctagon" "tripleoctagon" "invtriangle" + "invtrapezium" "invhouse" "Mdiamond" "Msquare" "Mcircle" "record" + "Mrecord" "dashed" "dotted" "solid" "invis" "bold" "filled" + "diagonals" "rounded" ) + "*Keywords for attribute values. This is used by the auto completion +code. The actual completion tables are built when the mode is loaded, +so changes to this are not immediately visible." + :type '(repeat (string :tag "Keyword")) + :group 'graphviz) + +;;; Font-locking: +(defvar graphviz-dot-colors-list + '(aliceblue antiquewhite antiquewhite1 antiquewhite2 + antiquewhite3 antiquewhite4 aquamarine aquamarine1 + aquamarine2 aquamarine3 aquamarine4 azure azure1 + azure2 azure3 azure4 beige bisque bisque1 bisque2 + bisque3 bisque4 black blanchedalmond blue blue1 + blue2 blue3 blue4 blueviolet brown brown1 brown2 + brown3 brown4 burlywood burlywood1 burlywood2 + burlywood3 burlywood4 cadetblue cadetblue1 + cadetblue2 cadetblue3 cadetblue4 chartreuse + chartreuse1 chartreuse2 chartreuse3 chartreuse4 + chocolate chocolate1 chocolate2 chocolate3 chocolate4 + coral coral1 coral2 coral3 coral4 cornflowerblue + cornsilk cornsilk1 cornsilk2 cornsilk3 cornsilk4 + crimson cyan cyan1 cyan2 cyan3 cyan4 darkgoldenrod + darkgoldenrod1 darkgoldenrod2 darkgoldenrod3 + darkgoldenrod4 darkgreen darkkhaki darkolivegreen + darkolivegreen1 darkolivegreen2 darkolivegreen3 + darkolivegreen4 darkorange darkorange1 darkorange2 + darkorange3 darkorange4 darkorchid darkorchid1 + darkorchid2 darkorchid3 darkorchid4 darksalmon + darkseagreen darkseagreen1 darkseagreen2 + darkseagreen3 darkseagreen4 darkslateblue + darkslategray darkslategray1 darkslategray2 + darkslategray3 darkslategray4 darkslategrey + darkturquoise darkviolet deeppink deeppink1 + deeppink2 deeppink3 deeppink4 deepskyblue + deepskyblue1 deepskyblue2 deepskyblue3 deepskyblue4 + dimgray dimgrey dodgerblue dodgerblue1 dodgerblue2 + dodgerblue3 dodgerblue4 firebrick firebrick1 + firebrick2 firebrick3 firebrick4 floralwhite + forestgreen gainsboro ghostwhite gold gold1 gold2 + gold3 gold4 goldenrod goldenrod1 goldenrod2 + goldenrod3 goldenrod4 gray gray0 gray1 gray10 gray100 + gray11 gray12 gray13 gray14 gray15 gray16 gray17 + gray18 gray19 gray2 gray20 gray21 gray22 gray23 + gray24 gray25 gray26 gray27 gray28 gray29 gray3 + gray30 gray31 gray32 gray33 gray34 gray35 gray36 + gray37 gray38 gray39 gray4 gray40 gray41 gray42 + gray43 gray44 gray45 gray46 gray47 gray48 gray49 + gray5 gray50 gray51 gray52 gray53 gray54 gray55 + gray56 gray57 gray58 gray59 gray6 gray60 gray61 + gray62 gray63 gray64 gray65 gray66 gray67 gray68 + gray69 gray7 gray70 gray71 gray72 gray73 gray74 + gray75 gray76 gray77 gray78 gray79 gray8 gray80 + gray81 gray82 gray83 gray84 gray85 gray86 gray87 + gray88 gray89 gray9 gray90 gray91 gray92 gray93 + gray94 gray95 gray96 gray97 gray98 gray99 green + green1 green2 green3 green4 greenyellow grey grey0 + grey1 grey10 grey100 grey11 grey12 grey13 grey14 + grey15 grey16 grey17 grey18 grey19 grey2 grey20 + grey21 grey22 grey23 grey24 grey25 grey26 grey27 + grey28 grey29 grey3 grey30 grey31 grey32 grey33 + grey34 grey35 grey36 grey37 grey38 grey39 grey4 + grey40 grey41 grey42 grey43 grey44 grey45 grey46 + grey47 grey48 grey49 grey5 grey50 grey51 grey52 + grey53 grey54 grey55 grey56 grey57 grey58 grey59 + grey6 grey60 grey61 grey62 grey63 grey64 grey65 + grey66 grey67 grey68 grey69 grey7 grey70 grey71 + grey72 grey73 grey74 grey75 grey76 grey77 grey78 + grey79 grey8 grey80 grey81 grey82 grey83 grey84 + grey85 grey86 grey87 grey88 grey89 grey9 grey90 + grey91 grey92 grey93 grey94 grey95 grey96 grey97 + grey98 grey99 honeydew honeydew1 honeydew2 honeydew3 + honeydew4 hotpink hotpink1 hotpink2 hotpink3 hotpink4 + indianred indianred1 indianred2 indianred3 indianred4 + indigo ivory ivory1 ivory2 ivory3 ivory4 khaki khaki1 + khaki2 khaki3 khaki4 lavender lavenderblush + lavenderblush1 lavenderblush2 lavenderblush3 + lavenderblush4 lawngreen lemonchiffon lemonchiffon1 + lemonchiffon2 lemonchiffon3 lemonchiffon4 lightblue + lightblue1 lightblue2 lightblue3 lightblue4 + lightcoral lightcyan lightcyan1 lightcyan2 lightcyan3 + lightcyan4 lightgoldenrod lightgoldenrod1 + lightgoldenrod2 lightgoldenrod3 lightgoldenrod4 + lightgoldenrodyellow lightgray lightgrey lightpink + lightpink1 lightpink2 lightpink3 lightpink4 + lightsalmon lightsalmon1 lightsalmon2 lightsalmon3 + lightsalmon4 lightseagreen lightskyblue lightskyblue1 + lightskyblue2 lightskyblue3 lightskyblue4 + lightslateblue lightslategray lightslategrey + lightsteelblue lightsteelblue1 lightsteelblue2 + lightsteelblue3 lightsteelblue4 lightyellow + lightyellow1 lightyellow2 lightyellow3 lightyellow4 + limegreen linen magenta magenta1 magenta2 magenta3 + magenta4 maroon maroon1 maroon2 maroon3 maroon4 + mediumaquamarine mediumblue mediumorchid + mediumorchid1 mediumorchid2 mediumorchid3 + mediumorchid4 mediumpurple mediumpurple1 + mediumpurple2 mediumpurple3 mediumpurple4 + mediumseagreen mediumslateblue mediumspringgreen + mediumturquoise mediumvioletred midnightblue + mintcream mistyrose mistyrose1 mistyrose2 mistyrose3 + mistyrose4 moccasin navajowhite navajowhite1 + navajowhite2 navajowhite3 navajowhite4 navy navyblue + oldlace olivedrab olivedrap olivedrab1 olivedrab2 + olivedrap3 oragne palegoldenrod palegreen palegreen1 + palegreen2 palegreen3 palegreen4 paleturquoise + paleturquoise1 paleturquoise2 paleturquoise3 + paleturquoise4 palevioletred palevioletred1 + palevioletred2 palevioletred3 palevioletred4 + papayawhip peachpuff peachpuff1 peachpuff2 + peachpuff3 peachpuff4 peru pink pink1 pink2 pink3 + pink4 plum plum1 plum2 plum3 plum4 powderblue + purple purple1 purple2 purple3 purple4 red red1 red2 + red3 red4 rosybrown rosybrown1 rosybrown2 rosybrown3 + rosybrown4 royalblue royalblue1 royalblue2 royalblue3 + royalblue4 saddlebrown salmon salmon1 salmon2 salmon3 + salmon4 sandybrown seagreen seagreen1 seagreen2 + seagreen3 seagreen4 seashell seashell1 seashell2 + seashell3 seashell4 sienna sienna1 sienna2 sienna3 + sienna4 skyblue skyblue1 skyblue2 skyblue3 skyblue4 + slateblue slateblue1 slateblue2 slateblue3 slateblue4 + slategray slategray1 slategray2 slategray3 slategray4 + slategrey snow snow1 snow2 snow3 snow4 springgreen + springgreen1 springgreen2 springgreen3 springgreen4 + steelblue steelblue1 steelblue2 steelblue3 steelblue4 + tan tan1 tan2 tan3 tan4 thistle thistle1 thistle2 + thistle3 thistle4 tomato tomato1 tomato2 tomato3 + tomato4 transparent turquoise turquoise1 turquoise2 + turquoise3 turquoise4 violet violetred violetred1 + violetred2 violetred3 violetred4 wheat wheat1 wheat2 + wheat3 wheat4 white whitesmoke yellow yellow1 yellow2 + yellow3 yellow4 yellowgreen) + "Possible color constants in the dot language. +The list of constant is available at http://www.research.att.com/~erg/graphviz\ +/info/colors.html") + + +(defvar graphviz-dot-color-keywords + (mapcar 'symbol-name graphviz-dot-colors-list)) + +(defvar graphviz-attr-keywords + (mapcar '(lambda (elm) (cons elm 0)) graphviz-dot-attr-keywords)) + +(defvar graphviz-value-keywords + (mapcar '(lambda (elm) (cons elm 0)) graphviz-dot-value-keywords)) + +(defvar graphviz-color-keywords + (mapcar '(lambda (elm) (cons elm 0)) graphviz-dot-color-keywords)) + +;;; Key map +(defvar graphviz-dot-mode-map () + "Keymap used in Graphviz Dot mode.") + +(if graphviz-dot-mode-map + () + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'electric-graphviz-dot-terminate-line) + (define-key map "{" 'electric-graphviz-dot-open-brace) + (define-key map "}" 'electric-graphviz-dot-close-brace) + (define-key map ";" 'electric-graphviz-dot-semi) + (define-key map "\M-\t" 'graphviz-dot-complete-word) + (define-key map "\C-\M-q" 'graphviz-dot-indent-graph) + (define-key map "\C-cp" 'graphviz-dot-preview) + (define-key map "\C-cc" 'compile) + (define-key map "\C-cv" 'graphviz-dot-view) + (define-key map "\C-c\C-c" 'comment-region) + (define-key map "\C-c\C-u" 'graphviz-dot-uncomment-region) + (setq graphviz-dot-mode-map map) + )) + +;;; Syntax table +(defvar graphviz-dot-mode-syntax-table nil + "Syntax table for `graphviz-dot-mode'.") + +(if graphviz-dot-mode-syntax-table + () + (let ((st (make-syntax-table))) + (modify-syntax-entry ?/ ". 124b" st) + (modify-syntax-entry ?* ". 23" st) + (modify-syntax-entry ?\n "> b" st) + (modify-syntax-entry ?= "." st) + (modify-syntax-entry ?_ "_" st) + (modify-syntax-entry ?- "_" st) + (modify-syntax-entry ?> "." st) + (modify-syntax-entry ?[ "(" st) + (modify-syntax-entry ?] ")" st) + (modify-syntax-entry ?\" "\"" st) + (setq graphviz-dot-mode-syntax-table st) + )) + +(defvar graphviz-dot-font-lock-keywords + `(("\\(:?di\\|sub\\)?graph \\(\\sw+\\)" + (2 font-lock-function-name-face)) + (,(regexp-opt graphviz-dot-value-keywords 'words) + . font-lock-reference-face) + ;; to build the font-locking for the colors, + ;; we need more room for max-specpdl-size, + ;; after that we take the list of symbols, + ;; convert them to a list of strings, and make + ;; an optimized regexp from them + (,(let ((max-specpdl-size (max max-specpdl-size 1200))) + (regexp-opt graphviz-dot-color-keywords)) + . font-lock-string-face) + (,(concat + (regexp-opt graphviz-dot-attr-keywords 'words) + "[ \\t\\n]*=") + ;; RR - ugly, really, but I dont know why xemacs does not work + ;; if I change the next car to "1"... + (0 font-lock-variable-name-face))) + "Keyword highlighting specification for `graphviz-dot-mode'.") + +;;;###autoload +(defun graphviz-dot-mode () + "Major mode for the dot language. \\<graphviz-dot-mode-map> +TAB indents for graph lines. + +\\[graphviz-dot-indent-graph]\t- Indentaion function. +\\[graphviz-dot-preview]\t- Previews graph in a buffer. +\\[graphviz-dot-view]\t- Views graph in an external viewer. +\\[graphviz-dot-indent-line]\t- Indents current line of code. +\\[graphviz-dot-complete-word]\t- Completes the current word. +\\[electric-graphviz-dot-terminate-line]\t- Electric newline. +\\[electric-graphviz-dot-open-brace]\t- Electric open braces. +\\[electric-graphviz-dot-close-brace]\t- Electric close braces. +\\[electric-graphviz-dot-semi]\t- Electric semi colons. + +Variables specific to this mode: + + graphviz-dot-dot-program (default `dot') + Location of the dot program. + graphviz-dot-view-command (default `doted %s') + Command to run when `graphviz-dot-view' is executed. + graphviz-dot-view-edit-command (default nil) + If the user should be asked to edit the view command. + graphviz-dot-save-before-view (default t) + Automatically save current buffer berore `graphviz-dot-view'. + graphviz-dot-preview-extension (default `png') + File type to use for `graphviz-dot-preview'. + graphviz-dot-auto-indent-on-newline (default t) + Whether to run `electric-graphviz-dot-terminate-line' when + newline is entered. + graphviz-dot-auto-indent-on-braces (default t) + Whether to run `electric-graphviz-dot-open-brace' and + `electric-graphviz-dot-close-brace' when braces are + entered. + graphviz-dot-auto-indent-on-semi (default t) + Whether to run `electric-graphviz-dot-semi' when semi colon + is typed. + graphviz-dot-toggle-completions (default nil) + If completions should be displayed in the buffer instead of a + completion buffer when \\[graphviz-dot-complete-word] is + pressed repeatedly. + +This mode can be customized by running \\[graphviz-dot-customize]. + +Turning on Graphviz Dot mode calls the value of the variable +`graphviz-dot-mode-hook' with no args, if that value is non-nil." + (interactive) + (kill-all-local-variables) + (use-local-map graphviz-dot-mode-map) + (setq major-mode 'graphviz-dot-mode) + (setq mode-name "dot") + (setq local-abbrev-table graphviz-dot-mode-abbrev-table) + (set-syntax-table graphviz-dot-mode-syntax-table) + (set (make-local-variable 'indent-line-function) 'graphviz-dot-indent-line) + (set (make-local-variable 'comment-start) "//") + (set (make-local-variable 'comment-start-skip) "/\\*+ *\\|//+ *") + (set (make-local-variable 'font-lock-defaults) + '(graphviz-dot-font-lock-keywords)) + ;; RR - If user is running this in the scratch buffer, there is no + ;; buffer file name... + (if (buffer-file-name) + (set (make-local-variable 'compile-command) + (concat graphviz-dot-dot-program + " -T" graphviz-dot-preview-extension " " + buffer-file-name + " > " + (file-name-sans-extension + buffer-file-name) + "." graphviz-dot-preview-extension))) + (set (make-local-variable 'compilation-parse-errors-function) + 'graphviz-dot-compilation-parse-errors) + (if dot-menu + (easy-menu-add dot-menu)) + (run-hooks 'graphviz-dot-mode-hook) + ) + +;;;; Menu definitions + +(defvar dot-menu nil + "Menu for Graphviz Dot Mode. +This menu will get created automatically if you have the `easymenu' +package. Note that the latest X/Emacs releases contain this package.") + +(and (condition-case nil + (require 'easymenu) + (error nil)) + (easy-menu-define + dot-menu graphviz-dot-mode-map "Graphviz Mode menu" + '("Graphviz" + ["Indent Graph" graphviz-dot-indent-graph t] + ["Comment Out Region" comment-region (mark)] + ["Uncomment Region" graphviz-dot-uncomment-region (mark)] + "-" + ["Compile" compile t] + ["Preview" graphviz-dot-preview + (and (buffer-file-name) + (not (buffer-modified-p)))] + ["External Viewer" graphviz-dot-view (buffer-file-name)] + "-" + ["Customize..." graphviz-dot-customize t] + ))) + +;;;; Compilation + +;; note on graphviz-dot-compilation-parse-errors: +;; It would nicer if we could just use compilation-error-regexp-alist +;; to do that, 3 options: +;; - still write dot-compilation-parse-errors, don't build +;; a return list, but modify the *compilation* buffer +;; in a way compilation-error-regexp-alist recognizes the +;; format. +;; to do that, I should globally change compilation-parse-function +;; to this function, and call the old value of comp..-parse-fun.. +;; to provide the return value. +;; two drawbacks are that, every compilation would be run through +;; this function (performance) and that in autoload there would +;; be a chance that this function would not yet be known. +;; - let the compilation run through a filter that would +;; modify the output of dot or neato: +;; dot -Tpng input.dot | filter +;; drawback: ugly, extra work for user, extra decency ... +;; no-option +;; - modify dot and neato !!! (PP:15/02/2005 seems to have happend, +;; so version 0.4.0 should clean this mess up!) +(defun graphviz-dot-compilation-parse-errors (limit-search find-at-least) + "Parse the current buffer for dot errors. +See variable `compilation-parse-errors-functions' for interface." + (interactive) + (save-excursion + (set-buffer "*compilation*") + (goto-char (point-min)) + (setq compilation-error-list nil) + (let (buffer-of-error) + (while (not (eobp)) + (cond + ((looking-at "^dot\\( -[^ ]+\\)* \\(.*\\)") + (setq buffer-of-error (find-file-noselect + (buffer-substring-no-properties + (nth 4 (match-data t)) + (nth 5 (match-data t)))))) + ((looking-at ".*:.*line \\([0-9]+\\)") + (let ((line-of-error + (string-to-number (buffer-substring-no-properties + (nth 2 (match-data t)) + (nth 3 (match-data t)))))) + (setq compilation-error-list + (cons + (cons + (point-marker) + (save-excursion + (set-buffer buffer-of-error) + (goto-line line-of-error) + (beginning-of-line) + (point-marker))) + compilation-error-list)))) + (t t)) + (forward-line 1)) ))) + +;;;; +;;;; Indentation +;;;; +(defun graphviz-dot-uncomment-region (begin end) + "Uncomments a region of code." + (interactive "r") + (comment-region begin end '(4))) + +(defun graphviz-dot-indent-line () + "Indent current line of dot code." + (interactive) + (if (bolp) + (graphviz-dot-real-indent-line) + (save-excursion + (graphviz-dot-real-indent-line)))) + +(defun graphviz-dot-real-indent-line () + "Indent current line of dot code." + (beginning-of-line) + (cond + ((bobp) + ;; simple case, indent to 0 + (indent-line-to 0)) + ((looking-at "^[ \t]*}[ \t]*$") + ;; block closing, deindent relative to previous line + (indent-line-to (save-excursion + (forward-line -1) + (max 0 (- (current-indentation) graphviz-dot-indent-width))))) + ;; other cases need to look at previous lines + (t + (indent-line-to (save-excursion + (forward-line -1) + (cond + ((looking-at "\\(^.*{[^}]*$\\)") + ;; previous line opened a block + ;; indent to that line + (+ (current-indentation) graphviz-dot-indent-width)) + ((and (not (looking-at ".*\\[.*\\].*")) + (looking-at ".*\\[.*")) ; TODO:PP : can be 1 regex + ;; previous line started filling + ;; attributes, intend to that start + (search-forward "[") + (current-column)) + ((and (not (looking-at ".*\\[.*\\].*")) + (looking-at ".*\\].*")) ; TODO:PP : " + ;; previous line stopped filling + ;; attributes, find the line that started + ;; filling them and indent to that line + (while (or (looking-at ".*\\[.*\\].*") + (not (looking-at ".*\\[.*"))) ; TODO:PP : " + (forward-line -1)) + (current-indentation)) + (t + ;; default case, indent the + ;; same as previous line + (current-indentation)) ))) ))) + +(defun graphviz-dot-indent-graph () + "Indent the graph/digraph/subgraph where point is at. +This will first teach the beginning of the graph were point is at, and +then indent this and each subgraph in it." + (interactive) + (save-excursion + ;; position point at start of graph + (while (not (or (looking-at "\\(^.*{[^}]*$\\)") (bobp))) + (forward-line -1)) + ;; bracket { one +; bracket } one - + (let ((bracket-count 0)) + (while + (progn + (cond + ;; update bracket-count + ((looking-at "\\(^.*{[^}]*$\\)") + (setq bracket-count (+ bracket-count 1))) + ;; update bracket-count + ((looking-at "^[ \t]*}[ \t]*$") + (setq bracket-count (- bracket-count 1)))) + ;; indent this line and move on + (graphviz-dot-indent-line) + (forward-line 1) + ;; as long as we are not completed or at end of buffer + (and (> bracket-count 0) (not (eobp)))))))) + +;;;; +;;;; Electric indentation +;;;; +(defun graphviz-dot-comment-or-string-p () + (let ((state (parse-partial-sexp (point-min) (point)))) + (or (nth 4 state) (nth 3 state)))) + +(defun graphviz-dot-newline-and-indent () + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (graphviz-dot-indent-line)) + (delete-horizontal-space) + (newline) + (graphviz-dot-indent-line)) + +(defun electric-graphviz-dot-terminate-line () + "Terminate line and indent next line." + (interactive) + (if graphviz-dot-auto-indent-on-newline + (graphviz-dot-newline-and-indent) + (newline))) + +(defun electric-graphviz-dot-open-brace () + "Terminate line and indent next line." + (interactive) + (insert "{") + (if (and graphviz-dot-auto-indent-on-braces + (not (graphviz-dot-comment-or-string-p))) + (graphviz-dot-newline-and-indent))) + +(defun electric-graphviz-dot-close-brace () + "Terminate line and indent next line." + (interactive) + (insert "}") + (if (and graphviz-dot-auto-indent-on-braces + (not (graphviz-dot-comment-or-string-p))) + (progn + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (graphviz-dot-indent-line)) + (newline) + (graphviz-dot-indent-line)))) + +(defun electric-graphviz-dot-semi () + "Terminate line and indent next line." + (interactive) + (insert ";") + (if (and graphviz-dot-auto-indent-on-semi + (not (graphviz-dot-comment-or-string-p))) + (graphviz-dot-newline-and-indent))) + +;;;; +;;;; Preview +;;;; +(defun graphviz-dot-preview () + "Shows an example of the current dot file in an emacs buffer. +This assumes that we are running GNU Emacs or XEmacs under a windowing system. +See `image-file-name-extensions' for customizing the files that can be +loaded in GNU Emacs, and `image-formats-alist' for XEmacs." + (interactive) + ;; unsafe to compile ourself, ask it to the user + (if (buffer-modified-p) + (message "Buffer needs to be compiled.") + (if (string-match "XEmacs" emacs-version) + ;; things are easier in XEmacs... + (find-file-other-window (concat (file-name-sans-extension + buffer-file-name) + "." graphviz-dot-preview-extension)) + ;; run through all the extensions for images + (let ((l image-file-name-extensions)) + (while + (let ((f (concat (file-name-sans-extension (buffer-file-name)) + "." + (car l)))) + ;; see if a file matches, might be best also to check + ;; if file is up to date TODO:PP + (if (file-exists-p f) + (progn (auto-image-file-mode 1) + ;; OK, this is ugly, I would need to + ;; know how I can reload a file in an existing buffer + (if (get-buffer "*preview*") + (kill-buffer "*preview*")) + (set-buffer (find-file-noselect f)) + (rename-buffer "*preview*") + (display-buffer (get-buffer "*preview*")) + ;; stop iterating + '()) + ;; will stop iterating when l is nil + (setq l (cdr l))))) + ;; each extension tested and nothing found, let user know + (when (eq l '()) + (message "No image found.")))))) + +;;;; +;;;; View +;;;; +(defun graphviz-dot-view () + "Runs an external viewer. This creates an external process every time it +is executed. If `graphviz-dot-save-before-view' is set, the current +buffer is saved before the command is executed." + (interactive) + (let ((cmd (if graphviz-dot-view-edit-command + (if (string-match "XEmacs" emacs-version) + (read-shell-command "View command: " + (format graphviz-dot-view-command + (buffer-file-name))) + (read-from-minibuffer "View command: " + (format graphviz-dot-view-command + (buffer-file-name)))) + (format graphviz-dot-view-command (buffer-file-name))))) + (if graphviz-dot-save-before-view + (save-buffer)) + (setq novaproc (start-process-shell-command + (downcase mode-name) nil cmd)) + (message (format "Executing `%s'..." cmd)))) + +;;;; +;;;; Completion +;;;; +(defvar graphviz-dot-str nil) +(defvar graphviz-dot-all nil) +(defvar graphviz-dot-pred nil) +(defvar graphviz-dot-buffer-to-use nil) +(defvar graphviz-dot-flag nil) + +(defun graphviz-dot-get-state () + "Returns the syntax state of the current point." + (let ((state (parse-partial-sexp (point-min) (point)))) + (cond + ((nth 4 state) 'comment) + ((nth 3 state) 'string) + ((not (nth 1 state)) 'out) + (t (save-excursion + (skip-chars-backward "^[,=\\[]{};") + (backward-char) + (cond + ((looking-at "[\\[,]{};") 'attribute) + ((looking-at "=") (progn + (backward-word 1) + (if (looking-at "[a-zA-Z]*color") + 'color + 'value))) + (t 'other))))))) + +(defun graphviz-dot-get-keywords () + "Return possible completions for a word" + (let ((state (graphviz-dot-get-state))) + (cond + ((equal state 'comment) ()) + ((equal state 'string) ()) + ((equal state 'out) graphviz-attr-keywords) + ((equal state 'value) graphviz-value-keywords) + ((equal state 'color) graphviz-color-keywords) + ((equal state 'attribute) graphviz-attr-keywords) + (t graphviz-attr-keywords)))) + +(defvar graphviz-dot-last-word-numb 0) +(defvar graphviz-dot-last-word-shown nil) +(defvar graphviz-dot-last-completions nil) + +(defun graphviz-dot-complete-word () + "Complete word at current point." + (interactive) + (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) + (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) + (graphviz-dot-str (buffer-substring b e)) + (allcomp (if (and graphviz-dot-toggle-completions + (string= graphviz-dot-last-word-shown + graphviz-dot-str)) + graphviz-dot-last-completions + (all-completions graphviz-dot-str + (graphviz-dot-get-keywords)))) + (match (if graphviz-dot-toggle-completions + "" (try-completion + graphviz-dot-str (mapcar '(lambda (elm) + (cons elm 0)) allcomp))))) + ;; Delete old string + (delete-region b e) + + ;; Toggle-completions inserts whole labels + (if graphviz-dot-toggle-completions + (progn + ;; Update entry number in list + (setq graphviz-dot-last-completions allcomp + graphviz-dot-last-word-numb + (if (>= graphviz-dot-last-word-numb (1- (length allcomp))) + 0 + (1+ graphviz-dot-last-word-numb))) + (setq graphviz-dot-last-word-shown + (elt allcomp graphviz-dot-last-word-numb)) + ;; Display next match or same string if no match was found + (if (not (null allcomp)) + (insert "" graphviz-dot-last-word-shown) + (insert "" graphviz-dot-str) + (message "(No match)"))) + ;; The other form of completion does not necessarily do that. + + ;; Insert match if found, or the original string if no match + (if (or (null match) (equal match 't)) + (progn (insert "" graphviz-dot-str) + (message "(No match)")) + (insert "" match)) + ;; Give message about current status of completion + (cond ((equal match 't) + (if (not (null (cdr allcomp))) + (message "(Complete but not unique)") + (message "(Sole completion)"))) + ;; Display buffer if the current completion didn't help + ;; on completing the label. + ((and (not (null (cdr allcomp))) (= (length graphviz-dot-str) + (length match))) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list allcomp)) + ;; Wait for a keypress. Then delete *Completion* window + (momentary-string-display "" (point)) + (if graphviz-dot-delete-completions + (delete-window + (get-buffer-window (get-buffer "*Completions*")))) + ))))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.dot\\'" . graphviz-dot-mode)) + +;;; graphviz-dot-mode.el ends here + diff --git a/emacs/highlight-parentheses.el b/emacs/highlight-parentheses.el new file mode 100644 index 0000000..8df50ab --- /dev/null +++ b/emacs/highlight-parentheses.el @@ -0,0 +1,157 @@ +;;; highlight-parentheses.el --- highlight surrounding parentheses +;; +;; Copyright (C) 2007, 2009 Nikolaj Schumacher +;; +;; Author: Nikolaj Schumacher <bugs * nschum de> +;; Version: 1.0.1 +;; Keywords: faces, matching +;; URL: http://nschum.de/src/emacs/highlight-parentheses/ +;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x +;; +;; This file is NOT part of 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 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, see <http://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; Add the following to your .emacs file: +;; (require 'highlight-parentheses) +;; +;; Enable `highlight-parentheses-mode'. +;; +;;; Change Log: +;; +;; 2009-03-19 (1.0.1) +;; Added setter for color variables. +;; +;; 2007-07-30 (1.0) +;; Added background highlighting and faces. +;; +;; 2007-05-15 (0.9.1) +;; Support for defcustom. +;; +;; 2007-04-26 (0.9) +;; Initial Release. +;; +;;; Code: + +(eval-when-compile (require 'cl)) + +(defgroup highlight-parentheses nil + "Highlight surrounding parentheses" + :group 'faces + :group 'matching) + +(defun hl-paren-set (variable value) + (set variable value) + (when (fboundp 'hl-paren-color-update) + (hl-paren-color-update))) + +(defcustom hl-paren-colors + '("firebrick1" "IndianRed1" "IndianRed3" "IndianRed4") + "*List of colors for the highlighted parentheses. +The list starts with the the inside parentheses and moves outwards." + :type '(repeat color) + :set 'hl-paren-set + :group 'highlight-parentheses) + +(defcustom hl-paren-background-colors nil + "*List of colors for the background highlighted parentheses. +The list starts with the the inside parentheses and moves outwards." + :type '(repeat color) + :set 'hl-paren-set + :group 'highlight-parentheses) + +(defface hl-paren-face nil + "*Face used for highlighting parentheses. +Color attributes might be overriden by `hl-paren-colors' and +`hl-paren-background-colors'." + :group 'highlight-parentheses) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar hl-paren-overlays nil + "This buffers currently active overlays.") +(make-variable-buffer-local 'hl-paren-overlays) + +(defvar hl-paren-last-point 0 + "The last point for which parentheses were highlighted. +This is used to prevent analyzing the same context over and over.") +(make-variable-buffer-local 'hl-paren-last-point) + +(defun hl-paren-highlight () + "Highlight the parentheses around point." + (unless (= (point) hl-paren-last-point) + (setq hl-paren-last-point (point)) + (let ((overlays hl-paren-overlays) + pos1 pos2 + (pos (point))) + (save-excursion + (condition-case err + (while (and (setq pos1 (cadr (syntax-ppss pos1))) + (cddr overlays)) + (move-overlay (pop overlays) pos1 (1+ pos1)) + (when (setq pos2 (scan-sexps pos1 1)) + (move-overlay (pop overlays) (1- pos2) pos2) + )) + (error nil)) + (goto-char pos)) + (dolist (ov overlays) + (move-overlay ov 1 1))))) + +;;;###autoload +(define-minor-mode highlight-parentheses-mode + "Minor mode to highlight the surrounding parentheses." + nil " hl-p" nil + (if highlight-parentheses-mode + (progn + (hl-paren-create-overlays) + (add-hook 'post-command-hook 'hl-paren-highlight nil t)) + (mapc 'delete-overlay hl-paren-overlays) + (kill-local-variable 'hl-paren-overlays) + (kill-local-variable 'hl-paren-point) + (remove-hook 'post-command-hook 'hl-paren-highlight t))) + +;;; overlays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun hl-paren-create-overlays () + (let ((fg hl-paren-colors) + (bg hl-paren-background-colors) + attributes) + (while (or fg bg) + (setq attributes (face-attr-construct 'hl-paren-face)) + (when (car fg) + (setq attributes (plist-put attributes :foreground (car fg)))) + (pop fg) + (when (car bg) + (setq attributes (plist-put attributes :background (car bg)))) + (pop bg) + (dotimes (i 2) ;; front and back + (push (make-overlay 0 0) hl-paren-overlays) + (overlay-put (car hl-paren-overlays) 'face attributes))) + (setq hl-paren-overlays (nreverse hl-paren-overlays)))) + +(defun hl-paren-color-update () + (dolist (buffer (buffer-list)) + (with-current-buffer buffer + (when hl-paren-overlays + (mapc 'delete-overlay hl-paren-overlays) + (setq hl-paren-overlays nil) + (hl-paren-create-overlays) + (let ((hl-paren-last-point -1)) ;; force update + (hl-paren-highlight)))))) + +(provide 'highlight-parentheses) + +;;; highlight-parentheses.el ends here diff --git a/emacs/javascript.el b/emacs/javascript.el new file mode 100644 index 0000000..33d852f --- /dev/null +++ b/emacs/javascript.el @@ -0,0 +1,707 @@ +;;; javascript.el --- Major mode for editing JavaScript source text + +;; Copyright (C) 2006 Karl Landström + +;; Author: Karl Landström <kland@comhem.se> +;; Maintainer: Karl Landström <kland@comhem.se> +;; Version: 2.0 Beta 8 +;; Date: 2006-12-26 +;; Keywords: languages, oop + +;; 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: +;; +;; The main features of this JavaScript mode are syntactic +;; highlighting (enabled with `font-lock-mode' or +;; `global-font-lock-mode'), automatic indentation and filling of +;; comments. +;; +;; This package has (only) been tested with GNU Emacs 21.4 (the latest +;; stable release). +;; +;; Installation: +;; +;; Put this file in a directory where Emacs can find it (`C-h v +;; load-path' for more info). Then add the following lines to your +;; Emacs initialization file: +;; +;; (add-to-list 'auto-mode-alist '("\\.js\\'" . javascript-mode)) +;; (autoload 'javascript-mode "javascript" nil t) +;; +;; General Remarks: +;; +;; This mode assumes that block comments are not nested inside block +;; comments and that strings do not contain line breaks. +;; +;; Exported names start with "javascript-" whereas private names start +;; with "js-". +;; +;; Changes: +;; +;; See javascript.el.changelog. + +;;; Code: + +(require 'cc-mode) +(require 'font-lock) +(require 'newcomment) + +(defgroup javascript nil + "Customization variables for `javascript-mode'." + :tag "JavaScript" + :group 'languages) + +(defcustom javascript-indent-level 4 + "Number of spaces for each indentation step." + :type 'integer + :group 'javascript) + +(defcustom javascript-auto-indent-flag t + "Automatic indentation with punctuation characters. If non-nil, the +current line is indented when certain punctuations are inserted." + :type 'boolean + :group 'javascript) + + +;; --- Keymap --- + +(defvar javascript-mode-map nil + "Keymap used in JavaScript mode.") + +(unless javascript-mode-map + (setq javascript-mode-map (make-sparse-keymap))) + +(when javascript-auto-indent-flag + (mapc (lambda (key) + (define-key javascript-mode-map key 'javascript-insert-and-indent)) + '("{" "}" "(" ")" ":" ";" ","))) + +(defun javascript-insert-and-indent (key) + "Run command bound to key and indent current line. Runs the command +bound to KEY in the global keymap and indents the current line." + (interactive (list (this-command-keys))) + (call-interactively (lookup-key (current-global-map) key)) + (indent-according-to-mode)) + + +;; --- Syntax Table And Parsing --- + +(defvar javascript-mode-syntax-table + (let ((table (make-syntax-table))) + (c-populate-syntax-table table) + + ;; The syntax class of underscore should really be `symbol' ("_") + ;; but that makes matching of tokens much more complex as e.g. + ;; "\\<xyz\\>" matches part of e.g. "_xyz" and "xyz_abc". Defines + ;; it as word constituent for now. + (modify-syntax-entry ?_ "w" table) + + table) + "Syntax table used in JavaScript mode.") + + +(defun js-re-search-forward-inner (regexp &optional bound count) + "Auxiliary function for `js-re-search-forward'." + (let ((parse) + (saved-point (point-min))) + (while (> count 0) + (re-search-forward regexp bound) + (setq parse (parse-partial-sexp saved-point (point))) + (cond ((nth 3 parse) + (re-search-forward + (concat "\\([^\\]\\|^\\)" (string (nth 3 parse))) + (save-excursion (end-of-line) (point)) t)) + ((nth 7 parse) + (forward-line)) + ((or (nth 4 parse) + (and (eq (char-before) ?\/) (eq (char-after) ?\*))) + (re-search-forward "\\*/")) + (t + (setq count (1- count)))) + (setq saved-point (point)))) + (point)) + + +(defun js-re-search-forward (regexp &optional bound noerror count) + "Search forward but ignore strings and comments. Invokes +`re-search-forward' but treats the buffer as if strings and +comments have been removed." + (let ((saved-point (point)) + (search-expr + (cond ((null count) + '(js-re-search-forward-inner regexp bound 1)) + ((< count 0) + '(js-re-search-backward-inner regexp bound (- count))) + ((> count 0) + '(js-re-search-forward-inner regexp bound count))))) + (condition-case err + (eval search-expr) + (search-failed + (goto-char saved-point) + (unless noerror + (error (error-message-string err))))))) + + +(defun js-re-search-backward-inner (regexp &optional bound count) + "Auxiliary function for `js-re-search-backward'." + (let ((parse) + (saved-point (point-min))) + (while (> count 0) + (re-search-backward regexp bound) + (when (and (> (point) (point-min)) + (save-excursion (backward-char) (looking-at "/[/*]"))) + (forward-char)) + (setq parse (parse-partial-sexp saved-point (point))) + (cond ((nth 3 parse) + (re-search-backward + (concat "\\([^\\]\\|^\\)" (string (nth 3 parse))) + (save-excursion (beginning-of-line) (point)) t)) + ((nth 7 parse) + (goto-char (nth 8 parse))) + ((or (nth 4 parse) + (and (eq (char-before) ?/) (eq (char-after) ?*))) + (re-search-backward "/\\*")) + (t + (setq count (1- count)))))) + (point)) + + +(defun js-re-search-backward (regexp &optional bound noerror count) + "Search backward but ignore strings and comments. Invokes +`re-search-backward' but treats the buffer as if strings and +comments have been removed." + (let ((saved-point (point)) + (search-expr + (cond ((null count) + '(js-re-search-backward-inner regexp bound 1)) + ((< count 0) + '(js-re-search-forward-inner regexp bound (- count))) + ((> count 0) + '(js-re-search-backward-inner regexp bound count))))) + (condition-case err + (eval search-expr) + (search-failed + (goto-char saved-point) + (unless noerror + (error (error-message-string err))))))) + + +(defun js-continued-var-decl-list-p () + "Return non-nil if point is inside a continued variable declaration +list." + (interactive) + (let ((start (save-excursion (js-re-search-backward "\\<var\\>" nil t)))) + (and start + (save-excursion (re-search-backward "\n" start t)) + (not (save-excursion + (js-re-search-backward + ";\\|[^, \t][ \t]*\\(/[/*]\\|$\\)" start t)))))) + + +;; --- Font Lock --- + +(defun js-inside-param-list-p () + "Return non-nil if point is inside a function parameter list." + (condition-case err + (save-excursion + (up-list -1) + (and (looking-at "(") + (progn (backward-word 1) + (or (looking-at "function") + (progn (backward-word 1) (looking-at "function")))))) + (error nil))) + + +(defconst js-function-heading-1-re + "^[ \t]*function[ \t]+\\(\\w+\\)" + "Regular expression matching the start of a function header.") + +(defconst js-function-heading-2-re + "^[ \t]*\\(\\w+\\)[ \t]*:[ \t]*function\\>" + "Regular expression matching the start of a function entry in + an associative array.") + +(defconst js-keyword-re + (regexp-opt '("abstract" "break" "case" "catch" "class" "const" + "continue" "debugger" "default" "delete" "do" "else" + "enum" "export" "extends" "final" "finally" "for" + "function" "goto" "if" "implements" "import" "in" + "instanceof" "interface" "native" "new" "package" + "private" "protected" "public" "return" "static" + "super" "switch" "synchronized" "this" "throw" + "throws" "transient" "try" "typeof" "var" "void" + "volatile" "while" "with" + "let") 'words) + "Regular expression matching any JavaScript keyword.") + +(defconst js-basic-type-re + (regexp-opt '("boolean" "byte" "char" "double" "float" "int" "long" + "short" "void") 'words) + "Regular expression matching any predefined type in JavaScript.") + +(defconst js-constant-re + (regexp-opt '("false" "null" "true") 'words) + "Regular expression matching any future reserved words in JavaScript.") + + +(defconst js-font-lock-keywords-1 + (list + "\\<import\\>" + (list js-function-heading-1-re 1 font-lock-function-name-face) + (list js-function-heading-2-re 1 font-lock-function-name-face) + (list "[=(][ \t]*\\(/.*?[^\\]/\\w*\\)" 1 font-lock-string-face)) + "Level one font lock.") + +(defconst js-font-lock-keywords-2 + (append js-font-lock-keywords-1 + (list (list js-keyword-re 1 font-lock-keyword-face) + (cons js-basic-type-re font-lock-type-face) + (cons js-constant-re font-lock-constant-face))) + "Level two font lock.") + + +;; Limitations with variable declarations: There seems to be no +;; sensible way to highlight variables occuring after an initialized +;; variable in a variable list. For instance, in +;; +;; var x, y = f(a, b), z +;; +;; z will not be highlighted. + +(defconst js-font-lock-keywords-3 + (append + js-font-lock-keywords-2 + (list + + ;; variable declarations + (list + (concat "\\<\\(const\\|var\\)\\>\\|" js-basic-type-re) + (list "\\(\\w+\\)[ \t]*\\([=;].*\\|,\\|/[/*]\\|$\\)" + nil + nil + '(1 font-lock-variable-name-face))) + + ;; continued variable declaration list + (list + (concat "^[ \t]*\\w+[ \t]*\\([,;=]\\|/[/*]\\|$\\)") + (list "\\(\\w+\\)[ \t]*\\([=;].*\\|,\\|/[/*]\\|$\\)" + '(if (save-excursion (backward-char) (js-continued-var-decl-list-p)) + (backward-word 1) + (end-of-line)) + '(end-of-line) + '(1 font-lock-variable-name-face))) + + ;; formal parameters + (list + (concat "\\<function\\>\\([ \t]+\\w+\\)?[ \t]*([ \t]*\\w") + (list "\\(\\w+\\)\\([ \t]*).*\\)?" + '(backward-char) + '(end-of-line) + '(1 font-lock-variable-name-face))) + + ;; continued formal parameter list + (list + (concat "^[ \t]*\\w+[ \t]*[,)]") + (list "\\w+" + '(if (save-excursion (backward-char) (js-inside-param-list-p)) + (backward-word 1) + (end-of-line)) + '(end-of-line) + '(0 font-lock-variable-name-face))))) + "Level three font lock.") + +(defconst js-font-lock-keywords + '(js-font-lock-keywords-3 js-font-lock-keywords-1 js-font-lock-keywords-2 + js-font-lock-keywords-3) + "See `font-lock-keywords'.") + + +;; --- Indentation --- + +(defconst js-possibly-braceless-keyword-re + (regexp-opt + '("catch" "do" "else" "finally" "for" "if" "try" "while" "with" "let") + 'words) + "Regular expression matching keywords that are optionally + followed by an opening brace.") + +(defconst js-indent-operator-re + (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|" + (regexp-opt '("in" "instanceof") 'words)) + "Regular expression matching operators that affect indentation + of continued expressions.") + + +(defun js-looking-at-operator-p () + "Return non-nil if text after point is an operator (that is not +a comma)." + (save-match-data + (and (looking-at js-indent-operator-re) + (or (not (looking-at ":")) + (save-excursion + (and (js-re-search-backward "[?:{]\\|\\<case\\>" nil t) + (looking-at "?"))))))) + + +(defun js-continued-expression-p () + "Returns non-nil if the current line continues an expression." + (save-excursion + (back-to-indentation) + (or (js-looking-at-operator-p) + (and (js-re-search-backward "\n" nil t) + (progn + (skip-chars-backward " \t") + (backward-char) + (and (> (point) (point-min)) + (save-excursion (backward-char) (not (looking-at "[/*]/"))) + (js-looking-at-operator-p) + (and (progn (backward-char) + (not (looking-at "++\\|--\\|/[/*]")))))))))) + + +(defun js-end-of-do-while-loop-p () + "Returns non-nil if word after point is `while' of a do-while +statement, else returns nil. A braceless do-while statement +spanning several lines requires that the start of the loop is +indented to the same column as the current line." + (interactive) + (save-excursion + (save-match-data + (when (looking-at "\\s-*\\<while\\>") + (if (save-excursion + (skip-chars-backward "[ \t\n]*}") + (looking-at "[ \t\n]*}")) + (save-excursion + (backward-list) (backward-word 1) (looking-at "\\<do\\>")) + (js-re-search-backward "\\<do\\>" (point-at-bol) t) + (or (looking-at "\\<do\\>") + (let ((saved-indent (current-indentation))) + (while (and (js-re-search-backward "^[ \t]*\\<" nil t) + (/= (current-indentation) saved-indent))) + (and (looking-at "[ \t]*\\<do\\>") + (not (js-re-search-forward + "\\<while\\>" (point-at-eol) t)) + (= (current-indentation) saved-indent))))))))) + + +(defun js-ctrl-statement-indentation () + "Returns the proper indentation of the current line if it +starts the body of a control statement without braces, else +returns nil." + (save-excursion + (back-to-indentation) + (when (save-excursion + (and (not (looking-at "[{]")) + (progn + (js-re-search-backward "[[:graph:]]" nil t) + (forward-char) + (when (= (char-before) ?\)) (backward-list)) + (skip-syntax-backward " ") + (skip-syntax-backward "w") + (looking-at js-possibly-braceless-keyword-re)) + (not (js-end-of-do-while-loop-p)))) + (save-excursion + (goto-char (match-beginning 0)) + (+ (current-indentation) javascript-indent-level))))) + + +(defun js-proper-indentation (parse-status) + "Return the proper indentation for the current line." + (save-excursion + (back-to-indentation) + (let ((ctrl-stmt-indent (js-ctrl-statement-indentation)) + (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>")) + (continued-expr-p (js-continued-expression-p))) + (cond (ctrl-stmt-indent) + ((js-continued-var-decl-list-p) + (js-re-search-backward "\\<var\\>" nil t) + (+ (current-indentation) javascript-indent-level)) + ((nth 1 parse-status) + (goto-char (nth 1 parse-status)) + (if (looking-at "[({[][ \t]*\\(/[/*]\\|$\\)") + (progn + (skip-syntax-backward " ") + (when (= (char-before) ?\)) (backward-list)) + (back-to-indentation) + (cond (same-indent-p + (current-column)) + (continued-expr-p + (+ (current-column) (* 2 javascript-indent-level))) + (t + (+ (current-column) javascript-indent-level)))) + (unless same-indent-p + (forward-char) + (skip-chars-forward " \t")) + (current-column))) + (continued-expr-p javascript-indent-level) + (t 0))))) + + +(defun javascript-indent-line () + "Indent the current line as JavaScript source text." + (interactive) + (let ((parse-status + (save-excursion (parse-partial-sexp (point-min) (point-at-bol)))) + (offset (- (current-column) (current-indentation)))) + (when (not (nth 8 parse-status)) + (indent-line-to (js-proper-indentation parse-status)) + (when (> offset 0) (forward-char offset))))) + + +;; --- Filling --- + +;; FIXME: It should be possible to use the more sofisticated function +;; `c-fill-paragraph' in `cc-cmds.el' instead. However, just setting +;; `fill-paragraph-function' to `c-fill-paragraph' does not work; +;; inside `c-fill-paragraph', `fill-paragraph-function' evaluates to +;; nil!? + +(defun js-backward-paragraph () + "Move backward to start of paragraph. Postcondition: Point is at +beginning of buffer or the previous line contains only whitespace." + (forward-line -1) + (while (not (or (bobp) (looking-at "^[ \t]*$"))) + (forward-line -1)) + (when (not (bobp)) (forward-line 1))) + + +(defun js-forward-paragraph () + "Move forward to end of paragraph. Postcondition: Point is at +end of buffer or the next line contains only whitespace." + (forward-line 1) + (while (not (or (eobp) (looking-at "^[ \t]*$"))) + (forward-line 1)) + (when (not (eobp)) (backward-char 1))) + + +(defun js-fill-block-comment-paragraph (parse-status justify) + "Fill current paragraph as a block comment. PARSE-STATUS is the +result of `parse-partial-regexp' from beginning of buffer to +point. JUSTIFY has the same meaning as in `fill-paragraph'." + (let ((offset (save-excursion + (goto-char (nth 8 parse-status)) (current-indentation)))) + (save-excursion + (save-restriction + (narrow-to-region (save-excursion + (goto-char (nth 8 parse-status)) (point-at-bol)) + (save-excursion + (goto-char (nth 8 parse-status)) + (re-search-forward "*/"))) + (narrow-to-region (save-excursion + (js-backward-paragraph) + (when (looking-at "^[ \t]*$") (forward-line 1)) + (point)) + (save-excursion + (js-forward-paragraph) + (when (looking-at "^[ \t]*$") (backward-char)) + (point))) + (goto-char (point-min)) + (while (not (eobp)) + (delete-horizontal-space) + (forward-line 1)) + (let ((fill-column (- fill-column offset)) + (fill-paragraph-function nil)) + (fill-paragraph justify)) + + ;; In Emacs 21.4 as opposed to CVS Emacs 22, + ;; `fill-paragraph' seems toadd a newline at the end of the + ;; paragraph. Remove it! + (goto-char (point-max)) + (when (looking-at "^$") (backward-delete-char 1)) + + (goto-char (point-min)) + (while (not (eobp)) + (indent-to offset) + (forward-line 1)))))) + + +(defun js-sline-comment-par-start () + "Return point at the beginning of the line where the current +single-line comment paragraph starts." + (save-excursion + (beginning-of-line) + (while (and (not (bobp)) + (looking-at "^[ \t]*//[ \t]*[[:graph:]]")) + (forward-line -1)) + (unless (bobp) (forward-line 1)) + (point))) + + +(defun js-sline-comment-par-end () + "Return point at end of current single-line comment paragraph." + (save-excursion + (beginning-of-line) + (while (and (not (eobp)) + (looking-at "^[ \t]*//[ \t]*[[:graph:]]")) + (forward-line 1)) + (unless (bobp) (backward-char)) + (point))) + + +(defun js-sline-comment-offset (line) + "Return the column at the start of the current single-line +comment paragraph." + (save-excursion + (goto-line line) + (re-search-forward "//" (point-at-eol)) + (goto-char (match-beginning 0)) + (current-column))) + + +(defun js-sline-comment-text-offset (line) + "Return the column at the start of the text of the current +single-line comment paragraph." + (save-excursion + (goto-line line) + (re-search-forward "//[ \t]*" (point-at-eol)) + (current-column))) + + +(defun js-at-empty-sline-comment-p () + "Return non-nil if inside an empty single-line comment." + (and (save-excursion + (beginning-of-line) + (not (looking-at "^.*//.*[[:graph:]]"))) + (save-excursion + (re-search-backward "//" (point-at-bol) t)))) + + +(defun js-fill-sline-comments (parse-status justify) + "Fill current paragraph as a sequence of single-line comments. +PARSE-STATUS is the result of `parse-partial-regexp' from +beginning of buffer to point. JUSTIFY has the same meaning as in +`fill-paragraph'." + (when (not (js-at-empty-sline-comment-p)) + (let* ((start (js-sline-comment-par-start)) + (start-line (1+ (count-lines (point-min) start))) + (end (js-sline-comment-par-end)) + (offset (js-sline-comment-offset start-line)) + (text-offset (js-sline-comment-text-offset start-line))) + (save-excursion + (save-restriction + (narrow-to-region start end) + (goto-char (point-min)) + (while (re-search-forward "^[ \t]*//[ \t]*" nil t) + (replace-match "") + (forward-line 1)) + (let ((fill-paragraph-function nil) + (fill-column (- fill-column text-offset))) + (fill-paragraph justify)) + + ;; In Emacs 21.4 as opposed to CVS Emacs 22, + ;; `fill-paragraph' seems toadd a newline at the end of the + ;; paragraph. Remove it! + (goto-char (point-max)) + (when (looking-at "^$") (backward-delete-char 1)) + + (goto-char (point-min)) + (while (not (eobp)) + (indent-to offset) + (insert "//") + (indent-to text-offset) + (forward-line 1))))))) + + +(defun js-trailing-comment-p (parse-status) + "Return non-nil if inside a trailing comment. PARSE-STATUS is +the result of `parse-partial-regexp' from beginning of buffer to +point." + (save-excursion + (when (nth 4 parse-status) + (goto-char (nth 8 parse-status)) + (skip-chars-backward " \t") + (not (bolp))))) + + +(defun js-block-comment-p (parse-status) + "Return non-nil if inside a block comment. PARSE-STATUS is the +result of `parse-partial-regexp' from beginning of buffer to +point." + (save-excursion + (save-match-data + (when (nth 4 parse-status) + (goto-char (nth 8 parse-status)) + (looking-at "/\\*"))))) + + +(defun javascript-fill-paragraph (&optional justify) + "If inside a comment, fill the current comment paragraph. +Trailing comments are ignored." + (interactive) + (let ((parse-status (parse-partial-sexp (point-min) (point)))) + (when (and (nth 4 parse-status) + (not (js-trailing-comment-p parse-status))) + (if (js-block-comment-p parse-status) + (js-fill-block-comment-paragraph parse-status justify) + (js-fill-sline-comments parse-status justify)))) + t) + + +;; --- Imenu --- + +(defconst js-imenu-generic-expression + (list + (list + nil + "function\\s-+\\(\\w+\\)\\s-*(" + 1)) + "Regular expression matching top level procedures. Used by imenu.") + + +;; --- Main Function --- + +;;;###autoload +(defun javascript-mode () + "Major mode for editing JavaScript source text. + +Key bindings: + +\\{javascript-mode-map}" + (interactive) + (kill-all-local-variables) + + (use-local-map javascript-mode-map) + (set-syntax-table javascript-mode-syntax-table) + (set (make-local-variable 'indent-line-function) 'javascript-indent-line) + (set (make-local-variable 'font-lock-defaults) (list js-font-lock-keywords)) + + (set (make-local-variable 'parse-sexp-ignore-comments) t) + + ;; Comments + (setq comment-start "// ") + (setq comment-end "") + (set (make-local-variable 'fill-paragraph-function) + 'javascript-fill-paragraph) + + ;; Make c-mark-function work + (setq c-nonsymbol-token-regexp "!=\\|%=\\|&[&=]\\|\\*[/=]\\|\\+[+=]\\|-[=-]\\|/[*/=]\\|<\\(?:<=\\|[<=]\\)\\|==\\|>\\(?:>\\(?:>=\\|[=>]\\)\\|[=>]\\)\\|\\^=\\||[=|]\\|[]!%&(-,./:-?[{-~^-]" + c-stmt-delim-chars "^;{}?:" + c-syntactic-ws-end "[ \n \f/]" + c-syntactic-eol "\\(\\s \\|/\\*\\([^*\n ]\\|\\*[^/\n ]\\)*\\*/\\)*\\(\\(/\\*\\([^*\n ]\\|\\*[^/\n ]\\)*\\|\\\\\\)?$\\|//\\)") + + ;; Imenu + (setq imenu-case-fold-search nil) + (set (make-local-variable 'imenu-generic-expression) + js-imenu-generic-expression) + + (setq major-mode 'javascript-mode) + (setq mode-name "JavaScript") + (run-hooks 'javascript-mode-hook)) + + +(provide 'javascript-mode) +;;; javascript.el ends here diff --git a/emacs/lacarte.el b/emacs/lacarte.el new file mode 100644 index 0000000..98e543e --- /dev/null +++ b/emacs/lacarte.el @@ -0,0 +1,605 @@ +;;; lacarte.el --- Execute menu items as commands, with completion. +;; +;; Filename: lacarte.el +;; Description: Execute menu items as commands, with completion. +;; Author: Drew Adams +;; Maintainer: Drew Adams +;; Copyright (C) 2005-2010, Drew Adams, all rights reserved. +;; Created: Fri Aug 12 17:18:02 2005 +;; Version: 22.0 +;; Last-Updated: Fri Jun 25 21:05:15 2010 (-0700) +;; By: dradams +;; Update #: 632 +;; URL: http://www.emacswiki.org/cgi-bin/wiki/lacarte.el +;; Keywords: menu-bar, menu, command, help, abbrev, minibuffer, keys, +;; completion, matching, local, internal, extensions, +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Q. When is a menu not a menu? A. When it's a la carte. +;; +;; Library La Carte lets you execute menu items as commands, with +;; completion. You can use it as an alternative to standard library +;; `tmm.el'. +;; +;; Type a menu item. Completion is available. Completion candidates +;; are of the form menu > submenu > subsubmenu > ... > menu item. +;; For example: +;; +;; File > Open Recent > Cleanup list +;; File > Open Recent > Edit list... +;; +;; When you choose a menu-item candidate, the corresponding command +;; is executed. +;; +;; Put this in your init file (~/.emacs): +;; +;; (require 'lacarte) +;; +;; Suggested key bindings: +;; +;; (global-set-key [?\e ?\M-x] 'lacarte-execute-command) +;; (global-set-key [?\M-`] 'lacarte-execute-menu-command) +;; (global-set-key [f10] 'lacarte-execute-menu-command) +;; +;; (The latter two replace standard bindings for `tmm-menubar'. On +;; MS Windows, `f10' is normally bound to `menu-bar-open', which uses +;; the Windows native keyboard access to menus.) +;; +;; To really take advantage of La Carte, use it together with +;; Icicles. Icicles is not required to be able to use La Carte, but +;; it enhances the functionality of `lacarte.el' considerably. +;; (Note: `lacarte.el' was originally called `icicles-menu.el'.) +;; +;; If you use MS Windows keyboard accelerators, consider using +;; `lacarte-remove-w32-keybd-accelerators' as the value of +;; `lacarte-convert-menu-item-function'. It removes any unescaped +;; `&' characters (indicating an accelerator) from the menu items. +;; One library that adds keyboard accelerators to your menu items is +;; `menuacc.el', by Lennart Borgman (< l e n n a r t . b o r g m a n +;; @ g m a i l . c o m >). +;; +;; +;; Commands defined here: +;; +;; `lacarte-execute-command', `lacarte-execute-menu-command'. +;; +;; Options defined here: `lacarte-convert-menu-item-function'. +;; +;; Non-interactive functions defined here: +;; +;; `lacarte-escape-w32-accel', `lacarte-get-a-menu-item-alist', +;; `lacarte-get-a-menu-item-alist-1', +;; `lacarte-get-overall-menu-item-alist', `lacarte-menu-first-p', +;; `lacarte-remove-w32-keybd-accelerators'. +;; +;; Internal variables defined here: +;; +;; `lacarte-history', `lacarte-menu-items-alist'. +;; +;; +;; Getting Started +;; --------------- +;; +;; In your init file (`~/.emacs'), bind `ESC M-x' as suggested above: +;; +;; (global-set-key [?\e ?\M-x] 'lacarte-execute-command) +;; +;; Type `ESC M-x' (or `ESC ESC x', which is the same thing). You are +;; prompted for a command or menu command to execute. Just start +;; typing its name. Each menu item's full name, for completion, has +;; its parent menu names as prefixes. +;; +;; ESC M-x +;; Command: +;; Command: t [TAB] +;; Command: Tools > +;; Command: Tools > Compa [TAB] +;; Command: Tools > Compare (Ediff) > Two F [TAB] +;; Command: Tools > Compare (Ediff) > Two Files... [RET] +;; +;; +;; Not Just for Wimps and Noobs Anymore +;; ------------------------------------ +;; +;; *You* don't use menus. Nah, they're too slow! Only newbies and +;; wimps use menus. Well not any more. Use the keyboard to access +;; any menu item, without knowing where it is or what its full name +;; is. Type just part of its name and use completion to get the +;; rest: the complete path and item name. +;; +;; +;; Commands and Menu Commands +;; -------------------------- +;; +;; You can bind either `lacarte-execute-menu-command' or +;; `lacarte-execute-command' to a key such as `ESC M-x'. +;; +;; `lacarte-execute-menu-command' uses only menu commands. +;; `lacarte-execute-command' lets you choose among ordinary Emacs +;; commands, in addition to menu commands. You can use a prefix arg +;; with `lacarte-execute-command' to get the same effect as +;; `lacarte-execute-menu-command'. +;; +;; Use `lacarte-execute-command' if you don't care whether a command +;; is on a menu. Then, if you want a command that affects a buffer, +;; just type `buf'. This is especially useful if you use Icicles - +;; see below. +;; +;; By default, in Icicle mode, `ESC M-x' is bound to +;; `lacarte-execute-command', and `M-`' is bound to +;; `lacarte-execute-menu-command'. +;; +;; +;; Icicles Enhances Dining A La Carte +;; ---------------------------------- +;; +;; Use Icicles with La Carte to get more power and convenience. +;; +;; It is Icicles that lets you choose menu items a la carte, in fact. +;; That is, you can access them directly, wherever they might be in +;; the menu hierachy. Without Icicles, you are limited to choosing +;; items by their menu-hierarchy prefixes, and you must complete the +;; entire menu prefix to the item, from the top of the menu on down. +;; With Icicles, you can directly match any parts of a menu item and +;; its hierarchy path. Icicles is here: +;; http://www.emacswiki.org/cgi-bin/wiki/Icicles. +;; +;; Type any part of a menu-item, then use the Page Up and Page Down +;; keys (`prior' and `next') to cycle through all menu commands that +;; contain the text you typed somewhere in their name. You can match +;; within any menu or within all menus; that is, you can match any +;; part(s) of the menu-hierachy prefix. +;; +;; You can use `S-TAB' to show and choose from all such "apropos +;; completions", just as you normally use `TAB' to show all prefix +;; completions (that is, ordinary completions). Vanilla, prefix +;; completion is still available using `TAB', and you can cycle +;; through the prefix completions using the arrow keys. +;; +;; You can use Icicles "progressive completion" to match multiple +;; parts of a menu item separately, in any order. For example, if +;; you want a menu command that has to do with buffers and +;; highlighting, type `buf M-SPC hig S-TAB'. +;; +;; Icicles apropos completion also lets you type a regular expression +;; (regexp) - it is matched against all of the possible menu items. +;; So, for instance, you could type `^e.+buff [next] [next]...' to +;; quickly cycle to menu command `Edit > Go To > Goto End of Buffer'. +;; Or type `.*print.*buf S-TAB' to choose from the list of all menu +;; commands that match `print' followed somewhere by `buf'. +;; +;; If you know how to use regexps, you can easily and quickly get to +;; a menu command you want, or at least narrow the list of candidates +;; for completion and cycling. +;; +;; Additional benefits of using Icicles with La Carte: +;; +;; * When you cycle to a candidate menu item, or you complete to one +;; (entirely), the Emacs command associated with the menu item is +;; shown in the mode line of buffer `*Completions*'. +;; +;; * You can use `M-h' to complete your minibuffer input against +;; commands, including menu-item commands, that you have entered +;; previously. You can also use the standard history keys +;; (e.g. `M-p', `M-r') to access these commands. +;; +;; +;; Menu Organization Helps You Find a Command +;; ------------------------------------------ +;; +;; Unlike commands listed in a flat `*Apropos*' page, menu items are +;; organized, grouped logically by common area of application +;; (`File', `Edit',...). This grouping is also available when +;; cycling completion candidates using Icicles, and you can take +;; advantage of it to hasten your search for the right command. +;; +;; You want to execute a command that puts the cursor at the end of a +;; buffer, but you don't remember its name, what menu it might be a +;; part of, or where it might appear in that (possibly complex) menu. +;; With Icicles and La Carte, you type `ESC M-x' and then type +;; `buffer' at the prompt. You use the Page Up and Page Down keys to +;; cycle through all menu items that contain the word `buffer'. +;; +;; There are lots of such menu items. But all items from the same +;; menu (e.g. `File') are grouped together. You cycle quickly (not +;; reading) to the `Edit' menu, because you guess that moving the +;; cursor has more to do with editing than with file operations, tool +;; use, buffer choice, help, etc. Then you cycle more slowly among +;; the `buffer' menu items in the `Edit' menu. You quickly find +;; `Edit > Go To > Goto End of Buffer'. QED. +;; +;; +;; Learn About Menu Items By Exploring Them +;; ---------------------------------------- +;; +;; With Icicles, you can display the complete documentation (doc +;; string) for the command corresponding to each menu item, as the +;; item appears in the minibuffer. To do this, just cycle menu-item +;; candidates using `C-down' or `C-next', instead of `[down]' or +;; `[next]'. The documentation appears in buffer `*Help*'. +;; +;; In sum, if you use La Carte, you will want to use it with Icicles +;; - enjoy! +;; +;; +;; To Do? +;; ------ +;; +;; 1. Provide sorting by menu-bar order, instead of alphabetically. +;; 2. Echo key bindings for each completed menu item. +;; +;; 3. Maybe use tmm-get-bind? + +;;(@> "Index") +;; +;; If you have library `linkd.el' and Emacs 22 or later, load +;; `linkd.el' and turn on `linkd-mode' now. It lets you easily +;; navigate around the sections of this doc. Linkd mode will +;; highlight this Index, as well as the cross-references and section +;; headings throughout this file. You can get `linkd.el' here: +;; http://dto.freeshell.org/notebook/Linkd.html. +;; +;; (@> "Change log") +;; (@> "User Options") +;; (@> "Internal Variables") +;; (@> "Functions") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;;(@* "Change log") +;; +;; 2010/06/26 dadams +;; lacarte-execute-command: Protected Icicles vars with boundp. Thx to Alexey Romanov. +;; 2010/05/11 dadams +;; lacarte-get-a-menu-item-alist-1: Add keyboard shortcuts to item names. +;; Applied Icicles renamings (belatedly): +;; icicle-sort-functions-alist to icicle-sort-orders-alist, +;; icicle-sort-function to icicle-sort-comparer. +;; 2009/12/25 dadams +;; Added: lacarte-execute-command, lacarte-menu-first-p. +;; lacarte-get-a-menu-item-alist-1: Handle :filter (e.g. File > Open Recent submenus). +;; lacarte-execute-menu-command: +;; Just let-bind lacarte-menu-items-alist - don't use unwind-protect. +;; lacarte-get-overall-menu-item-alist: Reset lacarte-menu-items-alist to nil. +;; lacarte-get-a-menu-item-alist: Set to the return value. +;; 2009/07/29 dadams +;; Added: lacarte-history. +;; lacarte-execute-menu-command: +;; Use lacarte-history as the history list. Use strict completion. +;; 2009/07/26 dadams +;; lacarte-execute-menu-command: Use icicle-interactive-history as the history list. +;; 2008/08/28 dadams +;; Renamed from alacarte to lacarte. Confusion with alacarte Ubuntu source package. +;; 2008/05/21 dadams +;; Renamed library icicles-menu.el to alacarte.el. +;; alacarte-execute-menu-command: Case-insensitive completion, by default. +;; 2008/05/20 dadams +;; icicle-get-a-menu-item-alist-1: Don't add non-selectable item to alist. +;; 2006/12/22 dadams +;; icicle-convert-menu-item-function: Use choice as :type, allowing nil. +;; :group 'icicles -> :group 'Icicles. +;; 2006/10/16 dadams +;; icicle-get-overall-menu-item-alist: Include minor-mode keymaps. +;; 2006/03/16 dadams +;; Added to Commentary. +;; 2006/02/18 dadams +;; icicle-execute-menu-command: \s -> \\s. (Thx to dslcustomer-211-74.vivodi.gr.) +;; 2006/01/07 dadams +;; Added :link for sending bug reports. +;; 2006/01/06 dadams +;; Changed defgroup to icicles-menu from icicles. +;; Added :link. +;; 2005/11/08 dadams +;; icicle-execute-menu-command: +;; Reset icicle-menu-items-alist in unwind-protect. +;; Fix for dynamic menus Select and Paste, Buffers, and Frames: +;; Treat special cases of last-command-event. +;; icicle-get-overall-menu-item-alist: setq result of sort. +;; 2005/11/05 dadams +;; Replaced icicle-menu-items with icicle-menu-items-alist (no need for both). +;; icicle-execute-menu-command: Set, don't bind icicle-menu-items-alist. +;; 2005/08/23 dadams +;; icicle-execute-menu-command: renamed alist to icicle-menu-items-alist, so can +;; refer to it unambiguously in icicle-help-on-candidate (in icicles.el). +;; 2005/08/19 dadams +;; Added: icicle-convert-menu-item-function, icicle-remove-w32-keybd-accelerators, +;; icicle-escape-w32-accel. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(unless (fboundp 'replace-regexp-in-string) (require 'subr-21 nil t)) + +;;;;;;;;;;;;;;;;;;;;;;;;; + +;;(@* "User Options") + +;;; User Options ------------------------------------------- + +(defgroup lacarte nil + "Execute menu items as commands, with completion." + :prefix "lacarte-" :group 'menu + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject= +lacarte.el bug: \ +&body=Describe bug here, starting with `emacs -q'. \ +Don't forget to mention your Emacs and library versions.")) + :link '(url-link :tag "Other Libraries by Drew" + "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries") + :link '(url-link :tag "Download" "http://www.emacswiki.org/cgi-bin/wiki/lacarte.el") + :link '(url-link :tag "Description" "http://www.emacswiki.org/cgi-bin/wiki/LaCarte") + :link '(emacs-commentary-link :tag "Commentary" "lacarte.el") + ) + +(defcustom lacarte-convert-menu-item-function nil + "*Function to call to convert a menu item. +Used by `lacarte-execute-menu-command'. A typical use would be to +remove the `&' characters used in MS Windows menus to define keyboard +accelerators. See `lacarte-remove-w32-keybd-accelerators'." + :type '(choice (const :tag "None" nil) function) :group 'lacarte) + +;; $$$ NOT YET IMPLEMENTED +;; (defcustom lacarte-sort-menu-bar-order-flag nil +;; "*Non-nil means that `lacarte-execute-menu-command' uses menu-bar order. +;; Nil means use alphabetic order. +;; The order is what is used for completion. +;; Note: Using a non-nil value imposes an extra sorting operation, which +;; slows down the creation of the completion-candidates list." +;; :type 'boolean :group 'lacarte) + +;;; Internal Variables ------------------------------------- + +(defvar lacarte-history nil "History for menu items read using La Carte completion.") + +;; This is used also in `icicle-help-on-candidate', which is defined in Icicles +;; (library `icicles-mcmd.el'). +(defvar lacarte-menu-items-alist nil + "Alist of pairs (MENU-ITEM . COMMAND). +The pairs are defined by the current local and global keymaps. +MENU-ITEM is a menu item, with ancestor-menu prefixes. + Example: `(\"Files > Insert File...\" . insert-file)'. +COMMAND is the command bound to the menu item.") + +;;; Functions ------------------------------- + +(defun lacarte-execute-command (&optional no-commands-p) + "Execute a menu-bar menu command or an ordinary command. +Type a menu item or a command name. Completion is available. +With a prefix arg, only menu items are available. +Completion is not case-sensitive. However, if you use Icicles, then +you can use `C-A' in the minibuffer to toggle case-sensitivity. + +If you use Icicles, then you can also sort the completion candidates +in different ways, using `C-,'. With Icicles, by default menu items +are sorted before non-menu commands, and menu items are highlighted +using face `icicle-special-candidate'." + (interactive "P") + (let ((lacarte-menu-items-alist (lacarte-get-overall-menu-item-alist)) + (completion-ignore-case t) ; Not case-sensitive, by default. + (icicle-special-candidate-regexp (and (not no-commands-p) ".* > \\(.\\|\n\\)*")) + (icicle-sort-orders-alist (and (boundp 'icicle-sort-orders-alist) + (if no-commands-p + icicle-sort-orders-alist + (cons '("menu items first" + . lacarte-menu-first-p) + icicle-sort-orders-alist)))) + (icicle-sort-comparer (and (boundp 'icicle-sort-comparer) + (if no-commands-p + icicle-sort-comparer + 'lacarte-menu-first-p))) + choice cmd) + (unless no-commands-p + (mapatoms (lambda (symb) + (when (commandp symb) + (push (cons (symbol-name symb) symb) lacarte-menu-items-alist))))) + (setq choice (completing-read (if no-commands-p "Menu command: " "Command: ") + lacarte-menu-items-alist nil t nil 'lacarte-history) + cmd (cdr (assoc choice lacarte-menu-items-alist))) + (unless cmd (error "No such menu command")) + ;; Treat special cases of `last-command-event', reconstructing it for + ;; menu items that get their meaning from the click itself. + (cond ((eq cmd 'menu-bar-select-buffer) + (string-match " >\\s-+\\(.+\\)\\s-+\\*?%?\\s-+\\S-*\\s-*$" choice) + (setq choice (substring choice (match-beginning 1) (match-end 1))) + (when (string-match " \\*?%?" choice) + (setq choice (substring choice 0 (match-beginning 0)))) + (setq last-command-event choice)) + ((eq cmd 'menu-bar-select-yank) + (string-match "Edit > Select and Paste > \\(.*\\)$" choice) + (setq last-command-event + (substring choice (match-beginning 1) (match-end 1)))) + ((eq cmd 'menu-bar-select-frame) + (string-match " >\\s-[^>]+>\\s-+\\(.+\\)$" choice) + (setq choice (substring choice (match-beginning 1) (match-end 1))) + (setq last-command-event choice))) + (call-interactively cmd))) + +(defun lacarte-menu-first-p (s1 s2) + "Return non-nil if S1 is a menu item and S2 is not." + (save-match-data + (and (string-match " > " s1) (not (string-match " > " s2))))) + +(defun lacarte-execute-menu-command () + "Execute a menu-bar menu command. +Type a menu item. Completion is available. +Completion is not case-sensitive. However, if you use Icicles, then +you can use `C-A' in the minibuffer to toggle case-sensitivity. +If you use Icicles, then you can also sort the completion candidates +in different ways, using `C-,'." + (interactive) + (let* ((lacarte-menu-items-alist (lacarte-get-overall-menu-item-alist)) + (completion-ignore-case t) ; Not case-sensitive, by default. + (menu-item (completing-read "Menu command: " + lacarte-menu-items-alist + nil t nil 'lacarte-history)) + (cmd (cdr (assoc menu-item lacarte-menu-items-alist)))) + (unless cmd (error "No such menu command")) + ;; Treat special cases of `last-command-event', reconstructing it for + ;; menu items that get their meaning from the click itself. + (cond ((eq cmd 'menu-bar-select-buffer) + (string-match " >\\s-+\\(.+\\)\\s-+\\*?%?\\s-+\\S-*\\s-*$" + menu-item) + (setq menu-item (substring menu-item (match-beginning 1) (match-end 1))) + (when (string-match " \\*?%?" menu-item) + (setq menu-item (substring menu-item 0 (match-beginning 0)))) + (setq last-command-event menu-item)) + ((eq cmd 'menu-bar-select-yank) + (string-match "Edit > Select and Paste > \\(.*\\)$" menu-item) + (setq last-command-event + (substring menu-item (match-beginning 1) (match-end 1)))) + ((eq cmd 'menu-bar-select-frame) + (string-match " >\\s-[^>]+>\\s-+\\(.+\\)$" menu-item) + (setq menu-item (substring menu-item (match-beginning 1) (match-end 1))) + (setq last-command-event menu-item))) + (call-interactively cmd))) + +(defun lacarte-get-overall-menu-item-alist () + "Alist formed from menu items in current active keymaps. +See `lacarte-get-a-menu-item-alist' for the structure. +As a side effect, this modifies `lacarte-get-a-menu-item-alist' and +then resets it to ()" + (let ((alist + (apply #'nconc + (lacarte-get-a-menu-item-alist (assq 'menu-bar (current-local-map))) + (lacarte-get-a-menu-item-alist (assq 'menu-bar (current-global-map))) + (mapcar (lambda (map) (lacarte-get-a-menu-item-alist (assq 'menu-bar map))) + (current-minor-mode-maps))))) + (setq lacarte-menu-items-alist ()) + (if nil;; `lacarte-sort-menu-bar-order-flag' ; Not yet implemented. + (setq alist (sort alist SOME-PREDICATE)) + alist))) + +(defun lacarte-get-a-menu-item-alist (keymap) + "Alist of pairs (MENU-ITEM . COMMAND) defined by KEYMAP. +KEYMAP is any keymap that has menu items. +MENU-ITEM is a menu item, with ancestor-menu prefixes. + Example: `(\"Files > Insert File...\" . insert-file)'. +COMMAND is the command bound to the menu item. +Returns `lacarte-menu-items-alist' which it modifies." + (setq lacarte-menu-items-alist ()) + (lacarte-get-a-menu-item-alist-1 keymap) + (setq lacarte-menu-items-alist (nreverse lacarte-menu-items-alist))) + +(defun lacarte-get-a-menu-item-alist-1 (keymap &optional root) + "Helper function for `lacarte-get-a-menu-item-alist'. +This calls itself recursively, to process submenus. +Returns `lacarte-menu-items-alist', which it modifies." + (let ((scan keymap)) + (setq root (or root)) ; nil, for top level. + (while (consp scan) + (if (atom (car scan)) + (setq scan (cdr scan)) + (let ((defn (cdr (car scan))) + composite-name) + ;; Get REAL-BINDING for the menu item. + (cond + ;; (menu-item ITEM-STRING): non-selectable item - skip it. + ((and (eq 'menu-item (car-safe defn)) + (null (cdr-safe (cdr-safe defn)))) + (setq defn nil)) ; So `keymapp' test, below, fails. + + ;; (ITEM-STRING): non-selectable item - skip it. + ((and (stringp (car-safe defn)) (null (cdr-safe defn))) + (setq defn nil)) ; So `keymapp' test, below, fails. + + ;; (menu-item ITEM-STRING REAL-BINDING . PROPERTIES), with `:filter' + ((and (eq 'menu-item (car-safe defn)) + (member :filter (cdr (cddr defn)))) + (let ((filt (cadr (member :filter (cdr (cddr defn)))))) + (setq composite-name + (concat root (and root " > ") (eval (cadr defn)) + (let ((keys (car-safe (cdr-safe (cdr-safe (cdr-safe defn)))))) + (and (consp keys) (stringp (cdr keys)) (cdr keys))))) + (setq defn (if (functionp filt) ; Apply the filter to REAL-BINDING. + (funcall filt (car (cddr defn))) + (car (cddr defn)))))) + + ;; (menu-item ITEM-STRING REAL-BINDING . PROPERTIES) + ((eq 'menu-item (car-safe defn)) + (setq composite-name + (concat root (and root " > ") (eval (cadr defn)) + (let ((keys (car-safe (cdr-safe (cdr-safe (cdr-safe defn)))))) + (and (consp keys) (stringp (cdr keys)) (cdr keys))))) + (setq defn (car (cddr defn)))) + + ;; (ITEM-STRING . REAL-BINDING) or + ;; (ITEM-STRING [HELP-STRING] (KEYBD-SHORTCUTS) . REAL-BINDING) + ((stringp (car-safe defn)) + (setq composite-name (concat root (and root " > ") (eval (car defn)))) + (setq defn (cdr defn)) + ;; Skip HELP-STRING + (when (stringp (car-safe defn)) (setq defn (cdr defn))) + ;; Skip (KEYBD-SHORTCUTS): cached key-equivalence data for menu items. + ;; But first add shortcuts to composite name. + (when (and (consp defn) (consp (car defn))) + (when (stringp (cdar defn)) ; Add shortcuts to name. + (setq composite-name (concat composite-name (cdar defn)))) + (setq defn (cdr defn))))) + + ;; If REAL-BINDING is a keymap, then recurse on it. + (when (keymapp defn) + ;; Follow indirections to ultimate symbol naming a command. + (while (and (symbolp defn) (fboundp defn) (keymapp (symbol-function defn))) + (setq defn (symbol-function defn))) + (if (eq 'keymap (car-safe defn)) + (lacarte-get-a-menu-item-alist-1 (cdr defn) composite-name) + (lacarte-get-a-menu-item-alist-1 (symbol-function defn) composite-name))) + + ;; Add menu item + command pair to `lacarte-menu-items-alist' alist. + ;; Don't add it if `composite-name' is nil - that's a non-selectable item. + (when (and root composite-name (not (keymapp defn))) + (setq lacarte-menu-items-alist + (cons + (cons (if (and (functionp lacarte-convert-menu-item-function) + (stringp composite-name)) ; Could be nil + (funcall lacarte-convert-menu-item-function composite-name) + composite-name) + defn) + lacarte-menu-items-alist)))) + (when (consp scan) (setq scan (cdr scan))))) + lacarte-menu-items-alist)) + +(defun lacarte-remove-w32-keybd-accelerators (menu-item) + "Remove `&' characters that define keyboard accelerators in MS Windows. +\"&&\" is an escaped `&' - it is replaced by a single `&'. +This is a candidate value for `lacarte-convert-menu-item-function'." + (replace-regexp-in-string "&&?" 'lacarte-escape-w32-accel menu-item)) + +(defun lacarte-escape-w32-accel (match-string) + "If STRING is \"&&\", then return \"&\". Else return \"\"." + (if (> (length match-string) 1) "&" "")) + +;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'lacarte) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; lacarte.el ends here diff --git a/emacs/ll-debug.el b/emacs/ll-debug.el new file mode 100644 index 0000000..713ec41 --- /dev/null +++ b/emacs/ll-debug.el @@ -0,0 +1,634 @@ +;; -*- Emacs-Lisp -*- + +;;; ll-debug.el --- low level debug tools + +;; Copyright (C) 2002-2005 Claus Brunzema <mail@cbrunzema.de> + +;; http://www.cbrunzema.de/software.html#ll-debug + +;; Version: 2.0.0 +;; $Id: ll-debug.el,v 1.22 2004/12/28 22:23:16 chb Exp $ + +;; 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. +;; +;; It 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, 675 Mass Ave, Cambridge, MA 02139, USA. +;; ----------------------------------------------------------------------- + + +;;; Commentary: + +;; ll-debug.el provides commands to support a low level debug style. +;; It features quick insertion of various debug output statements and +;; improved functions for commenting and uncommenting chunks of code. +;; +;; I don't use debuggers very much. I know they can be a big help in +;; some situations and I tried some of them, but I find it almost +;; always more direct/convenient/enlightening to put a quick 'printf' +;; into a critical area to see what is happening than to fire up a big +;; clumsy extra program where it takes me ages just to step through to +;; the interesting point. In order to avoid repeated typing of +;; 'printf("I AM HERE\n");' and similar stuff, I created +;; `ll-debug-insert'. It inserts a statement into your +;; sourcecode that will display a debug message. It generates +;; unique messages on each invocation (the message consists of a big +;; fat DEBUG together with a counter and the current filename). +;; +;; See variable `ll-debug-statement-alist' if you want to know which +;; modes are currently supported by ll-debug. You can add new modes +;; with `ll-debug-register-mode'. +;; +;; When I have found the buggy spot, I like to keep a version of the +;; old code in place, just in case I mess things up. +;; `ll-debug-copy-and-comment-region-or-line' helps here, it makes a +;; copy of the current line (or the current region, if active) and +;; comments out the original version. +;; +;; I always missed a keystroke that toggles the 'comment state' of a +;; line (or region) of sourcecode. I need to turn a line or a block of +;; code on and off quickly. `ll-debug-toggle-comment-region-or-line' +;; does just that. +;; +;; Finally, if you want to spit out the values of a lot of variables +;; you can use `ll-debug-insert' with a C-u prefix arg. It calls +;; mode-specific skeletons that keep asking for variable names (and +;; sometimes format specifiers) in the minibuffer. If you just press +;; return here the skeleton interaction ends and a statement to print +;; the names and the values of the variables is inserted in the +;; buffer. +;; +;; If you want to get rid of the debug messages, use +;; `ll-debug-revert'. It finds and removes the lines with the debug +;; output statements, asking for confirmation before it removes +;; anything. + + +;; Prerequisites: +;; +;; I made the latest version of ll-debug with the following emacs: +;; GNU Emacs 21.3.1 +;; Please let me know if other versions work. + + +;; Installation: +;; +;; Get the newest version of ll-debug.el via +;; +;; http://www.cbrunzema.de/software.html#ll-debug +;; +;; and put it in your load-path. Add the following form to your init +;; file (~/.emacs or ~/.xemacs/init.el): +;; +;; (require 'll-debug) +;; +;; Now you can bind ll-debug commands to keystrokes yourself or just +;; call `ll-debug-install-suggested-keybindings'. It clobbers C-v, +;; which may not be completely emacs-political-correct, but it happens +;; to be the stuff I use daily, it is only a suggestion, blah, if you +;; don't like it, don't use it blah blah, do it your own way blah bla +;; blah and don't flame me.... +;; `ll-debug-install-suggested-keybindings' installs the following +;; keybindings: +;; +;; C-v C-v ll-debug-toggle-comment-region-or-line +;; C-v v ll-debug-uncomment-region-or-line +;; C-v C-y ll-debug-copy-and-comment-region-or-line +;; C-v C-d ll-debug-insert + + +;; Usage example 1: +;; +;; If you use `ll-debug-install-suggested-keybindings', hitting C-v C-d +;; in a c-mode buffer called 'main.c' produces: +;; +;; printf("DEBUG-1-main.c\n"); +;; +;; a second C-v C-d prints +;; +;; printf("DEBUG-2-main.c\n"); +;; +;; and so on. The following conversation uses the variable output (the +;; part in '[' and ']' takes place in the minibuffer): +;; +;; C-u C-v C-d [ foo <RET> s <RET> bar <RET> d <RET> baz <RET> f <RET> <RET> ] +;; +;; This gives: +;; +;; printf("DEBUG-3-main.c foo:%s bar:%d baz:%f\n", foo, bar, baz); +;; +;; +;; Usage example 2: +;; +;; In a lisp-mode buffer called 'tree.lisp' this: +;; +;; C-v C-d +;; C-v C-d +;; C-u C-v C-d [ foo <RET> bar <RET> baz <RET> <RET> ] +;; +;; produces the following lines: +;; +;; (CL:format t "DEBUG-1-tree.lisp~%") +;; (CL:format t "DEBUG-2-tree.lisp~%") +;; (CL:format t "DEBUG-3-tree.lisp foo:~S bar:~S baz:~S~%" foo bar baz) +;; +;; +;; Usage example 3: +;; +;; The keybindings installed via +;; `ll-debug-install-suggested-keybindings' will call an alternative +;; versions for variable output if one ore more C-u prefix args are +;; given. An alternative version is currently available in (c)perl-mode +;; only. So, in a (c)perl-mode buffer called 'answer.pl' these keys +;; +;; C-u C-u C-v C-d [ @quux <RET> %thud <RET> $grunt <RET> <RET> ] +;; +;; produce: +;; +;; print "DEBUG-1-answer.pl ", Data::Dumper->Dump([\@quux, \%thud, $grunt], [qw/*quux *thud grunt/]), "\n"; + + +;; Customisation: +;; +;; You can use a different string for the debug messages by setting the +;; variable `ll-debug-output-prefix'. If you set it e.g. to "# DEBUG-" +;; your debug output won't disturb gnuplot datafiles anymore. +;; +;; If you don't like c++'s streams, you can request the printf style +;; output by putting the following in your init file: +;; +;; (setcdr (assq 'c++-mode ll-debug-statement-alist) +;; (cdr (assq 'c-mode ll-debug-statement-alist))) +;; +;; +;; If you want to have dynamic output not only according to the major +;; mode, you can substitute functions in `ll-debug-statement-alist'. +;; For example, the following snippet uses prefix 'printk' instead of +;; 'printf' if you are editing c-sources in a file on a path +;; containing a 'linux' component: +;; +;; (setf (ll-debug-struct-prefix (cdr (assq 'c-mode +;; ll-debug-statement-alist))) +;; #'(lambda () +;; (if (string-match "linux" (buffer-file-name)) +;; "printk(" +;; "printf("))) +;; +;; +;; +;; Please read the documentation for `ll-debug-insert' and +;; `ll-debug-expand' to see what is possible. +;; +;; +;; If you want to teach ll-debug new modes, see +;; `ll-debug-register-mode' and consider sending a patch to +;; <mail@cbrunzema.de>. + + +;; History: +;; 2004-12-28 Claus Brunzema +;; * Major rewrite using defstruct. +;; * New ll-debug-insert instead of +;; ll-debug-insert-debug-output and +;; ll-debug-insert-variable-output. +;; * New ll-debug-register-mode. +;; * Version 2.0.0 +;; 2003-05-21 Claus Brunzema +;; * Added java support. +;; * Moved prefix calculation stuff into new +;; ll-debug-insert-debug-output-statement. +;; * Some cleanup. +;; * Version 1.3.0 +;; 2003-05-15 Claus Brunzema +;; * Added ll-debug-install-suggested-keybindings. +;; 2003-03-10 Claus Brunzema +;; * Added package/namespace identifiers to common lisp/c++ code +;; * Version 1.2.6 +;; 2003-03-10 Claus Brunzema +;; * Put in ll-debug-output-prefix instead of the hardcoded +;; default (thanks to Stefan Kamphausen for the idea with +;; gnuplot). +;; * More documentation. +;; * Version 1.2.5 +;; 2003-01-30 Claus Brunzema +;; * added ll-debug-insert-emacs-lisp-variable-output. +;; * ll-debug-insert-perl-variable-output doesn't insert +;; the '$' automatically anymore. That always confused me. +;; * various cleanup and documentation changes. +;; * Version 1.2.3 +;; 2003-01-29 Claus Brunzema +;; * added ll-debug-insert-perl-variable-dumper-output. +;; 2003-01-28 Claus Brunzema +;; * after (un)commenting a single line the point is moved +;; to the next line. +;; 2002-11-20 Claus Brunzema +;; * added ll-debug-insert-scheme-variable-output. +;; * Version 1.2.0 +;; 2002-11-11 Claus Brunzema +;; * added ll-debug-create-next-debug-string (thanks to Scott Frazer). +;; * updated skeletons to use ll-debug-create-next-debug-string. +;; * Version 1.1.0 +;; 2002-11-09 Claus Brunzema +;; * added DEBUG to skeletons. +;; * added ll-debug-revert (thanks to Scott Frazer for the idea). +;; * removed automatic linebreaks from skeletons, so ll-debug-revert +;; doesn't leave half statemets behind. +;; 2002-10-15 Claus Brunzema +;; * fixed ll-debug-region-or-line-comment-start to look +;; for comment-chars starting a line only (thanks to Stefan +;; Kamphausen for the bug report). +;; * Code cleanup. +;; * Version 1.0.0 +;; 2002-09-04 Claus Brunzema +;; * fixed point position after +;; ll-debug-copy-and-comment-region-or-line +;; * Version 0.2.2 +;; 2002-08-17 Claus Brunzema +;; * use (search-forward comment-start ...) instead of +;; (re-search-forward comment-start-skip ...). +;; * use ll-debug-region-or-line-comment-start instead of +;; the optional ignore-current-column argument for +;; ll-debug-region-or-line-start. +;; * ll-debug-copy-and-comment-region-or-line works correctly +;; now if point is in the middle of the line. +;; * Version 0.2.1 +;; 2002-08-11 Claus Brunzema +;; * Variable output support for Common Lisp, perl and c. +;; * Various cleanup. +;; * Version 0.2.0 +;; 2002-08-08 Claus Brunzema +;; * Uncommenting doesn't check the current column anymore +;; (thanks to Stefan Kamphausen). +;; * More blurb. +;; * Version 0.1.1 +;; 2002-08-07 Claus Brunzema +;; * First public version 0.1.0 + + +;; ToDo: +;; * Check if the strange log calculation in ll-debug-insert is really +;; necessary. I want the number of C-u keypresses to dispatch +;; alternatives on the content slot value of a ll-debug-struct, but +;; every C-u multiplies prefix-numeric-value by 4. Is there a better +;; way to do this? +;; * Make preferred output stream customizable. + + +;;; Code: + +(require 'skeleton) +(require 'cl) + +;; Struct------------------------------------------------------------------ +(defstruct ll-debug-struct + "Strings/functions/skeletons to create debug messages for a single mode. +See `ll-debug-statement-alist' and `ll-debug-expand', too." + (prefix "") + (postfix "") + (content '() :type list)) + + +;; Variables -------------------------------------------------------------- +(defvar ll-debug-output-prefix "DEBUG-" + "*Prefix string for debug output messages.") + +(defvar ll-debug-statement-alist () + "Stores mode-specific ll-debug-structs.") + + +;;; gnuemacs / xemacs compatibility --------------------------------------- +(defun ll-debug-region-exists-p () + (if (fboundp 'region-exists-p) + (region-exists-p) ;XEmacs + (and transient-mark-mode mark-active))) ;GNUEmacs + +(defun ll-debug-uncomment-region (beg end) + (if (fboundp 'uncomment-region) + (uncomment-region beg end) ;GNUEmacs + (comment-region beg end -1))) ;XEmacs + + +;;; misc. Functions ------------------------------------------------------- +(defun ll-debug-region-or-line-start () + (save-excursion + (if (ll-debug-region-exists-p) + (progn + (goto-char (region-beginning)) + (point-at-bol)) + (if (= (current-column) (current-indentation)) + (point) + (point-at-bol))))) + +(defun ll-debug-region-or-line-end () + (save-excursion + (if (ll-debug-region-exists-p) + (progn + (goto-char (region-end)) + (unless (bolp) + (forward-line)) + (point)) + (progn + (forward-line) + (point))))) + +(defun ll-debug-install-suggested-keybindings () + "Install suggested keybindings for ll-debug. +This installs the following keybindings (clobbering C-v): + +C-v C-v ll-debug-toggle-comment-region-or-line +C-v v ll-debug-uncomment-region-or-line +C-v C-y ll-debug-copy-and-comment-region-or-line +C-v C-d ll-debug-insert" + (interactive) + (unless (keymapp (global-key-binding '[(control v)])) + (global-unset-key '[(control v)])) + + (define-key global-map '[(control v) (control v)] + #'ll-debug-toggle-comment-region-or-line) + (define-key global-map '[(control v) v] + #'ll-debug-uncomment-region-or-line) + (define-key global-map '[(control v) (control y)] + #'ll-debug-copy-and-comment-region-or-line) + (define-key global-map '[(control v) (control d)] + #'ll-debug-insert)) + + +(defun ll-debug-expand (thing) + "Expands THING into the current buffer. +If THING is a string, it is inserted. +If THING is a list, it is treated as a skeleton (see `skeleton-insert') +If THING is a function, it is funcalled and `ll-debug-expand' is +invoked recursively on the returned value." + (when thing + (etypecase thing + (string + (insert thing)) + (list + (skeleton-insert thing)) + (function + (ll-debug-expand + (funcall thing)))))) + + +;; comment in and out ----------------------------------------------------- +(defun ll-debug-region-or-line-comment-start () + "Find the comment marker at the beginning of the line or region." + (save-excursion + (when (ll-debug-region-exists-p) (goto-char (region-beginning))) + (beginning-of-line) + (skip-chars-forward " \t" (point-at-eol)) + (if (looking-at (regexp-quote comment-start)) + (point) + nil))) + +(defun ll-debug-copy-and-comment-region-or-line () + "Copy the current line/region and comment out the original." + (interactive) + (let* ((start (ll-debug-region-or-line-start)) + (end (ll-debug-region-or-line-end)) + (src-code (buffer-substring start end))) + (goto-char end) + (comment-region start end) + (save-excursion + (insert-string src-code)))) + +(defun ll-debug-comment-region-or-line () + "Comment out the current line or all lines of the region." + (interactive) + (comment-region (ll-debug-region-or-line-start) + (ll-debug-region-or-line-end)) + (unless (ll-debug-region-exists-p) + (forward-line))) + +(defun ll-debug-uncomment-region-or-line () + "Uncomment the current line or all lines of the region." + (interactive) + (ll-debug-uncomment-region (ll-debug-region-or-line-comment-start) + (ll-debug-region-or-line-end)) + (unless (ll-debug-region-exists-p) + (forward-line))) + +(defun ll-debug-toggle-comment-region-or-line () + "Toggle the current line/region between uncommented and commented state." + (interactive) + (if (ll-debug-region-or-line-comment-start) + (ll-debug-uncomment-region-or-line) + (ll-debug-comment-region-or-line))) + + +;; debug output statements ------------------------------------------------ +(defun ll-debug-before-text-p () + "Return t iff point is at bol or in leading whitespace." + (save-excursion + (skip-chars-backward " \t" (point-at-bol)) + (bolp))) + +(defun ll-debug-after-text-p () + "Return t iff point is at eol or in trailing whitespace." + (save-excursion + (skip-chars-forward " \t" (point-at-eol)) + (eolp))) + +(defun ll-debug-open-fresh-line () + "Make room for a debug output statement." + (cond + ((ll-debug-before-text-p) + (open-line 1)) + ((ll-debug-after-text-p) + (open-line 1) + (forward-line)) + (t + (open-line 2) + (forward-line))) + (indent-according-to-mode)) + +(defun ll-debug-register-mode (modes prefix postfix skel1 &rest skels) + "Register mode info in `ll-debug-statement-alist'. +MODES can be a single symbol denoting a mode or a list of mode +symbols. If it is a list, the following info is registered in every +listed mode. PREFIX is the prefix thing for debug statements, POSTFIX +is the postfix thing. SKEL1 and all following SKELS are the content +things. For more information about these, see the documentation of +`ll-debug-insert'. If an entry for a given mode already exists in +`ll-debug-statement-alist', it will be overwritten." + (unless (listp modes) + (setq modes (list modes))) + (push skel1 skels) + (dolist (mode modes) + (setq ll-debug-statement-alist + (cons (cons mode (make-ll-debug-struct :prefix prefix + :postfix postfix + :content skels)) + (assq-delete-all mode ll-debug-statement-alist))))) + +(defun ll-debug-create-next-debug-string () + "Create the next unique debug string." + (let ((max-used 0)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward + (concat (regexp-quote ll-debug-output-prefix) + "\\([0-9]+\\)-") + nil t) + (setq max-used (max max-used + (string-to-number (match-string 1)))))) + (format "%s%d-%s" + ll-debug-output-prefix + (+ 1 max-used) + (if (buffer-file-name) + (file-name-nondirectory (buffer-file-name)) + "nofile")))) + +(defun ll-debug-insert (arg) + "Insert a line of debug output at point according to mode. +Looks up the current mode in `ll-debug-statement-alist'. The prefix +thing of the coressponding ll-debug-struct gets inserted by +`ll-debug-insert'. The number of times C-u was pressed (prefix arg) +determines the entry from the content list of the ll-debug-struct that +gets inserted next. Finally the postfix thing from the ll-debug-struct +is inserted into the current buffer. +" + (interactive "P") + (when (listp arg) + (if (null arg) + (setq arg 0) + (setq arg (floor (/ (log (car arg)) + (log 4)))))) + (let ((mode-data (cdr (assoc major-mode ll-debug-statement-alist)))) + (cond + ((null mode-data) + (message "%s not supported by ll-debug-insert yet." major-mode)) + ((>= arg (length (ll-debug-struct-content mode-data))) + (message "Only %d flavours of debug output defined for %s." + (length (ll-debug-struct-content mode-data)) + major-mode)) + (t + (ll-debug-open-fresh-line) + (ll-debug-expand (ll-debug-struct-prefix mode-data)) + (ll-debug-expand (elt (ll-debug-struct-content mode-data) arg)) + (ll-debug-expand (ll-debug-struct-postfix mode-data)) + (indent-according-to-mode) + (forward-line) + (indent-according-to-mode))))) + +(defun ll-debug-revert () + "Deletes (with confirmation) lines containing the regexp 'DEBUG-[0-9]+-'. +Uses `query-replace-regexp' internally." + (interactive) + (save-excursion + (goto-char (point-min)) + (query-replace-regexp (concat "^.*" + (regexp-quote ll-debug-output-prefix) + "[0-9]+-.*\n") + ""))) + + +;; register modes --------------------------------------------------------- +(ll-debug-register-mode 'scheme-mode + "(begin " "(newline))" + '(nil "(display \"" + (ll-debug-create-next-debug-string) "\")") + '(nil "(display \"" + (ll-debug-create-next-debug-string) "\")" + ("Variable name: " + "(display \" " str ":\")(display " str ")"))) + +(ll-debug-register-mode 'lisp-mode + "(CL:format t " ")" + '(nil "\"" (ll-debug-create-next-debug-string) "~%\"") + '(nil "\"" (ll-debug-create-next-debug-string) + ("Variable name: " + " " str ":~S" + '(progn (setq v1 (concat v1 " " str)) nil) + ) + "~%\" " v1)) + + +(ll-debug-register-mode '(emacs-lisp-mode lisp-interaction-mode) + "(message " ")" + '(nil "\"" (ll-debug-create-next-debug-string) "\"") + '(nil "\"" (ll-debug-create-next-debug-string) + ("Variable name: " + " " str ":%S" + '(progn (setq v1 (concat v1 " " str)) nil)) + "\" " v1)) + +(ll-debug-register-mode '(perl-mode cperl-mode) + "print " ";" + '(nil "\"" (ll-debug-create-next-debug-string) "\\n\"") + '(nil "\"" (ll-debug-create-next-debug-string) + ("Variable: " + " \\" str ":" str) + "\\n\"") + '(nil "\"" (ll-debug-create-next-debug-string) + " \", Data::Dumper->Dump([" + ("Variable: " + str + '(progn + (if (string= "$" (substring str 0 1)) + (setq v1 (concat v1 " " + (substring str 1))) + (progn + (backward-word 1) + (backward-char 1) + (insert "\\") + (forward-char 1) + (forward-word 1) + (setq v1 (concat v1 + " *" + (substring str 1))))) + nil) + ", ") + "], [qw/" v1 "/]), \"\\n\"")) + +(ll-debug-register-mode 'c++-mode + "std::cout << " " << std::endl;" + '(nil "\"" (ll-debug-create-next-debug-string) "\"") + '(nil "\"" (ll-debug-create-next-debug-string) "\"" + ("Variable name: " + " << \" " str ":\" << " str))) + +(ll-debug-register-mode 'c-mode + "printf(" ");" + '(nil "\"" (ll-debug-create-next-debug-string) "\\n\"") + '(nil "\"" (ll-debug-create-next-debug-string) + ("Variable name: " + " " str ":%" + '(progn + (if v1 + (setq v1 (concat v1 ", " str)) + (setq v1 str)) + nil) + (read-string "Format: ")) + "\\n\", " v1)) + +(ll-debug-register-mode '(java-mode jde-mode) + "System.out.println(" ");" + '(nil "\"" (ll-debug-create-next-debug-string) "\"") + '(nil "\"" (ll-debug-create-next-debug-string) "\"" + ("Variable name: " + "+\" " str ":\"+" str))) + +(ll-debug-register-mode 'ruby-mode + "puts " "" + '(nil "\"" (ll-debug-create-next-debug-string) "\"")) + +(ll-debug-register-mode 'sh-mode + "echo " "" + '(nil (ll-debug-create-next-debug-string))) + +(ll-debug-register-mode '(octave-mode matlab-mode) + "disp(" ");" + '(nil "'" (ll-debug-create-next-debug-string) "'")) + +(provide 'll-debug) + +;;; ll-debug.el ends here diff --git a/emacs/malyon.el b/emacs/malyon.el new file mode 100644 index 0000000..423f05b --- /dev/null +++ b/emacs/malyon.el @@ -0,0 +1,3211 @@ +; malyon.el --- mode to execute z code files version 3, 5, 8 + +;; Copyright (C) 1999-2009 Peter Ilberg + +;; Maintainer: Peter Ilberg <peter.ilberg@gmail.com> + +;; Credits: +;; The author would like to thank the following people for reporting +;; bugs, testing, suggesting and/or contributing improvements: +;; Bernhard Barde, Jonathan Craven, Alberto Petrofsky, Alan Shutko + +;;; Commentary: + +;; This package provides a basic interpreter for version 3, 5, 8 z code +;; story files as generated by Inform (C) Graham Nelson and Infocom. + +;; If you encounter a bug please send a report to Peter Ilberg at +;; peter.ilberg@gmail.com. Thank you! + +;; To play a story file simple type M-x malyon and enter the path to the +;; story file. If anything goes wrong and you want to manually clean +;; up type M-x malyon-quit. In addition, you can switch back to a game in +;; progress by typing M-x malyon-restore. + +;; A note on the format of saved game states: + +;; As of version 1.0, Malyon supports the quetzal file format for saved +;; games. Support for this format required changes to several internal +;; data structures (stack frames and catch-throw) that are incompatible +;; with the old implementation. Unfortunately, the old file format for +;; saved games cannot be converted into quetzal. + +;; For backwards compatibility, however, Malyon still supports the old +;; file format. And you can continue to play your old game states. + +;; Because of the incompatibility of the two file formats, Malyon now +;; runs, as follows, in either of two modes: quetzal and compatibility. + +;; - in quetzal mode, game states are saved in quetzal format +;; - in compatibility mode, games states are saved in the old format +;; - loading a game state in quetzal format switches to quetzal mode +;; - loading an old game state switches to compatibility mode +;; - quetzal mode is the default setting + +;; In other words, Malyon will only use the old file format if you've +;; restored a game state saved in the old file format. + +;; Enjoy! + +;;; Code: + +;; global variables - moved here to appease the byte-code compiler + +;; story file information + +(defvar malyon-story-file-name nil + "The name of the story file being executed.") + +(defvar malyon-story-file nil + "The story file which is currently being run.") + +(defvar malyon-story-version nil + "The story file version.") + +(defvar malyon-supported-versions '(3 5 8) + "A list of supported story file versions.") + +;; status and transcript buffers + +(defvar malyon-transcript-buffer nil + "The main transcript buffer of the story file execution.") + +(defvar malyon-transcript-buffer-buffered nil + "Is output in the transcript buffer buffered?") + +(defvar malyon-status-buffer nil + "The status bar buffer of the story file execution.") + +(defvar malyon-status-buffer-lines nil + "The number of lines in the status bar buffer.") + +(defvar malyon-status-buffer-delayed-split nil + "If the number of lines in the status buffer is reduced, +the window configuration is not changed immediately. It +is changed after the next turn (read or read_char).") + +(defvar malyon-status-buffer-point nil + "The point location in the status bar buffer.") + +(defvar malyon-max-column 72 + "Maximum column for text display.") + +;; window management + +(defvar malyon-window-configuration nil + "The current window configuration of the malyon interpreter.") + +(defvar malyon-current-window nil + "The currently active window for text output.") + +;; z machine registers + +(defvar malyon-stack nil + "The stack of the z machine.") + +(defvar malyon-stack-pointer nil + "The stack pointer of the z machine.") + +(defvar malyon-frame-pointer nil + "The frame pointer of the z machine.") + +(defvar malyon-instruction-pointer nil + "The instruction pointer of the z machine.") + +;; game file related global variables + +(defvar malyon-score-game nil + "A flag indicating whether this story uses score or time.") + +(defvar malyon-packed-multiplier nil + "The amount by which packed addresses are multiplied to get byte +addresses.") + +(defvar malyon-global-variables nil + "A pointer to the global variable section in the story file.") + +(defvar malyon-abbreviations nil + "A pointer to the abbreviations in the story file.") + +(defvar malyon-alphabet nil + "The z machine's text alphabet.") + +(defvar malyon-whitespace nil + "A string of whitespace characters recognized by the interpreter.") + +;; object tables + +(defvar malyon-object-table nil + "A pointer to the object table in the story file.") + +(defvar malyon-object-table-entry-size nil + "The size of one entry in the object table.") + +(defvar malyon-object-properties nil + "The number of properties per object minus one.") + +(defvar malyon-object-property-offset nil + "The byte offset of the properties table in the object.") + +;; dictionaries + +(defvar malyon-dictionary nil + "A pointer to the dictionary of the story file.") + +(defvar malyon-dictionary-entry-length nil + "The length of a dictionary entry.") + +(defvar malyon-dictionary-num-entries nil + "The number of dictionary entries.") + +(defvar malyon-dictionary-entries nil + "A pointer to the first dictionary entry.") + +(defvar malyon-dictionary-word-length nil + "The length of a dictionary word.") + +;; game state information + +(defvar malyon-game-state-restart nil + "The machine state for implementing restart.") + +(defvar malyon-game-state-undo nil + "The machine state for implementing undo.") + +(defvar malyon-game-state-quetzal t + "Store game state information for quetzal.") + +;; various + +(defvar malyon-current-face nil + "The current face in which to display text.") + +(defvar malyon-last-cursor-position-after-input nil + "The last cursor position after reading input from the keyboard.") + +;; interactive functions + +(defun malyon (file-name) + "Major mode for playing z3/5/8 story files. +This mode allows execution of version 3, 5, 8 z code story files." + (interactive "fStory file name: ") + (if malyon-story-file + (message "You are already playing a game.") + (if (not (string-match ".*\.z[358]$" file-name)) + (message "%s is not a version 3, 5, or 8 story file." file-name) + (condition-case nil + (malyon-load-story-file file-name) + (error + (malyon-fatal-error "loading of story file failed."))) + (setq malyon-story-version (aref malyon-story-file 0)) + (cond ((memq malyon-story-version malyon-supported-versions) + (condition-case nil + (malyon-initialize) + (error + (malyon-fatal-error "initialization of interpreter failed."))) + (malyon-interpreter)) + (t + (message "%s is not a version 3, 5, or 8 story file." file-name) + (malyon-cleanup)))))) + +(defun malyon-restore () + "Restore the save window configuration for the interpreter." + (interactive) + (condition-case nil + (progn + (malyon-restore-window-configuration) + (malyon-adjust-transcript)) + (error + (malyon-fatal-error "restoring window configuration failed.")))) + +(defun malyon-quit () + "Exit the malyon interpreter." + (interactive) + (if malyon-story-file + (progn + (malyon-restore) + (if (malyon-yes-or-no-p-minibuf "Do you really want to quit? ") + (malyon-cleanup))))) + +(defun malyon-mode () + "This mode provides a basic interpreter for version 3, 5, 8 z code +story files as generated by Inform (C) Graham Nelson and Infocom. + +Note that this package is by no means complete and bug free. +If you encounter a bug please send a report to Peter Ilberg at +peter.ilberg@natinst.com. Thank you! + +To play a story file simple type M-x malyon and enter the path to the +story file. If anything goes wrong and you want to manually clean +up type M-x malyon-quit. In addition, you can switch back to a game in +progress by typing M-x malyon-restore. + +The author would like to thank the following people for reporting +bugs, testing, suggesting and/or contributing improvements: + Bernhard Barde, Jonathan Craven, Alberto Petrofsky, Alan Shutko" + (message "Use M-x malyon if you want to play a zcode game.")) + +;; compatibility functions for GNU emacs + +(if (fboundp 'cadr) + (defalias 'malyon-cadr 'cadr) + (defun malyon-cadr (list) + "Take the cadr of the list." + (car (cdr list)))) + +(if (fboundp 'caddr) + (defalias 'malyon-caddr 'caddr) + (defun malyon-caddr (list) + "Take the caddr of the list." + (car (cdr (cdr list))))) + +(if (fboundp 'cdddr) + (defalias 'malyon-cdddr 'cdddr) + (defun malyon-cdddr (list) + "Take the cdddr of the list." + (cdr (cdr (cdr list))))) + +(if (fboundp 'char-before) + (defalias 'malyon-char-before 'char-before) + (defun malyon-char-before () + "Return the character before the point." + (char-after (- (point) 1)))) + +(if (fboundp 'char-to-int) + (defalias 'malyon-char-to-int 'char-to-int) + (defun malyon-char-to-int (c) + "Convert a character into an integer." + c)) + +(if (fboundp 'characterp) + (defalias 'malyon-characterp 'characterp) + (defun malyon-characterp (x) + "Test for a character." + (and (numberp x) (<= 0 x) (< x 256)))) + +(defun malyon-disable-multibyte () + "Disable multibyte support in the current buffer." + (condition-case nil (set-buffer-multibyte nil) (error))) + +(defun malyon-erase-buffer (&optional buffer) + "Erase the given buffer." + (save-excursion + (if buffer (set-buffer buffer)) + (if (and buffer (eq buffer malyon-transcript-buffer)) + (malyon-begin-section) + (erase-buffer)))) + +(if (fboundp 'int-to-char) + (defalias 'malyon-int-to-char 'int-to-char) + (defun malyon-int-to-char (i) + "Convert an integer into a character." + i)) + +(if (fboundp 'mapc) + (defalias 'malyon-mapc 'mapc) + (defun malyon-mapc (function list) + "Apply fun to every element of args ignoring the results." + (if (null list) + '() + (funcall function (car list)) + (malyon-mapc function (cdr list))))) + +(if (fboundp 'mapcan) + (defalias 'malyon-mapcan 'mapcan) + (defun malyon-mapcan (function list) + "Apply fun to every element of args nconc'ing the result." + (if (null list) + '() + (nconc (funcall function (car list)) + (malyon-mapcan function (cdr list)))))) + +; Do not use the built-in conversion via 'multibyte-char-to-unibyte. +(defun malyon-multibyte-char-to-unibyte (char) + "Convert a multibyte character to unibyte." + char) + +(defun malyon-point-max (&optional buffer) + "Get the point-max of the given buffer." + (save-excursion + (if buffer (set-buffer buffer)) + (point-max))) + +(if (fboundp 'redisplay-frame) + (defalias 'malyon-redisplay-frame 'redisplay-frame) + (defun malyon-redisplay-frame (frame &rest ignore) + "Redisplay the given frame.")) + +(if (fboundp 'remove) + (defalias 'malyon-remove 'remove) + (defun malyon-remove (element list) + "Remove the element from the list." + (cond ((null list) + '()) + ((eq element (car list)) + (malyon-remove element (cdr list))) + ((equal element (car list)) + (malyon-remove element (cdr list))) + (t + (cons (car list) + (malyon-remove element (cdr list))))))) + +(if (fboundp 'set-keymap-name) + (defalias 'malyon-set-keymap-name 'set-keymap-name) + (defun malyon-set-keymap-name (keymap name) + "Set the name of the keymap.")) + +(if (fboundp 'string-to-list) + (defalias 'malyon-string-to-list 'string-to-list) + (defun malyon-string-to-list (s) + "Convert a string into a list of characters." + (let ((i (- (length s) 1)) (l '())) + (while (<= 0 i) + (setq l (cons (aref s i) l) + i (- i 1))) + l))) + +(if (fboundp 'string-to-vector) + (defalias 'malyon-string-to-vector 'string-to-vector) + (defun malyon-string-to-vector (s) + "Convert a string into a vector of characters." + (let* ((i 0) (l (length s)) (v (make-vector l 0))) + (while (< i l) + (aset v i (aref s i)) + (setq i (+ 1 i))) + v))) + +; Do not use the built-in conversion via 'unibyte-char-to-multibyte. +(defun malyon-unibyte-char-to-multibyte (char) + "Convert a unibyte character to multibyte." + char) + +(defun malyon-vector-to-list (v begin end) + "Return a list of elements in v in the range [begin, end)." + (let ((result '())) + (while (< begin end) + (setq result (cons (aref v begin) result)) + (setq begin (+ 1 begin))) + (reverse result))) + +(if (fboundp 'window-displayed-height) + (defalias 'malyon-window-displayed-height 'window-displayed-height) + (defun malyon-window-displayed-height (&optional window) + "Get the height of the window's displayed region." + (- (window-height) 1))) + +(if (fboundp 'yes-or-no-p-minibuf) + (defalias 'malyon-yes-or-no-p-minibuf 'yes-or-no-p-minibuf) + (defun malyon-yes-or-no-p-minibuf (prompt) + "Ask a yes or no question." + (yes-or-no-p prompt))) + +;; global variables for the malyon mode + +(defvar malyon-syntax-table nil + "Syntax table used while in malyon mode (same as in text-mode).") + +(if malyon-syntax-table + '() + (setq malyon-syntax-table (make-syntax-table)) + (modify-syntax-entry ?\" ". " malyon-syntax-table) + (modify-syntax-entry ?\\ ". " malyon-syntax-table) + (modify-syntax-entry ?' "w " malyon-syntax-table)) + +(defvar malyon-keymap-read nil + "Keymap for malyon mode for reading input into a buffer.") + +(defvar malyon-history-saved-up nil + "The saved binding for the up arrow key.") + +(defvar malyon-history-saved-down nil + "The saved binding for the down arrow key.") + +(if malyon-keymap-read + '() + (setq malyon-keymap-read (make-sparse-keymap)) + (malyon-set-keymap-name malyon-keymap-read 'malyon-keymap-read) + (setq malyon-history-saved-up (global-key-binding [up])) + (setq malyon-history-saved-down (global-key-binding [down])) + (define-key malyon-keymap-read "\r" 'malyon-end-input) + (define-key malyon-keymap-read [up] 'malyon-history-previous-char) + (define-key malyon-keymap-read [down] 'malyon-history-next-char) + (define-key malyon-keymap-read "\M-p" 'malyon-history-previous-char) + (define-key malyon-keymap-read "\M-n" 'malyon-history-next-char) + (define-key malyon-keymap-read "\C-a" 'malyon-beginning-of-line) + (define-key malyon-keymap-read "\C-w" 'malyon-kill-region) + (define-key malyon-keymap-read "\C-k" 'malyon-kill-line) + (define-key malyon-keymap-read "\M-d" 'malyon-kill-word) + (define-key malyon-keymap-read "\C-y" 'malyon-yank) + (define-key malyon-keymap-read "\M-y" 'malyon-yank-pop) + (define-key malyon-keymap-read "\C-d" 'malyon-delete-char) + (define-key malyon-keymap-read "\d" 'malyon-backward-delete-char) + (define-key malyon-keymap-read [del] 'malyon-delete-char) + (define-key malyon-keymap-read [backspace] 'malyon-backward-delete-char) + (substitute-key-definition (lookup-key (current-global-map) "a") + 'malyon-self-insert-command + malyon-keymap-read (current-global-map))) + +(defvar malyon-keymap-readchar nil + "Keymap for malyon mode for waiting for input.") + +(if malyon-keymap-readchar + '() + (setq malyon-keymap-readchar (make-sparse-keymap)) + (malyon-set-keymap-name malyon-keymap-readchar 'malyon-keymap-readchar) + (define-key malyon-keymap-readchar "\r" 'malyon-wait-char) + (substitute-key-definition (lookup-key (current-global-map) "a") + 'malyon-wait-char + malyon-keymap-readchar (current-global-map))) + +(defvar malyon-keymap-more nil + "Keymap for malyon mode for browsing through text.") + +(if malyon-keymap-more + '() + (setq malyon-keymap-more (make-sparse-keymap)) + (malyon-set-keymap-name malyon-keymap-more 'malyon-keymap-more) + (define-key malyon-keymap-more "\r" 'malyon-more-char) + (substitute-key-definition (lookup-key (current-global-map) "a") + 'malyon-more-char + malyon-keymap-more (current-global-map))) + +(defvar malyon-keymap-more-status nil + "Keymap for malyon mode for browsing through the status buffer.") + +(if malyon-keymap-more-status + '() + (setq malyon-keymap-more-status (make-sparse-keymap)) + (malyon-set-keymap-name malyon-keymap-more-status 'malyon-keymap-more-status) + (define-key malyon-keymap-more-status "\r" 'malyon-more-char-status) + (substitute-key-definition (lookup-key (current-global-map) "a") + 'malyon-more-char-status + malyon-keymap-more-status (current-global-map))) + +(defvar malyon-faces nil + "An association list of text faces used by the malyon mode.") + +(defun malyon-initialize-faces () + (copy-face 'default 'malyon-face-plain) + (copy-face 'bold 'malyon-face-reverse) + (copy-face 'bold 'malyon-face-bold) + (copy-face 'italic 'malyon-face-italic) + (copy-face 'default 'malyon-face-error) + (set-face-foreground 'malyon-face-error "red") + (setq malyon-faces '((0 . malyon-face-plain) + (1 . malyon-face-reverse) + (2 . malyon-face-bold) + (4 . malyon-face-italic) + (8 . malyon-face-plain)))) + +(defvar malyon-print-separator nil + "A flag indicating whether to print the * * * separator.") + +(defun malyon-begin-section () + "Print a section divider and begin a new section." + (if malyon-print-separator + (progn + (malyon-mapc 'malyon-putchar-transcript '(?\n ?\n ?* ? ?* ? ?*)) + (center-line) + (malyon-mapc 'malyon-putchar-transcript '(?\n ?\n)) + (setq malyon-print-separator nil))) + (narrow-to-region (point-max) (point-max))) + +(if malyon-whitespace + '() + (setq malyon-whitespace (list (malyon-char-to-int ? ) + (malyon-char-to-int ?\t) + (malyon-char-to-int ?\n) + (malyon-char-to-int ?\r)))) + +;; memory utilities + +(defsubst malyon-read-byte (address) + "Read a byte at address in the story file." + (if (<= 0 address) + (aref malyon-story-file address) + (aref malyon-story-file (+ 65536 address)))) + +(defsubst malyon-store-byte (address value) + "Store a byte at address in the story file." + (if (<= 0 address) + (aset malyon-story-file address (logand 255 value)) + (aset malyon-story-file (+ 65536 address) (logand 255 value)))) + +(defsubst malyon-read-word (address) + "Read a word at address in the story file." + (if (<= 0 address) + (logior (lsh (aref malyon-story-file address) 8) + (aref malyon-story-file (+ 1 address))) + (logior (lsh (aref malyon-story-file (+ 65536 address)) 8) + (aref malyon-story-file (+ 65537 address))))) + +(defsubst malyon-store-word (address value) + "Store a word at address in the story file." + (if (<= 0 address) + (progn + (aset malyon-story-file address (logand 255 (lsh value -8))) + (aset malyon-story-file (+ 1 address) (logand 255 value))) + (aset malyon-story-file (+ 65536 address) (logand 255 (lsh value -8))) + (aset malyon-story-file (+ 65537 address) (logand 255 value)))) + +(defsubst malyon-read-code-byte () + "Read the next byte at the program counter location." + (setq malyon-instruction-pointer (+ malyon-instruction-pointer 1)) + (malyon-read-byte (- malyon-instruction-pointer 1))) + +(defsubst malyon-read-code-word () + "Read the next word at the program counter location." + (setq malyon-instruction-pointer (+ malyon-instruction-pointer 2)) + (malyon-read-word (- malyon-instruction-pointer 2))) + +(defsubst malyon-pop-stack () + "Pop a value off the stack." + (if (> 0 malyon-stack-pointer) + (malyon-fatal-error "stack underflow.")) + (setq malyon-stack-pointer (- malyon-stack-pointer 1)) + (aref malyon-stack (+ malyon-stack-pointer 1))) + +(defsubst malyon-read-local-variable (variable) + "Read a local variable." + (aref malyon-stack (+ variable malyon-frame-pointer))) + +(defsubst malyon-read-global-variable (variable) + "Read a global variable." + (malyon-read-word (+ malyon-global-variables (* 2 variable)))) + +(defsubst malyon-read-variable (variable) + "Read a variable." + (cond ((= variable 0) (malyon-pop-stack)) + ((< variable 16) (malyon-read-local-variable variable)) + (t (malyon-read-global-variable (- variable 16))))) + +(defsubst malyon-push-stack (value) + "Push a value onto the stack." + (setq malyon-stack-pointer (+ malyon-stack-pointer 1)) + (aset malyon-stack malyon-stack-pointer value)) + +(defsubst malyon-store-local-variable (variable value) + "Store a value in a local variable." + (aset malyon-stack (+ variable malyon-frame-pointer) value)) + +(defsubst malyon-store-global-variable (variable value) + "Store a value in a global variable." + (malyon-store-word (+ malyon-global-variables (* 2 variable)) value)) + +(defsubst malyon-store-variable (var value) + "Store the value in a variable." + (setq value (logand 65535 value)) + (cond ((= var 0) (malyon-push-stack value)) + ((< var 16) (malyon-store-local-variable var value)) + (t (malyon-store-global-variable (- var 16) value)))) + +;; list of opcodes + +(defvar malyon-opcodes + [malyon-opcode-nop + malyon-opcode-je malyon-opcode-jl + malyon-opcode-jg malyon-opcode-dec-chk + malyon-opcode-inc-chk malyon-opcode-jin + malyon-opcode-test malyon-opcode-or + malyon-opcode-and malyon-opcode-test-attr + malyon-opcode-set-attr malyon-opcode-clear-attr + malyon-opcode-store malyon-opcode-insert-obj + malyon-opcode-loadw malyon-opcode-loadb + malyon-opcode-get-prop malyon-opcode-get-prop-addr + malyon-opcode-get-next-prop malyon-opcode-add + malyon-opcode-sub malyon-opcode-mul + malyon-opcode-div malyon-opcode-mod + malyon-opcode-calls malyon-opcode-calln + malyon-opcode-set-color malyon-opcode-throw + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-je malyon-opcode-jl + malyon-opcode-jg malyon-opcode-dec-chk + malyon-opcode-inc-chk malyon-opcode-jin + malyon-opcode-test malyon-opcode-or + malyon-opcode-and malyon-opcode-test-attr + malyon-opcode-set-attr malyon-opcode-clear-attr + malyon-opcode-store malyon-opcode-insert-obj + malyon-opcode-loadw malyon-opcode-loadb + malyon-opcode-get-prop malyon-opcode-get-prop-addr + malyon-opcode-get-next-prop malyon-opcode-add + malyon-opcode-sub malyon-opcode-mul + malyon-opcode-div malyon-opcode-mod + malyon-opcode-calls malyon-opcode-calln + malyon-opcode-set-color malyon-opcode-throw + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-je malyon-opcode-jl + malyon-opcode-jg malyon-opcode-dec-chk + malyon-opcode-inc-chk malyon-opcode-jin + malyon-opcode-test malyon-opcode-or + malyon-opcode-and malyon-opcode-test-attr + malyon-opcode-set-attr malyon-opcode-clear-attr + malyon-opcode-store malyon-opcode-insert-obj + malyon-opcode-loadw malyon-opcode-loadb + malyon-opcode-get-prop malyon-opcode-get-prop-addr + malyon-opcode-get-next-prop malyon-opcode-add + malyon-opcode-sub malyon-opcode-mul + malyon-opcode-div malyon-opcode-mod + malyon-opcode-calls malyon-opcode-calln + malyon-opcode-set-color malyon-opcode-throw + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-je malyon-opcode-jl + malyon-opcode-jg malyon-opcode-dec-chk + malyon-opcode-inc-chk malyon-opcode-jin + malyon-opcode-test malyon-opcode-or + malyon-opcode-and malyon-opcode-test-attr + malyon-opcode-set-attr malyon-opcode-clear-attr + malyon-opcode-store malyon-opcode-insert-obj + malyon-opcode-loadw malyon-opcode-loadb + malyon-opcode-get-prop malyon-opcode-get-prop-addr + malyon-opcode-get-next-prop malyon-opcode-add + malyon-opcode-sub malyon-opcode-mul + malyon-opcode-div malyon-opcode-mod + malyon-opcode-calls malyon-opcode-calln + malyon-opcode-set-color malyon-opcode-throw + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-nop malyon-opcode-jz + malyon-opcode-get-sibling malyon-opcode-get-child + malyon-opcode-get-parent malyon-opcode-get-prop-len + malyon-opcode-inc malyon-opcode-dec + malyon-opcode-print-addr malyon-opcode-calls + malyon-opcode-remove-obj malyon-opcode-print-obj + malyon-opcode-ret malyon-opcode-jump + malyon-opcode-print-paddr malyon-opcode-load + malyon-opcode-calln malyon-opcode-jz + malyon-opcode-get-sibling malyon-opcode-get-child + malyon-opcode-get-parent malyon-opcode-get-prop-len + malyon-opcode-inc malyon-opcode-dec + malyon-opcode-print-addr malyon-opcode-calls + malyon-opcode-remove-obj malyon-opcode-print-obj + malyon-opcode-ret malyon-opcode-jump + malyon-opcode-print-paddr malyon-opcode-load + malyon-opcode-calln malyon-opcode-jz + malyon-opcode-get-sibling malyon-opcode-get-child + malyon-opcode-get-parent malyon-opcode-get-prop-len + malyon-opcode-inc malyon-opcode-dec + malyon-opcode-print-addr malyon-opcode-calls + malyon-opcode-remove-obj malyon-opcode-print-obj + malyon-opcode-ret malyon-opcode-jump + malyon-opcode-print-paddr malyon-opcode-load + malyon-opcode-calln malyon-opcode-rtrue + malyon-opcode-rfalse malyon-opcode-print + malyon-opcode-print-ret malyon-opcode-nop + malyon-opcode-illegal malyon-opcode-illegal + malyon-opcode-restart malyon-opcode-ret-popped + malyon-opcode-catch malyon-opcode-quit + malyon-opcode-new-line malyon-opcode-illegal + malyon-opcode-verify malyon-opcode-illegal + malyon-opcode-piracy malyon-opcode-nop + malyon-opcode-je malyon-opcode-jl + malyon-opcode-jg malyon-opcode-dec-chk + malyon-opcode-inc-chk malyon-opcode-jin + malyon-opcode-test malyon-opcode-or + malyon-opcode-and malyon-opcode-test-attr + malyon-opcode-set-attr malyon-opcode-clear-attr + malyon-opcode-store malyon-opcode-insert-obj + malyon-opcode-loadw malyon-opcode-loadb + malyon-opcode-get-prop malyon-opcode-get-prop-addr + malyon-opcode-get-next-prop malyon-opcode-add + malyon-opcode-sub malyon-opcode-mul + malyon-opcode-div malyon-opcode-mod + malyon-opcode-calls malyon-opcode-calln + malyon-opcode-set-color malyon-opcode-throw + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-nop malyon-opcode-calls + malyon-opcode-storew malyon-opcode-storeb + malyon-opcode-put-prop malyon-opcode-aread + malyon-opcode-print-char malyon-opcode-print-num + malyon-opcode-random malyon-opcode-push + malyon-opcode-pull malyon-opcode-split-window + malyon-opcode-set-window malyon-opcode-calls + malyon-opcode-erase-window malyon-opcode-erase-line + malyon-opcode-set-cursor malyon-opcode-get-cursor + malyon-opcode-set-text-style malyon-opcode-buffer-mode + malyon-opcode-output-stream malyon-opcode-input-stream + malyon-opcode-nop malyon-opcode-read-char + malyon-opcode-scan-table malyon-opcode-not + malyon-opcode-calln malyon-opcode-calln + malyon-opcode-tokenise malyon-opcode-encode-text + malyon-opcode-copy-table malyon-opcode-print-table + malyon-opcode-check-arg-count malyon-opcode-save + malyon-opcode-restore malyon-opcode-log-shift + malyon-opcode-art-shift malyon-opcode-set-font + malyon-opcode-illegal malyon-opcode-illegal + malyon-opcode-illegal malyon-opcode-illegal + malyon-opcode-save-undo malyon-opcode-restore-undo + malyon-opcode-print-unicode malyon-opcode-check-unicode + malyon-opcode-nop malyon-opcode-nop + malyon-opcode-nop] + "A vector of all known legal z code opcodes.") + +;; initialization + +(defun malyon-load-story-file (file-name) + "Load a z code story file into an internal vector." + (save-excursion + (set-buffer (create-file-buffer file-name)) + (malyon-disable-multibyte) + (malyon-erase-buffer) + (let ((coding-system-for-read 'binary)) + (insert-file-contents file-name)) + (setq malyon-story-file-name file-name) + (setq malyon-story-file (buffer-substring-no-properties (point-min) + (point-max))) + (setq malyon-story-file (malyon-string-to-vector malyon-story-file)) + (if (not (eq ?\^A 1)) + (let ((i 0)) + (while (< i (length malyon-story-file)) + (aset malyon-story-file + i + (malyon-char-to-int (aref malyon-story-file i))) + (setq i (+ 1 i))))) + (kill-buffer nil))) + +(defun malyon-initialize () + "Initialize the z code interpreter." +; (malyon-trace-file) + (setq malyon-game-state-quetzal t) + (malyon-initialize-faces) + (malyon-initialize-status) + (malyon-initialize-transcript) + (malyon-initialize-windows) + (malyon-initialize-story-header) + (malyon-initialize-registers) + (malyon-initialize-opcodes) + (malyon-history-clear) + (setq malyon-game-state-restart (malyon-current-game-state)) + (malyon-print-header)) + +(defun malyon-initialize-status () + "Initialize the status buffer." + (setq malyon-status-buffer (get-buffer-create "Malyon Status")) + (switch-to-buffer malyon-status-buffer) + (malyon-erase-buffer) + (kill-all-local-variables) + (setq malyon-status-buffer-point (point)) + (setq malyon-status-buffer-lines 0) + (setq malyon-status-buffer-delayed-split nil) + (use-local-map malyon-keymap-read) + (set-syntax-table malyon-syntax-table) + (setq mode-name "Malyon") + (setq major-mode 'malyon-mode) + (run-hooks 'malyon-mode-hook)) + +(defun malyon-initialize-transcript () + "Initialize the transcript buffer." + (setq malyon-transcript-buffer (get-buffer-create "Malyon Transcript")) + (switch-to-buffer malyon-transcript-buffer) + (malyon-erase-buffer) + (kill-all-local-variables) + (setq malyon-last-cursor-position-after-input + (malyon-point-max malyon-transcript-buffer)) + (use-local-map malyon-keymap-read) + (set-syntax-table malyon-syntax-table) + (setq fill-column malyon-max-column) + (auto-fill-mode 1) + (setq mode-name "Malyon") + (setq major-mode 'malyon-mode) + (run-hooks 'malyon-mode-hook)) + +(defun malyon-initialize-windows () + "Initialize the window configuration for the z machine." + (setq window-min-height 3) + (setq malyon-transcript-buffer-buffered t) + (malyon-set-window-configuration 0) + (malyon-opcode-set-window 0)) + +(defun malyon-initialize-story-header () + "Initializes the header section of the story file." + (malyon-store-byte 1 + (if (>= malyon-story-version 5) + 28 + (logior 48 (malyon-read-byte 1)))) + (malyon-store-byte 16 (logand 440 (malyon-read-byte 16))) + (malyon-store-byte 30 1) + (malyon-store-byte 31 65) + (malyon-store-byte 32 255) + (malyon-store-byte 33 (- malyon-max-column 1)) + (malyon-store-word 34 (- malyon-max-column 1)) + (malyon-store-word 36 255) + (malyon-store-word 38 1) + (malyon-store-word 39 1) + (malyon-store-byte 44 0) + (malyon-store-byte 45 0) + (malyon-store-byte 50 1) + (malyon-store-byte 51 0)) + +(defun malyon-initialize-registers () + "Initialize the interpreter's internal registers." + (setq malyon-stack (make-vector 1024 0)) + (setq malyon-stack-pointer -1) + (malyon-push-initial-frame) + (setq malyon-frame-pointer malyon-stack-pointer) + (setq malyon-instruction-pointer (malyon-read-word 6)) + (setq malyon-global-variables (malyon-read-word 12)) + (setq malyon-object-table (malyon-read-word 10)) + (cond ((< malyon-story-version 5) + (setq malyon-object-table-entry-size 9) + (setq malyon-object-properties 31) + (setq malyon-object-property-offset 7)) + (t + (setq malyon-object-table-entry-size 14) + (setq malyon-object-properties 63) + (setq malyon-object-property-offset 12))) + (setq malyon-abbreviations (malyon-read-word 24)) + (if (< malyon-story-version 5) + (setq malyon-score-game (zerop (logand 2 (malyon-read-byte 1))))) + (setq malyon-packed-multiplier + (malyon-cadr (assq malyon-story-version '((3 2) (5 4) (8 8))))) + (if (or (< malyon-story-version 5) (zerop (malyon-read-word 52))) + (setq malyon-alphabet (concat "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + " \n0123456789.,!?_#'\"/\\-:()")) + (setq malyon-alphabet (make-string 78 ? )) + (let ((i 0)) + (while (< i 78) + (aset malyon-alphabet i + (malyon-read-byte (+ i (malyon-read-word 52)))) + (setq i (+ 1 i))))) + (malyon-initialize-unicode-table) + (setq malyon-dictionary (malyon-read-word 8)) + (setq malyon-dictionary-entry-length + (malyon-read-byte + (+ 1 malyon-dictionary (malyon-read-byte malyon-dictionary)))) + (setq malyon-dictionary-num-entries + (malyon-read-word + (+ 2 malyon-dictionary (malyon-read-byte malyon-dictionary)))) + (setq malyon-dictionary-entries + (+ 4 malyon-dictionary (malyon-read-byte malyon-dictionary))) + (setq malyon-dictionary-word-length (if (< malyon-story-version 5) 3 5)) + (setq malyon-current-face 'malyon-face-plain) + (setq malyon-print-separator nil) + (malyon-initialize-output-streams)) + +(defun malyon-initialize-opcodes () + "Initialize the opcode table used by the story file." + (cond ((< malyon-story-version 5) + (aset malyon-opcodes 143 'malyon-opcode-not) + (aset malyon-opcodes 181 'malyon-opcode-save) + (aset malyon-opcodes 182 'malyon-opcode-restore) + (aset malyon-opcodes 185 'malyon-opcode-pop) + (aset malyon-opcodes 188 'malyon-opcode-show-status)) + (t + (aset malyon-opcodes 143 'malyon-opcode-calln) + (aset malyon-opcodes 181 'malyon-opcode-illegal) + (aset malyon-opcodes 182 'malyon-opcode-illegal) + (aset malyon-opcodes 185 'malyon-opcode-catch) + (aset malyon-opcodes 188 'malyon-opcode-illegal)))) + +(defun malyon-print-header () + "Print malyon mode header information." + (malyon-opcode-set-text-style 2) + (malyon-print "Malyon V 1.0.2") + (malyon-opcode-set-text-style 0) + (malyon-newline) + (malyon-print "A z-code interpreter for version 3, 5, and 8 games.") + (malyon-newline) + (malyon-print "(c) 1999-2009 by Peter Ilberg <peter.ilberg@gmail.com>") + (malyon-newline) + (malyon-newline)) + +;; cleanup + +(defun malyon-cleanup () + "Clean up the z code interpreter." + (condition-case nil + (progn + (setq malyon-story-file nil) + (setq malyon-window-configuration nil) + (setq malyon-game-state-restart nil) + (setq malyon-game-state-undo nil) + (if (get-buffer "Malyon Status") + (kill-buffer (get-buffer "Malyon Status"))) + (if (get-buffer "Malyon Transcript") + (progn + (switch-to-buffer (get-buffer "Malyon Transcript")) + (malyon-redisplay-frame (selected-frame) t) + (delete-other-windows (get-buffer-window (current-buffer))) + (widen) + (text-mode))) + (setq malyon-status-buffer nil) + (setq malyon-transcript-buffer nil)) + (error + (malyon-fatal-error "cleanup failed.")))) + +;; error handling + +(defun malyon-fatal-error (message) + "Print error message and abort." + (setq message (concat "Malyon fatal error: " message)) + (unwind-protect + (save-excursion + (set-buffer malyon-transcript-buffer) + (goto-char (point-max)) + (newline) + (newline) + (put-text-property 0 + (length message) + 'face + 'malyon-face-error + message) + (insert message) + (newline)) + (malyon-cleanup) + (malyon-redisplay-frame (selected-frame) t) + (error message))) + +;; conversion of zscii to ascii + +(defvar malyon-unicode-table nil + "An array mapping zscii characters to latin-1 ones.") + +(defvar malyon-default-unicode-table nil + "The default array mapping zscii characters to latin-1 ones.") + +(if malyon-default-unicode-table + '() + (setq malyon-default-unicode-table + [32 + 0 0 0 0 0 0 0 ; 1 - 7 + 8 0 0 0 0 10 0 0 ; 8 - 15 + 0 0 0 0 0 0 0 0 ; 16 - 23 + 0 0 0 39 0 0 0 0 ; 24 - 31 + 32 33 34 35 36 37 38 39 ; 32 - 39 + 40 41 42 43 44 45 46 47 ; 40 - 47 + 48 49 50 51 52 53 54 55 ; 48 - 55 + 56 57 58 59 60 61 62 63 ; 56 - 63 + 64 65 66 67 68 69 70 71 ; 64 - 71 + 72 73 74 75 76 77 78 79 ; 72 - 79 + 80 81 82 83 84 85 86 87 ; 80 - 87 + 88 89 90 91 92 93 94 95 ; 88 - 95 + 96 97 98 99 100 101 102 103 ; 96 - 103 + 104 105 106 107 108 109 110 111 ; 104 - 111 + 112 113 114 115 116 117 118 119 ; 112 - 119 + 120 121 122 123 124 125 126 0 ; 120 - 127 + 0 0 0 0 0 0 0 0 ; 128 - 135 + 0 0 0 0 0 0 0 0 ; 136 - 143 + 0 48 49 50 51 52 53 54 ; 144 - 151 + 55 56 57 228 246 252 196 214 ; 152 - 159 + 220 223 187 171 235 239 255 203 ; 160 - 167 + 207 225 233 237 243 250 253 193 ; 168 - 175 + 201 205 211 218 221 224 232 236 ; 176 - 183 + 242 249 192 200 204 210 217 226 ; 184 - 191 + 234 238 244 251 194 202 206 212 ; 192 - 199 + 219 229 197 248 216 227 241 245 ; 200 - 207 + 195 209 213 230 198 231 199 254 ; 208 - 215 + 240 222 208 163 63 63 161 191 ; 216 - 223 + 0 0 0 0 0 0 0 0 ; 224 - 231 + 0 0 0 0 0 0 0 0 ; 232 - 239 + 0 0 0 0 0 0 0 0 ; 240 - 247 + 0 0 0 0 0 0 0 0 ; 248 - 255 + ])) + +(defun malyon-initialize-unicode-table () + "Initializes the zscii-to-unicode conversion table." + (setq malyon-unicode-table + (copy-sequence malyon-default-unicode-table)) + (let* ((ext (malyon-read-word 54)) + (len (if (zerop ext) 0 (malyon-read-word ext))) + (table (if (< len 3) 0 (malyon-read-word (+ ext 6))))) + (if (or (< malyon-story-version 5) (zerop table)) + '() + (let ((i 0)) + (while (< i 96) + (aset malyon-unicode-table (+ 155 i) (malyon-char-to-int ??)) + (setq i (+ 1 i)))) + (setq len (malyon-read-byte table)) + (let ((i 0)) + (while (< i len) + (aset malyon-unicode-table (+ 155 i) + (malyon-read-word (+ table 1 i))) + (setq i (+ 1 i))))))) + +(defsubst malyon-zscii-to-unicode (char) + "Converts a zscii character to unicode." + (if (or (< char 0) (> char 255)) + ?? + (let ((uni (aref malyon-unicode-table char))) + (if (zerop uni) + ?? + (malyon-unibyte-char-to-multibyte (malyon-int-to-char uni)))))) + +(defsubst malyon-unicode-to-zscii (char) + "Converts a unicode character to zscii." + (setq char (malyon-multibyte-char-to-unibyte char)) + (setq char (if (malyon-characterp char) (malyon-char-to-int char) char)) + (if (= 13 char) + ?\r + (let ((i 1) (found 0)) + (while (and (< i 255) (zerop found)) + (if (= char (aref malyon-unicode-table i)) + (setq found i)) + (setq i (+ i 1))) + (malyon-int-to-char found)))) + +;; output streams + +(defvar malyon-output-streams nil + "Valid output streams for the interpreter.") + +(defvar malyon-output-streams-tables nil + "A list of active tables for stream 3.") + +(defun malyon-initialize-output-streams () + "Initializes the output streams." + (setq malyon-output-streams '()) + (setq malyon-output-streams-tables '()) + (malyon-add-output-stream 1 0)) + +(defun malyon-output-stream-function (stream) + "Returns the output function representing the given stream." + (cond ((= 1 stream) (if (zerop malyon-current-window) + 'malyon-putchar-transcript + 'malyon-putchar-status)) + ((= 2 stream) 'malyon-putchar-printer))) + +(defun malyon-add-output-stream (stream table) + "Add a new output stream." + (if (= stream 3) + (progn + (setq malyon-output-streams-tables + (cons table malyon-output-streams-tables)) + (malyon-store-word table 0)) + (let ((function (malyon-output-stream-function stream))) + (setq malyon-output-streams + (if (member function malyon-output-streams) + malyon-output-streams + (cons function malyon-output-streams)))))) + +(defun malyon-remove-output-stream (stream) + "Remove an output stream." + (if (= stream 3) + (setq malyon-output-streams-tables (cdr malyon-output-streams-tables)) + (setq malyon-output-streams + (malyon-remove (malyon-output-stream-function stream) + malyon-output-streams)))) + +(defun malyon-update-output-streams () + "Update output streams when the output window has changed." + (let ((one (or (member 'malyon-putchar-transcript malyon-output-streams) + (member 'malyon-putchar-status malyon-output-streams)))) + (setq malyon-output-streams + (malyon-remove 'malyon-putchar-transcript + (malyon-remove 'malyon-putchar-status + malyon-output-streams))) + (if one + (malyon-add-output-stream 1 0)))) + +(defsubst malyon-output-character (char) + "Output a single character on all active streams." + (setq char (malyon-zscii-to-unicode char)) + (if malyon-output-streams-tables + (malyon-putchar-table char (car malyon-output-streams-tables)) + (malyon-mapc (lambda (s) (funcall s char)) malyon-output-streams))) + +;; printing text + +(defsubst malyon-abbrev (abbrev x) + "Print an abbreviation." + (malyon-print-ztext + (* 2 (malyon-read-word (+ malyon-abbreviations + (* 2 (+ x (* 32 (1- abbrev))))))))) + +(defun malyon-newline () + "Print a newline." + (if (eq malyon-status-buffer (current-buffer)) + (goto-char malyon-status-buffer-point) + (goto-char (point-max))) + (malyon-output-character ?\r) + (if (eq malyon-status-buffer (current-buffer)) + (setq malyon-status-buffer-point (point)) + (goto-char malyon-last-cursor-position-after-input)) + (malyon-redisplay-frame (selected-frame) nil)) + +(defun malyon-print (object) + "Print text." + (let ((text (if (malyon-characterp object) (char-to-string object) object)) + (start)) + (if (eq malyon-transcript-buffer (current-buffer)) + (goto-char (point-max)) + (goto-char malyon-status-buffer-point)) + (setq start (point)) + (malyon-print-characters (malyon-string-to-list text)) + (put-text-property start (point) 'face malyon-current-face) + (if (eq malyon-status-buffer (current-buffer)) + (setq malyon-status-buffer-point (point)) + (goto-char malyon-last-cursor-position-after-input)))) + +(defun malyon-print-characters (text) + "Print a list of characters." + (malyon-mapc 'malyon-output-character text)) + +(defsubst malyon-print-state-new (char shift abbr zscii zcode) + "Generate a new print state." + (list char shift abbr zscii zcode)) + +(defsubst malyon-print-state-initial () + "Returns an initial state for the ztext decoder." + (malyon-print-state-new nil -6 0 0 0)) + +(defsubst malyon-print-state-next (x ignore shift abbr zscii z) + "Print state transition function." + (cond ((= zscii 2) + (malyon-print-state-new (+ z x) -6 0 0 0)) + ((= zscii 1) + (malyon-print-state-new nil -6 0 2 (* 32 x))) + ((> abbr 0) + (malyon-abbrev abbr x) + (malyon-print-state-initial)) + ((= x 0) + (malyon-print-state-new ? -6 0 0 0)) + ((< x 4) + (malyon-print-state-new nil -6 x 0 0)) + ((= x 4) + (malyon-print-state-new nil 20 0 0 0)) + ((= x 5) + (malyon-print-state-new nil 46 0 0 0)) + ((and (= shift 46) (= x 6)) + (malyon-print-state-new nil -6 0 1 0)) + ((and (= shift 46) (= x 7)) + (malyon-print-state-new ?\r -6 0 0 0)) + (t + (malyon-print-state-new + (aref malyon-alphabet (+ shift x)) -6 0 0 0)))) + +(defun malyon-print-text (address) + "Print text at address and return the address of the following byte." + (let ((start)) + (if (eq malyon-transcript-buffer (current-buffer)) + (goto-char (point-max)) + (goto-char malyon-status-buffer-point)) + (setq start (point)) + (setq address (malyon-print-ztext address)) + (put-text-property start (point) 'face malyon-current-face) + (if (eq malyon-status-buffer (current-buffer)) + (setq malyon-status-buffer-point (point)) + (goto-char malyon-last-cursor-position-after-input)) + (malyon-redisplay-frame (selected-frame) nil) + address)) + +(defun malyon-print-ztext (address) + "Print the ztext stored at the given address." + (let ((high 0) (low) (a) (b) (c) (state (malyon-print-state-initial))) + (while (zerop (logand 128 high)) + (setq high (malyon-read-byte address)) + (setq low (malyon-read-byte (+ 1 address))) + (setq a (logand 31 (lsh high -2))) + (setq b (logand 31 (logior (lsh high 3) (lsh low -5)))) + (setq c (logand 31 low)) + (setq state (apply 'malyon-print-state-next a state)) + (if (car state) (malyon-output-character (car state))) + (setq state (apply 'malyon-print-state-next b state)) + (if (car state) (malyon-output-character (car state))) + (setq state (apply 'malyon-print-state-next c state)) + (if (car state) (malyon-output-character (car state))) + (setq address (+ 2 address))) + address)) + +(defun malyon-putchar-transcript (char) + "Print a single character in the transcript window." + (if (char-equal char ?\n) + (newline 1) + (insert char) + (setq malyon-print-separator (null (member char malyon-whitespace)))) + (if (and malyon-transcript-buffer-buffered + (> (current-column) (current-fill-column))) + (progn + (end-of-line) + (forward-word -1) + (if (< 0 (current-column)) + (newline 1)) + (end-of-line)))) + +(defun malyon-putchar-status (char) + "Print a single character in the status window." + (if malyon-status-buffer-delayed-split + (progn + (malyon-split-buffer-windows malyon-status-buffer-delayed-split) + (other-window 1))) + (if (char-equal char ?\n) + (progn + (beginning-of-line) + (forward-line 1) + (if (= (point) (point-max)) + (forward-line -1))) + (if (> (current-column) (current-fill-column)) + '() + (insert char) + (delete-char 1)))) + +(defun malyon-putchar-table (char table) + "Print a single character into a table." + (setq char (malyon-unicode-to-zscii char)) + (malyon-store-byte (+ 2 table (malyon-read-word table)) char) + (malyon-store-word table (+ 1 (malyon-read-word table)))) + +(defun malyon-putchar-printer (char) + "Print a single character onto a printer."); not yet implemented + +;; more + +(defvar malyon-more-continue-keymap nil + "The keymap with which to continue after More has finished.") + +(defun malyon-more (keymap) + "Enter More mode." + (if (eq malyon-status-buffer (current-buffer)) + (use-local-map keymap) + (if (< malyon-story-version 5) (malyon-opcode-show-status)) + (if (< (count-lines malyon-last-cursor-position-after-input (point-max)) + (malyon-window-displayed-height)) + (progn + (malyon-adjust-transcript) + (use-local-map keymap)) + (goto-char malyon-last-cursor-position-after-input) + (beginning-of-line) + (recenter 1) + (setq malyon-more-continue-keymap keymap) + (use-local-map malyon-keymap-more) + (message "[More]")))) + +(defun malyon-more-status-buffer () + "Enter More mode for the status buffer." + (setq malyon-more-continue-keymap (current-local-map)) + (use-local-map malyon-keymap-more-status) + (message "[More]") + (throw 'malyon-end-of-interpreter-loop 'malyon-waiting-for-input)) + +;; input history + +(defvar malyon-history nil + "The input history.") + +(defun malyon-history-previous () + "Move one entry up in the input history." + (let ((prev (aref malyon-history 0)) + (curr (aref malyon-history 1)) + (next (aref malyon-history 2))) + (if (null prev) + curr + (aset malyon-history 2 (if curr (cons curr next) next)) + (aset malyon-history 0 (cdr prev)) + (aset malyon-history 1 (car prev))))) + +(defun malyon-history-next () + "Move one entry down in the input history." + (let ((prev (aref malyon-history 0)) + (curr (aref malyon-history 1)) + (next (aref malyon-history 2))) + (if (null next) + curr + (aset malyon-history 0 (if curr (cons curr prev) prev)) + (aset malyon-history 2 (cdr next)) + (aset malyon-history 1 (car next))))) + +(defun malyon-history-clear () + "Clear the input history." + (setq malyon-history (vector '() nil '()))) + +(defun malyon-history-insert (entry) + "Insert an entry into the input history." + (let* ((prev (aref malyon-history 0)) + (curr (aref malyon-history 1)) + (next (aref malyon-history 2)) + (l (malyon-remove entry + (append (nreverse prev) + (if curr (cons curr next) next)))) + (cut (- (length l) 19))) + (while (> cut 0) + (setq l (cdr l) + cut (- cut 1))) + (aset malyon-history 0 + (malyon-remove nil (malyon-remove "" (cons entry (nreverse l))))) + (aset malyon-history 1 nil) + (aset malyon-history 2 '()))) + +;; dictionary lookup + +(defun malyon-dictionary-word (chars) + "Convert a list of characters into a dictionary word." + (list (car (car chars)) + (length chars) + (malyon-encode-dictionary-word (append (malyon-mapcan 'cdr chars) + '(5 5 5 5 5 5 5 5))))) + +(defsubst malyon-join-characters (stop list) + "Joins three ztext characters into two bytes." + (let ((a (car list)) + (b (malyon-cadr list)) + (c (malyon-caddr list)) + (x (if (zerop stop) 0 128))) + (list (logior x (logand 255 (logior (lsh a 2) (lsh b -3)))) + (logand 255 (logior (lsh b 5) c))))) + +(defun malyon-encode-dictionary-word (l) + "Converts a list of ztext characters into a dictionary word." + (let* ((first l) + (second (malyon-cdddr first)) + (third (malyon-cdddr second))) + (apply 'vector + (if (< malyon-story-version 5) + (append (malyon-join-characters 0 first) + (malyon-join-characters 1 second)) + (append (malyon-join-characters 0 first) + (malyon-join-characters 0 second) + (malyon-join-characters 1 third)))))) + +(defun malyon-lookup (dict code) + "Look for the given code in the dictionary and return its address." + (cond ((not code) 0) + ((not dict) (malyon-binary-search code)) + ((= dict malyon-dictionary) (malyon-binary-search code)) + (t (malyon-linear-search dict code)))) + +(defsubst malyon-compare-words (word address) + "Compares the given word to the word stored at address." + (let* ((i 0) + (j address) + (x (aref word i)) + (y (malyon-read-byte j))) + (while (not (or (/= x y) (= i malyon-dictionary-word-length))) + (setq i (+ 1 i) + j (+ 1 j) + x (aref word i) + y (malyon-read-byte j))) + (- x y))) + +;; search functions + +(defun malyon-binary-search (code) + "Binary search through the main dictionary." + (let* ((lower 0) + (upper (- malyon-dictionary-num-entries 1)) + (median (/ (+ lower upper) 2)) + (entry (+ malyon-dictionary-entries + (* malyon-dictionary-entry-length median))) + (looking (malyon-compare-words code entry))) + (while (not (or (> lower upper) (zerop looking))) + (setq lower (if (< 0 looking) (+ median 1) lower) + upper (if (> 0 looking) (- median 1) upper) + median (/ (+ lower upper) 2) + entry (+ malyon-dictionary-entries + (* malyon-dictionary-entry-length median)) + looking (malyon-compare-words code entry))) + (if (zerop looking) entry 0))) + +(defun malyon-linear-search (dictionary code) + "Linear search through the given dictionary." + (let* ((length (malyon-read-byte (+ dictionary 1 + (malyon-read-byte dictionary)))) + (number (malyon-read-word (+ dictionary 2 + (malyon-read-byte dictionary)))) + (entries (+ dictionary 4 (malyon-read-byte dictionary))) + (i 0) + (entry (+ entries (* length i))) + (looking (malyon-compare-words code entry))) + (while (not (or (>= i number) (zerop looking))) + (setq i (+ 1 i) + entry (+ entries (* length i)) + looking (malyon-compare-words code entry))) + (if (zerop looking) entry 0))) + +;; encoding text and lexical analysis + +(defun malyon-split-list (sep list &optional x) + "Split a list into sublists as indicated by the separators." + (cond ((null list) + (list (nreverse x))) + ((eq sep (car list)) + (cons (nreverse x) (malyon-split-list sep (cdr list) '()))) + (t + (malyon-split-list sep (cdr list) (cons (car list) x))))) + +(defun malyon-characters-to-words (list) + "Turn the list of characters into a list of words." + (mapcar 'malyon-dictionary-word + (delete '() (malyon-split-list 'malyon-word-separator list)))) + +(defsubst malyon-char-in-string (c s) + "Returns the index of c in s if found, or length of s." + (let ((i 0)) + (while (not (or (= i (length s)) (= c (aref s i)))) + (setq i (+ 1 i))) + i)) + +(defsubst malyon-encode-into-ztext (c) + "Convert a character into ztext." + (let* ((index (malyon-char-in-string c malyon-alphabet)) + (shift (floor index 26)) + (char (+ 6 (mod index 26)))) + (cond ((> shift 2) (list 5 6 (logand 31 (lsh c -5)) (logand 31 c))) + ((= shift 2) (list 5 char)) + ((= shift 1) (list 4 char)) + (t (list char))))) + +(defun malyon-encode-single-character (terminating-characters char) + "Encode a character into ztext." + (let ((pos (car char)) + (c (cdr char))) + (cond ((member c malyon-whitespace) + (list 'malyon-word-separator)) + ((member c terminating-characters) + (list 'malyon-word-separator + (cons pos (malyon-encode-into-ztext c)) + 'malyon-word-separator)) + (t (list (cons pos (malyon-encode-into-ztext c))))))) + +(defun malyon-encode-character-list (dict list) + "Encode the list of characters into ztext." + (let ((l '()) + (i 0)) + (while (< i (malyon-read-byte dict)) + (setq l (cons (malyon-read-byte (+ dict 1 i)) l) + i (+ 1 i))) + (malyon-mapcan (lambda (x) (malyon-encode-single-character l x)) list))) + +(defun malyon-text-length (address) + "Return the length of the input text." + (if (>= malyon-story-version 5) + (malyon-read-byte (+ 1 address)) + (let ((i 0)) + (while (not (zerop (malyon-read-byte (+ i 1 address)))) + (setq i (+ i 1))) + i))) + +(defun malyon-text-to-character-list (address) + "Convert the input text into a list of characters." + (let ((i (malyon-text-length address)) + (text '())) + (while (< 0 i) + (setq text (cons + (cons (if (< malyon-story-version 5) i (+ 1 i)) + (malyon-read-byte + (+ i address (if (< malyon-story-version 5) 0 1)))) + text) + i (- i 1))) + text)) + +(defun malyon-text-to-words (address dictionary) + "Turn ztext into a list of dictionary words." + (malyon-characters-to-words + (malyon-encode-character-list (if dictionary dictionary malyon-dictionary) + (malyon-text-to-character-list address)))) + +;; window management + +(defvar malyon-status-buffer-grew-this-turn nil + "A flag signalling if the status buffer grew this turn.") + +(defun malyon-adjust-transcript () + "Adjust the position of the transcript text." + (save-excursion + (setq malyon-status-buffer-grew-this-turn nil) + (set-buffer malyon-transcript-buffer) + (goto-char (point-max)) + (recenter (- (malyon-window-displayed-height) 2)))) + +(defun malyon-prepare-status-buffer (status) + "Fill the status buffer with empty lines." + (save-excursion + (set-buffer malyon-status-buffer) + (let ((lines (count-lines (point-min) (point-max))) + (new status)) + (if (zerop lines) + (newline 1)) + (goto-char (point-max)) + (setq status (- status lines -1)) + (while (> status 0) + (insert (make-string (+ 3 malyon-max-column) ? )) + (newline 1) + (setq status (- status 1))) + (goto-char (point-min)) + (forward-line (+ 1 new)) + (kill-region (point) (point-max)) + (insert (make-string (+ 3 malyon-max-column) ? )) + (newline 1)))) + +(defun malyon-restore-window-configuration () + "Restore the saved window configuration." + (let ((buffer (window-buffer (selected-window)))) + (if malyon-window-configuration + (set-window-configuration malyon-window-configuration)) + (cond ((eq malyon-status-buffer buffer) (other-window 1)) + ((eq malyon-transcript-buffer buffer) (goto-char (point-max)))))) + +(defun malyon-set-window-configuration (status) + "Set up the new window configuration." + (cond ((< status malyon-status-buffer-lines) + (setq malyon-status-buffer-delayed-split status) + (if malyon-status-buffer-grew-this-turn + (malyon-more-status-buffer))) + ((> status malyon-status-buffer-lines) + (malyon-split-buffer-windows status) + (setq malyon-status-buffer-grew-this-turn t)) + ((not malyon-window-configuration) + (malyon-split-buffer-windows status)))) + +(defun malyon-split-buffer-windows (status) + "Split the buffer windows. +The status buffer gets 'status' lines while the transcript buffer +gets the remaining lines." + (delete-other-windows (get-buffer-window (current-buffer))) + (setq malyon-status-buffer-lines status) + (setq malyon-status-buffer-delayed-split nil) + (if (zerop status) + '() + (split-window (get-buffer-window (current-buffer)) (+ status 3)) + (switch-to-buffer malyon-status-buffer) + (malyon-prepare-status-buffer status) + (malyon-opcode-set-cursor 1 1) + (other-window 1)) + (switch-to-buffer malyon-transcript-buffer) + (setq malyon-window-configuration (current-window-configuration))) + +;; getting and setting the machine state + +(defun malyon-current-game-state () + "Return the current state of the interpreter." + (vector malyon-instruction-pointer + malyon-stack-pointer + malyon-frame-pointer + (copy-sequence malyon-stack) + (copy-sequence malyon-story-file) + malyon-game-state-quetzal)) + +(defun malyon-set-game-state (state) + "Installs the given state as the new state of the interpreter." + (setq malyon-instruction-pointer (aref state 0)) + (setq malyon-stack-pointer (aref state 1)) + (setq malyon-frame-pointer (aref state 2)) + (setq malyon-stack (copy-sequence (aref state 3))) + (setq malyon-story-file (copy-sequence (aref state 4))) + (setq malyon-game-state-quetzal (aref state 5)) + (save-excursion + (malyon-erase-buffer malyon-status-buffer) + (malyon-split-buffer-windows 0) + (setq malyon-last-cursor-position-after-input + (malyon-point-max malyon-transcript-buffer)))) + +;; file utilities + +(defsubst malyon-write-byte-to-file (byte) + "Write a byte to a file." + (insert-char (logand 255 byte) 1)) + +(defsubst malyon-write-word-to-file (word) + "Write a word to the last opened file." + (insert-char (logand 255 (lsh word -8)) 1) + (insert-char (logand 255 word) 1)) + +(defsubst malyon-write-dword-to-file (dword) + "Write a dword to the last opened file." + (insert-char (logand 255 (lsh dword -24)) 1) + (insert-char (logand 255 (lsh dword -16)) 1) + (insert-char (logand 255 (lsh dword -8)) 1) + (insert-char (logand 255 dword) 1)) + +(defsubst malyon-write-chunk-id-to-file (id) + "Write a quetzal chunk id to the last opened file." + (insert id)) + +(defsubst malyon-read-byte-from-file () + "Read the next byte from a file." + (if (= (point) (point-max)) + 0 + (forward-char 1) + (malyon-char-to-int (malyon-char-before)))) + +(defsubst malyon-read-word-from-file () + "Read the next word from the last opened file." + (logior (lsh (malyon-read-byte-from-file) 8) (malyon-read-byte-from-file))) + +(defsubst malyon-read-dword-from-file () + "Read the next dword from the last opened file." + (logior (lsh (malyon-read-byte-from-file) 24) + (lsh (malyon-read-byte-from-file) 16) + (lsh (malyon-read-byte-from-file) 8) + (malyon-read-byte-from-file))) + +(defsubst malyon-read-chunk-id-from-file () + "Read a quetzal chunk id from the last opened file." + (string (malyon-int-to-char (malyon-read-byte-from-file)) + (malyon-int-to-char (malyon-read-byte-from-file)) + (malyon-int-to-char (malyon-read-byte-from-file)) + (malyon-int-to-char (malyon-read-byte-from-file)))) + +(defun malyon-get-file-name (address) + "Retrieves the file name stored at address." + (let ((name (make-string (malyon-read-byte address) ? )) + (i 0)) + (while (< i (length name)) + (aset name i (malyon-read-byte (+ address 1 i))) + (setq i (+ 1 i))) + name)) + +;; saving data to disk + +(defun malyon-save-file (file &optional table length) + "Save the current game state or a memory section to disk." + (interactive "FSave file: ") + (condition-case nil + (save-excursion + (set-buffer (create-file-buffer file)) + (malyon-disable-multibyte) + (malyon-erase-buffer) + (cond (table (malyon-save-table table length)) + (malyon-game-state-quetzal + (malyon-save-quetzal-state (malyon-current-game-state))) + (t + (malyon-save-game-state (malyon-current-game-state)))) + (let ((coding-system-for-write 'binary)) + (write-file file)) + (kill-buffer nil) + 1) + (error 0))) + +(defun malyon-save-table (table length) + "Save the given section of memory to the file." + (let ((i 0) + (j table)) + (while (< i length) + (malyon-write-byte-to-file (malyon-read-byte j)) + (setq i (+ 1 i) + j (+ 1 j))))) + +(defun malyon-save-game-state (state) + "Saves the game state to disk." + (let ((ip (aref state 0)) + (sp (aref state 1)) + (fp (aref state 2)) + (stack (aref state 3)) + (mem (aref state 4)) + (dyn (malyon-read-word 14)) + (i 0)) + (malyon-write-word-to-file (length malyon-story-file-name)) + (while (< i (length malyon-story-file-name)) + (malyon-write-byte-to-file (aref malyon-story-file-name i)) + (setq i (+ 1 i))) + (malyon-write-dword-to-file ip) + (malyon-write-word-to-file sp) + (malyon-write-word-to-file fp) + (malyon-write-word-to-file dyn) + (setq i 0) + (while (<= i sp) + (malyon-write-dword-to-file (aref stack i)) + (setq i (+ 1 i))) + (setq i 0) + (while (< i dyn) + (malyon-write-byte-to-file (aref mem i)) + (setq i (+ 1 i))))) + +(defun malyon-save-quetzal-state (state) + "Saves the game state to disk in quetzal format." + (goto-char (point-min)) + (malyon-save-quetzal-ifhd state) + (malyon-save-quetzal-cmem state) + (malyon-save-quetzal-stks state) + (goto-char (point-min)) + (malyon-write-chunk-id-to-file "IFZS") + (goto-char (point-min)) + (malyon-write-dword-to-file (- (point-max) (point-min))) + (goto-char (point-min)) + (malyon-write-chunk-id-to-file "FORM")) + +(defun malyon-save-quetzal-ifhd (state) + "Saves the IFhd chunk of the quetzal format." + (malyon-write-chunk-id-to-file "IFhd") + (malyon-write-dword-to-file 13) + (malyon-write-word-to-file (malyon-read-word 2)) + (malyon-write-word-to-file (malyon-read-word 18)) + (malyon-write-word-to-file (malyon-read-word 20)) + (malyon-write-word-to-file (malyon-read-word 22)) + (malyon-write-word-to-file (malyon-read-word 28)) + (malyon-write-byte-to-file (lsh (aref state 0) -16)) + (malyon-write-byte-to-file (lsh (aref state 0) -8)) + (malyon-write-byte-to-file (aref state 0)) + (malyon-write-byte-to-file 0)) + +(defun malyon-save-quetzal-cmem (state) + "Saves the CMem chunk of the quetzal format." + (let ((beginning (point-max)) + (original (aref malyon-game-state-restart 4)) + (current (aref state 4)) + (size (malyon-read-word 14)) + (byte 0) + (count 0) + (i 0)) + (goto-char (point-max)) + (while (< i size) + (setq byte (logxor (aref current i) (aref original i))) + (if (zerop byte) + (setq count (+ 1 count)) + (while (> count 0) + (malyon-write-byte-to-file 0) + (setq count (- count 1)) + (malyon-write-byte-to-file (min 255 count)) + (setq count (- count (min 255 count)))) + (malyon-write-byte-to-file byte)) + (setq i (+ 1 i))) + (setq size (- (point-max) beginning)) + (if (zerop (mod size 2)) '() (malyon-write-byte-to-file 0)) + (goto-char beginning) + (malyon-write-chunk-id-to-file "CMem") + (malyon-write-dword-to-file size))) + +(defun malyon-save-quetzal-stks (state) + "Saves the Stks chunk of the quetzal format." + (let ((beginning (point-max)) + (size 0)) + (goto-char (point-max)) + (malyon-save-quetzal-stack-frame (- (aref state 2) 4) + (aref state 1) + (aref state 3)) + (setq size (- (point-max) beginning)) + (if (zerop (mod size 2)) '() (malyon-write-byte-to-file 0)) + (goto-char beginning) + (malyon-write-chunk-id-to-file "Stks") + (malyon-write-dword-to-file size))) + +(defun malyon-save-quetzal-stack-frame (fp sp stack) + "Saves the stack frames for the Stks chunk." + (let* ((frame (malyon-get-stack-frame fp sp stack)) + (frame-id (aref frame 0)) + (previous-fp (aref frame 1)) + (previous-sp (aref frame 2)) + (return-addr (aref frame 3)) + (result-addr (aref frame 4)) + (local-vars (aref frame 5)) + (num-args (aref frame 6)) + (eval-stack (aref frame 7))) + (if (> frame-id 0) + (malyon-save-quetzal-stack-frame previous-fp previous-sp stack)) + (malyon-write-byte-to-file (lsh return-addr -16)) + (malyon-write-byte-to-file (lsh return-addr -8)) + (malyon-write-byte-to-file return-addr) + (if (zerop frame-id) + (malyon-write-byte-to-file 0) + (malyon-write-byte-to-file (logior (if result-addr 0 16) + (length local-vars)))) + (malyon-write-byte-to-file (if result-addr result-addr 0)) + (malyon-write-byte-to-file (- (lsh 1 num-args) 1)) + (malyon-write-word-to-file (length eval-stack)) + (while (not (null local-vars)) + (malyon-write-word-to-file (car local-vars)) + (setq local-vars (cdr local-vars))) + (while (not (null eval-stack)) + (malyon-write-word-to-file (car eval-stack)) + (setq eval-stack (cdr eval-stack))))) + +;; restoring data from disk + +(defvar malyon-restore-data-error nil + "An error message if restoring data from a file failed.") + +(defvar malyon-restore-quetzal-stack nil + "A temporary stack for restoring quetzal game states.") + +(defvar malyon-restore-quetzal-stack-pointer nil + "A temporary stack pointer for restoring quetzal game states.") + +(defvar malyon-restore-quetzal-frame-pointer nil + "A temporary frame-pointer for restoring quetzal game states.") + +(defun malyon-restore-file (file &optional table length) + "Restore a game state or a memory section from disk." + (interactive "fLoad file: ") + (if (not (and (file-exists-p file) (file-readable-p file))) + 0 + (condition-case nil + (save-excursion + (setq malyon-restore-data-error nil) + (set-buffer (create-file-buffer file)) + (malyon-disable-multibyte) + (malyon-erase-buffer) + (let ((coding-system-for-read 'binary)) + (insert-file-contents file)) + (goto-char (point-min)) + (if table + (malyon-restore-table table length) + (let* ((first (malyon-read-chunk-id-from-file)) + (second (malyon-read-dword-from-file)) + (third (malyon-read-chunk-id-from-file))) + (if (and (string= "FORM" first) (string= "IFZS" third)) + (malyon-restore-quetzal-state (+ 8 second)) + (goto-char (point-min)) + (malyon-restore-game-state)))) + (kill-buffer nil) + (if (null malyon-restore-data-error) + 2 + (message malyon-restore-data-error) + 0)) + (error 0)))) + +(defun malyon-restore-table (table length) + "Restore the given section of memory from a file." + (let ((i 0) + (j table)) + (while (< i length) + (malyon-store-byte j (malyon-read-byte-from-file)) + (setq i (+ 1 i) + j (+ 1 j))))) + +(defun malyon-restore-game-state () + "Restore a saved game state from disk." + (let ((len 0) + (name 0) + (story 0) + (ip 0) + (sp 0) + (fp 0) + (dyn 0) + (stack (copy-sequence malyon-stack)) + (mem (copy-sequence malyon-story-file)) + (i 0)) + (setq len (malyon-read-word-from-file)) + (setq name (make-string len ? )) + (while (< i len) + (aset name i (malyon-read-byte-from-file)) + (setq i (+ 1 i))) + (setq ip (malyon-read-dword-from-file)) + (setq sp (malyon-read-word-from-file)) + (setq fp (malyon-read-word-from-file)) + (setq dyn (malyon-read-word-from-file)) + (setq i 0) + (while (<= i sp) + (aset stack i (malyon-read-dword-from-file)) + (setq i (+ 1 i))) + (setq i 0) + (while (< i dyn) + (aset mem i (malyon-read-byte-from-file)) + (setq i (+ 1 i))) + (setq name (file-name-nondirectory name)) + (setq story (file-name-nondirectory malyon-story-file-name)) + (if (or (string-match name story) (string-match story name)) + (malyon-set-game-state (vector ip sp fp stack mem nil)) + (setq malyon-restore-data-error "Invalid save file.")))) + +(defun malyon-restore-quetzal-state (size) + "Restore a saved quetzal game state from disk." + (let ((chunk-id nil) + (chunk-len 0) + (ip 0) + (memory nil) + (stack nil) + (beginning 0)) + (while (< (point) size) + (setq chunk-id (malyon-read-chunk-id-from-file)) + (setq chunk-len (malyon-read-dword-from-file)) + (setq beginning (point)) + (cond ((string= chunk-id "IFhd") + (setq ip (malyon-restore-quetzal-ifhd chunk-len))) + ((string= chunk-id "CMem") + (setq memory (malyon-restore-quetzal-cmem chunk-len))) + ((string= chunk-id "UMem") + (setq memory (malyon-restore-quetzal-umem chunk-len))) + ((string= chunk-id "Stks") + (setq stack (malyon-restore-quetzal-stks chunk-len)))) + (if (zerop (mod chunk-len 2)) '() (setq chunk-len (+ 1 chunk-len))) + (goto-char (+ beginning chunk-len))) + (cond ((and ip memory stack) + (malyon-set-game-state (vector ip + (aref stack 0) + (aref stack 1) + (aref stack 2) + memory + t))) + ((null malyon-restore-data-error) + (setq malyon-restore-data-error "invalid quetzal file."))))) + +(defun malyon-restore-quetzal-ifhd (size) + "Restore an IFhd chunk from disk. Return the instruction pointer." + (if (and (= (malyon-read-word-from-file) (malyon-read-word 2)) + (= (malyon-read-word-from-file) (malyon-read-word 18)) + (= (malyon-read-word-from-file) (malyon-read-word 20)) + (= (malyon-read-word-from-file) (malyon-read-word 22)) + (= (malyon-read-word-from-file) (malyon-read-word 28))) + (logior (lsh (malyon-read-byte-from-file) 16) + (lsh (malyon-read-byte-from-file) 8) + (malyon-read-byte-from-file)) + (setq malyon-restore-data-error "quetzal file doesn't belong to game.") + nil)) + +(defun malyon-restore-quetzal-cmem (size) + "Restore a CMem chunk from disk. Return the entire memory layout." + (let ((memory (copy-sequence (aref malyon-game-state-restart 4))) + (max-size (+ (point) size)) + (byte 0) + (i 0)) + (while (< (point) max-size) + (setq byte (malyon-read-byte-from-file)) + (if (zerop byte) + (setq i (+ 1 i (malyon-read-byte-from-file))) + (aset memory i (logxor byte (aref memory i))) + (setq i (+ 1 i)))) + memory)) + +(defun malyon-restore-quetzal-umem (size) + "Restore a UMem chunk from disk. Return the entire memory layout." + (let ((memory (copy-sequence (aref malyon-game-state-restart 4))) + (i 0)) + (while (< i size) + (aset memory i (malyon-read-byte-from-file)) + (setq i (+ 1 i))) + memory)) + +(defun malyon-restore-quetzal-stks (size) + "Restore a Stks chunk from disk. Return a vector containing the +stack pointer, the frame pointer, and the stack itself." + (let ((i 0) (frame-id 0)) + (setq malyon-restore-quetzal-stack + (copy-sequence (aref malyon-game-state-restart 3))) + (setq malyon-restore-quetzal-stack-pointer -1) + (setq malyon-restore-quetzal-frame-pointer 2) + (while (< i size) + (let* ((beginning (point)) + (return3 (malyon-read-byte-from-file)) + (return2 (malyon-read-byte-from-file)) + (return1 (malyon-read-byte-from-file)) + (return-addr (logior (lsh return3 16) (lsh return2 8) return1)) + (result-locals (malyon-read-byte-from-file)) + (has-result (zerop (logand 16 result-locals))) + (num-locals (logand 15 result-locals)) + (result-addr (malyon-read-byte-from-file)) + (arg-flags (+ 1 (malyon-read-byte-from-file))) + (num-args 0) + (eval-size (malyon-read-word-from-file)) + (local-vars '()) + (eval-stack '())) + (while (> num-locals 0) + (setq local-vars (cons (malyon-read-word-from-file) local-vars)) + (setq num-locals (- num-locals 1))) + (while (> eval-size 0) + (setq eval-stack (cons (malyon-read-word-from-file) eval-stack)) + (setq eval-size (- eval-size 1))) + (while (> arg-flags 1) + (setq arg-flags (lsh arg-flags -1)) + (setq num-args (+ num-args 1))) + (malyon-push-stack-frame frame-id + return-addr + (if (zerop frame-id) + nil + (if has-result result-addr nil)) + (reverse local-vars) + num-args + (reverse eval-stack)) + (setq frame-id (+ 1 frame-id)) + (setq i (+ i (- (point) beginning))))) + (vector malyon-restore-quetzal-stack-pointer + malyon-restore-quetzal-frame-pointer + malyon-restore-quetzal-stack))) + +;; object table management + +(defsubst malyon-object-address (object) + "Compute the address at which the object is stored." + (+ malyon-object-table + (* 2 malyon-object-properties) + (* malyon-object-table-entry-size (- object 1)))) + +(defsubst malyon-object-read-parent (address) + "Return the parent." + (if (< malyon-story-version 5) + (malyon-read-byte (+ 4 address)) + (malyon-read-word (+ 6 address)))) + +(defsubst malyon-object-read-sibling (address) + "Return the next sibling." + (if (< malyon-story-version 5) + (malyon-read-byte (+ 5 address)) + (malyon-read-word (+ 8 address)))) + +(defsubst malyon-object-read-child (address) + "Return the first child." + (if (< malyon-story-version 5) + (malyon-read-byte (+ 6 address)) + (malyon-read-word (+ 10 address)))) + +(defsubst malyon-object-store-parent (address value) + "Set the parent." + (if (< malyon-story-version 5) + (malyon-store-byte (+ 4 address) value) + (malyon-store-word (+ 6 address) value))) + +(defsubst malyon-object-store-sibling (address value) + "Set the next sibling." + (if (< malyon-story-version 5) + (malyon-store-byte (+ 5 address) value) + (malyon-store-word (+ 8 address) value))) + +(defsubst malyon-object-store-child (address value) + "Set the first child." + (if (< malyon-story-version 5) + (malyon-store-byte (+ 6 address) value) + (malyon-store-word (+ 10 address) value))) + +(defun malyon-find-property (object property) + "Return the address of the object's property, or 0 if it doesn't exist." + (let ((next (malyon-first-property object)) + (number 0)) + (setq number (logand (malyon-read-byte next) malyon-object-properties)) + (while (> number property) + (setq next (malyon-next-property next)) + (setq number (logand (malyon-read-byte next) malyon-object-properties))) + (if (= number property) next 0))) + +(defun malyon-first-property (object) + "Get the address of the object's first property." + (let ((header (malyon-read-word (+ malyon-object-property-offset + (malyon-object-address object))))) + (+ header 1 (* 2 (malyon-read-byte header))))) + +(defun malyon-next-property (property) + "Get the address of the following property." + (let ((size (malyon-read-byte property)) + (addr (+ property 1))) + (+ 1 addr (cond ((< malyon-story-version 5) (lsh size -5)) + ((zerop (logand 128 size)) (lsh size -6)) + (t + (let ((second (logand 63 (malyon-read-byte addr)))) + (if (= 0 second) 64 second))))))) + +(defun malyon-remove-object (object) + "Remove the object from the children list of its parent." + (let* ((address (malyon-object-address object)) + (parent (malyon-object-read-parent address)) + (sibling (malyon-object-read-sibling address))) + (malyon-object-store-parent address 0) + (malyon-object-store-sibling address 0) + (if (/= parent 0) + (let ((parent-addr (malyon-object-address parent))) + (let ((children (malyon-object-read-child parent-addr))) + (if (or (= children 0) (= children object)) + (malyon-object-store-child parent-addr sibling) + (let ((this (malyon-object-address children))) + (let ((next (malyon-object-read-sibling this))) + (while (/= next object) + (setq this (malyon-object-address next)) + (setq next (malyon-object-read-sibling this))) + (malyon-object-store-sibling this sibling))))))))) + +;; function calls and code branches + +(defun malyon-call-routine (routine arguments &optional result) + "Call a routine with the given arguments and return its result." + (if (= routine 0) + (if result (malyon-store-variable result 0) 0) + (malyon-push-stack (if result 0 1)) + (malyon-push-stack (if result result 0)) + (malyon-push-stack malyon-instruction-pointer) + (malyon-push-stack + (logior (lsh (- malyon-stack-pointer malyon-frame-pointer) 8) + (length arguments))) + (setq malyon-instruction-pointer (* malyon-packed-multiplier routine)) + (let ((args (malyon-read-code-byte)) (value nil)) + (if malyon-game-state-quetzal + (let ((id (lsh (aref malyon-stack malyon-frame-pointer) -8))) + (malyon-push-stack (logior (lsh (+ 1 id) 8) args)))) + (setq malyon-frame-pointer malyon-stack-pointer) + (while (> args 0) + (setq value (if (< malyon-story-version 5) (malyon-read-code-word) 0)) + (malyon-push-stack (if (null arguments) value (car arguments))) + (setq arguments (cdr arguments)) + (setq args (- args 1)))))) + +(defun malyon-jump-if (condition) + "Jump depending on the condition and the following jump data." + (let ((byte (malyon-read-code-byte)) + (offset nil) + (iftrue nil)) + (setq iftrue (/= 0 (logand byte 128))) + (setq offset (logand byte 63)) + (if (= 0 (logand byte 64)) + (progn + (setq offset (logior (lsh offset 8) (malyon-read-code-byte))) + (if (>= offset 8192) (setq offset (- offset 16384))))) + (if (or (and iftrue condition) (and (not iftrue) (not condition))) + (progn + (cond ((= offset 0) (malyon-opcode-rfalse)) + ((= offset 1) (malyon-opcode-rtrue)) + (t (setq + malyon-instruction-pointer + (+ malyon-instruction-pointer offset -2)))))))) + +(defun malyon-return (value) + "Return from a routine." + (setq malyon-stack-pointer malyon-frame-pointer) + (if malyon-game-state-quetzal (malyon-pop-stack)) + (setq malyon-frame-pointer + (- malyon-stack-pointer 1 (lsh (malyon-pop-stack) -8))) + (setq malyon-instruction-pointer (malyon-pop-stack)) + (let ((result (malyon-pop-stack)) + (store (malyon-pop-stack))) + (if (zerop store) + (malyon-return-store result value) + (malyon-return-ignore result value)))) + +(defun malyon-return-ignore (where value) + "Return from a routine ignoring the result.") + +(defun malyon-return-store (where value) + "Return from a routine storing the result." + (malyon-store-variable where value)) + +(defun malyon-push-initial-frame () + "Push the initial stack frame required in quetzal mode." + (if malyon-game-state-quetzal + (progn + (malyon-push-stack 1) + (malyon-push-stack 0) + (malyon-push-stack 0) + (malyon-push-stack 0) + (malyon-push-stack 0)))) + +(defun malyon-get-stack-frame (fp sp stack) + "Return a decoded stack frame in quetzal mode. +The result is a vector containing the frame id, the fp of the +previous frame, the sp of the previous frame, the return address, +the result variable if any, a list of local variables, the number +of arguments, and a list of the evaluation stack elements." + (let* ((has-result (zerop (aref stack fp))) + (result-addr (if has-result (aref stack (+ 1 fp)) nil)) + (return-addr (aref stack (+ 2 fp))) + (offset (lsh (aref stack (+ 3 fp)) -8)) + (num-args (logand 255 (aref stack (+ 3 fp)))) + (frame-id (lsh (aref stack (+ 4 fp)) -8)) + (num-locals (logand 255 (aref stack (+ 4 fp)))) + (start-locals (+ 5 fp)) + (start-eval (+ 5 fp num-locals)) + (local-vars '()) + (eval-stack '())) + (if (not (zerop num-locals)) + (setq local-vars + (malyon-vector-to-list stack start-locals start-eval))) + (if (> sp start-eval) + (setq eval-stack + (malyon-vector-to-list stack start-eval (+ 1 sp)))) + (vector frame-id + (- fp offset 2) + (- fp 1) + return-addr + result-addr + local-vars + num-args + eval-stack))) + +(defsubst malyon-restore-quetzal-push-stack (value) + "Push a value onto the restore quetzal stack." + (setq malyon-restore-quetzal-stack-pointer + (+ malyon-restore-quetzal-stack-pointer 1)) + (aset malyon-restore-quetzal-stack + malyon-restore-quetzal-stack-pointer + value)) + +(defun malyon-push-stack-frame + (frame-id return-addr result local-vars num-args eval-stack) + "Pushes a new stack frame in quetzal mode." + (malyon-restore-quetzal-push-stack (if result 0 1)) + (malyon-restore-quetzal-push-stack (if result result 0)) + (malyon-restore-quetzal-push-stack return-addr) + (malyon-restore-quetzal-push-stack + (logior (lsh (- malyon-restore-quetzal-stack-pointer + malyon-restore-quetzal-frame-pointer) 8) + num-args)) + (malyon-restore-quetzal-push-stack + (logior (lsh frame-id 8) (length local-vars))) + (setq malyon-restore-quetzal-frame-pointer + malyon-restore-quetzal-stack-pointer) + (while (not (null local-vars)) + (malyon-restore-quetzal-push-stack (car local-vars)) + (setq local-vars (cdr local-vars))) + (while (not (null eval-stack)) + (malyon-restore-quetzal-push-stack (car eval-stack)) + (setq eval-stack (cdr eval-stack)))) + +;; other stuff + +(defvar malyon-aread-text nil + "Text buffer for user input.") + +(defvar malyon-aread-parse nil + "Parse buffer for user input.") + +(defvar malyon-aread-beginning-of-line nil + "The beginning of the input line.") + +;; execution + +(defun malyon-interpreter () + "Run the z code interpreter on the given story file." +; (condition-case nil + (progn + (malyon-restore-window-configuration) + (if malyon-story-file + (catch 'malyon-end-of-interpreter-loop + (setq malyon-last-cursor-position-after-input + (malyon-point-max malyon-transcript-buffer)) + (malyon-execute)))) +; (error +; (malyon-fatal-error "unspecified internal runtime error.")))) +) +(defsubst malyon-fetch-variable-operands (specifier) + "Fetch a variable number of operands based on the specifier argument." + (let ((var (logand specifier 49152)) + (op '())) + (setq specifier (logand 65535 specifier)) + (while (/= 0 specifier) + (cond ((= var 0) (setq op (cons (malyon-read-code-word) op))) + ((= var 16384) (setq op (cons (malyon-read-code-byte) op))) + ((= var 32768) (setq op (cons (malyon-read-variable + (malyon-read-code-byte)) op))) + (t (setq specifier 0))) + (setq specifier (logand 65535 (lsh specifier 2))) + (setq var (logand specifier 49152))) + (nreverse op))) + +(defsubst malyon-fetch-extended (opcode) + "Fetch operands for an extended instruction." + (malyon-fetch-variable-operands + (logior (lsh (malyon-read-code-byte) 8) 255))) + +(defsubst malyon-fetch-variable (opcode) + "Fetch operands for a variable instruction." + (malyon-fetch-variable-operands + (if (or (= opcode 236) (= opcode 250)) + (malyon-read-code-word) + (logior (lsh (malyon-read-code-byte) 8) 255)))) + +(defsubst malyon-fetch-short (opcode) + "Fetch operands for a short instruction." + (let ((op (logand opcode 48))) + (cond ((= op 0) (list (malyon-read-code-word))) + ((= op 16) (list (malyon-read-code-byte))) + ((= op 32) (list (malyon-read-variable (malyon-read-code-byte))))))) + +(defsubst malyon-fetch-long (instr) + "Fetch operands for a long instruction." + (let ((byte1 (malyon-read-code-byte)) + (byte2 (malyon-read-code-byte))) + (list (if (= (logand instr 64) 0) byte1 (malyon-read-variable byte1)) + (if (= (logand instr 32) 0) byte2 (malyon-read-variable byte2))))) + +(defun malyon-execute () + "Execute z code instructions. +Load the next instruction opcode and its operands and execute it. +Repeat ad infinitum." + (let ((opcode) (operands)); (pc)) + (while t +; (setq pc malyon-instruction-pointer) + (setq opcode (malyon-read-code-byte)) + (setq operands (cond ((= opcode 190) + (setq opcode (+ 256 (malyon-read-code-byte))) + (malyon-fetch-extended opcode)) + ((>= opcode 192) + (malyon-fetch-variable opcode)) + ((>= opcode 128) + (malyon-fetch-short opcode)) + (t + (malyon-fetch-long opcode)))) +; (malyon-trace-opcode pc opcode operands) + (apply (aref malyon-opcodes opcode) operands)))) + +;; opcodes + +(defsubst malyon-number (n) + "Convert an unsigned number into a signed one." + (if (< n 32768) n (- n 65536))) + +(defun malyon-opcode-add (a b) + "Addition." + (malyon-store-variable (malyon-read-code-byte) + (+ (malyon-number a) (malyon-number b)))) + +(defun malyon-opcode-and (a b) + "Bitwise and." + (malyon-store-variable (malyon-read-code-byte) (logand a b))) + +(defun malyon-opcode-aread (text parse &optional time routine) + "Read input text." + (setq malyon-aread-text text) + (setq malyon-aread-parse parse) + (goto-char (point-max)) + (setq malyon-aread-beginning-of-line (point)) +; Some games violate these assumptions for the "Quit" question. +; (if (> 3 (malyon-read-byte text)) +; (malyon-fatal-error "text buffer less than 3 bytes.")) +; (if (and (not (zerop parse)) (> 2 (malyon-read-byte parse))) +; (malyon-fatal-error "parse buffer less than 2 bytes.")) + (malyon-more malyon-keymap-read) + (throw 'malyon-end-of-interpreter-loop 'malyon-waiting-for-input)) + +(defun malyon-opcode-art-shift (value places) + "Arithmetic shift." + (malyon-store-variable (malyon-read-code-byte) (ash value places))) + +(defun malyon-opcode-buffer-mode (mode) + "Toggles buffering of text in the transcript window." + (setq malyon-transcript-buffer-buffered (/= 0 mode))) + +(defun malyon-opcode-calln (routine &rest arguments) + "Call a routine and ignore the result." + (malyon-call-routine routine arguments)) + +(defun malyon-opcode-calls (routine &rest arguments) + "Call a routine and store the result." + (malyon-call-routine routine arguments (malyon-read-code-byte))) + +(defun malyon-opcode-catch () + "Return the current stack frame." + (malyon-store-variable + (malyon-read-code-byte) + (if malyon-game-state-quetzal + (lsh (aref malyon-stack malyon-frame-pointer) -8) + malyon-frame-pointer))) + +(defun malyon-opcode-check-arg-count (count) + "Tests the number of arguments passed to routine." + (malyon-jump-if + (<= count (logand 255 (aref malyon-stack + (if malyon-game-state-quetzal + (- malyon-frame-pointer 1) + malyon-frame-pointer)))))) + +(defun malyon-opcode-check-unicode (char) + "Check whether the given character is valid for input/output." + (malyon-store-variable (malyon-read-code-byte) 0)) + +(defun malyon-opcode-clear-attr (object attribute) + "Clear the given attribute in the given object." + (let ((attributes (malyon-object-address object)) + (byte (lsh attribute -3))) + (malyon-store-byte (+ attributes byte) + (logand (malyon-read-byte (+ attributes byte)) + (logxor (lsh 128 (- (logand attribute 7))) + 255))))) + +(defun malyon-opcode-copy-table (first second size) + "Copies first table onto second one." + (let* ((length (abs (malyon-number size))) + (zero (zerop second)) + (forward (or (< (malyon-number size) 0) (> first second))) + (i 0) + (a (if forward first (+ first length -1))) + (b (if forward (if zero first second) (+ second length -1)))) + (while (< i length) + (malyon-store-byte b (if zero 0 (malyon-read-byte a))) + (setq i (+ i 1) + a (if forward (+ a 1) (- a 1)) + b (if forward (+ b 1) (- b 1)))))) + +(defun malyon-opcode-dec (var) + "Decrement variable." + (malyon-store-variable var + (- (malyon-number (malyon-read-variable var)) 1))) + +(defun malyon-opcode-dec-chk (variable threshold) + "Decrement variable and jump if it's less than the given value." + (let ((value (malyon-number (malyon-read-variable variable)))) + (malyon-store-variable variable (- value 1)) + (malyon-jump-if (< (- value 1) (malyon-number threshold))))) + +(defun malyon-opcode-div (a b) + "Division." + (if (zerop b) (malyon-fatal-error "division by 0.")) + (malyon-store-variable (malyon-read-code-byte) + (/ (malyon-number a) (malyon-number b)))) + +(defun malyon-opcode-encode-text (text length from encoded) + "Encode the zscii text starting at from with the given length. +The result is stored at encoded." + (let* ((i length) + (j encoded) + (l '()) + (word '())) + (while (< 0 i) + (setq l (cons (malyon-read-byte (+ text from i -1)) l) + i (- i 1))) + (setq word (malyon-encode-dictionary-word + (append (malyon-mapcan 'malyon-encode-into-ztext l) + '(5 5 5 5 5 5 5 5)))) + (while (< i 6) + (malyon-store-byte j (car l)) + (setq i (+ 1 i) + j (+ 1 j) + l (cdr word))))) + +(defun malyon-opcode-erase-line (value) + "Erases the rest of the line." + (if (= value 1) + (if (eq malyon-transcript-buffer (current-buffer)) + (kill-line nil) + (save-excursion + (let ((i (current-column))) + (while (<= i malyon-max-column) + (insert ? ) + (delete-char 1) + (setq i (+ 1 i)))))))) + +(defun malyon-opcode-erase-window (window) + "Erase the contents of the given window." + (save-excursion + (let ((w (malyon-number window))) + (if (or (= w 0) (= w -1) (= w -2)) + (malyon-erase-buffer malyon-transcript-buffer)) + (if (or (= w 1) (= w -1) (= w -2)) + (malyon-erase-buffer malyon-status-buffer)) + (if (= w -1) + (malyon-split-buffer-windows 0))) + (setq malyon-last-cursor-position-after-input + (malyon-point-max malyon-transcript-buffer)))) + +(defun malyon-opcode-get-child (object) + "Get the first child of the given object and jump." + (let ((child (malyon-object-read-child (malyon-object-address object)))) + (malyon-store-variable (malyon-read-code-byte) child) + (malyon-jump-if (/= 0 child)))) + +(defun malyon-opcode-get-cursor (array) + "Retrieves the current cursor position." + (save-excursion + (set-buffer malyon-status-buffer) + (malyon-store-word array (- (count-lines (point-min) (point)) 1)) + (malyon-store-word (+ 2 array) (+ 1 (current-column))))) + +(defun malyon-opcode-get-next-prop (object property) + "Retrieve the first or next property id of object." + (let ((next (malyon-first-property object)) + (number 0)) + (if (zerop property) + '() + (setq number (logand (malyon-read-byte next) + malyon-object-properties)) + (setq next (malyon-next-property next)) + (while (> number property) + (setq number (logand (malyon-read-byte next) + malyon-object-properties)) + (setq next (malyon-next-property next))) + (if (/= number property) + (malyon-fatal-error "property does not exist."))) + (setq number (logand (malyon-read-byte next) malyon-object-properties)) + (malyon-store-variable (malyon-read-code-byte) number))) + +(defun malyon-opcode-get-parent (object) + "Get the parent of the given object." + (malyon-store-variable (malyon-read-code-byte) + (malyon-object-read-parent + (malyon-object-address object)))) + +(defun malyon-opcode-get-prop (object property) + "Get the value of the object's property." + (let* ((address (malyon-find-property object property)) + (size (malyon-read-byte address))) + (malyon-store-variable + (malyon-read-code-byte) + (cond ((zerop address) + (malyon-read-word (+ malyon-object-table (* 2 (- property 1))))) + ((and (< malyon-story-version 5) (zerop (lsh size -5))) + (malyon-read-byte (+ address 1))) + ((and (>= malyon-story-version 5) (zerop (logand 192 size))) + (malyon-read-byte (+ address 1))) + (t + (malyon-read-word (+ address 1))))))) + +(defun malyon-opcode-get-prop-addr (object property) + "Get the address of the object's property." + (let* ((address (malyon-find-property object property)) + (size (malyon-read-byte address)) + (offset (if (< malyon-story-version 5) + 1 + (if (zerop (logand 128 size)) 1 2)))) + (malyon-store-variable (malyon-read-code-byte) + (if (zerop address) 0 (+ address offset))))) + +(defun malyon-opcode-get-prop-len (property) + "Get the length of the object's property." + (let ((size (malyon-read-byte (- property 1)))) + (malyon-store-variable + (malyon-read-code-byte) + (cond ((< malyon-story-version 5) (+ 1 (lsh size -5))) + ((zerop (logand 128 size)) (+ 1 (lsh size -6))) + ((zerop (logand 63 size)) 64) + (t (logand 63 size)))))) + +(defun malyon-opcode-get-sibling (object) + "Get the next object in the tree and jump." + (let ((sibling (malyon-object-read-sibling (malyon-object-address object)))) + (malyon-store-variable (malyon-read-code-byte) sibling) + (malyon-jump-if (/= 0 sibling)))) + +(defun malyon-opcode-illegal (&rest ignore) + "Print an error message and exit the interpreter." + (malyon-fatal-error "illegal opcode.")) + +(defun malyon-opcode-inc (var) + "Increment variable." + (malyon-store-variable var + (+ (malyon-number (malyon-read-variable var)) 1))) + +(defun malyon-opcode-inc-chk (variable threshold) + "Increment variable and jump if it's greater than the given value." + (let ((value (malyon-number (malyon-read-variable variable)))) + (malyon-store-variable variable (+ value 1)) + (malyon-jump-if (> (+ value 1) (malyon-number threshold))))) + +(defun malyon-opcode-input-stream (number) + "Select the given input stream. Only the keyboard is supported." + (if (zerop (malyon-number number)) + '() + (message "Only the keyboard is supported as an input stream."))) + +(defun malyon-opcode-insert-obj (object destination) + "Insert an object into the children list of another." + (let ((child (malyon-object-address object)) + (parent (malyon-object-address destination))) + (malyon-remove-object object) + (malyon-object-store-parent child destination) + (malyon-object-store-sibling child (malyon-object-read-child parent)) + (malyon-object-store-child parent object))) + +(defun malyon-opcode-je (a &rest rest) + "Jump if first operand equals any of the following." + (malyon-jump-if (member (malyon-number a) (mapcar 'malyon-number rest)))) + +(defun malyon-opcode-jg (a b) + "Jump if first operand > second operand." + (malyon-jump-if (> (malyon-number a) (malyon-number b)))) + +(defun malyon-opcode-jin (child parent) + "Jump if second object is parent of the first one." + (malyon-jump-if + (= parent (malyon-object-read-parent (malyon-object-address child))))) + +(defun malyon-opcode-jl (a b) + "Jump if first operand < second operand." + (malyon-jump-if (< (malyon-number a) (malyon-number b)))) + +(defun malyon-opcode-jump (offset) + "Jump unconditionally." + (setq malyon-instruction-pointer (+ malyon-instruction-pointer + (malyon-number offset) -2))) + +(defun malyon-opcode-jz (a) + "Jump if operand = 0." + (malyon-jump-if (zerop a))) + +(defun malyon-opcode-load (variable) + "Load a variable." + (malyon-store-variable (malyon-read-code-byte) + (malyon-read-variable variable))) + +(defun malyon-opcode-loadb (array index) + "Load an array element into a variable." + (malyon-store-variable (malyon-read-code-byte) + (malyon-read-byte (+ array index)))) + +(defun malyon-opcode-loadw (array index) + "Load an array element into a variable." + (malyon-store-variable (malyon-read-code-byte) + (malyon-read-word (+ array (* 2 index))))) + +(defun malyon-opcode-log-shift (value places) + "Logical shift." + (malyon-store-variable (malyon-read-code-byte) (lsh value places))) + +(defun malyon-opcode-mod (a b) + "Modulo." + (malyon-store-variable (malyon-read-code-byte) + (mod (malyon-number a) (malyon-number b)))) + +(defun malyon-opcode-mul (a b) + "Multiplication." + (malyon-store-variable (malyon-read-code-byte) + (* (malyon-number a) (malyon-number b)))) + +(defun malyon-opcode-new-line () + "Print a newline." + (malyon-newline)) + +(defun malyon-opcode-nop (&rest ignore) + "Do nothing.") + +(defun malyon-opcode-not (a) + "Bitwise not." + (malyon-store-variable (malyon-read-code-byte) (logand 65535 (lognot a)))) + +(defun malyon-opcode-or (a b) + "Bitwise or." + (malyon-store-variable (malyon-read-code-byte) (logior a b))) + +(defun malyon-opcode-output-stream (stream &optional table) + "Select an output stream." + (let ((stream (malyon-number stream))) + (cond ((< 0 stream) (malyon-add-output-stream stream table)) + ((> 0 stream) (malyon-remove-output-stream (- stream)))))) + +(defun malyon-opcode-piracy () + "Piracy check, effectively an unconditional jump." + (malyon-jump-if 1)) + +(defun malyon-opcode-print () + "Print a string." + (setq malyon-instruction-pointer + (malyon-print-text malyon-instruction-pointer))) + +(defun malyon-opcode-print-addr (address) + "Print a string." + (malyon-print-text address)) + +(defun malyon-opcode-print-char (c) + "Print a character." + (malyon-print (char-to-string c))) + +(defun malyon-opcode-print-num (n) + "Print a number." + (malyon-print (number-to-string (malyon-number n)))) + +(defun malyon-opcode-print-obj (obj) + "Print the short name of the object." + (malyon-print-text + (+ 1 (malyon-read-word (+ malyon-object-property-offset + (malyon-object-address obj)))))) + +(defun malyon-opcode-print-paddr (address) + "Print a string." + (malyon-print-text (* malyon-packed-multiplier address))) + +(defun malyon-opcode-print-ret () + "Print a string, print a newline, return true/1." + (setq malyon-instruction-pointer + (malyon-print-text malyon-instruction-pointer)) + (malyon-newline) + (malyon-return 1)) + +(defun malyon-opcode-print-table (text width &optional height skip) + "Print the given table." + (if (not height) (setq height 1)) + (if (not skip) (setq skip 0)) + (let ((column (current-column)) + (address text) + (y 0) + (x 0)) + (while (< y height) + (if (zerop y) + '() + (malyon-newline) + (malyon-print-characters (make-string column ? ))) + (setq x 0) + (while (< x width) + (malyon-output-character (malyon-read-byte address)) + (setq address (+ 1 address)) + (setq x (+ 1 x))) + (setq address (+ skip address)) + (setq y (+ 1 y))))) + +(defun malyon-opcode-print-unicode (char) + "Prints a unicode character.") + +(defun malyon-opcode-pull (variable) + "Pull value off stack." + (malyon-store-variable variable (malyon-pop-stack))) + +(defun malyon-opcode-push (value) + "Push value onto stack." + (malyon-push-stack value)) + +(defun malyon-opcode-put-prop (object property value) + "Set the object's property to the given value." + (let* ((address (malyon-find-property object property)) + (size (malyon-read-byte address))) + (cond ((= address 0) + (malyon-fatal-error "property does not exist.")) + ((and (< malyon-story-version 5) (zerop (lsh size -5))) + (malyon-store-byte (+ 1 address) (logand 255 value))) + ((and (>= malyon-story-version 5) (zerop (logand size 192))) + (malyon-store-byte (+ 1 address) (logand 255 value))) + (t + (malyon-store-word (+ 1 address) value))))) + +(defun malyon-opcode-quit () + "End the game immediately." + (malyon-adjust-transcript) + (malyon-cleanup) + (throw 'malyon-end-of-interpreter-loop 'malyon-opcode-quit)) + +(defun malyon-opcode-random (limit) + "Generate a random number or set the seed value." + (malyon-store-variable (malyon-read-code-byte) + (if (>= 0 (malyon-number limit)) + 0 + (+ 1 (random (malyon-number limit)))))) + +(defun malyon-opcode-read-char (&optional device &rest ignore) + "Read a character." + (if (and device (/= 1 device)) + (malyon-fatal-error "illegal device specified in read_char.")) + (if (eq malyon-transcript-buffer (current-buffer)) + (goto-char (point-max))) + (message "[Press a key.]") + (malyon-more malyon-keymap-readchar) + (throw 'malyon-end-of-interpreter-loop 'malyon-waiting-for-character)) + +(defun malyon-opcode-remove-obj (object) + "Remove an object from its parent's children list." + (malyon-remove-object object)) + +(defun malyon-opcode-restart () + "Restart the game." + (malyon-set-game-state malyon-game-state-restart)) + +(defun malyon-opcode-restore (&optional table bytes name) + "Restore a saved game state or a section of memory from a file." + (let ((result (if name + (malyon-restore-file + (malyon-get-file-name name) table bytes) + (call-interactively 'malyon-restore-file)))) + (if (< malyon-story-version 5) + (malyon-jump-if (not (zerop result))) + (malyon-store-variable (malyon-read-code-byte) result)))) + +(defun malyon-opcode-restore-undo () + "Restore game state for undo." + (if malyon-game-state-undo + (malyon-set-game-state malyon-game-state-undo)) + (malyon-store-variable (malyon-read-code-byte) 2)) + +(defun malyon-opcode-ret (value) + "Return a value." + (malyon-return value)) + +(defun malyon-opcode-ret-popped () + "Return top of stack." + (malyon-return (malyon-pop-stack))) + +(defun malyon-opcode-rfalse () + "Return false/0." + (malyon-return 0)) + +(defun malyon-opcode-rtrue () + "Return true/1." + (malyon-return 1)) + +(defun malyon-opcode-save (&optional table bytes name) + "Save the current game state or a section of memory to a file." + (let ((result (if name + (malyon-save-file (malyon-get-file-name name) table bytes) + (call-interactively 'malyon-save-file)))) + (if (< malyon-story-version 5) + (malyon-jump-if (not (zerop result))) + (malyon-store-variable (malyon-read-code-byte) result)))) + +(defun malyon-opcode-save-undo () + "Save game state for undo." + (setq malyon-game-state-undo (malyon-current-game-state)) + (malyon-store-byte (malyon-read-code-byte) 1)) + +(defun malyon-opcode-scan-table (x table len &optional form) + "Scan the given table for the first occurrence of x." + (if (not form) (setq form 130)) + (let ((inc (logand 127 form)) + (byte (zerop (logand 128 form))) + (addr table) + (found 0) + (index 0)) + (while (and (zerop found) (< index len)) + (setq found + (if byte + (if (= x (malyon-read-byte addr)) addr 0) + (if (= x (malyon-read-word addr)) addr 0))) + (setq addr (+ addr inc)) + (setq index (+ index 1))) + (malyon-store-variable (malyon-read-code-byte) found) + (malyon-jump-if (not (zerop found))))) + +(defun malyon-opcode-set-attr (object attribute) + "Set the given attribute in the given object." + (let ((attributes (malyon-object-address object)) + (byte (lsh attribute -3))) + (malyon-store-byte (+ attributes byte) + (logior (malyon-read-byte (+ attributes byte)) + (lsh 128 (- (logand attribute 7))))))) + +(defun malyon-opcode-set-color (foreground background) + "Sets the fore- and background colors ie. does nothing.") + +(defun malyon-opcode-set-cursor (&optional line column) + "Set the cursor." + (if (eq malyon-transcript-buffer (current-buffer)) + (goto-char (point-max)) + (if malyon-status-buffer-delayed-split + (progn + (malyon-split-buffer-windows malyon-status-buffer-delayed-split) + (other-window 1))) + (if line '() (setq line (count-lines (point-min) (point)))) + (if column '() (setq column (current-column))) + (if (> line malyon-status-buffer-lines) + (progn + (malyon-split-buffer-windows line) + (other-window 1))) + (goto-char (point-min)) + (if (and (<= 1 line) (<= line malyon-status-buffer-lines)) + (forward-line line) + (beginning-of-line)) + (if (and (<= 1 column) (<= column malyon-max-column)) + (forward-char (- column 1)) + (beginning-of-line)) + (setq malyon-status-buffer-point (point)))) + +(defun malyon-opcode-set-font (font) + "Sets the font if available or 0 otherwise." + (malyon-store-variable (malyon-read-code-byte) 0)) + +(defun malyon-opcode-set-text-style (style) + "Set the text style/face." + (let ((face (assq style malyon-faces))) + (setq malyon-current-face (if face (cdr face) 'malyon-face-plain)))) + +(defun malyon-opcode-set-window (window) + "Set the current window." + (malyon-restore-window-configuration) + (setq malyon-current-window window) + (malyon-update-output-streams) + (if (zerop window) + (if (not (eq malyon-transcript-buffer (current-buffer))) + (other-window 1)) + (if (not (eq malyon-status-buffer (current-buffer))) + (other-window 1)) + (malyon-opcode-set-cursor 1 1))) + +(defun malyon-opcode-show-status () + "Display the status line." + (save-excursion + (malyon-opcode-split-window 1) + (malyon-restore-window-configuration) + (malyon-opcode-set-window 1) + (malyon-prepare-status-buffer 1) + (malyon-opcode-set-cursor 1 1) + (malyon-opcode-print-obj (malyon-read-global-variable 0)) + (if (<= (current-column) (- (current-fill-column) 10)) + (let* ((x (malyon-read-global-variable 1)) + (y (malyon-read-global-variable 2)) + (hours (if (> x 12) (- x 12) x)) + (ampm (if (> x 12) "PM" "AM")) + (score (format "%4d/%4d" x y)) + (time (format "%02d:%02d%s" hours y ampm))) + (malyon-opcode-set-cursor 1 (- (current-fill-column) 10)) + (malyon-print (if malyon-score-game score time)))) + (malyon-opcode-set-window 0) + (malyon-adjust-transcript))) + +(defun malyon-opcode-split-window (size) + "Split upper and lower window." + (malyon-set-window-configuration size)) + +(defun malyon-opcode-store (variable value) + "Store a value in a variable." + (malyon-store-variable variable value)) + +(defun malyon-opcode-storeb (array index value) + "Store a value in an array at the given index." + (malyon-store-byte (+ array index) value)) + +(defun malyon-opcode-storew (array index value) + "Store a value in an array at the given index." + (malyon-store-word (+ array (* 2 index)) value)) + +(defun malyon-opcode-sub (a b) + "Subtraction." + (malyon-store-variable (malyon-read-code-byte) + (- (malyon-number a) (malyon-number b)))) + +(defun malyon-opcode-test (bitmap flags) + "Test if all of the flags are set in the bitmap." + (malyon-jump-if (= flags (logand bitmap flags)))) + +(defun malyon-opcode-test-attr (object attribute) + "Jump depending on the given attribute in the given object." + (malyon-jump-if + (/= 0 (logand (malyon-read-byte (+ (malyon-object-address object) + (lsh attribute -3))) + (lsh 128 (- (logand attribute 7))))))) + +(defun malyon-opcode-throw (value frame) + "Return from the given stack frame." + (if malyon-game-state-quetzal + (let ((id (lsh (aref malyon-stack malyon-frame-pointer) -8))) + (while (/= frame id) + (setq malyon-stack-pointer malyon-frame-pointer) + (malyon-pop-stack) + (setq malyon-frame-pointer + (- malyon-stack-pointer 1 (lsh (malyon-pop-stack) -8))) + (malyon-pop-stack) + (malyon-pop-stack) + (setq id (lsh (aref malyon-stack malyon-frame-pointer) -8)))) + (setq malyon-frame-pointer frame)) + (malyon-return value)) + +(defun malyon-opcode-tokenise (text parse &optional dict flag) + "Perform lexical analysis on the text buffer." + (let* ((words (malyon-text-to-words text dict)) + (word (car words)) + (start (car word)) + (len (malyon-cadr word)) + (code (malyon-caddr word)) + (entry (malyon-lookup dict code)) + (i 0)) + (while (not (or (null words) (= i (malyon-read-byte parse)))) + (if (and (zerop entry) flag (/= 0 flag)) + '() + (malyon-store-word (+ 2 parse (* 4 i)) entry) + (malyon-store-byte (+ 4 parse (* 4 i)) len) + (malyon-store-byte (+ 5 parse (* 4 i)) start)) + (setq words (cdr words) + word (car words) + start (car word) + len (malyon-cadr word) + code (malyon-caddr word) + entry (malyon-lookup dict code) + i (+ 1 i))) + (malyon-store-byte (+ 1 parse) i))) + +(defun malyon-opcode-verify () + "Verify the correctness of the story file." + (let ((length (+ 1 (* malyon-packed-multiplier (malyon-read-word 26)))) + (sum 0) + (i 64)) + (while (< i length) + (setq sum (mod (+ sum (malyon-read-byte i)) 65536) + i (+ 1 i))) + (malyon-jump-if (= (malyon-read-word 28) sum)))) + +;; keymap utilities + +(defun malyon-end-input () + "Store the input line in a text buffer and perform lexical analysis." + (interactive) + (condition-case nil + (progn + (malyon-adjust-transcript) + (switch-to-buffer malyon-transcript-buffer) + (goto-char (point-max)) + (let* ((input (downcase + (buffer-substring-no-properties + (if (< malyon-aread-beginning-of-line (point)) + malyon-aread-beginning-of-line + (point)) + (point)))) + (vec (malyon-string-to-vector input)) + (text (apply 'vector (mapcar 'malyon-unicode-to-zscii vec))) + (len (min (malyon-read-byte malyon-aread-text) (length text))) + (i 0)) + (malyon-history-insert input) + (if (>= malyon-story-version 5) + (malyon-store-byte (+ malyon-aread-text 1) len)) + (while (< i len) + (malyon-store-byte + (+ malyon-aread-text (if (< malyon-story-version 5) 1 2) i) + (malyon-char-to-int (aref text i))) + (setq i (+ 1 i))) + (if (< malyon-story-version 5) + (malyon-store-byte (+ malyon-aread-text 1 len) 0))) + (if (/= 0 malyon-aread-parse) + (malyon-opcode-tokenise malyon-aread-text malyon-aread-parse)) + (newline) + (if (>= malyon-story-version 5) + (malyon-store-variable (malyon-read-code-byte) 10)) + (malyon-interpreter)) + (error + (malyon-fatal-error "unspecified internal runtime error.")))) + +(defun malyon-more-char () + "Page down in More mode." + (interactive) + (condition-case nil + (scroll-up) + (error)) + (if (>= (count-lines (point) (point-max)) + (malyon-window-displayed-height)) + (message "[More]") + (goto-char (point-max)) + (malyon-adjust-transcript) + (use-local-map malyon-more-continue-keymap))) + +(defun malyon-more-char-status () + "Wait for a key then continue." + (interactive) + (condition-case nil + (progn + (malyon-adjust-transcript) + (use-local-map malyon-more-continue-keymap) + (malyon-interpreter)) + (error + (malyon-fatal-error "unspecified internal runtime error.")))) + +(defun malyon-wait-char () + "Store the input character in a variable and resume execution." + (interactive) + (condition-case nil + (progn + (malyon-store-variable + (malyon-read-code-byte) + (malyon-char-to-int (malyon-unicode-to-zscii last-command-char))) + (use-local-map malyon-keymap-read) + (malyon-interpreter)) + (error + (malyon-fatal-error "unspecified internal runtime error.")))) + +(defun malyon-history-previous-char (arg) + "Display the previous item in the input history." + (interactive "p") + (let ((input (malyon-history-previous))) + (cond ((> malyon-aread-beginning-of-line (point)) + (funcall malyon-history-saved-up arg)) + (input + (save-excursion + (set-buffer malyon-transcript-buffer) + (delete-region malyon-aread-beginning-of-line (point-max))) + (goto-char (point-max)) + (insert input) + (malyon-adjust-transcript))))) + +(defun malyon-history-next-char (arg) + "Display the next item in the input history." + (interactive "p") + (let ((input (malyon-history-next))) + (cond ((> malyon-aread-beginning-of-line (point)) + (funcall malyon-history-saved-down arg)) + (input + (save-excursion + (set-buffer malyon-transcript-buffer) + (delete-region malyon-aread-beginning-of-line (point-max))) + (goto-char (point-max)) + (insert input) + (malyon-adjust-transcript))))) + +(defun malyon-beginning-of-line (arg) + "Go to the beginning of the line." + (interactive "p") + (if (> malyon-aread-beginning-of-line (point)) + (beginning-of-line) + (goto-char malyon-aread-beginning-of-line))) + +(defun malyon-kill-region (arg) + "Kill region." + (interactive "p") + (if (<= malyon-aread-beginning-of-line (point)) + (kill-region (point) (mark)) + (message "Editing is restricted to the input prompt."))) + +(defun malyon-kill-line (arg) + "Kill rest of the current line." + (interactive "p") + (if (<= malyon-aread-beginning-of-line (point)) + (kill-line) + (message "Editing is restricted to the input prompt."))) + +(defun malyon-kill-word (arg) + "Kill the current word." + (interactive "p") + (if (<= malyon-aread-beginning-of-line (point)) + (kill-word 1) + (message "Editing is restricted to the input prompt."))) + +(defun malyon-yank (arg) + "Yank." + (interactive "p") + (if (<= malyon-aread-beginning-of-line (point)) + (yank) + (message "Editing is restricted to the input prompt."))) + +(defun malyon-yank-pop (arg) + "Yank pop." + (interactive "p") + (if (<= malyon-aread-beginning-of-line (point)) + (yank-pop 1) + (message "Editing is restricted to the input prompt."))) + +(defun malyon-delete-char (arg) + "Delete a character." + (interactive "p") + (if (<= malyon-aread-beginning-of-line (point)) + (delete-char 1) + (message "Editing is restricted to the input prompt."))) + +(defun malyon-backward-delete-char (arg) + "Delete a character backwards." + (interactive "p") + (if (< malyon-aread-beginning-of-line (point)) + (backward-delete-char-untabify 1) + (message "Editing is restricted to the input prompt."))) + +(defun malyon-self-insert-command (arg) + "Insert a character." + (interactive "p") + (if (> malyon-aread-beginning-of-line (point)) + (goto-char (point-max))) + (self-insert-command 1)) + +;; tracing utility + +(defun malyon-trace-file () + "Turn tracing on for a particular file." + (let ((trace + (get-buffer-create + (concat "Malyon Trace " malyon-story-file-name)))) + (if trace + (save-excursion + (set-buffer trace) + (malyon-erase-buffer) + (insert (concat "Tracing " malyon-story-file-name "...")) + (newline))))) + +(defun malyon-trace-newline () + "Output tracing newline." + (let ((trace (get-buffer (concat "Malyon Trace " malyon-story-file-name)))) + (if trace + (save-excursion + (set-buffer trace) + (goto-char (point-max)) + (newline))))) + +(defun malyon-trace-opcode (pc opcode operands) + "Output a z code instruction." + (malyon-trace-string + (format "%8d %-3d %-25s %s\n" + pc + opcode + (symbol-name (aref malyon-opcodes opcode)) + (apply 'concat (malyon-mapcan + (lambda (x) + (list " " + (number-to-string + (if (malyon-characterp x) + (malyon-char-to-int x) + x)))) + operands))))) + +(defun malyon-trace-string (s) + "Output tracing string." + (let ((trace (get-buffer (concat "Malyon Trace " malyon-story-file-name)))) + (if (and trace s) + (save-excursion + (set-buffer trace) + (goto-char (point-max)) + (insert s))))) + +(defun malyon-trace-object (o) + "Output tracing object." + (let ((trace (get-buffer (concat "Malyon Trace " malyon-story-file-name)))) + (if (and trace o) + (save-excursion + (set-buffer trace) + (goto-char (point-max)) + (prin1 o trace))))) + +;;; announce malyon-mode + +(provide 'malyon-mode) +(provide 'malyon) + +;;; malyon-mode.el ends here diff --git a/emacs/maxframe.el b/emacs/maxframe.el new file mode 100644 index 0000000..e824e77 --- /dev/null +++ b/emacs/maxframe.el @@ -0,0 +1,110 @@ +;;; $Id: maxframe.el 331 2007-02-20 16:58:21Z ryan $ +;; maximize the emacs frame based on display size + +;; Copyright (C) 2007 Ryan McGeary +;; Author: Ryan McGeary +;; Keywords: display frame window maximize + +;; This code is free; 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. + +;;; Commentary: +;; +;; Purpose +;; ------- +;; maxframe provides the ability to maximize the emacs frame and stay within +;; the display resolution. +;; +;; Usage +;; ----- +;; Example of lines to be added to your .emacs: +;; +;; (require 'maxframe) +;; (add-hook 'window-setup-hook 'maximize-frame t) +;; +;; How it works +;; ------------ +;; puts the emacs frame in the top left corner of the display and calculates +;; the maximum number of columns and rows that can fit in the display +;; +;; Limitations +;; ----------- +;; Requires Emacs 22 (for fringe support), but maximize-frame still works +;; under Emacs 21 on Windows. +;; +;; Emacs does not recognize when the display's resolution is changed. This is +;; a problem because I would like to be able to re-maximize the frame after +;; connecting to a display with different resolution. Unfortunately, +;; display-pixel-width and display-pixel-height yield the display resolution +;; values from when emacs was started instead of the current display +;; values. Perhaps there's a way to have emacs re-sniff these values, but I'm +;; not yet sure how. + + +(defgroup maxframe nil "Handle maximizing frames.") + +(defcustom mf-display-padding-width 0 + "*Any extra display padding that you want to account for while +determining the maximize number of columns to fit on a display" + :type 'integer + :group 'maxframe) + +;; The default accounts for a Mac OS X display with a menubar +;; height of 22 pixels, a titlebar of 23 pixels, and no dock. +(defcustom mf-display-padding-height (+ 22 23) + "*Any extra display padding that you want to account for while +determining the maximize number of rows to fit on a display" + :type 'integer + :group 'maxframe) + +(defun w32-maximize-frame () + "Maximize the current frame (windows only)" + (interactive) + (w32-send-sys-command 61488)) + +(defun w32-restore-frame () + "Restore a minimized/maximized frame (windows only)" + (interactive) + (w32-send-sys-command 61728)) + +(defun mf-max-columns (width) + "Calculates the maximum number of columns that can fit in +pixels specified by WIDTH." + (let ((scroll-bar (or (frame-parameter nil 'scroll-bar-width) 0)) + (left-fringe (or left-fringe-width (nth 0 (window-fringes)) 0)) + (right-fringe (or right-fringe-width (nth 1 (window-fringes)) 0))) + (/ (- width scroll-bar left-fringe right-fringe + mf-display-padding-width) + (frame-char-width)))) + +(defun mf-max-rows (height) + "Calculates the maximum number of rows that can fit in pixels +specified by HEIGHT." + (/ (- height + mf-display-padding-height) + (frame-char-height))) + +(defun mf-set-frame-pixel-size (frame width height) + "Sets size of FRAME to WIDTH by HEIGHT, measured in pixels." + (set-frame-size frame (mf-max-columns width) (mf-max-rows height))) + +(defun x-maximize-frame () + "Maximize the current frame (x or mac only)" + (interactive) + (mf-set-frame-pixel-size (selected-frame) + (display-pixel-width) + (display-pixel-height)) + (set-frame-position (selected-frame) 0 0)) + +(defun maximize-frame () + "Maximizes the frame to fit the display if under a windowing +system." + (interactive) + (cond ((eq window-system 'w32) (w32-maximize-frame)) + ((memq window-system '(x mac)) (x-maximize-frame)))) + +(defalias 'mf 'maximize-frame) + +(provide 'maxframe) diff --git a/emacs/moz.el b/emacs/moz.el new file mode 100644 index 0000000..a11324c --- /dev/null +++ b/emacs/moz.el @@ -0,0 +1,282 @@ +;;; moz.el --- Lets current buffer interact with inferior mozilla. + +;; URL: http://github.com/bard/mozrepl/raw/master/chrome/content/moz.el + +;; Copyright (C) 2006 by Massimiliano Mirra +;; +;; 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +;; +;; Author: Massimiliano Mirra, <bard [at] hyperstruct [dot] net> +;; Contributors: +;; - Lennart Borgman + +;;; Commentary: +;; +;; This file implements communication with Firefox via MozRepl +;; (http://hyperstruct.net/projects/mozrepl). It is a slightly +;; modified version of the file moz.el that comes with MozLab. To use +;; it you have to install the MozRepl addon in Firefox. +;; +;; This file contains +;; +;; * a major mode for direct interaction in a buffer (as with +;; telnet) with MozRepl, `inferior-moz-mode'. +;; * a minor mode for sending code portions or whole files from +;; other buffers to MozRepl, `moz-minor-mode'. +;; +;; Assuming you want to use javascript-mode to edit Javascript files, +;; enter the following in your .emacs initialization file (from Emacs +;; integration in the help text): +;; +;; (add-to-list 'auto-mode-alist '("\\.js$" . javascript-mode)) +;; (autoload 'inferior-moz-mode "moz" "MozRepl Inferior Mode" t) +;; (autoload 'moz-minor-mode "moz" "MozRepl Minor Mode" t) +;; (add-hook 'javascript-mode-hook 'javascript-moz-setup) +;; (defun javascript-moz-setup () (moz-minor-mode 1)) +;; +;; Replace javascript-mode above with the name of your favorite +;; javascript mode. +;; +;; If you got this with nXhtml the setup above is already done for +;; you. +;; +;; *Note 1* You have to start the MozRepl server in Firefox (or +;; whatever Mozilla browser you use). From the menus do +;; +;; Tools - MozRepl - Start +;; +;; *Note 2* For clearness and brevity the documentation says Firefox +;; where the correct term should rather be "your Mozilla web +;; browser". + +;;; Change log: +;; +;; 2008-07-20: Lennart Borgman +;; - Add `moz-minor-mode-map'. +;; - Add `inferior-moz-insert-moz-repl'. +;; - Add `inferior-moz-mode-map'. +;; - Add doc strings to interactive functions. +;; - Make minor enhancements to documentation etc. +;; - Change Mozilla to Firefox/MozRepl for clarity and brevity. +;; - Add error handling when starting MozRepl. + +;;; Code: + +(require 'comint) + +;; Maybe fix-me: C-c control-char are reserved for major modes. But +;; this minor mode is used in only one major mode (or one family of +;; major modes) so it complies I think ... +(defvar moz-minor-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-s" 'run-mozilla) + (define-key map "\C-\M-x" 'moz-send-defun) + (define-key map "\C-c\C-c" 'moz-send-defun-and-go) + (define-key map "\C-c\C-r" 'moz-send-region) + (define-key map "\C-c\C-l" 'moz-save-buffer-and-send) + map)) + +;;;###autoload +(define-minor-mode moz-minor-mode + "MozRepl minor mode for interaction with Firefox. +With no argument, this command toggles the mode. +Non-null prefix argument turns on the mode. +Null prefix argument turns off the mode. + +When this minor mode is enabled, some commands become available +to send current code area \(as understood by c-mark-function) or +region or buffer to an inferior MozRepl process (which will be +started as needed). + +The following keys are bound in this minor mode: + +\\{moz-minor-mode-map}" + nil + " Moz" + :keymap moz-minor-mode-map + :group 'moz) + +(defalias 'run-mozilla 'inferior-moz-switch-to-mozilla) + +(defvar moz-repl-name "repl" + "The current name of the repl.") + +(defvar moz-input-separator "\n--end-remote-input\n") + +(defvar moz-repl-host "localhost") + +(defvar moz-repl-port 4242) + +(defun moz-temporary-file () + (if (and moz-temporary-file + (file-readable-p moz-temporary-file)) + moz-temporary-file + (setq moz-temporary-file (make-temp-file "emacs-mozrepl")))) + +(defun moz-send-region (start end) + "Send the region to Firefox via MozRepl." + (interactive "r") + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".pushenv('printPrompt', 'inputMode'); " + moz-repl-name ".setenv('printPrompt', false); " + moz-repl-name ".setenv('inputMode', 'multiline'); " + "undefined; \n")) + ;; Give the previous line a chance to be evaluated on its own. If + ;; it gets concatenated to the following ones, we are doomed. + (sleep-for 0 1) + (comint-send-region (inferior-moz-process) + start end) + (comint-send-string (inferior-moz-process) + "\n--end-remote-input\n") + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".popenv('inputMode', 'printPrompt'); " + "undefined; \n")) + (comint-send-string (inferior-moz-process) + "\n--end-remote-input\n") + (display-buffer (process-buffer (inferior-moz-process)))) + +(defun moz-send-defun () + "Send the current function to Firefox via MozRepl. +Curent function is the one recognized by c-mark-function." + (interactive) + (save-excursion + (mark-defun) + (moz-send-region (point) (mark)))) + +(defun moz-send-defun-and-go () + "Send the current function to Firefox via MozRepl. +Also switch to the interaction buffer." + (interactive) + (moz-send-defun) + (inferior-moz-switch-to-mozilla nil)) + +(defun moz-save-buffer-and-send () + "Save the current buffer and load it in Firefox via MozRepl." + (interactive) + (save-buffer) + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".pushenv('printPrompt', 'inputMode'); " + moz-repl-name ".setenv('inputMode', 'line'); " + moz-repl-name ".setenv('printPrompt', false); undefined; ")) + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".load('file://localhost/" (buffer-file-name) "');\n" + moz-repl-name ".popenv('inputMode', 'printPrompt'); undefined;\n")) + (display-buffer (process-buffer (inferior-moz-process)))) + +;;; Inferior Mode + +(defvar inferior-moz-buffer nil + "The buffer in which the inferior process is running.") + +(defun inferior-moz-insert-moz-repl () + "Insert value of `moz-repl-name' and a dot (.)." + (interactive) (insert moz-repl-name ".")) + +(defvar inferior-moz-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-cc" 'inferior-moz-insert-moz-repl) + map)) + +;;;###autoload +(define-derived-mode inferior-moz-mode comint-mode "Inf-MozRepl" + "Major mode for interacting with Firefox via MozRepl." + (setq comint-input-sender 'inferior-moz-input-sender) + (add-hook 'comint-output-filter-functions 'inferior-moz-track-repl-name nil t)) + +(defun inferior-moz-track-repl-name (comint-output) + (when (string-match "\\(\\w+\\)> $" comint-output) + (setq moz-repl-name (match-string 1 comint-output)))) + +(defun inferior-moz-self-insert-or-repl-name () + (interactive) + (if (looking-back "\\(\\w+\\)> $") + (insert moz-repl-name ".") + (insert last-command-char))) + +(defun inferior-moz-input-sender (proc string) + "Custom function to send input with comint-send-input. +Instead of sending input and newline separately like in +comint-simple-send, here we *first* concatenate input and +newline, then send it all together. This prevents newline to be +interpreted on its own." + (comint-send-string proc (concat string "\n"))) + +(defun inferior-moz-switch-to-mozilla (arg) + "Switch to the inferior MozRepl buffer. +Create the buffer and start the MozRepl process and connect to +Firefox if needed. + +See also `inferior-moz-start-process'." + (interactive "P") + (when arg + (setq moz-repl-host (read-string "Host: " "localhost")) + (setq moz-repl-port (read-number "Port: " 4242))) + (pop-to-buffer (process-buffer (inferior-moz-process))) + (goto-char (process-mark (inferior-moz-process)))) + +(defun inferior-moz-process () + "Return inferior MozRepl process. Start it if necessary. +See also `inferior-moz-start-process'." + (or (if (buffer-live-p inferior-moz-buffer) + (get-buffer-process inferior-moz-buffer)) + (progn + (inferior-moz-start-process) + (inferior-moz-process)))) + +(defun inferior-moz-start-process () + "Start an inferior Mozrepl process and connect to Firefox. +It runs the hook `inferior-moz-hook' after starting the process +and setting up the inferior Firefox buffer. + +Note that you have to start the MozRepl server from Firefox." + (interactive) + (condition-case err + (progn + (setq inferior-moz-buffer + (apply 'make-comint "MozRepl" (cons moz-repl-host moz-repl-port) nil nil)) + (sleep-for 0 100) + (with-current-buffer inferior-moz-buffer + (inferior-moz-mode) + (run-hooks 'inferior-moz-hook))) + (file-error + (with-output-to-temp-buffer "*MozRepl Error*" + (with-current-buffer (get-buffer "*MozRepl Error*") + (insert "Can't start MozRepl, the error message was:\n\n " + (error-message-string err) + "\n" + "\nA possible reason is that you have not installed" + "\nthe MozRepl add-on to Firefox or that you have not" + "\nstarted it. You start it from the menus in Firefox:" + "\n\n Tools / MozRepl / Start" + "\n" + "\nSee ") + (insert-text-button + "MozRepl home page" + 'action (lambda (button) + (browse-url + "http://hyperstruct.net/projects/mozrepl") + ) + 'face 'button) + (insert + " for more information." + "\n" + "\nMozRepl is also available directly from Firefox add-on" + "\npages, but is updated less frequently there.") + )) + (error "Can't start MozRepl")))) + +(provide 'moz) + +;;; moz.el ends here diff --git a/emacs/my-c-mode.el b/emacs/my-c-mode.el new file mode 100644 index 0000000..bf0caaf --- /dev/null +++ b/emacs/my-c-mode.el @@ -0,0 +1,29 @@ +(require 'cc-mode) + +(defconst vu3rdd-c-style + '((c-basic-offset . 2) + (tab-width . 4) + (indent-tabs-mode . nil) + (c-comment-only-line-offset . 0) + (c-hanging-braces-alist . ((substatement-open before after))) + (c-offsets-alist . ((topmost-intro . 0) + (substatement . +) + (substatement-open . 0) + (case-label . +) + (access-label . -) + (inclass . ++) + (inline-open . 0) + )))) + + +(c-add-style "vu3rddstyle" vu3rdd-c-style nil) + +(defun vu3rdd-c-hook () + (c-set-style "vu3rddstyle") + ;; parenthesis matching {}[]() + (global-set-key "%" 'match-paren)) + +(add-hook 'c-mode-common-hook 'vu3rdd-c-hook) + +(add-hook 'c-mode-common-hook + (lambda () (which-function-mode t))) diff --git a/emacs/my-erc.el b/emacs/my-erc.el new file mode 100644 index 0000000..53718da --- /dev/null +++ b/emacs/my-erc.el @@ -0,0 +1,77 @@ +;;; erc +(require 'erc) + +;; Load authentication info from an external source. Put sensitive +;; passwords and the like in here. +(load "~/.emacs.d/emacs/.erc-auth") + +(require 'erc-services) +(require 'erc-match) +(erc-services-mode 1) + +(setq erc-prompt-for-nickserv-password nil) + +(setq erc-nickserv-passwords + `((freenode (("vu3rdd" . ,freenode-nick-pass))) + (debian (("vu3rdd" . ,debian-nick-pass))))) + +(setq erc-autojoin-channels-alist + '((".*\\.freenode.net" "#racket" "#haskell") + (".*\\.oftc.net" "#debian-arm" "#debian" "#debian-devel"))) + +(global-set-key "\C-cef" (lambda () (interactive) + (erc :server "irc.freenode.net" :port "8000" + :nick "vu3rdd"))) +(global-set-key "\C-ced" (lambda () (interactive) + (erc :server "irc.debian.org" :port "6668" + :nick "vu3rdd"))) + +(setq erc-user-full-name "Ramakrishnan Muthukrishnan") +(setq erc-email-userid "vu3rdd@gmail.com") + +(require 'erc-track) +(erc-track-mode 1) +(setq erc-track-switch-direction 'importance) + +;; Only track my nick(s) +(defadvice erc-track-find-face (around erc-track-find-face-promote-query activate) + (if (erc-query-buffer-p) + (setq ad-return-value (intern "erc-current-nick-face")) + ad-do-it)) + +(setq erc-keywords '("vu3rdd" "rkrishnan")) + +(setq erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE" + "324" "329" "332" "333" "353" "477")) + +(global-set-key (kbd "C-c SPC") 'erc-track-switch-buffer) + +;; erc notification via notify +(defun clean-message (s) + (setq s (replace-regexp-in-string "'" "'" + (replace-regexp-in-string "\"" """ + (replace-regexp-in-string "&" "&" + (replace-regexp-in-string "<" "<" + (replace-regexp-in-string ">" ">" s))))))) + +(defun call-libnotify (matched-type nick msg) + (let* ((cmsg (split-string (clean-message msg))) + (nick (first (split-string nick "!"))) + (msg (mapconcat 'identity (rest cmsg) " "))) + (shell-command-to-string + (format "notify-send -t 5000 -u critical '%s says:' '%s'" nick msg)))) + +(add-hook 'erc-text-matched-hook 'call-libnotify) + +;; Enable logging +(setq erc-log-insert-log-on-open nil) +(setq erc-log-channels t) +(setq erc-log-channels-directory "~/.erc/logs/") +(setq erc-save-buffer-on-part t) +(setq erc-save-queries-on-quit nil + erc-log-write-after-send t + erc-log-write-after-insert t) +(defadvice save-buffers-kill-emacs (before save-logs (arg) activate) + (save-some-buffers t (lambda () (when (and (eq major-mode 'erc-mode) + (not (null buffer-file-name))))))) +(add-hook 'erc-insert-post-hook 'erc-save-buffer-in-logs) diff --git a/emacs/my-generic-stuff.el b/emacs/my-generic-stuff.el new file mode 100644 index 0000000..e6b5bee --- /dev/null +++ b/emacs/my-generic-stuff.el @@ -0,0 +1,44 @@ +;; inhibit splash screen +(setq inhibit-splash-screen t) + +;; prevent backup file creation +(setq make-backup-files nil) + +(transient-mark-mode t) + +;; disable startup message +(setq inhibit-startup-message t) + +;; Show column number at bottom of screen +(column-number-mode 1) + +;; alias y to yes and n to no +(defalias 'yes-or-no-p 'y-or-n-p) + +;; Pgup/dn will return exactly to the starting point. +(setq scroll-preserve-screen-position 1) + +;; format the title-bar to always include the buffer name +(setq frame-title-format "emacs - %b") + +;; scroll just one line when hitting the bottom of the window +(setq scroll-step 1) +(setq scroll-conservatively 1) + +;; scroll bar +(setq toggle-scroll-bar t) + +;; iswitchb +(setq iswitchb-mode t) + +(setq cursor-type 'bar) + +;; how long to wait? +(setq show-paren-delay 0) +;; turn paren-mode on + +;; alternatives are 'parenthesis' and 'mixed' +;(setq show-paren-style 'expression) + +;; font lock +(global-font-lock-mode t) diff --git a/emacs/my-haskell.el b/emacs/my-haskell.el new file mode 100644 index 0000000..4ae37a3 --- /dev/null +++ b/emacs/my-haskell.el @@ -0,0 +1,24 @@ +(add-to-list 'load-path "~/.emacs.d/vendor/haskell-mode") + +;;; haskell mode +(setq auto-mode-alist + (append auto-mode-alist + '(("\\.[hg]s$" . haskell-mode) + ("\\.hic?$" . haskell-mode) + ("\\.hsc$" . haskell-mode) + ("\\.chs$" . haskell-mode) + ("\\.l[hg]s$" . literate-haskell-mode)))) +(autoload 'haskell-mode "haskell-mode" + "Major mode for editing Haskell scripts." t) +(autoload 'literate-haskell-mode "haskell-mode" + "Major mode for editing literate Haskell scripts." t) + +;adding the following lines according to which modules you want to use: +(require 'inf-haskell) + +(add-hook 'haskell-mode-hook 'turn-on-font-lock) +(add-hook 'haskell-mode-hook 'turn-on-haskell-ghci) +(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode) +(add-hook 'haskell-mode-hook 'turn-on-haskell-indent) +(set-variable 'haskell-program-name "ghci") + diff --git a/emacs/my-org-mode.el b/emacs/my-org-mode.el new file mode 100644 index 0000000..c073c80 --- /dev/null +++ b/emacs/my-org-mode.el @@ -0,0 +1,33 @@ +;; org mode +(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) +(define-key global-map "\C-cb" 'org-iswitchb) +(setq org-log-done 'time) +(setq org-startup-indented t) + +(setq org-agenda-files (list "~/org/work.org" + "~/org/remember.org" + "~/org/debian.org" + "~/org/clojure.org" + "~/org/learning.org" + "~/org/reading.org" + "~/org/investments.org")) + +;; adapted from <http://doc.norang.ca/org-mode.html> +(setq org-todo-keywords '((sequence "TODO(t)" + "STARTED(s!)" + "|" + "DONE(d!/!)") + (sequence "WAITING(w@/!)" + "SOMEDAY(S!)" + "|" + "CANCELLED(c@/!)"))) + +(setq org-todo-keyword-faces (quote (("TODO" :foreground "red" :weight bold) + ("STARTED" :foreground "blue" :weight bold) + ("DONE" :foreground "forest green" :weight bold) + ("WAITING" :foreground "orange" :weight bold) + ("SOMEDAY" :foreground "magenta" :weight bold) + ("CANCELLED" :foreground "forest green" :weight bold)))) diff --git a/emacs/my-python.el b/emacs/my-python.el new file mode 100644 index 0000000..6dabf3d --- /dev/null +++ b/emacs/my-python.el @@ -0,0 +1,19 @@ +(require 'ac-python) + +;;; Use python-mode with files with these extensions +(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode)) +(add-to-list 'auto-mode-alist '("\\.pyx\\'" . python-mode)) + +;;; Turn on auto-complete in python shells +(add-hook 'inferior-python-mode-hook (lambda () (auto-complete-mode 1))) + +;;; Use python major mode if 'python' is in hashbang. +(add-to-list 'interpreter-mode-alist '("python" . python-mode)) + +;;; Use python as the python interpreter (can be changed to "ipython" in time +;;; when it works) +(setq python-python-command "python") + +;;; Check files for pep8 mistakes +(autoload 'python-pep8 "python-pep8") +(autoload 'pep8 "python-pep8") diff --git a/emacs/my-search.el b/emacs/my-search.el new file mode 100644 index 0000000..eb2049d --- /dev/null +++ b/emacs/my-search.el @@ -0,0 +1,4 @@ +;; highlight matches from searches +(setq isearch-highlight t) +(setq search-highlight t) +(setq-default transient-mark-mode t) diff --git a/emacs/my-slime.el b/emacs/my-slime.el new file mode 100644 index 0000000..2691f4c --- /dev/null +++ b/emacs/my-slime.el @@ -0,0 +1,43 @@ +;; slime +(add-to-list 'load-path "~/.emacs.d/vendor/slime") + +(eval-after-load "slime" + '(progn + (setq slime-use-autodoc-mode nil) + (slime-setup '(inferior-slime + ;; slime-asdf + ;; slime-autodoc + slime-banner + ;; slime-c-p-c + ;; slime-editing-commands + slime-fancy-inspector + slime-fancy + slime-fuzzy + ;; slime-highlight-edits + ;; slime-parse + ;; slime-presentation-streams + ;; slime-presentations + ;; slime-references + slime-repl + slime-scratch + ;;slime-tramp + ;;slime-typeout-frame + slime-xref-browser + slime-scheme)) + + (setq slime-protocol-version 'ignore) + (setq slime-complete-symbol*-fancy t) + (setq slime-complete-symbol-function 'slime-fuzzy-complete-symbol))) + +(require 'slime) +;(setq inferior-lisp-program "~/src/sbcl/src/runtime/sbcl") +(add-to-list 'slime-lisp-implementations '(sbcl ("/usr/bin/sbcl"))) +(setq slime-default-lisp 'sbcl) + +;; enable cldoc for slime +(dolist (hook '(lisp-mode-hook + slime-repl-mode-hook)) + (add-hook hook 'turn-on-cldoc-mode)) + +;; needed for overriding default method for invoking slime +; (ad-activate 'slime-read-interactive-args) diff --git a/emacs/my-swank-js.el b/emacs/my-swank-js.el new file mode 100644 index 0000000..2046066 --- /dev/null +++ b/emacs/my-swank-js.el @@ -0,0 +1,3 @@ +;; swank-js +(add-to-list 'load-path "~/.emacs.d/vendor/swank-js") +(require 'slime-js) diff --git a/emacs/my-twitter.el b/emacs/my-twitter.el new file mode 100644 index 0000000..bbd9495 --- /dev/null +++ b/emacs/my-twitter.el @@ -0,0 +1,4 @@ +(add-to-list 'load-path "~/.emacs.d/emacs/twittering-mode") +(require 'twittering-mode) + +(add-hook 'twittering-edit-mode-hook (lambda () (ispell-minor-mode) (flyspell-mode))) diff --git a/emacs/naquadah-theme.el b/emacs/naquadah-theme.el new file mode 100644 index 0000000..974c15e --- /dev/null +++ b/emacs/naquadah-theme.el @@ -0,0 +1,185 @@ +;;; naquadah-theme.el --- A color theme + +;; Copyright (C) 2011 Julien Danjou + +;; Authors: Julien Danjou <julien@danjou.info> + +;; This file is NOT 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 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(deftheme naquadah + "Naquadah theme.") + +(let ((light-blue "#72A0CF") + (pale-yellow "#D4F77F") + (violet "#C66CD0") + (green "#89E234") + (blue "#374EAB") + (yellow "#FCCD3A") + (pink "#DE336D") + (red "#8A0B0B") + (violet-blue "#5337AD") + (orange "#FFA500") + (tomato "#FC683A") + (background "#252A2B") + (shadow "#888a85")) + (custom-theme-set-faces + 'naquadah + `(default ((((min-colors 4096)) (:background ,background :foreground "#eeeeec")))) + `(shadow ((t (:foreground ,shadow)))) + '(cursor ((t (:background "#aa0000")))) + '(hl-line ((t (:background "#191919")))) + '(highlight ((t (:background "brown1" :foreground nil)))) + '(fringe ((t (:background "gray10")))) + '(mode-line ((t (:foreground "#fafafa" :background "#000000" :box (:line-width 1 :color "#444444"))))) + '(mode-line-inactive ((t (:foreground "#888888" :background "#2c2f2f" :box (:line-width 1 :color "black"))))) + `(mode-line-buffer-id ((t (:bold t :foreground ,orange)))) + '(header-line ((t (:foreground "#dddddd" :background "#1e2426" :box (:line-width 1 :color "#444444"))))) + '(region ((t (:background "grey30")))) + `(link ((t (:underline t :foreground ,light-blue)))) + '(custom-link ((t (:inherit 'link)))) + '(match ((t (:bold t :background "#e9b96e" :foreground "#2e3436")))) + '(tooltip ((t (:inherit 'variable-pitch :foreground "LightYellow" :background "black")))) + '(bold ((t (:bold t :underline nil :background nil)))) + '(italic ((t (:italic t :underline nil :background nil)))) + `(font-lock-builtin-face ((t (:foreground ,light-blue)))) + '(font-lock-comment-face ((t (:inherit 'shadow :italic t)))) + '(font-lock-comment-delimiter-face ((t (:inherit 'font-lock-comment-face)))) + `(font-lock-constant-face ((t (:foreground ,green)))) + '(font-lock-doc-face ((t (:inherit 'shadow)))) + '(font-lock-keyword-face ((t (:inherit 'font-lock-builtin-face :bold t)))) + `(font-lock-string-face ((t (:foreground ,violet)))) + '(font-lock-type-face ((t (:inherit 'font-lock-constant-face :bold t)))) + `(font-lock-variable-name-face ((t (:foreground ,tomato)))) + `(font-lock-warning-face ((t (:bold t :foreground ,orange)))) + `(font-lock-function-name-face ((t (:foreground ,yellow :bold t)))) + '(comint-highlight-input ((t (:italic t :bold t)))) + `(comint-highlight-prompt ((t (:foreground ,green)))) + `(isearch ((t (:background ,orange :foreground ,background)))) + `(show-paren-match-face ((t (:background ,green)))) + `(show-paren-mismatch-face ((t (:background ,violet)))) + `(minibuffer-prompt ((t (:foreground ,light-blue :bold t)))) + `(info-xref ((t (:foreground ,light-blue)))) + `(info-xref-visited ((t (:foreground ,violet)))) + '(widget-button ((t (:bold t)))) + `(widget-mouse-face ((t (:bold t :foreground "white" :background ,red)))) + `(widget-field ((t (:foreground ,orange :background "gray30")))) + `(widget-single-line-field ((t (:foreground ,orange :background "gray30")))) + `(custom-group-tag ((t (:bold t :foreground ,orange :height 1.3)))) + '(custom-variable-tag ((t (:bold t :foreground "#edd400" :height 1.1)))) + '(custom-face-tag ((t (:bold t :foreground "#edd400" :height 1.1)))) + `(custom-state-face ((t (:foreground ,light-blue)))) + '(custom-button ((t (:box (:line-width 1 :style released-button) :background "gray50" :foreground "black")))) + '(custom-variable-button ((t (:inherit 'custom-button)))) + '(custom-button-mouse ((t (:inherit 'custom-button :background "gray60")))) + '(custom-button-unraised ((t (:background "gray50" :foreground "black")))) + '(custom-button-mouse-unraised ((t (:inherit 'custom-button-unraised :background "gray60")))) + '(custom-button-pressed ((t (:inherit 'custom-button :box (:style pressed-button))))) + '(custom-button-mouse-pressed-unraised ((t (:inherit 'custom-button-unraised :background "gray60")))) + '(custom-documentation ((t (:italic t)))) + '(gnus-cite-face-1 ((t (:foreground "#ad7fa3")))) + '(gnus-cite-face-2 ((t (:foreground "sienna3")))) + '(gnus-cite-face-3 ((t (:foreground "khaki4")))) + '(gnus-cite-face-4 ((t (:foreground "PaleTurquoise4")))) + '(gnus-header-name-face ((t (:bold t :foreground "#729fcf")))) + '(gnus-header-from ((t (:bold t :foreground "#e0d400")))) + '(gnus-header-subject ((t (:foreground "#e0d400")))) + '(gnus-header-content ((t (:italic t :foreground "#8ae234")))) + '(gnus-header-newsgroups-face ((t (:italic t :bold t :foreground "LightSkyBlue3")))) + '(gnus-signature-face ((t (:italic t :foreground "OliveDrab1")))) + `(gnus-summary-cancelled-face ((t (:background "black" :foreground ,yellow)))) + '(gnus-summary-normal-ancient-face ((t (:foreground "medium sea green")))) + '(gnus-summary-normal-read-face ((t (:foreground "lime green")))) + `(gnus-summary-normal-ticked-face ((t (:foreground ,tomato)))) + '(gnus-summary-normal-unread-face ((t (:foreground "white")))) + '(gnus-summary-high-ancient-face ((t (:inherit 'gnus-summary-normal-ancient-face)))) + '(gnus-summary-high-read-face ((t (:inherit 'gnus-summary-normal-read-face)))) + `(gnus-summary-high-ticked-face ((t (:inherit 'gnus-summary-normal-ticked-face))))) + '(gnus-summary-high-unread-face ((t (:inherit 'gnus-summary-normal-unread-face)))) + '(gnus-summary-low-ancient-face ((t (:inherit 'gnus-summary-normal-ancient-face) :italic t))) + '(gnus-summary-low-read-face ((t (:inherit 'gnus-summary-normal-read-face :italic t)))) + '(gnus-summary-low-ticked-face ((t (:inherit 'gnus-summary-normal-ticked-face :italic t)))) + '(gnus-summary-low-unread-face ((t (:inherit 'gnus-summary-normal-unread-face :italic t)))) + '(spam-face ((t (:background "black" :foreground "magenta3")))) + `(gnus-summary-selected ((t (:background ,light-blue :foreground "white")))) + '(message-header-name-face ((t (:foreground "#729cfc")))) + '(message-header-newsgroups-face ((t (:italic t :bold t :foreground "LightSkyBlue3")))) + '(message-header-other-face ((t (:foreground "LightSkyBlue3")))) + '(message-header-xheader-face ((t (:foreground "DodgerBlue3")))) + '(message-header-subject ((t (:foreground "white")))) + '(message-header-to ((t (:foreground "white")))) + '(message-header-cc ((t (:foreground "white")))) + '(org-hide ((t (:foreground "#252a2b")))) + '(org-level-1 ((t (:bold t :foreground "#4788cc" :height 1.2)))) + '(org-level-2 ((t (:bold t :foreground "#6ac214" :height 1.1)))) + '(org-level-3 ((t (:bold t :foreground "#edd400" :height 1.0)))) + '(org-level-4 ((t (:bold t :foreground "tomato" :height 1.0)))) + '(org-footnote ((t (:underline t :foreground "magenta3")))) + '(org-link ((t (:foreground "SkyBlue2")))) + '(org-special-keyword ((t (:foreground "brown1")))) + '(org-verbatim ((t (:foreground "#eeeeec" :underline t :slant italic)))) + '(org-block ((t (:foreground "#bbbbbc")))) + '(org-quote ((t (:inherit org-block :slant italic)))) + '(org-verse ((t (:inherit org-block :slant italic)))) + '(org-todo ((t (:bold t :foreground "#ff2020")))) + '(org-done ((t (:bold t :foreground "forest green")))) + '(org-mode-line-clock ((t (:foreground "#cc77ff" :background nil)))) + '(org-date ((t (:underline nil :foreground "#edd466" :background nil)))) + '(org-agenda-date ((t (:underline nil :foreground "SkyBlue2" :height 1.2)))) + '(org-agenda-date-today ((t (:inherit org-agenda-date :foreground "#edd466" :weight bold)))) + '(org-agenda-date-telecommuting ((t (:inherit org-agenda-date :foreground "#ffbb22" :weight bold)))) + '(org-agenda-date-weekend ((t (:inherit org-agenda-date :foreground "brown3" :weight bold)))) + '(anything-header ((t (:bold t :background "gray15" :foreground "#edd400")))) + '(egocentric-face ((t (:foreground "#ff4289" :weight bold)))) + '(erc-direct-msg-face ((t (:foreground "#ee5577")))) + '(erc-header-line ((t (:background "black" :foreground "white")))) + '(erc-input-face ((t (:foreground "gray70")))) + '(erc-my-nick-face ((t (:inherit egocentric-face :weight thin :foreground nil)))) + '(erc-notice-face ((t (:foreground "light blue" :weight thin)))) + '(erc-prompt-face ((t (:background "black" :foreground "gray80" :weight bold)))) + '(erc-timestamp-face ((t (:foreground "gray70" :weight bold)))) + '(erc-pal-face ((t (:foreground "DarkOliveGreen3" :weight bold)))) + '(erc-fool-face ((t (:foreground "gray60" :weight thin)))) + '(erc-current-nick-face ((t (:inherit egocentric-face :weight thin :foreground nil)))) + '(ido-subdir ((t (:foreground "orange1")))) + '(which-func ((t (:foreground "#729cfc")))) + '(mm-uu-extract ((t (:background "#404040")))) + `(diff-added ((t (:foreground ,green)))) + `(diff-changed ((t (:foreground ,orange)))) + `(diff-removed ((t (:foreground ,red)))) + '(diff-hunk-header ((t (:bold t)))) + `(diff-function ((t (:foreground ,orange)))) + '(diff-header ((t (:background "grey10")))) + '(diff-file-header ((t (:background nil :foreground "white")))) + '(git-commit-summary-face ((t (:bold t)))) + `(git-commit-branch-face ((t (:foreground ,orange :bold t)))) + '(git-commit-nonempty-second-line-face ((t (:foreground "red")))) + '(git-commit-comment-face ((t (:inherit font-lock-comment-face)))) + '(git-commit-known-pseudo-header-face ((t (:inherit gnus-header-name-face)))) + '(git-commit-pseudo-header-face ((t (:inherit gnus-header-content)))) + '(rst-level-1-face ((t (:inherit org-level-1 :background nil)))) + '(rst-level-2-face ((t (:inherit org-level-2 :background nil)))) + '(rst-level-3-face ((t (:inherit org-level-3 :background nil)))) + '(rst-level-4-face ((t (:inherit org-level-4 :background nil))))) + +(provide-theme 'naquadah) + +;; Local Variables: +;; no-byte-compile: t +;; End: + +;;; naquadah-theme.el ends here diff --git a/emacs/notify.el b/emacs/notify.el new file mode 100644 index 0000000..599d0e5 --- /dev/null +++ b/emacs/notify.el @@ -0,0 +1,99 @@ +;;; notify.el --- notification frontend + +;; Copyright (C) 2008 Mark A. Hershberger + +;; Original Author: Mark A. Hershberger <mhersberger@intrahealth.org> +;; Keywords: extensions, convenience, lisp + +;; 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This provides a single function, notify, that will produce a notify +;; pop-up via DBus. + +;;; Code: + +(defvar notify-last '(0 0 0)) + +(defvar notify-defaults + (list :app "GNU Emacs" + :icon "/usr/share/icons/emacs22/emacs_48.png" + :timeout 10000 + :urgency "low" + :category "emacs.message")) + +(defvar notify-id 0) + +(defvar notify-delay '(0 5 0)) + +(defvar notify-last-notification '(0 5 0)) + +;; We could set up other notification methods like notify-via-shell or +;; notify-via-pointer +(defvar notify-method 'notify-via-dbus) + +(defun notify-next-id () + "Return the next notification id." + (setq notify-id (+ notify-id 1))) + +(defun notify-via-dbus (title body params) + "Send notification via DBus." + (when (and (fboundp 'dbus-ping) + (dbus-ping :session "org.freedesktop.Notifications")) + (dbus-call-method :session "org.freedesktop.Notifications" + "/org/freedesktop/Notifications" + "org.freedesktop.Notifications" "Notify" + (get 'params :app) + (notify-next-id) + (get 'params :icon) + title + body + '(:array) + '(:array :signature "{sv}") + ':int32 (get 'params :timeout)))) + +(defun notify (title body &rest args) + "Use pop-up notifications for events." + (when (and + (time-less-p notify-delay + (time-since notify-last-notification)) + (let ((params)) + (keywords-to-properties 'params args notify-defaults) + (setq notify-last-notification (current-time)) + (funcall notify-method title body params))))) + +(defun keywords-to-properties (symbol args &optional defaults) + "Convert a list in the form (:keywordA valueA + :keywordB valueB ...) +to a list of propertys with the given values" + (when (car-safe defaults) ; probably need to avoid recursion + (keywords-to-properties symbol defaults)) + (while args + (let ((arg (car args))) + (setq args (cdr args)) + (unless (symbolp arg) + (error "Junk in args %S" args)) + (let ((keyword arg) + (value (car args))) + (unless args + (error "Keyword %s is missing an argument" keyword)) + (setq args (cdr args)) + (put symbol keyword value))))) + +(provide 'notify) + +;;; notify.el ends here diff --git a/emacs/nxhtml/README.txt b/emacs/nxhtml/README.txt new file mode 100644 index 0000000..e9204b4 --- /dev/null +++ b/emacs/nxhtml/README.txt @@ -0,0 +1,46 @@ +To install nXhtml put this in your .emacs: + + (load "YOUR-PATH-TO/nxhtml/autostart.el") + +where autostart.el is the file in the same directory as this +readme.txt file. + +Note 1: If you are using Emacs+EmacsW32 then nXhtml is already + installed. + +Note 2: If you are using Emacs 22 then you need to install nXml + separately. (It is included in Emacs 23.) + +Note 3: You may optionally also byte compile nXhtml from the nXhtml + menu (recommended). + + + +Files that are now in Emacs' development (CVS/Bazaar) repository +================================================================ + +Some files that were previously distributed with nXhtml are now in +Emacs' development repository. Distributing them also with nXhtml is +a bad idea since that can lead to that the wrong file is loaded. They +are therefore not distributed with nXhtml anymore. + +Instead you can (if you do not have the files in your Emacs) in many +cases use the version from the repository. To do that you can +currently start from + + http://cvs.savannah.gnu.org/viewvc/emacs/emacs/lisp/ + +Files you can download and use this way are for example + + js.el (JavaScript, formerly called espresso.el) + htmlfontify.el + +If you do that I suggest that you put these files in a special +directory and add that to load-path in your .emacs and make that +adding to load-path depend on your Emacs version so that they will not +be loaded when you have upgraded your Emacs. + +Note that if you want to use nxml-mode (and it is not in your Emacs) +you should not download it from Emacs' development directory. Instead go to + + http://www.thaiopensource.com/download/ diff --git a/emacs/nxhtml/alts/find-recursive-orig.el b/emacs/nxhtml/alts/find-recursive-orig.el new file mode 100644 index 0000000..509a038 --- /dev/null +++ b/emacs/nxhtml/alts/find-recursive-orig.el @@ -0,0 +1,137 @@ +;; find-recursive.el -- Find files recursively into a directory +;; +;; Copyright (C) 2001 Ovidiu Predescu +;; +;; Author: Ovidiu Predescu <ovidiu@cup.hp.com> +;; Date: March 26, 2001 +;; +;; 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. + +;; +;; Setup: put this file in your Lisp path and add the following line in +;; your .emacs: +;; +;; (require 'find-recursive) +;; + +(require 'cl) + +(defcustom find-recursive-exclude-files '(".*.class$" ".*~$" ".*.elc$") + "List of regular expressions of files to be excluded when recursively searching for files." + :type '(repeat (string :tag "File regexp"))) + +(defun find-file-recursively (file-regexp directory) + (interactive "sFile name to search for recursively: \nDIn directory: ") + (let ((directory (if (equal (substring directory -1) "/") + directory + (concat directory "/"))) + (matches + (find-recursive-filter-out + find-recursive-exclude-files + (find-recursive-directory-relative-files directory "" file-regexp)))) + (cond ((eq (length matches) 0) (message "No file(s) found!")) + ((eq (length matches) 1) + (find-file (concat directory (car matches)))) + (t + (run-with-timer 0.001 nil + (lambda () + (dispatch-event + (make-event 'key-press '(key tab))))) + (let ((file (completing-read "Choose file: " + (mapcar 'list matches) + nil t))) + (if (or (eq file nil) (equal file "")) + (message "No file selected.") + (find-file (concat directory file)))))))) + +(defun find-recursive-directory-relative-files (directory + relative-directory + file-regexp) + (let* ((full-dir (concat directory "/" relative-directory)) + (matches + (mapcar + (function (lambda (x) + (concat relative-directory x))) + (find-recursive-filter-out '(nil) + (directory-files full-dir nil + file-regexp nil t)))) + (inner + (mapcar + (function + (lambda (dir) + (find-recursive-directory-relative-files directory + (concat relative-directory + dir "/") + file-regexp))) + (find-recursive-filter-out '(nil "\\." "\\.\\.") + (directory-files full-dir nil ".*" + nil 'directories))))) + (mapcar (function (lambda (dir) (setq matches (append matches dir)))) + inner) + matches)) + +(defun find-recursive-filter-out (remove-list list) + "Remove all the elements in *remove-list* from *list*" + (if (eq list nil) + nil + (let ((elem (car list)) + (rest (cdr list))) + (if (some + (lambda (regexp) + (if (or (eq elem nil) (eq regexp nil)) + nil + (not (eq (string-match regexp elem) nil)))) + remove-list) + (find-recursive-filter-out remove-list rest) + (cons elem (find-recursive-filter-out remove-list rest)))))) + +(defvar find-recursive-running-xemacs (string-match "XEmacs\\|Lucid" emacs-version)) + +(if find-recursive-running-xemacs + nil + (defadvice directory-files (after + directory-files-xemacs + (dirname &optional full match nosort files-only) + activate) + "Add an additional argument, FILES-ONLY to the list of arguments +for GNU Emacs. If the symbol is t, then only the files in the +directory will be returned. If FILES-ONLY is nil, then both files and +directories are selected. If FILES-ONLY is not nil and not t, then +only sundirectories are returned." + (setq ad-return-value + (cond ((null files-only) ad-return-value) + ((eq files-only t) + (find-recursive-remove-if (lambda (f) + (file-directory-p + (concat dirname "/" f))) + ad-return-value)) + (t + (find-recursive-remove-if (lambda (f) + (not (file-directory-p + (concat dirname "/" f)))) + ad-return-value))))) + + (defun find-recursive-remove-if (func list) + "Removes all elements satisfying FUNC from LIST." + (let ((result nil)) + (while list + (if (not (funcall func (car list))) + (setq result (cons (car list) result))) + (setq list (cdr list))) + (nreverse result)))) + +(global-set-key [(control x) (meta f)] 'find-file-recursively) + +(provide 'find-recursive) diff --git a/emacs/nxhtml/alts/javascript-mozlab.el b/emacs/nxhtml/alts/javascript-mozlab.el new file mode 100644 index 0000000..bcec39b --- /dev/null +++ b/emacs/nxhtml/alts/javascript-mozlab.el @@ -0,0 +1,712 @@ +;;; javascript.el --- Major mode for editing JavaScript source text + +;; Copyright (C) 2006 Karl Landström + +;; Author: Karl Landström <kland@comhem.se> +;; Maintainer: Karl Landström <kland@comhem.se> +;; Version: 2.0 Beta 8 +;; Date: 2006-12-26 +;; Keywords: languages, oop + +;; 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: +;; +;; The main features of this JavaScript mode are syntactic +;; highlighting (enabled with `font-lock-mode' or +;; `global-font-lock-mode'), automatic indentation and filling of +;; comments. +;; +;; This package has (only) been tested with GNU Emacs 21.4 (the latest +;; stable release). +;; +;; Installation: +;; +;; Put this file in a directory where Emacs can find it (`C-h v +;; load-path' for more info). Then add the following lines to your +;; Emacs initialization file: +;; +;; (add-to-list 'auto-mode-alist '("\\.js\\'" . javascript-mode)) +;; (autoload 'javascript-mode "javascript" nil t) +;; +;; General Remarks: +;; +;; This mode assumes that block comments are not nested inside block +;; comments and that strings do not contain line breaks. +;; +;; Exported names start with "javascript-" whereas private names start +;; with "js-". +;; +;; Changes: +;; +;; See javascript.el.changelog. + +;;; Code: + +(require 'cc-mode) +(require 'font-lock) +(require 'newcomment) + +(defgroup javascript nil + "Customization variables for `javascript-mode'." + :tag "JavaScript" + :group 'languages) + +(defcustom javascript-indent-level 4 + "Number of spaces for each indentation step." + :type 'integer + :group 'javascript) + +(defcustom javascript-auto-indent-flag t + "Automatic indentation with punctuation characters. If non-nil, the +current line is indented when certain punctuations are inserted." + :type 'boolean + :group 'javascript) + + +;; --- Keymap --- + +(defvar javascript-mode-map nil + "Keymap used in JavaScript mode.") + +(unless javascript-mode-map + (setq javascript-mode-map (make-sparse-keymap))) + +(when javascript-auto-indent-flag + (mapc (lambda (key) + (define-key javascript-mode-map key 'javascript-insert-and-indent)) + '("{" "}" "(" ")" ":" ";" ","))) + +(defun javascript-insert-and-indent (key) + "Run command bound to key and indent current line. Runs the command +bound to KEY in the global keymap and indents the current line." + (interactive (list (this-command-keys))) + (call-interactively (lookup-key (current-global-map) key)) + (indent-according-to-mode)) + + +;; --- Syntax Table And Parsing --- + +(defvar javascript-mode-syntax-table + (let ((table (make-syntax-table))) + (c-populate-syntax-table table) + + ;; The syntax class of underscore should really be `symbol' ("_") + ;; but that makes matching of tokens much more complex as e.g. + ;; "\\<xyz\\>" matches part of e.g. "_xyz" and "xyz_abc". Defines + ;; it as word constituent for now. + (modify-syntax-entry ?_ "w" table) + + table) + "Syntax table used in JavaScript mode.") + + +(defun js-re-search-forward-inner (regexp &optional bound count) + "Auxiliary function for `js-re-search-forward'." + (let ((parse) + (saved-point (point-min))) + (while (> count 0) + (re-search-forward regexp bound) + (setq parse (parse-partial-sexp saved-point (point))) + (cond ((nth 3 parse) + (re-search-forward + (concat "\\([^\\]\\|^\\)" (string (nth 3 parse))) + (save-excursion (end-of-line) (point)) t)) + ((nth 7 parse) + (forward-line)) + ((or (nth 4 parse) + (and (eq (char-before) ?\/) (eq (char-after) ?\*))) + (re-search-forward "\\*/")) + (t + (setq count (1- count)))) + (setq saved-point (point)))) + (point)) + + +(defun js-re-search-forward (regexp &optional bound noerror count) + "Search forward but ignore strings and comments. Invokes +`re-search-forward' but treats the buffer as if strings and +comments have been removed." + (let ((saved-point (point)) + (search-expr + (cond ((null count) + '(js-re-search-forward-inner regexp bound 1)) + ((< count 0) + '(js-re-search-backward-inner regexp bound (- count))) + ((> count 0) + '(js-re-search-forward-inner regexp bound count))))) + (condition-case err + (eval search-expr) + (search-failed + (goto-char saved-point) + (unless noerror + (error (error-message-string err))))))) + + +(defun js-re-search-backward-inner (regexp &optional bound count) + "Auxiliary function for `js-re-search-backward'." + (let ((parse) + (saved-point (point-min))) + (while (> count 0) + (re-search-backward regexp bound) + (when (and (> (point) (point-min)) + (save-excursion (backward-char) (looking-at "/[/*]"))) + (forward-char)) + (setq parse (parse-partial-sexp saved-point (point))) + (cond ((nth 3 parse) + (re-search-backward + (concat "\\([^\\]\\|^\\)" (string (nth 3 parse))) + (save-excursion (beginning-of-line) (point)) t)) + ((nth 7 parse) + (goto-char (nth 8 parse))) + ((or (nth 4 parse) + (and (eq (char-before) ?/) (eq (char-after) ?*))) + (re-search-backward "/\\*")) + (t + (setq count (1- count)))))) + (point)) + + +(defun js-re-search-backward (regexp &optional bound noerror count) + "Search backward but ignore strings and comments. Invokes +`re-search-backward' but treats the buffer as if strings and +comments have been removed." + (let ((saved-point (point)) + (search-expr + (cond ((null count) + '(js-re-search-backward-inner regexp bound 1)) + ((< count 0) + '(js-re-search-forward-inner regexp bound (- count))) + ((> count 0) + '(js-re-search-backward-inner regexp bound count))))) + (condition-case err + (eval search-expr) + (search-failed + (goto-char saved-point) + (unless noerror + (error (error-message-string err))))))) + + +(defun js-continued-var-decl-list-p () + "Return non-nil if point is inside a continued variable declaration +list." + (interactive) + (let ((start (save-excursion (js-re-search-backward "\\<var\\>" nil t)))) + (and start + (save-excursion (re-search-backward "\n" start t)) + (not (save-excursion + (js-re-search-backward + ";\\|[^, \t][ \t]*\\(/[/*]\\|$\\)" start t)))))) + + +;; --- Font Lock --- + +(defun js-inside-param-list-p () + "Return non-nil if point is inside a function parameter list." + (condition-case err + (save-excursion + (up-list -1) + (and (looking-at "(") + (progn (backward-word 1) + (or (looking-at "function") + (progn (backward-word 1) (looking-at "function")))))) + (error nil))) + + +(defconst js-function-heading-1-re + "^[ \t]*function[ \t]+\\(\\w+\\)" + "Regular expression matching the start of a function header.") + +(defconst js-function-heading-2-re + "^[ \t]*\\(\\w+\\)[ \t]*:[ \t]*function\\>" + "Regular expression matching the start of a function entry in + an associative array.") + +(defconst js-keyword-re + (regexp-opt '("abstract" "break" "case" "catch" "class" "const" + "continue" "debugger" "default" "delete" "do" "else" + "enum" "export" "extends" "final" "finally" "for" + "function" "goto" "if" "implements" "import" "in" + "instanceof" "interface" "native" "new" "package" + "private" "protected" "public" "return" "static" + "super" "switch" "synchronized" "this" "throw" + "throws" "transient" "try" "typeof" "var" "void" + "volatile" "while" "with" + "let") 'words) + "Regular expression matching any JavaScript keyword.") + +(defconst js-basic-type-re + (regexp-opt '("boolean" "byte" "char" "double" "float" "int" "long" + "short" "void") 'words) + "Regular expression matching any predefined type in JavaScript.") + +(defconst js-constant-re + (regexp-opt '("false" "null" "true") 'words) + "Regular expression matching any future reserved words in JavaScript.") + + +(defconst js-font-lock-keywords-1 + (list + "\\<import\\>" + (list js-function-heading-1-re 1 font-lock-function-name-face) + (list js-function-heading-2-re 1 font-lock-function-name-face) + (list "[=(][ \t]*\\(/.*?[^\\]/\\w*\\)" 1 font-lock-string-face)) + "Level one font lock.") + +(defconst js-font-lock-keywords-2 + (append js-font-lock-keywords-1 + (list (list js-keyword-re 1 font-lock-keyword-face) + (cons js-basic-type-re font-lock-type-face) + (cons js-constant-re font-lock-constant-face))) + "Level two font lock.") + + +;; Limitations with variable declarations: There seems to be no +;; sensible way to highlight variables occuring after an initialized +;; variable in a variable list. For instance, in +;; +;; var x, y = f(a, b), z +;; +;; z will not be highlighted. + +(defconst js-font-lock-keywords-3 + (append + js-font-lock-keywords-2 + (list + + ;; variable declarations + (list + (concat "\\<\\(const\\|var\\)\\>\\|" js-basic-type-re) + (list "\\(\\w+\\)[ \t]*\\([=;].*\\|,\\|/[/*]\\|$\\)" + nil + nil + '(1 font-lock-variable-name-face))) + + ;; continued variable declaration list + (list + (concat "^[ \t]*\\w+[ \t]*\\([,;=]\\|/[/*]\\|$\\)") + (list "\\(\\w+\\)[ \t]*\\([=;].*\\|,\\|/[/*]\\|$\\)" + '(if (save-excursion (backward-char) (js-continued-var-decl-list-p)) + (backward-word 1) + (end-of-line)) + '(end-of-line) + '(1 font-lock-variable-name-face))) + + ;; formal parameters + (list + (concat "\\<function\\>\\([ \t]+\\w+\\)?[ \t]*([ \t]*\\w") + (list "\\(\\w+\\)\\([ \t]*).*\\)?" + '(backward-char) + '(end-of-line) + '(1 font-lock-variable-name-face))) + + ;; continued formal parameter list + (list + (concat "^[ \t]*\\w+[ \t]*[,)]") + (list "\\w+" + '(if (save-excursion (backward-char) (js-inside-param-list-p)) + (backward-word 1) + (end-of-line)) + '(end-of-line) + '(0 font-lock-variable-name-face))))) + "Level three font lock.") + +(defconst js-font-lock-keywords + '(js-font-lock-keywords-3 js-font-lock-keywords-1 js-font-lock-keywords-2 + js-font-lock-keywords-3) + "See `font-lock-keywords'.") + + +;; --- Indentation --- + +(defconst js-possibly-braceless-keyword-re + (regexp-opt + '("catch" "do" "else" "finally" "for" "if" "try" "while" "with" "let") + 'words) + "Regular expression matching keywords that are optionally + followed by an opening brace.") + +(defconst js-indent-operator-re + (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|" + (regexp-opt '("in" "instanceof") 'words)) + "Regular expression matching operators that affect indentation + of continued expressions.") + + +(defun js-looking-at-operator-p () + "Return non-nil if text after point is an operator (that is not +a comma)." + (save-match-data + (and (looking-at js-indent-operator-re) + (or (not (looking-at ":")) + (save-excursion + (and (js-re-search-backward "[?:{]\\|\\<case\\>" nil t) + (looking-at "?"))))))) + + +(defun js-continued-expression-p () + "Returns non-nil if the current line continues an expression." + (save-excursion + (back-to-indentation) + (or (js-looking-at-operator-p) + (and (js-re-search-backward "\n" nil t) + (progn + (skip-chars-backward " \t") + (backward-char) + (and (> (point) (point-min)) + (save-excursion (backward-char) (not (looking-at "[/*]/"))) + (js-looking-at-operator-p) + (and (progn (backward-char) + (not (looking-at "++\\|--\\|/[/*]")))))))))) + + +(defun js-end-of-do-while-loop-p () + "Returns non-nil if word after point is `while' of a do-while +statement, else returns nil. A braceless do-while statement +spanning several lines requires that the start of the loop is +indented to the same column as the current line." + (interactive) + (save-excursion + (save-match-data + (when (looking-at "\\s-*\\<while\\>") + (if (save-excursion + (skip-chars-backward "[ \t\n]*}") + (looking-at "[ \t\n]*}")) + (save-excursion + (backward-list) (backward-word 1) (looking-at "\\<do\\>")) + (js-re-search-backward "\\<do\\>" (point-at-bol) t) + (or (looking-at "\\<do\\>") + (let ((saved-indent (current-indentation))) + (while (and (js-re-search-backward "^[ \t]*\\<" nil t) + (/= (current-indentation) saved-indent))) + (and (looking-at "[ \t]*\\<do\\>") + (not (js-re-search-forward + "\\<while\\>" (point-at-eol) t)) + (= (current-indentation) saved-indent))))))))) + + +(defun js-ctrl-statement-indentation () + "Returns the proper indentation of the current line if it +starts the body of a control statement without braces, else +returns nil." + (save-excursion + (back-to-indentation) + (when (save-excursion + (and (not (looking-at "[{]")) + (progn + (js-re-search-backward "[[:graph:]]" nil t) + (forward-char) + (when (= (char-before) ?\)) (backward-list)) + (skip-syntax-backward " ") + (skip-syntax-backward "w") + (looking-at js-possibly-braceless-keyword-re)) + (not (js-end-of-do-while-loop-p)))) + (save-excursion + (goto-char (match-beginning 0)) + (+ (current-indentation) javascript-indent-level))))) + + +(defun js-proper-indentation (parse-status) + "Return the proper indentation for the current line." + (save-excursion + (back-to-indentation) + (let ((ctrl-stmt-indent (js-ctrl-statement-indentation)) + (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>")) + (continued-expr-p (js-continued-expression-p))) + (cond (ctrl-stmt-indent) + ((js-continued-var-decl-list-p) + (js-re-search-backward "\\<var\\>" nil t) + (+ (current-indentation) javascript-indent-level)) + ((nth 1 parse-status) + (goto-char (nth 1 parse-status)) + (if (looking-at "[({[][ \t]*\\(/[/*]\\|$\\)") + (progn + (skip-syntax-backward " ") + (when (= (char-before) ?\)) (backward-list)) + (back-to-indentation) + (cond (same-indent-p + (current-column)) + (continued-expr-p + (+ (current-column) (* 2 javascript-indent-level))) + (t + (+ (current-column) javascript-indent-level)))) + (unless same-indent-p + (forward-char) + (skip-chars-forward " \t")) + (current-column))) + (continued-expr-p javascript-indent-level) + (t 0))))) + + +(defun javascript-indent-line () + "Indent the current line as JavaScript source text." + (interactive) + (let ((parse-status + (save-excursion (parse-partial-sexp (point-min) (point-at-bol)))) + (offset (- (current-column) (current-indentation)))) + (when (not (nth 8 parse-status)) + (indent-line-to (js-proper-indentation parse-status)) + (when (> offset 0) (forward-char offset))))) + + +;; --- Filling --- + +;; FIXME: It should be possible to use the more sofisticated function +;; `c-fill-paragraph' in `cc-cmds.el' instead. However, just setting +;; `fill-paragraph-function' to `c-fill-paragraph' does not work; +;; inside `c-fill-paragraph', `fill-paragraph-function' evaluates to +;; nil!? + +(defun js-backward-paragraph () + "Move backward to start of paragraph. Postcondition: Point is at +beginning of buffer or the previous line contains only whitespace." + (forward-line -1) + (while (not (or (bobp) (looking-at "^[ \t]*$"))) + (forward-line -1)) + (when (not (bobp)) (forward-line 1))) + + +(defun js-forward-paragraph () + "Move forward to end of paragraph. Postcondition: Point is at +end of buffer or the next line contains only whitespace." + (forward-line 1) + (while (not (or (eobp) (looking-at "^[ \t]*$"))) + (forward-line 1)) + (when (not (eobp)) (backward-char 1))) + + +(defun js-fill-block-comment-paragraph (parse-status justify) + "Fill current paragraph as a block comment. PARSE-STATUS is the +result of `parse-partial-regexp' from beginning of buffer to +point. JUSTIFY has the same meaning as in `fill-paragraph'." + (let ((offset (save-excursion + (goto-char (nth 8 parse-status)) (current-indentation)))) + (save-excursion + (save-restriction + (narrow-to-region (save-excursion + (goto-char (nth 8 parse-status)) (point-at-bol)) + (save-excursion + (goto-char (nth 8 parse-status)) + (re-search-forward "*/"))) + (narrow-to-region (save-excursion + (js-backward-paragraph) + (when (looking-at "^[ \t]*$") (forward-line 1)) + (point)) + (save-excursion + (js-forward-paragraph) + (when (looking-at "^[ \t]*$") (backward-char)) + (point))) + (goto-char (point-min)) + (while (not (eobp)) + (delete-horizontal-space) + (forward-line 1)) + (let ((fill-column (- fill-column offset)) + (fill-paragraph-function nil)) + (fill-paragraph justify)) + + ;; In Emacs 21.4 as opposed to CVS Emacs 22, + ;; `fill-paragraph' seems toadd a newline at the end of the + ;; paragraph. Remove it! + (goto-char (point-max)) + (when (looking-at "^$") (backward-delete-char 1)) + + (goto-char (point-min)) + (while (not (eobp)) + (indent-to offset) + (forward-line 1)))))) + + +(defun js-sline-comment-par-start () + "Return point at the beginning of the line where the current +single-line comment paragraph starts." + (save-excursion + (beginning-of-line) + (while (and (not (bobp)) + (looking-at "^[ \t]*//[ \t]*[[:graph:]]")) + (forward-line -1)) + (unless (bobp) (forward-line 1)) + (point))) + + +(defun js-sline-comment-par-end () + "Return point at end of current single-line comment paragraph." + (save-excursion + (beginning-of-line) + (while (and (not (eobp)) + (looking-at "^[ \t]*//[ \t]*[[:graph:]]")) + (forward-line 1)) + (unless (bobp) (backward-char)) + (point))) + + +(defun js-sline-comment-offset (line) + "Return the column at the start of the current single-line +comment paragraph." + (save-excursion + (goto-line line) + (re-search-forward "//" (point-at-eol)) + (goto-char (match-beginning 0)) + (current-column))) + + +(defun js-sline-comment-text-offset (line) + "Return the column at the start of the text of the current +single-line comment paragraph." + (save-excursion + (goto-line line) + (re-search-forward "//[ \t]*" (point-at-eol)) + (current-column))) + + +(defun js-at-empty-sline-comment-p () + "Return non-nil if inside an empty single-line comment." + (and (save-excursion + (beginning-of-line) + (not (looking-at "^.*//.*[[:graph:]]"))) + (save-excursion + (re-search-backward "//" (point-at-bol) t)))) + + +(defun js-fill-sline-comments (parse-status justify) + "Fill current paragraph as a sequence of single-line comments. +PARSE-STATUS is the result of `parse-partial-regexp' from +beginning of buffer to point. JUSTIFY has the same meaning as in +`fill-paragraph'." + (when (not (js-at-empty-sline-comment-p)) + (let* ((start (js-sline-comment-par-start)) + (start-line (1+ (count-lines (point-min) start))) + (end (js-sline-comment-par-end)) + (offset (js-sline-comment-offset start-line)) + (text-offset (js-sline-comment-text-offset start-line))) + (save-excursion + (save-restriction + (narrow-to-region start end) + (goto-char (point-min)) + (while (re-search-forward "^[ \t]*//[ \t]*" nil t) + (replace-match "") + (forward-line 1)) + (let ((fill-paragraph-function nil) + (fill-column (- fill-column text-offset))) + (fill-paragraph justify)) + + ;; In Emacs 21.4 as opposed to CVS Emacs 22, + ;; `fill-paragraph' seems toadd a newline at the end of the + ;; paragraph. Remove it! + (goto-char (point-max)) + (when (looking-at "^$") (backward-delete-char 1)) + + (goto-char (point-min)) + (while (not (eobp)) + (indent-to offset) + (insert "//") + (indent-to text-offset) + (forward-line 1))))))) + + +(defun js-trailing-comment-p (parse-status) + "Return non-nil if inside a trailing comment. PARSE-STATUS is +the result of `parse-partial-regexp' from beginning of buffer to +point." + (save-excursion + (when (nth 4 parse-status) + (goto-char (nth 8 parse-status)) + (skip-chars-backward " \t") + (not (bolp))))) + + +(defun js-block-comment-p (parse-status) + "Return non-nil if inside a block comment. PARSE-STATUS is the +result of `parse-partial-regexp' from beginning of buffer to +point." + (save-excursion + (save-match-data + (when (nth 4 parse-status) + (goto-char (nth 8 parse-status)) + (looking-at "/\\*"))))) + + +(defun javascript-fill-paragraph (&optional justify) + "If inside a comment, fill the current comment paragraph. +Trailing comments are ignored." + (interactive) + (let ((parse-status (parse-partial-sexp (point-min) (point)))) + (when (and (nth 4 parse-status) + (not (js-trailing-comment-p parse-status))) + (if (js-block-comment-p parse-status) + (js-fill-block-comment-paragraph parse-status justify) + (js-fill-sline-comments parse-status justify)))) + t) + + +;; --- Imenu --- + +(defconst js-imenu-generic-expression + (list + (list + nil + "function\\s-+\\(\\w+\\)\\s-*(" + 1)) + "Regular expression matching top level procedures. Used by imenu.") + + +;; --- Main Function --- + +;;;###autoload +(defun javascript-mode () + "Major mode for editing JavaScript source text. + +Key bindings: + +\\{javascript-mode-map}" + (interactive) + (kill-all-local-variables) + + (use-local-map javascript-mode-map) + (set-syntax-table javascript-mode-syntax-table) + (set (make-local-variable 'indent-line-function) 'javascript-indent-line) + (set (make-local-variable 'font-lock-defaults) (list js-font-lock-keywords)) + + (set (make-local-variable 'parse-sexp-ignore-comments) t) + + ;; Comments + (setq comment-start "// ") + (setq comment-end "") + (set (make-local-variable 'fill-paragraph-function) + 'javascript-fill-paragraph) + + ;; Make c-mark-function work + (setq c-nonsymbol-token-regexp "!=\\|%=\\|&[&=]\\|\\*[/=]\\|\\+[+=]\\|-[=-]\\|/[*/=]\\|<\\(?:<=\\|[<=]\\)\\|==\\|>\\(?:>\\(?:>=\\|[=>]\\)\\|[=>]\\)\\|\\^=\\||[=|]\\|[]!%&(-,./:-?[{-~^-]" + c-stmt-delim-chars "^;{}?:" + c-syntactic-ws-end "[ \n +\f/]" + c-syntactic-eol "\\(\\s \\|/\\*\\([^*\n +]\\|\\*[^/\n +]\\)*\\*/\\)*\\(\\(/\\*\\([^*\n +]\\|\\*[^/\n +]\\)*\\|\\\\\\)?$\\|//\\)") + + ;; Imenu + (setq imenu-case-fold-search nil) + (set (make-local-variable 'imenu-generic-expression) + js-imenu-generic-expression) + + (setq major-mode 'javascript-mode) + (setq mode-name "JavaScript") + (run-hooks 'javascript-mode-hook)) + + +(provide 'javascript-mode) +;;; javascript.el ends here diff --git a/emacs/nxhtml/alts/smarty-mode-vdebout.el b/emacs/nxhtml/alts/smarty-mode-vdebout.el new file mode 100644 index 0000000..94d7352 --- /dev/null +++ b/emacs/nxhtml/alts/smarty-mode-vdebout.el @@ -0,0 +1,2715 @@ +;;; smarty-mode.el --- major mode for editing Smarty templates + +;; Author: Vincent DEBOUT <deboutv@free.fr> +;; Maintainer: Vincent DEBOUT <deboutv@free.fr> +;; Keywords: languages smarty templates +;; WWW: http://deboutv.free.fr/lisp/smarty/ + +;;; License + +;; 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; History + +;; $Log: smarty-mode.el,v $ +;; Revision 1.6 2006/12/16 19:54:26 vincent +;; Update release version +;; +;; Revision 1.5 2006/12/16 19:53:00 vincent +;; Fix bug #15 +;; +;; Revision 1.4 2006/12/16 14:59:46 vincent +;; Fix bugs for release +;; +;; Revision 1.3 2006/11/19 12:29:53 vincent +;; Fix highlight bug, add templates +;; +;; Revision 1.2 2006/11/12 11:44:18 vincent +;; First release commit +;; + +(defconst smarty-version "0.0.4" + "Smarty Mode version number.") + +(defconst smarty-time-stamp "2006-12-16" + "Smarty Mode time stamp for last update.") + +(require 'font-lock) +(require 'cc-mode) +(require 'custom) +(require 'etags) +(eval-when-compile +(require 'regexp-opt)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Customization +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defgroup smarty nil + "Customizations for Smarty mode." + :prefix "smarty-" + :group 'languages) + +(defgroup smarty-mode nil + "Customizations for Smarty mode." + :group 'smarty) + +(defcustom smarty-electric-mode t + "*Non-nil enables electrification (automatic template generation). +If nil, template generators can still be invoked through key bindings and +menu. Is indicated in the modeline by \"/e\" after the mode name and can be +toggled by `\\[smarty-electric-mode]'." + :type 'boolean + :group 'smarty-mode) + +(defcustom smarty-stutter-mode t + "*Non-nil enables stuttering. +Is indicated in the modeline by \"/s\" after the mode name and can be toggled +by `\\[smarty-stutter-mode]'." + :type 'boolean + :group 'smarty-mode) + +(defgroup smarty-menu nil + "Customizations for menues." + :group 'smarty) + +(defcustom smarty-source-file-menu t + "*Non-nil means add a menu of all source files in current directory." + :type 'boolean + :group 'smarty-menu) + +(defgroup smarty-highlight nil + "Customizations for highlight." + :group 'smarty) + +(defcustom smarty-highlight-plugin-functions t + "*Non-nil means highlight the plugin functions in the buffer." + :type 'boolean + :group 'smarty-highlight) + +(defgroup smarty-template nil + "Customizations for templates." + :group 'smarty) + +(defgroup smarty-header nil + "Customizations for header template." + :group 'smarty-template) + +(defcustom smarty-file-header "" + "*String or file to insert as file header. +If the string specifies an existing file name, the contents of the file is +inserted, otherwise the string itself is inserted as file header. +Type `C-j' for newlines. +If the header contains RCS keywords, they may be written as <RCS>Keyword<RCS> +if the header needs to be version controlled. + +The following keywords for template generation are supported: + <filename> : replaced by the name of the buffer + <author> : replaced by the user name and email address + \(`user-full-name',`mail-host-address', `user-mail-address') + <login> : replaced by user login name (`user-login-name') + <company> : replaced by contents of option `smarty-company-name' + <date> : replaced by the current date + <year> : replaced by the current year + <copyright> : replaced by copyright string (`smarty-copyright-string') + <cursor> : final cursor position." + :type 'string + :group 'smarty-header) + +(defcustom smarty-file-footer "" + "*String or file to insert as file footer. +If the string specifies an existing file name, the contents of the file is +inserted, otherwise the string itself is inserted as file footer (i.e. at +the end of the file). +Type `C-j' for newlines. +The same keywords as in option `smarty-file-header' can be used." + :type 'string + :group 'smarty-header) + +(defcustom smarty-company-name "" + "*Name of company to insert in file header. +See option `smarty-file-header'." + :type 'string + :group 'smarty-header) + +(defcustom smarty-copyright-string "" + "*Copyright string to insert in file header. +Can be multi-line string (type `C-j' for newline) and contain other file +header keywords (see option `smarty-file-header')." + :type 'string + :group 'smarty-header) + +(defcustom smarty-date-format "%Y-%m-%d" + "*Specifies the date format to use in the header. +This string is passed as argument to the command `format-time-string'. +For more information on format strings, see the documentation for the +`format-time-string' command (C-h f `format-time-string')." + :type 'string + :group 'smarty-header) + +(defcustom smarty-modify-date-prefix-string "" + "*Prefix string of modification date in Smarty file header. +If actualization of the modification date is called (menu, +`\\[smarty-template-modify]'), this string is searched and the rest +of the line replaced by the current date." + :type 'string + :group 'smarty-header) + +(defcustom smarty-modify-date-on-saving nil + "*Non-nil means update the modification date when the buffer is saved. +Calls function `\\[smarty-template-modify]'). + +NOTE: Activate the new setting in a Smarty buffer by using the menu entry + \"Activate Options\"." + :type 'boolean + :group 'smarty-header) + +(defgroup smarty-misc nil + "Miscellaneous customizations." + :group 'smarty) + +(defcustom smarty-left-delimiter "{" + "Left escaping delimiter." + :type 'string + :group 'smarty-misc) + +(defcustom smarty-right-delimiter "}" + "Right escaping delimiter." + :type 'string + :group 'smarty-misc) + +(defcustom smarty-intelligent-tab t + "*Non-nil means `TAB' does indentation, word completion and tab insertion. +That is, if preceding character is part of a word then complete word, +else if not at beginning of line then insert tab, +else if last command was a `TAB' or `RET' then dedent one step, +else indent current line (i.e. `TAB' is bound to `smarty-electric-tab'). +If nil, TAB always indents current line (i.e. `TAB' is bound to +`indent-according-to-mode'). + +NOTE: Activate the new setting in a Smarty buffer by using the menu entry + \"Activate Options\"." + :type 'boolean + :group 'smarty-misc) + +(defcustom smarty-word-completion-in-minibuffer t + "*Non-nil enables word completion in minibuffer (for template prompts). + +NOTE: Activate the new setting by restarting Emacs." + :type 'boolean + :group 'smarty-misc) + +(defcustom smarty-word-completion-case-sensitive nil + "*Non-nil means word completion using `TAB' is case sensitive. +That is, `TAB' completes words that start with the same letters and case. +Otherwise, case is ignored." + :type 'boolean + :group 'smarty-misc) + +;; Functions + +(defun smarty-customize () + "Call the customize function with `smarty' as argument." + (interactive) + (customize-browse 'smarty)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Variables +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-menu-max-size 20 + "*Specifies the maximum size of a menu before splitting it into submenues.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Menu tools functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-menu-split (list title) + "Split menu LIST into several submenues, if number of +elements > `smarty-menu-max-size'." + (if (> (length list) smarty-menu-max-size) + (let ((remain list) + (result '()) + (sublist '()) + (menuno 1) + (i 0)) + (while remain + (setq sublist (cons (car remain) sublist)) + (setq remain (cdr remain)) + (setq i (+ i 1)) + (if (= i smarty-menu-max-size) + (progn + (setq result (cons (cons (format "%s %s" title menuno) + (nreverse sublist)) result)) + (setq i 0) + (setq menuno (+ menuno 1)) + (setq sublist '())))) + (and sublist + (setq result (cons (cons (format "%s %s" title menuno) + (nreverse sublist)) result))) + (nreverse result)) + list)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Source file menu +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-sources-menu nil) + +;; Create the source menu +(defun smarty-add-source-files-menu () + "Scan directory for all Smarty source files and generate menu. +The directory of the current source file is scanned." + (interactive) + (message "Scanning directory for source files ...") + (let ((newmap (current-local-map)) + (file-list (smarty-get-source-files)) + menu-list found) + ;; Create list for menu + (setq found nil) + (while file-list + (setq found t) + (setq menu-list (cons (vector (car file-list) + (list 'find-file (car file-list)) t) + menu-list)) + (setq file-list (cdr file-list))) + (setq menu-list (smarty-menu-split menu-list "Sources")) + (when found (setq menu-list (cons "--" menu-list))) + (setq menu-list (cons ["*Rescan*" smarty-add-source-files-menu t] menu-list)) + (setq menu-list (cons "Sources" menu-list)) + ;; Create menu + (easy-menu-add menu-list) + (easy-menu-define smarty-sources-menu newmap + "Smarty source files menu" menu-list)) + (message "")) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Smarty menu +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-create-mode-menu () + "Create Smarty Mode menu." + `("Smarty" + ("Templates" + ("Built-in Functions" + ["capture" smarty-template-capture t] + ["config_load" smarty-template-config-load t] + ["else" smarty-template-else t] + ["elseif" smarty-template-elseif t] + ["foreach" smarty-template-foreach t] + ["foreachelse" smarty-template-foreachelse t] + ["if" smarty-template-if t] + ["include" smarty-template-include t] + ["include_php" smarty-template-include-php t] + ["insert" smarty-template-insert t] + ["ldelim" smarty-template-ldelim t] + ["literal" smarty-template-literal t] + ["php" smarty-template-php t] + ["rdelim" smarty-template-rdelim t] + ["section" smarty-template-section t] + ["sectionelse" smarty-template-sectionelse t] + ["strip" smarty-template-strip t]) + ("Custom Functions" + ["assign" smarty-template-assign t] + ["counter" smarty-template-counter t] + ["cycle" smarty-template-cycle t] + ["debug" smarty-template-debug t] + ["eval" smarty-template-eval t] + ["fetch" smarty-template-fetch t] + ["html_checkboxes" smarty-template-html-checkboxes t] + ["html_image" smarty-template-html-image t] + ["html_options" smarty-template-html-options t] + ["html_radios" smarty-template-html-radios t] + ["html_select_date" smarty-template-html-select-date t] + ["html_select_time" smarty-template-html-select-time t] + ["html_table" smarty-template-html-table t] + ["mailto" smarty-template-mailto t] + ["math" smarty-template-math t] + ["popup" smarty-template-popup t] + ["popup_init" smarty-template-popup-init t] + ["textformat" smarty-template-textformat t]) + ("Variable Modifiers" + ["capitalize" smarty-template-capitalize t] + ["cat" smarty-template-cat t] + ["count_characters" smarty-template-count-characters t] + ["count_paragraphs" smarty-template-count-paragraphs t] + ["count_sentences" smarty-template-count-sentences t] + ["count_words" smarty-template-count-words t] + ["date_format" smarty-template-date-format t] + ["default" smarty-template-default t] + ["escape" smarty-template-escape t] + ["indent" smarty-template-indent t] + ["lower" smarty-template-lower t] + ["nl2br" smarty-template-nl2br t] + ["regex_replace" smarty-template-regex-replace t] + ["replace" smarty-template-replace t] + ["spacify" smarty-template-spacify t] + ["string_format" smarty-template-string-format t] + ["strip" smarty-template-vstrip t] + ["strip_tags" smarty-template-strip-tags t] + ["truncate" smarty-template-truncate t] + ["upper" smarty-template-upper t] + ["wordwrap" smarty-template-wordwrap t]) + ("Plugins (Functions)" + ("SmartyFormtool" + ["formtool_checkall" smarty-template-formtool-checkall t] + ["formtool_copy" smarty-template-formtool-copy t] + ["formtool_count_chars" smarty-template-formtool-count-chars t] + ["formtool_init" smarty-template-formtool-init t] + ["formtool_move" smarty-template-formtool-move t] + ["formtool_moveall" smarty-template-formtool-moveall t] + ["formtool_movedown" smarty-template-formtool-movedown t] + ["formtool_moveup" smarty-template-formtool-moveup t] + ["formtool_remove" smarty-template-formtool-remove t] + ["formtool_rename" smarty-template-formtool-rename t] + ["formtool_save" smarty-template-formtool-save t] + ["formtool_selectall" smarty-template-formtool-selectall t]) + ("SmartyPaginate" + ["paginate_first" smarty-template-paginate-first t] + ["paginate_last" smarty-template-paginate-last t] + ["paginate_middle" smarty-template-paginate-middle t] + ["paginate_next" smarty-template-paginate-next t] + ["paginate_prev" smarty-template-paginate-prev t]) + ("SmartyValidate" + ["validate" smarty-template-validate t])) + ("Plugins (Variable Modifiers)" + ("AlternativeDateModifierPlugin" + ["date_format2" smarty-template-date-formatto t]) + ("B2Smilies" + ["B2Smilies" smarty-template-btosmilies t]) + ("BBCodePlugin" + ["bbcode2html" smarty-template-bbcodetohtml t]) + ) + "--" + ["Insert Header" smarty-template-header t] + ["Insert Footer" smarty-template-footer t] + ["Insert Date" smarty-template-insert-date t] + ["Modify Date" smarty-template-modify t]) + "--" + ["Show Messages" smarty-show-messages :keys "C-c M-m"] + ["Smarty Mode Documentation" smarty-doc-mode :keys "C-c C-h"] + ["Version" smarty-version :keys "C-c C-v"] + "--" + ("Options" + ("Mode" + ["Electric Mode" + (progn (customize-set-variable 'smarty-electric-mode + (not smarty-electric-mode)) + (smarty-mode-line-update)) + :style toggle :selected smarty-electric-mode :keys "C-c C-m C-e"] + ["Stutter Mode" + (progn (customize-set-variable 'smarty-stutter-mode + (not smarty-stutter-mode)) + (smarty-mode-line-update)) + :style toggle :selected smarty-stutter-mode :keys "C-c C-m C-s"] + "--" + ["Customize Group..." (customize-group 'smarty-mode) t]) + ("Menu" + ["Source Menu" + (customize-set-variable 'smarty-source-file-menu + (not smarty-source-file-menu)) + :style toggle :selected smarty-source-file-menu] + "--" + ["Customize Group..." (customize-group 'smarty-menu) t]) + ("Highlight" + ["Highlight plugin functions" + (progn (customize-set-variable 'smarty-highlight-plugin-functions + (not smarty-highlight-plugin-functions))) + :style toggle :selected smarty-highlight-plugin-functions] + "--" + ["Customize Group..." (customize-group 'smarty-highlight) t]) + ("Template" + ("Header" + ["Header template..." + (customize-option 'smarty-file-header) t] + ["Footer template..." + (customize-option 'smarty-file-footer) t] + ["Company..." + (customize-option 'smarty-company-name) t] + ["Copyright..." + (customize-option 'smarty-copyright-string) t] + ["Date format..." + (customize-option 'smarty-date-format) t] + ["Modify date prefix..." + (customize-option 'smarty-modify-date-prefix-string) t] + ["Modify date on saving" + (customize-set-variable 'smarty-modify-date-on-saving + (not smarty-modify-date-on-saving)) + :style toggle :selected smarty-modify-date-on-saving] + "--" + ["Customize Group..." (customize-group 'smarty-header) t]) + "--" + ["Customize Group..." (customize-group 'smarty-template) t]) + ("Miscellaneous" + ["Left delimiter..." + (customize-option 'smarty-left-delimiter) t] + ["Right delimiter..." + (customize-option 'smarty-right-delimiter) t] + ["Use Intelligent Tab" + (progn (customize-set-variable 'smarty-intelligent-tab + (not smarty-intelligent-tab)) + (smarty-activate-customizations)) + :style toggle :selected smarty-intelligent-tab] + ["Word Completion in Minibuffer" + (progn (customize-set-variable 'smarty-word-completion-in-minibuffer + (not smarty-word-completion-in-minibuffer)) + (message "Activate new setting by saving options and restarting Emacs")) + :style toggle :selected smarty-word-completion-in-minibuffer] + ["Completion is case sensitive" + (customize-set-variable 'smarty-word-completion-case-sensitive + (not smarty-word-completion-case-sensitive)) + :style toggle :selected smarty-word-completion-case-sensitive] + "--" + ["Customize Group..." (customize-group 'smarty-misc) t]) + "--" + ["Save Options" customize-save-customized t] + ["Activate Options" smarty-activate-customizations t] + ["Browse Options..." smarty-customize t]))) + +(defvar smarty-mode-menu-list (smarty-create-mode-menu) + "Smarty Mode menu.") + +(defvar smarty-mode-map nil + "Keymap for Smarty Mode.") + +(defun smarty-update-mode-menu () + "Update Smarty Mode menu." + (interactive) + (easy-menu-remove smarty-mode-menu-list) + (setq smarty-mode-menu-list (smarty-create-mode-menu)) + (easy-menu-add smarty-mode-menu-list) + (easy-menu-define smarty-mode-menu smarty-mode-map + "Menu keymap for Smarty Mode." smarty-mode-menu-list)) + + + + +(defvar smarty-mode-hook nil) + +(defvar smarty-functions nil + "List of Smarty functions.") + +(defvar smarty-functions-regexp nil + "Regexp for Smarty functions.") + +(defconst smarty-01-functions + '("capture" "config_load" "foreach" "foreachelse" "include" + "include_php" "insert" "if" "elseif" "else" "ldelim" "rdelim" + "literal" "php" "section" "sectionelse" "strip" "assign" "counter" + "cycle" "debug" "eval" "fetch" "html_checkboxes" "html_image" + "html_options" "html_radios" "html_select_date" "html_select_time" + "html_table" "math" "mailto" "popup_init" "popup" "textformat") + "Smarty built-in & custom functions.") + +(defvar smarty-modifiers nil + "List of Smarty variable modifiers.") + +(defvar smarty-modifiers-regexp nil + "Regexp for Smarty variable modifiers.") + +(defconst smarty-01-modifiers + '("capitalize" "cat" "count_characters" "count_paragraphs" + "count_sentences" "count_words" "date_format" "default" + "escape" "indent" "lower" "nl2br" "regex_replace" "replace" + "spacify" "string_format" "strip" "strip_tags" "truncate" + "upper" "wordwrap") + "Smarty variable modifiers.") + +(defvar smarty-plugins-functions nil + "List of Smarty functions.") + +(defvar smarty-plugins-functions-regexp nil + "Regexp for Smarty functions.") + +(defconst smarty-01-plugins-functions + '("validate" "formtool_checkall" "formtool_copy" "formtool_count_chars" + "formtool_init" "formtool_move" "formtool_moveall" + "formtool_movedown" "formtool_moveup" "formtool_remove" + "formtool_rename" "formtool_save" "formtool_selectall" + "paginate_first" "paginate_last" "paginate_middle" + "paginate_next" "paginate_prev") + "Smarty plugins functions.") + +(defvar smarty-plugins-modifiers nil + "List of Smarty variable modifiers.") + +(defvar smarty-plugins-modifiers-regexp nil + "Regexp for Smarty functions.") + +(defconst smarty-01-plugins-modifiers + '("B2Smilies" "bbcode2html" "date_format2") + "Smarty plugins modifiers.") + +(defconst smarty-constants + (eval-when-compile + (regexp-opt + '("TRUE" "FALSE" "NULL") t)) + "Smarty constants.") + + +;; Syntax table creation +(defvar smarty-mode-syntax-table nil + "Syntax table for smarty-mode.") + +(defvar smarty-mode-ext-syntax-table nil + "Syntax table extended by `_' used in `smarty-mode' buffers.") + +(defun smarty-create-syntax-table () + (if smarty-mode-syntax-table + () + (setq smarty-mode-syntax-table (make-syntax-table)) + + ;; Make | a punctuation character + (modify-syntax-entry ?| "." smarty-mode-syntax-table) + ;; Make " a punctuation character so highlighing works withing html strings + (modify-syntax-entry ?\" "." smarty-mode-syntax-table) + ;; define parentheses to match + (modify-syntax-entry ?\( "()" smarty-mode-syntax-table) + (modify-syntax-entry ?\) ")(" smarty-mode-syntax-table) + (modify-syntax-entry ?\[ "(]" smarty-mode-syntax-table) + (modify-syntax-entry ?\] ")[" smarty-mode-syntax-table) + (modify-syntax-entry ?\{ "(}" smarty-mode-syntax-table) + (modify-syntax-entry ?\} "){" smarty-mode-syntax-table) + ) + (set-syntax-table smarty-mode-syntax-table) + ;; extended syntax table including '_' (for simpler search regexps) + (setq smarty-mode-ext-syntax-table (copy-syntax-table smarty-mode-syntax-table)) + (modify-syntax-entry ?_ "w" smarty-mode-ext-syntax-table)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; File/directory manipulation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-directory-files (directory &optional full match) + "Call `directory-files' if DIRECTORY exists, otherwise generate error +message." + (if (not (file-directory-p directory)) + (smarty-warning-when-idle "No such directory: \"%s\"" directory) + (let ((dir (directory-files directory full match))) + (setq dir (delete "." dir)) + (setq dir (delete ".." dir)) + dir))) + +(defun smarty-get-source-files (&optional full directory) + "Get list of SMARTY source files in DIRECTORY or current directory." + (let ((mode-alist auto-mode-alist) + filename-regexp) + ;; create regular expressions for matching file names + (setq filename-regexp "\\`[^.].*\\(") + (while mode-alist + (when (eq (cdar mode-alist) 'smarty-mode) + (setq filename-regexp + (concat filename-regexp (caar mode-alist) "\\|"))) + (setq mode-alist (cdr mode-alist))) + (setq filename-regexp + (concat (substring filename-regexp 0 + (string-match "\\\\|$" filename-regexp)) "\\)")) + ;; find files + (smarty-directory-files + (or directory default-directory) full filename-regexp))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Messages reporting +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-warnings nil + "Warnings to tell the user during start up.") + +(defun smarty-run-when-idle (secs repeat function) + "Wait until idle, then run FUNCTION." + (if (fboundp 'start-itimer) + (start-itimer "smarty-mode" function secs repeat t) +; (run-with-idle-timer secs repeat function))) + ;; explicitely activate timer (necessary when Emacs is already idle) + (aset (run-with-idle-timer secs repeat function) 0 nil))) + +(defun smarty-warning-when-idle (&rest args) + "Wait until idle, then print out warning STRING and beep." + (if noninteractive + (smarty-warning (apply 'format args) t) + (unless smarty-warnings + (smarty-run-when-idle .1 nil 'smarty-print-warnings)) + (setq smarty-warnings (cons (apply 'format args) smarty-warnings)))) + +(defun smarty-warning (string &optional nobeep) + "Print out warning STRING and beep." + (message (concat "WARNING: " string)) + (unless (or nobeep noninteractive) (beep))) + +(defun smarty-print-warnings () + "Print out messages in variable `smarty-warnings'." + (let ((no-warnings (length smarty-warnings))) + (setq smarty-warnings (nreverse smarty-warnings)) + (while smarty-warnings + (message (concat "WARNING: " (car smarty-warnings))) + (setq smarty-warnings (cdr smarty-warnings))) + (beep) + (when (> no-warnings 1) + (message "WARNING: See warnings in message buffer (type `C-c M-m').")))) + +(defun smarty-show-messages () + "Get *Messages* buffer to show recent messages." + (interactive) + (display-buffer " *Message-Log*")) + +(defun smarty-version () + "Echo the current version of Smarty Mode in the minibuffer." + (interactive) + (message "Smarty Mode %s (%s)" smarty-version smarty-time-stamp) + (smarty-keep-region-active)) + +;; active regions +(defun smarty-keep-region-active () + "Do whatever is necessary to keep the region active in XEmacs. +Ignore byte-compiler warnings you might see." + (and (boundp 'zmacs-region-stays) + (setq zmacs-region-stays t))) + +(defmacro smarty-prepare-search-1 (&rest body) + "Enable case insensitive search and switch to syntax table that includes '_', +then execute BODY, and finally restore the old environment. Used for +consistent searching." + `(let ((case-fold-search t) ; case insensitive search + (current-syntax-table (syntax-table)) + result + (restore-prog ; program to restore enviroment + '(progn + ;; restore syntax table + (set-syntax-table current-syntax-table)))) + ;; use extended syntax table + (set-syntax-table smarty-mode-ext-syntax-table) + ;; execute BODY safely + (setq result + (condition-case info + (progn ,@body) + (error (eval restore-prog) ; restore environment on error + (error (cadr info))))) ; pass error up + ;; restore environment + (eval restore-prog) + result)) + +(defmacro smarty-prepare-search-2 (&rest body) + "Enable case insensitive search, switch to syntax table that includes '_', +and remove `intangible' overlays, then execute BODY, and finally restore the +old environment. Used for consistent searching." + `(let ((case-fold-search t) ; case insensitive search + (current-syntax-table (syntax-table)) + result overlay-all-list overlay-intangible-list overlay + (restore-prog ; program to restore enviroment + '(progn + ;; restore syntax table + (set-syntax-table current-syntax-table) + ;; restore `intangible' overlays + (when (fboundp 'overlay-lists) + (while overlay-intangible-list + (overlay-put (car overlay-intangible-list) 'intangible t) + (setq overlay-intangible-list + (cdr overlay-intangible-list))))))) + ;; use extended syntax table + (set-syntax-table smarty-mode-ext-syntax-table) + ;; remove `intangible' overlays + (when (fboundp 'overlay-lists) + (setq overlay-all-list (overlay-lists)) + (setq overlay-all-list + (append (car overlay-all-list) (cdr overlay-all-list))) + (while overlay-all-list + (setq overlay (car overlay-all-list)) + (when (memq 'intangible (overlay-properties overlay)) + (setq overlay-intangible-list + (cons overlay overlay-intangible-list)) + (overlay-put overlay 'intangible nil)) + (setq overlay-all-list (cdr overlay-all-list)))) + ;; execute BODY safely + (setq result + (condition-case info + (progn ,@body) + (error (eval restore-prog) ; restore environment on error + (error (cadr info))))) ; pass error up + ;; restore environment + (eval restore-prog) + result)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Enabling/disabling + +(defun smarty-mode-line-update () + "Update the modeline string for Smarty major mode." + (setq mode-name (concat "Smarty" + (and (or smarty-electric-mode smarty-stutter-mode) "/") + (and smarty-electric-mode "e") + (and smarty-stutter-mode "s"))) + (force-mode-line-update t)) + +(defun smarty-electric-mode (arg) + "Toggle Smarty electric mode. +Turn on if ARG positive, turn off if ARG negative, toggle if ARG zero or nil." + (interactive "P") + (setq smarty-electric-mode + (cond ((or (not arg) (zerop arg)) (not smarty-electric-mode)) + ((> arg 0) t) (t nil))) + (smarty-mode-line-update)) + +(defun smarty-stutter-mode (arg) + "Toggle Smarty stuttering mode. +Turn on if ARG positive, turn off if ARG negative, toggle if ARG zero or nil." + (interactive "P") + (setq smarty-stutter-mode + (cond ((or (not arg) (zerop arg)) (not smarty-stutter-mode)) + ((> arg 0) t) (t nil))) + (smarty-mode-line-update)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Smarty code delimitation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-in-literal () + "Determine if point is in a Smarty literal." + (save-excursion + (let ((here (point)) + start state) + (beginning-of-line) + (setq start (point)) + (goto-char here) + (setq state (parse-partial-sexp start (point))) + (cond + ((nth 3 state) 'string) + ((nth 4 state) 'comment) + (t nil))))) + +(defun smarty-in-comment-p () + "Check if point is in a comment." + (let ((result nil) (here (point-marker)) found) + (save-excursion + (setq found (re-search-backward (regexp-quote (concat smarty-left-delimiter "*")) nil t)) + (when found + (setq result (re-search-forward (regexp-quote (concat "*" smarty-right-delimiter)) here t)) + (setq result (not result)))) + result)) + +(defun smarty-after-ldelim () + "Check that the previous character is the left delimiter." + (let ((here (point-marker)) ldelim-found ldelim-point) + (save-excursion + (setq ldelim-found (re-search-backward (regexp-quote smarty-left-delimiter) nil t)) + (re-search-forward (regexp-quote smarty-left-delimiter) here t) + (setq ldelim-point (point-marker)) + (goto-char here) + (if (and (= here ldelim-point) ldelim-found) + t + nil)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Words to expand +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-words-init () + "Initialize reserved words." + (setq smarty-functions smarty-01-functions) + (setq smarty-modifiers smarty-01-modifiers) + (setq smarty-plugins-functions smarty-01-plugins-functions) + (setq smarty-plugins-modifiers smarty-01-plugins-modifiers) + (setq smarty-functions-regexp (concat "\\<\\(" (regexp-opt smarty-functions) "\\)\\>")) + (setq smarty-modifiers-regexp (concat "\\<\\(" (regexp-opt smarty-modifiers) "\\)\\>")) + (setq smarty-plugins-functions-regexp (concat "\\<\\(" (regexp-opt smarty-plugins-functions) "\\)\\>")) + (setq smarty-plugins-modifiers-regexp (concat "\\<\\(" (regexp-opt smarty-plugins-modifiers) "\\)\\>")) + (smarty-abbrev-list-init)) + +(defvar smarty-abbrev-list nil + "Predefined abbreviations for Smarty.") + +(defun smarty-abbrev-list-init () + (setq smarty-abbrev-list + (append + (list nil) smarty-functions + (list nil) smarty-modifiers + (list nil) smarty-plugins-functions + (list nil) smarty-plugins-modifiers))) + +(defvar smarty-expand-upper-case nil) + +(defun smarty-try-expand-abbrev (old) + "Try expanding abbreviations from `smarty-abbrev-list'." + (unless old + (he-init-string (he-dabbrev-beg) (point)) + (setq he-expand-list + (let ((abbrev-list smarty-abbrev-list) + (sel-abbrev-list '())) + (while abbrev-list + ; (if (stringp (car abbrev-list)) + ; (insert (concat " " (car abbrev-list)))) + (when (or (not (stringp (car abbrev-list))) + (string-match + (concat "^" he-search-string) (car abbrev-list))) + (setq sel-abbrev-list + (cons (car abbrev-list) sel-abbrev-list))) + (setq abbrev-list (cdr abbrev-list))) + (nreverse sel-abbrev-list)))) + (while (and he-expand-list + (or (not (stringp (car he-expand-list))) + (he-string-member (car he-expand-list) he-tried-table t))) + (unless (stringp (car he-expand-list)) + (setq smarty-expand-upper-case (car he-expand-list))) + (setq he-expand-list (cdr he-expand-list))) + (if (null he-expand-list) + (progn (when old (he-reset-string)) + nil) + (he-substitute-string + (if smarty-expand-upper-case + (upcase (car he-expand-list)) + (car he-expand-list)) + t) + (setq he-expand-list (cdr he-expand-list)) + t)) + +;; initialize reserved words for Smarty Mode +(smarty-words-init) + +;; function for expanding abbrevs and dabbrevs +(defun smarty-expand-abbrev (arg)) +(fset 'smarty-expand-abbrev (make-hippie-expand-function + '(try-expand-dabbrev + try-expand-dabbrev-all-buffers + smarty-try-expand-abbrev))) + +;; function for expanding parenthesis +(defun smarty-expand-paren (arg)) +(fset 'smarty-expand-paren (make-hippie-expand-function + '(try-expand-list + try-expand-list-all-buffers))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Stuttering +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-electric-tab (&optional prefix-arg) + "If preceding character is part of a word or a paren then hippie-expand, +else if right of non whitespace on line then insert tab, +else if last command was a tab or return then dedent one step or if a comment +toggle between normal indent and inline comment indent, +else indent `correctly'." + (interactive "*P") + (smarty-prepare-search-2 + (cond + ;; expand word + ((= (char-syntax (preceding-char)) ?w) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil) + (hippie-expand-only-buffers + (or (and (boundp 'hippie-expand-only-buffers) + hippie-expand-only-buffers) + '(smarty-mode)))) + (smarty-expand-abbrev prefix-arg))) + ;; expand parenthesis + ((or (= (preceding-char) ?\() (= (preceding-char) ?\))) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil)) + (smarty-expand-paren prefix-arg)))) + (setq this-command 'smarty-electric-tab))) + +(defun smarty-electric-space (count) + "Expand abbreviations and self-insert space(s)." + (interactive "p") + (let ((here (point-marker)) ldelim-found ldelim-point rdelim-found rdelim-point + delete-a) + (setq ldelim-found (re-search-backward (regexp-quote smarty-left-delimiter) nil t)) + (re-search-forward (regexp-quote smarty-left-delimiter) here t) + (setq ldelim-point (point-marker)) + (goto-char here) + (setq rdelim-found (re-search-backward (regexp-quote (concat " " smarty-right-delimiter)) nil t)) + (re-search-forward (regexp-quote (concat " " smarty-right-delimiter)) here t) + (setq rdelim-point (point-marker)) + (goto-char here) + (cond ((and (= here ldelim-point) ldelim-found) (insert (concat "ldelim" smarty-right-delimiter))) + ((and (= here rdelim-point) rdelim-found) + (re-search-backward (regexp-quote (concat " " smarty-right-delimiter)) nil t) + (delete-char 1) + (insert (concat " " smarty-left-delimiter "rdelim")) + (goto-char here)) + ((smarty-in-comment-p) + (self-insert-command count) + (cond ((>= (current-column) (+ 2 end-comment-column)) + (backward-char 1) + (skip-chars-backward "^ \t\n") + (indent-new-comment-line) + (skip-chars-forward "^ \t\n") + (forward-char 1)) + ((>= (current-column) end-comment-column) + (indent-new-comment-line)) + (t nil))) + ((or (and (>= (preceding-char) ?a) (<= (preceding-char) ?z)) + (and (>= (preceding-char) ?A) (<= (preceding-char) ?Z)) + (and (>= (preceding-char) ?0) (<= (preceding-char) ?9))) + (progn + (setq here (point-marker)) + (insert " ") + (setq delete-a t) + (if (re-search-backward "|" nil t) + (progn + (setq found (re-search-forward (regexp-quote "B2Smilies") here t)) + (if (and found (= here (point-marker))) + (replace-match "btosmilies") + (setq found (re-search-forward (regexp-quote "bbcode2html") here t)) + (if (and found (= here (point-marker))) + (replace-match "bbcodetohtml") + (setq found (re-search-forward (regexp-quote "date_format2") here t)) + (if (and found (= here (point-marker))) + (replace-match "date_formatto") + (goto-char here) + (setq delete-a nil) + (delete-char 1))))) + (goto-char here) + (setq delete-a nil) + (delete-char 1))) + (smarty-prepare-search-1 (expand-abbrev)) + (self-insert-command count) + (if (and delete-a (looking-at " ")) + (delete-char 1))) + (t (self-insert-command count))))) + +(defun smarty-electric-open-bracket (count) + "'(' --> '(', '((' --> '[', '[(' --> '{'" + (interactive "p") + (if (and smarty-stutter-mode (= count 1) (not (smarty-in-literal))) + (if (= (preceding-char) ?\() + (progn (delete-char -1) (insert-char ?\[ 1)) + (if (= (preceding-char) ?\[) + (progn (delete-char -1) (insert-char ?\{ 1)) + (insert-char ?\( 1))) + (self-insert-command count))) + +(defun smarty-electric-close-bracket (count) + "')' --> ')', '))' --> ']', '])' --> '}'" + (interactive "p") + (if (and smarty-stutter-mode (= count 1) (not (smarty-in-literal))) + (progn + (if (= (preceding-char) ?\)) + (progn (delete-char -1) (insert-char ?\] 1)) + (if (= (preceding-char) ?\]) + (progn (delete-char -1) (insert-char ?} 1)) + (insert-char ?\) 1))) + (blink-matching-open)) + (self-insert-command count))) + +(defun smarty-electric-star (count) + "After a left delimiter add a right delemiter to close the comment" + (interactive "p") + (let ((here (point-marker)) found) + (if (and smarty-stutter-mode (= count 1) (not (smarty-in-literal))) + (progn + (setq found (re-search-backward (regexp-quote smarty-left-delimiter) nil t)) + (re-search-forward (regexp-quote smarty-left-delimiter) here t) + (if (not (and (= here (point-marker)) found)) + (progn (goto-char here) + (self-insert-command count)) + (self-insert-command count) + (insert " ") + (setq here (point-marker)) + (insert " *") + (insert smarty-right-delimiter) + (goto-char here))) + (self-insert-command count)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Electrification +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst smarty-template-prompt-syntax "[^ =<>][^<>@.\n]*[^ =<>]" + "Syntax of prompt inserted by template generators.") + +(defvar smarty-template-invoked-by-hook nil + "Indicates whether a template has been invoked by a hook or by key or menu. +Used for undoing after template abortion.") + +(defun smarty-minibuffer-tab (&optional prefix-arg) + "If preceding character is part of a word or a paren then hippie-expand, +else insert tab (used for word completion in Smarty minibuffer)." + (interactive "P") + (cond + ;; expand word + ((= (char-syntax (preceding-char)) ?w) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil) + (hippie-expand-only-buffers + (or (and (boundp 'hippie-expand-only-buffers) + hippie-expand-only-buffers) + '(smarty-mode)))) + (smarty-expand-abbrev prefix-arg))) + ;; expand parenthesis + ((or (= (preceding-char) ?\() (= (preceding-char) ?\))) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil)) + (smarty-expand-paren prefix-arg))) + ;; insert tab + (t (insert-tab)))) + +;; correct different behavior of function `unread-command-events' in XEmacs +(defun smarty-character-to-event (arg)) +(defalias 'smarty-character-to-event + (if (fboundp 'character-to-event) 'character-to-event 'identity)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Abbrev ook bindings +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-mode-abbrev-table nil + "Abbrev table to use in `smarty-mode' buffers.") + +(defun smarty-mode-abbrev-table-init () + "Initialize `smarty-mode-abbrev-table'." + (when smarty-mode-abbrev-table (clear-abbrev-table smarty-mode-abbrev-table)) + (define-abbrev-table 'smarty-mode-abbrev-table + (append + '( + ("capture" "" smarty-template-capture-hook 0) + ("config_load" "" smarty-template-config-load-hook 0) + ("else" "" smarty-template-else-hook 0) + ("elseif" "" smarty-template-elseif-hook 0) + ("foreach" "" smarty-template-foreach-hook 0) + ("foreachelse" "" smarty-template-foreachelse-hook 0) + ("if" "" smarty-template-if-hook 0) + ("include" "" smarty-template-include-hook 0) + ("include_php" "" smarty-template-include-php-hook 0) + ("insert" "" smarty-template-insert-hook 0) + ("ldelim" "" smarty-template-ldelim-hook 0) + ("literal" "" smarty-template-literal-hook 0) + ("php" "" smarty-template-php-hook 0) + ("rdelim" "" smarty-template-rdelim-hook 0) + ("section" "" smarty-template-section-hook 0) + ("sectionelse" "" smarty-template-sectionelse-hook 0) + ("strip" "" smarty-template-strip-hook 0) + ("assign" "" smarty-template-assign-hook 0) + ("counter" "" smarty-template-counter-hook 0) + ("cycle" "" smarty-template-cycle-hook 0) + ("debug" "" smarty-template-debug-hook 0) + ("eval" "" smarty-template-eval-hook 0) + ("fetch" "" smarty-template-fetch-hook 0) + ("html_checkboxes" "" smarty-template-html-checkboxes-hook 0) + ("html_image" "" smarty-template-html-image-hook 0) + ("html_options" "" smarty-template-html-options-hook 0) + ("html_radios" "" smarty-template-html-radios-hook 0) + ("html_select_date" "" smarty-template-html-select-date-hook 0) + ("html_select_time" "" smarty-template-html-select-time-hook 0) + ("html_table" "" smarty-template-html-table-hook 0) + ("mailto" "" smarty-template-mailto-hook 0) + ("math" "" smarty-template-math-hook 0) + ("popup" "" smarty-template-popup-hook 0) + ("popup_init" "" smarty-template-popup-init-hook 0) + ("textformat" "" smarty-template-textformat-hook 0) + ("capitalize" "" smarty-template-capitalize-hook 0) + ("cat" "" smarty-template-cat-hook 0) + ("count_characters" "" smarty-template-count-characters-hook 0) + ("count_paragraphs" "" smarty-template-count-paragraphs-hook 0) + ("count_sentences" "" smarty-template-count-sentences-hook 0) + ("count_words" "" smarty-template-count-words-hook 0) + ("date_format" "" smarty-template-date-format-hook 0) + ("default" "" smarty-template-default-hook 0) + ("escape" "" smarty-template-escape-hook 0) + ("indent" "" smarty-template-indent-hook 0) + ("lower" "" smarty-template-lower-hook 0) + ("nl2br" "" smarty-template-nl2br-hook 0) + ("regex_replace" "" smarty-template-regex-replace-hook 0) + ("replace" "" smarty-template-replace-hook 0) + ("spacify" "" smarty-template-spacify-hook 0) + ("string_format" "" smarty-template-string-format-hook 0) + ("strip" "" smarty-template-vstrip-hook 0) + ("strip_tags" "" smarty-template-strip-tags-hook 0) + ("truncate" "" smarty-template-truncate-hook 0) + ("upper" "" smarty-template-upper-hook 0) + ("wordwrap" "" smarty-template-wordwrap-hook 0) + ("validate" "" smarty-template-validate-hook 0) + ("formtool_checkall" "" smarty-template-formtool-checkall-hook 0) + ("formtool_copy" "" smarty-template-formtool-copy-hook 0) + ("formtool_count_chars" "" smarty-template-formtool-count-chars-hook 0) + ("formtool_init" "" smarty-template-formtool-init-hook 0) + ("formtool_move" "" smarty-template-formtool-move-hook 0) + ("formtool_moveall" "" smarty-template-formtool-moveall-hook 0) + ("formtool_movedown" "" smarty-template-formtool-movedown-hook 0) + ("formtool_moveup" "" smarty-template-formtool-moveup-hook 0) + ("formtool_remove" "" smarty-template-formtool-remove-hook 0) + ("formtool_rename" "" smarty-template-formtool-rename-hook 0) + ("formtool_save" "" smarty-template-formtool-save-hook 0) + ("formtool_selectall" "" smarty-template-formtool-selectall-hook 0) + ("paginate_first" "" smarty-template-paginate-first-hook 0) + ("paginate_last" "" smarty-template-paginate-last-hook 0) + ("paginate_middle" "" smarty-template-paginate-middle-hook 0) + ("paginate_next" "" smarty-template-paginate-next-hook 0) + ("paginate_prev" "" smarty-template-paginate-prev-hook 0) + ("btosmilies" "" smarty-template-btosmilies-hook 0) + ("bbcodetohtml" "" smarty-template-bbcodetohtml-hook 0) + ("date_formatto" "" smarty-template-date-formatto-hook 0))))) + +;; initialize abbrev table for Smarty Mode +(smarty-mode-abbrev-table-init) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Abbrev hooks +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-hooked-abbrev (func) + "Do function, if syntax says abbrev is a keyword, invoked by hooked abbrev, +but not if inside a comment or quote)." + (if (or (smarty-in-literal) + (smarty-in-comment-p)) + (progn + (insert " ") + (unexpand-abbrev) + (delete-char -1)) + (if (not smarty-electric-mode) + (progn + (insert " ") + (unexpand-abbrev) + (backward-word 1) + (delete-char 1)) + (let ((invoke-char last-command-char) + (abbrev-mode -1) + (smarty-template-invoked-by-hook t)) + (let ((caught (catch 'abort + (funcall func)))) + (when (stringp caught) (message caught))) + (when (= invoke-char ?-) (setq abbrev-start-location (point))) + ;; delete CR which is still in event queue + (if (fboundp 'enqueue-eval-event) + (enqueue-eval-event 'delete-char -1) + (setq unread-command-events ; push back a delete char + (list (smarty-character-to-event ?\177)))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Fontification +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-font-lock-keywords-1 + (list + + ;; Fontify built-in functions + (cons + (concat (regexp-quote smarty-left-delimiter) "[/]*" smarty-functions-regexp) + '(1 font-lock-keyword-face)) + + (cons + (concat "\\<\\(" smarty-constants "\\)\\>") + 'font-lock-constant-face) + + (cons (concat "\\(" (regexp-quote (concat smarty-left-delimiter "*")) "\\(\\s-\\|\\w\\|\\s.\\|\\s_\\|\\s(\\|\\s)\\|\\s\\\\)*" (regexp-quote (concat "*" smarty-right-delimiter)) "\\)") + 'font-lock-comment-face) + + ) + "Subdued level highlighting for Smarty mode.") + +(defconst smarty-font-lock-keywords-2 + (append + smarty-font-lock-keywords-1 + (list + + ;; Fontify variable names (\\sw\\|\\s_\\) matches any word character + + ;; underscore + '("\\$\\(\\(?:\\sw\\|\\s_\\)+\\)" (1 font-lock-variable-name-face)) ; $variable + '("->\\(\\(?:\\sw\\|\\s_\\)+\\)" (1 font-lock-variable-name-face t t)) ; ->variable + '("\\.\\(\\(?:\\sw\\|\\s_\\)+\\)" (1 font-lock-variable-name-face t t)) ; .variable + '("->\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" (1 font-lock-function-name-face t t)) ; ->function_call + '("\\<\\(\\(?:\\sw\\|\\s_\\)+\\s-*\\)(" (1 font-lock-function-name-face)) ; word( + '("\\<\\(\\(?:\\sw\\|\\s_\\)+\\s-*\\)[[]" (1 font-lock-variable-name-face)) ; word[ + '("\\<[0-9]+" . default) ; number (also matches word) + + ;; Fontify strings + ;;'("\"\\([^\"]*\\)\"[^\"]+" (1 font-lock-string-face t t)) + )) + + "Medium level highlighting for Smarty mode.") + +(defconst smarty-font-lock-keywords-3 + (append + smarty-font-lock-keywords-2 + (list + ;; Fontify modifiers + (cons (concat "|\\(" smarty-modifiers-regexp "\\)[:|]+") '(1 font-lock-function-name-face)) + (cons (concat "|\\(" smarty-modifiers-regexp "\\)" (regexp-quote smarty-right-delimiter)) '(1 font-lock-function-name-face)) + + ;; Fontify config vars + (cons (concat (regexp-quote smarty-left-delimiter) "\\(#\\(?:\\sw\\|\\s_\\)+#\\)") '(1 font-lock-constant-face)))) + "Balls-out highlighting for Smarty mode.") + +(defconst smarty-font-lock-keywords-4 + (append + smarty-font-lock-keywords-3 + (list + ;; Fontify plugin functions + (cons + (concat (regexp-quote smarty-left-delimiter) "[/]*" smarty-plugins-functions-regexp) + '(1 font-lock-keyword-face)) + + (cons (concat "|\\(" smarty-plugins-modifiers-regexp "\\)[:|]+") '(1 font-lock-function-name-face)) + (cons (concat "|\\(" smarty-plugins-modifiers-regexp "\\)" (regexp-quote smarty-right-delimiter)) '(1 font-lock-function-name-face))))) + +(defvar smarty-font-lock-keywords smarty-font-lock-keywords-3 + "Default highlighting level for Smarty mode") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mode map +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-template-map nil + "Keymap for Smarty templates.") + +(defun smarty-template-map-init () + "Initialize `smarty-template-map'." + (setq smarty-template-map (make-sparse-keymap)) + ;; key bindings for Smarty templates + (define-key smarty-template-map "\C-ba" 'smarty-template-capture) + (define-key smarty-template-map "\C-bc" 'smarty-template-config-load) + (define-key smarty-template-map "\C-b\M-e" 'smarty-template-else) + (define-key smarty-template-map "\C-b\C-e" 'smarty-template-elseif) + (define-key smarty-template-map "\C-b\C-f" 'smarty-template-foreach) + (define-key smarty-template-map "\C-b\M-f" 'smarty-template-foreachelse) + (define-key smarty-template-map "\C-bf" 'smarty-template-if) + (define-key smarty-template-map "\C-b\C-i" 'smarty-template-include) + (define-key smarty-template-map "\C-b\M-i" 'smarty-template-include-php) + (define-key smarty-template-map "\C-bi" 'smarty-template-insert) + (define-key smarty-template-map "\C-bl" 'smarty-template-ldelim) + (define-key smarty-template-map "\C-b\C-l" 'smarty-template-literal) + (define-key smarty-template-map "\C-bp" 'smarty-template-php) + (define-key smarty-template-map "\C-br" 'smarty-template-rdelim) + (define-key smarty-template-map "\C-b\C-s" 'smarty-template-section) + (define-key smarty-template-map "\C-b\M-s" 'smarty-template-sectionelse) + (define-key smarty-template-map "\C-bs" 'smarty-template-strip) + (define-key smarty-template-map "\C-ca" 'smarty-template-assign) + (define-key smarty-template-map "\C-co" 'smarty-template-counter) + (define-key smarty-template-map "\C-cc" 'smarty-template-cycle) + (define-key smarty-template-map "\C-cd" 'smarty-template-debug) + (define-key smarty-template-map "\C-ce" 'smarty-template-eval) + (define-key smarty-template-map "\C-cf" 'smarty-template-fetch) + (define-key smarty-template-map "\C-c\C-hc" 'smarty-template-html-checkboxes) + (define-key smarty-template-map "\C-c\C-hi" 'smarty-template-html-image) + (define-key smarty-template-map "\C-c\C-ho" 'smarty-template-html-options) + (define-key smarty-template-map "\C-c\C-hr" 'smarty-template-html-radios) + (define-key smarty-template-map "\C-c\C-hd" 'smarty-template-html-select-date) + (define-key smarty-template-map "\C-c\C-hm" 'smarty-template-html-select-time) + (define-key smarty-template-map "\C-c\C-ht" 'smarty-template-html-table) + (define-key smarty-template-map "\C-ci" 'smarty-template-mailto) + (define-key smarty-template-map "\C-ch" 'smarty-template-math) + (define-key smarty-template-map "\C-c\C-p" 'smarty-template-popup) + (define-key smarty-template-map "\C-c\M-p" 'smarty-template-popup-init) + (define-key smarty-template-map "\C-ct" 'smarty-template-textformat) + (define-key smarty-template-map "\C-vp" 'smarty-template-capitalize) + (define-key smarty-template-map "\C-vc" 'smarty-template-cat) + (define-key smarty-template-map "\C-v\C-cc" 'smarty-template-count-characters) + (define-key smarty-template-map "\C-v\C-cp" 'smarty-template-count-paragraphs) + (define-key smarty-template-map "\C-v\C-cs" 'smarty-template-count-sentences) + (define-key smarty-template-map "\C-v\C-cw" 'smarty-template-count-words) + (define-key smarty-template-map "\C-vf" 'smarty-template-date-format) + (define-key smarty-template-map "\C-vd" 'smarty-template-default) + (define-key smarty-template-map "\C-ve" 'smarty-template-escape) + (define-key smarty-template-map "\C-vi" 'smarty-template-indent) + (define-key smarty-template-map "\C-vl" 'smarty-template-lower) + (define-key smarty-template-map "\C-vn" 'smarty-template-nl2br) + (define-key smarty-template-map "\C-vx" 'smarty-template-regex-replace) + (define-key smarty-template-map "\C-v\C-p" 'smarty-template-replace) + (define-key smarty-template-map "\C-vy" 'smarty-template-spacify) + (define-key smarty-template-map "\C-vs" 'smarty-template-string-format) + (define-key smarty-template-map "\C-v\C-s" 'smarty-template-vstrip) + (define-key smarty-template-map "\C-v\M-s" 'smarty-template-strip-tags) + (define-key smarty-template-map "\C-vt" 'smarty-template-truncate) + (define-key smarty-template-map "\C-vu" 'smarty-template-upper) + (define-key smarty-template-map "\C-vw" 'smarty-template-wordwrap) + (define-key smarty-template-map "\C-h" 'smarty-template-header) + (define-key smarty-template-map "\C-f" 'smarty-template-footer) + (define-key smarty-template-map "\C-di" 'smarty-template-insert-date) + (define-key smarty-template-map "\C-dm" 'smarty-template-modify)) + +;; initialize template map for Smarty Mode +(smarty-template-map-init) + +(defun smarty-mode-map-init () + "Initialize `smarty-mode-map'." + (setq smarty-mode-map (make-sparse-keymap)) + ;; template key bindings + (define-key smarty-mode-map "\C-c\C-t" smarty-template-map) + ;; mode specific key bindings + (define-key smarty-mode-map "\C-c\C-m\C-e" 'smarty-electric-mode) + (define-key smarty-mode-map "\C-c\C-m\C-s" 'smarty-stutter-mode) + (define-key smarty-mode-map "\C-c\C-s\C-u" 'smarty-add-source-files-menu) + (define-key smarty-mode-map "\C-c\M-m" 'smarty-show-messages) + (define-key smarty-mode-map "\C-c\C-h" 'smarty-doc-mode) + (define-key smarty-mode-map "\C-c\C-v" 'smarty-version) + ;; electric key bindings + (when smarty-intelligent-tab + (define-key smarty-mode-map "\t" 'smarty-electric-tab)) + (define-key smarty-mode-map " " 'smarty-electric-space) + (define-key smarty-mode-map "(" 'smarty-electric-open-bracket) + (define-key smarty-mode-map ")" 'smarty-electric-close-bracket) + (define-key smarty-mode-map "*" 'smarty-electric-star)) + +;; initialize mode map for Smarty Mode +(smarty-mode-map-init) + +(defvar smarty-minibuffer-local-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-map) + (when smarty-word-completion-in-minibuffer + (define-key map "\t" 'smarty-minibuffer-tab)) + map) + "Keymap for minibuffer used in Smarty Mode.") + +(mapcar + (function + (lambda (sym) + (put sym 'delete-selection t) ; for `delete-selection-mode' (Emacs) + (put sym 'pending-delete t))) ; for `pending-delete-mode' (XEmacs) + '(smarty-electric-space + smarty-electric-tab + smarty-electric-open-bracket + smarty-electric-close-bracket + smarty-electric-star)) + +;;;###autoload +(defun smarty-mode () + "Smarty Mode +*********** + +Smarty Mode is a GNU XEmacs major mode for editing Smarty templates. + +1 Introduction +************** + +Smarty-Mode is a mode allowing easy edit of Smarty templates: +highlight, templates, navigation into source files... + + + +Features (new features in bold) : + + * Completion + + * Customizable + + * Highlight + + * Menu + + * Stuttering + + * Templates + - Built-in Functions + + - User Functions + + - Variable Modifiers + + - Plugin (Functions) + * Smarty Formtool + + * Smarty Paginate + + * Smarty Validate + + - Plugin (Variable Modifiers) + * AlternativeDateModifierPlugin + + * B2Smilies + + * BBCodePlugin + + - Fonctions Non-Smarty + + + +This manual describes Smarty Mode version 0.0.4. + +2 Installation +************** + +2.1 Requirements +================ + +Smarty Mode is a XEmacs major mode that needs the following +software/packages: + + * XEmacs (http://www.xemacs.org/). + + * `font-lock' mode generaly installed with XEmacs. + + * `assoc' mode generaly installed with XEmacs. + + * `easymenu' mode generaly installed with XEmacs. + + * `hippie-exp' mode generaly installed with XEmacs. + +Before continuing, you must be sure to have all this packages +installed. + +2.2 Download +============ + +Two internet address to download Smarty Mode : + + * Principal: Smarty-Mode 0.0.4 + (http://deboutv.free.fr/lisp/smarty/download/smarty-0.0.4.tar.gz) + (http://deboutv.free.fr/lisp/smarty/) + + * Secondary: Smarty-Mode 0.0.4 + (http://www.morinie.fr/lisp/smarty/download/smarty-0.0.4.tar.gz) + (http://www.morinie.fr/lisp/smarty/) + + * Old releases: Smarty-Mode + (http://deboutv.free.fr/lisp/smarty/download.php) + (http://deboutv.free.fr/lisp/smarty/) + +2.3 Installation +================ + +2.3.1 Installation +------------------ + +To install Smarty Mode you need to choose an installation directory +(for example `/usr/local/share/lisp' or `c:\lisp'). The administrator +must have the write rights on this directory. + +With your favorite unzip software, unzip the archive in the +installation directory. + +Example: + cd /usr/local/share/lisp + tar zxvf smarty-0.0.4.tar.gz +Now you have a `smarty' directory in the installation directory. This +directory contains 2 files `smarty-mode.el' and `smarty-mode.elc' and +another directory `docs' containing the documentation. + +You need to configure XEmacs. open you initialization file `init.el' +(open the file or start XEmacs then choose the Options menu and Edit +Init File). Add the following lines (the installation directory in +this example is `/usr/local/share/lisp') : + + (setq load-path + (append (list \"/usr/local/share/lisp/\") load-path)) + (autoload 'smarty-mode \"smarty-mode\" \"Smarty Mode\" t) + +2.3.2 Update +------------ + +The update is easy. You need to unzip the archive in the installation +directory to remove the old release. + +Example: + cd /usr/local/share/lisp + rm -rf smarty + tar zxvf smarty-0.0.4.tar.gz + +2.4 Invoke Smarty-Mode +====================== + +You have two possibilities to invoke the Smarty Mode. + + - Manually: At each file opening you need to launch Smarty Mode + with the following command: + + `M-x smarty-mode' + + - Automatically: Add the following linesin your initialization + file `init.el' : + + (setq auto-mode-alist + (append + '((\"\\.tpl$\" . smarty-mode)) + auto-mode-alist)) + + +3 Customization +*************** + +This chapter describes the differents parameters and functions that +you can change to customize Smarty Mode. To do that, open a Smarty +file, click on the Smarty menu and choose Options then Browse +Options.... + +3.1 Parameters +============== + +3.1.1 Mode +---------- + +Smarty Mode has 2 modes allowing to simplify the writing of Smarty +templates. You can enable/disable each mode individually. + +`smarty-electric-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable automatic generation of template. + If `nil'; template generators can still be invoked through key + bindings and menu. Is indicated in the modeline by \"/e\" after + the mode name and can be toggled by `smarty-electric-mode'. + +`smarty-stutter-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable the stuttering. Is indicated in the + modeline by \"/s\" after the mode name and can be toggled by + `smarty-stutter-mode'. + +3.1.2 Menu +---------- + +Smarty Mode has also 1 menu that you can enable/disable. The menu +Sources is specific to each Smarty files opened. + +`smarty-source-file-menu' + Type: boolean + Default value: `t' + Description: If `t'; the Sources menu is enabled. This menu + contains the list of Smarty file located in the current + directory. The Sources menu scans the directory when a file is + opened. + +3.1.3 Menu +---------- + +`smarty-highlight-plugin-functions' + Type: boolean + Default value: `t' + Description: If `t'; the functions described in the smarty + plugins are highlighted. + +3.1.4 Templates +--------------- + +3.1.4.1 Header +.............. + +`smarty-file-header' + Type: string + Default value: `\"\"' + Description: String or file to insert as file header. If the + string specifies an existing file name the contents of the file + is inserted; otherwise the string itself is inserted as file + header. + Type `C-j' for newlines. + The follonwing keywords are supported: + <filename>: replaced by the file name. + <author>: replaced by the user name and email address. + <login>: replaced by `user-login-name'. + <company>: replaced by `smarty-company-name' content. + <date>: replaced by the current date. + <year>: replaced by the current year. + <copyright>: replaced by `smarty-copyright-string' content. + <cursor>: final cursor position. + +`smarty-file-footer' + Type: string + Default value: `\"\"' + Description: String or file to insert as file footer. See + `smarty-file-header' + +`smarty-company-name' + Type: string + Default value: `\"\"' + Description: Name of the company to insert in file header. + +`smarty-copyright-string' + Type: string + Default value: `\"\"' + Description: Coryright string to insert in file header. + +`smarty-date-format' + Type: string + Default value: `\"%Y-%m-%d\"' + Description: Date format. + +`smarty-modify-date-prefix-string' + Type: string + Default value: `\"\"' + Description: Prefix string of modification date in Smarty file + header. + +`smarty-modify-date-on-saving' + Type: bool + Default value: `nil' + Description: If `t'; update the modification date when the + buffer is saved. + +3.1.5 Miscellaneous +------------------- + +`smarty-left-delimiter' + Type: string + Default value: `\"\"' + Description: Left escaping delimiter for Smarty templates. + +`smarty-right-delimiter' + Type: string + Default value: `\"\"' + Description: Right escaping delimiter for Smarty templates. + +`smarty-intelligent-tab' + Type: bool + Default value: `t' + Description: If `t'; TAB does indentation; completion and insert + tabulations. If `nil'; TAB does only indentation. + +`smarty-word-completion-in-minibuffer' + Type: bool + Default value: `t' + Description: If `t'; enable completion in the minibuffer. + +`smarty-word-completion-case-sensitive' + Type: bool + Default value: `nil' + Description: If `t'; completion is case sensitive. + +3.2 Functions +============= + +3.2.1 Mode +---------- + +`smarty-electric-mode' + Menu: Smarty -> Options -> Mode -> Electric Mode + Keybinding: `C-c C-m C-e' + Description: This functions is used to enable/disable the + electric mode. + +`smarty-stutter-mode' + Menu: Smarty -> Options -> Mode -> Stutter Mode + Keybinding: `C-c C-m C-s' + Description: This function is used to enable/disable the stutter + mode. + +4 Menus +******* + +There are 2 menus: Smarty and Sources. All theses menus can be +accessed from the menubar or from the right click. This chapter +describes each menus. + +4.1 Smarty +========== + +This is the main menu of Smarty Mode. It allows an easy access to the +main features of the Smarty Mode: Templates (see *Note Templates::) +and Options (see *Note Customization::). + +This menu contains also 3 functions that are discussed in the next +part. + +4.1.1 Functions +--------------- + +`smarty-show-messages' + Menu: Smarty -> Show Messages + Keybinding: `C-c M-m' + Description: This function opens the *Messages* buffer to + display previous error messages. + +`smarty-doc-mode' + Menu: Smarty -> Smarty Mode Documentation + Keybinding: `C-c C-h' + Description: This function opens the *Help* buffer and prints in + it the Smarty Mode documentation. + +`smarty-version' + Menu: Smarty -> Version + Keybinding: `C-c C-v' + Description: This function displays in the minibuffer the + current Smarty Mode version with the timestamp. + +4.2 Sources +=========== + +The Sources menu shows the Smarty files in the current directory. If +you add or delete a file in the current directory, you need to +refresh the menu. + +4.2.1 Customization +------------------- + +`smarty-source-file-menu' + Type: boolean + Default value: `t' + Description: If `t'; the Sources menu is enabled. This menu + contains the list of Smarty file located in the current + directory. The Sources menu scans the directory when a file is + opened. + +4.2.2 Functions +--------------- + +`smarty-add-source-files-menu' + Menu: Sources -> *Rescan* + Keybinding: `C-c C-s C-u' + Description: This function is used to refresh the Sources menu. + +5 Stuttering +************ + +The stutter mode is a mode that affects a function to a key. For +example, when you use the `ENTER' key, the associated function will +create a new line and indent it. + +5.1 Customization +================= + +`smarty-stutter-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable the stuttering. Is indicated in the + modeline by \"/s\" after the mode name and can be toggled by + `smarty-stutter-mode'. + +5.2 Functions +============= + +`SPACE' + If in comment, indent the comment and add new line if necessary. + In other case, add a space. + +`(' + If the previous character is a `(', the `((' will be replaced by + `['. + If the previous character is a `[', the `[(' will be replaced by + `{'. + In other case, insert a `('. + +`)' + If the previous character is a `)', the `))' will be replaced by + `]'. + If the previous character is a `]', the `])' will be replaced by + `}'. + In other case, insert a `)'. + +6 Templates +*********** + +In the Smarty Mode, the Smarty functions (like if, while, for, fopen, +fclose) are predefined in functions called \"Templates\". + +Each template can be invoked by the function name or by using the +<SPACE> key after the Smarty function name in the buffer (Note, using +`M-<SPACE>' disable the template). + +A template can be aborted by using the `C-g' or by lefting empty the +tempate prompt (in the minibuffer). + +6.1 Customization +================= + +`smarty-electric-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable automatic generation of template. + If `nil'; template generators can still be invoked through key + bindings and menu. Is indicated in the modeline by \"/e\" after + the mode name and can be toggled by `smarty-electric-mode'. + +For a complete description of the template customizable variables, +see *Note Cu01-Pa01-Template:: + +6.2 Functions +============= + +6.2.1 Smarty Functions +---------------------- + +For Smarty functions, see PDF or HTML documentation. + +6.2.2 Non-Smarty Functions +-------------------------- + +`smarty-template-header' + Menu: Smarty -> Templates -> Insert Header + Keybinding: `C-c C-t C-h' + Description: This function is used to insert a header in the + current buffer. + +`smarty-template-footer' + Menu: Smarty -> Templates -> Insert Footer + Keybinding: `C-c C-t C-f' + Description: This function is used to insert a footer in the + current buffer. + +`smarty-template-insert-date' + Menu: Smarty -> Templates -> Insert Date + Keybinding: `C-c C-t C-d i' + Description: This function is used to insert the date in the + current buffer. + +`smarty-template-modify' + Menu: Smarty -> Templates -> Modify Date + Keybinding: `C-c C-t C-d m' + Description: This function is used to modify the last + modification date in the current buffer. + +7 Bugs, Help +************ + + * To report bugs: Bugtracker + (http://bugtracker.morinie.fr/lisp/set_project.php?project_id=2) + + * To obtain help you can post on the dedicated forum: Forum + (http://forum.morinie.fr/lisp/) + +8 Key bindings +************** + +\\{smarty-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'smarty-mode) + (setq mode-name "Smarty") + + (smarty-create-syntax-table) + + ;; set maps and tables + (use-local-map smarty-mode-map) + (set-syntax-table smarty-mode-syntax-table) + (setq local-abbrev-table smarty-mode-abbrev-table) + + (set (make-local-variable 'comment-start) (concat smarty-left-delimiter "*")) + (set (make-local-variable 'comment-end) (concat "*" smarty-right-delimiter)) + (set (make-local-variable 'comment-multi-line) t) + (set (make-local-variable 'end-comment-column) 80) + + (make-local-variable 'font-lock-defaults) + (if smarty-highlight-plugin-functions + (setq smarty-font-lock-keywords smarty-font-lock-keywords-4) + (setq smarty-font-lock-keywords smarty-font-lock-keywords-3)) + (setq font-lock-defaults + '((smarty-font-lock-keywords) + nil ; Keywords only (i.e. no comment or string highlighting + t ; case fold + nil ; syntax-alist + nil ; syntax-begin + )) + + (setq font-lock-maximum-decoration t + case-fold-search t) + + ;; add source file menu + (if smarty-source-file-menu (smarty-add-source-files-menu)) + ;; add Smarty menu + (easy-menu-add smarty-mode-menu-list) + (easy-menu-define smarty-mode-menu smarty-mode-map + "Menu keymap for Smarty Mode." smarty-mode-menu-list) + + (message "Smarty Mode %s.%s" smarty-version + (if noninteractive "" " See menu for documentation and release notes.")) + (smarty-mode-line-update) + (run-hooks 'smarty-mode-hook)) + +(defun smarty-doc-mode () + "Display Smarty Mode documentation in *Help* buffer." + (interactive) + (with-output-to-temp-buffer + (if (fboundp 'help-buffer) (help-buffer) "*Help*") + (princ mode-name) + (princ " mode:\n") + (princ (documentation 'smarty-mode)) + (with-current-buffer standard-output + (help-mode)) + (print-help-return-message))) + +(defun smarty-activate-customizations () + "Activate all customizations on local variables." + (interactive) + (smarty-mode-map-init) + (use-local-map smarty-mode-map) + (set-syntax-table smarty-mode-syntax-table) + (smarty-update-mode-menu) + (run-hooks 'menu-bar-update-hook) + (smarty-mode-line-update)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Templates +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-template-field (prompt &optional follow-string optional + begin end is-string string-char default) + "Prompt for string and insert it in buffer with optional FOLLOW-STRING. +If OPTIONAL is nil, the prompt is left if an empty string is inserted. If +an empty string is inserted, return nil and call `smarty-template-undo' for +the region between BEGIN and END. IS-STRING indicates whether a string +with double-quotes is to be inserted. DEFAULT specifies a default string." + (let ((position (point)) + string) + (insert "<" prompt ">") + (if (not (> (length string-char) 0)) + (setq string-char "\"")) + (setq string + (condition-case () + (read-from-minibuffer (concat prompt ": ") + (or (and is-string (cons (concat string-char string-char) 1)) default) + smarty-minibuffer-local-map) + (quit (if (and optional begin end) + (progn (beep) "") + (keyboard-quit))))) + (when (or (not (equal string "")) optional) + (delete-region position (point))) + (when (and (equal string "") optional begin end) + (smarty-template-undo begin end) + (message "Template aborted")) + (unless (equal string "") + (insert string)) + (when (or (not (equal string "")) (not optional)) + (insert (or follow-string ""))) + (if (equal string "") nil string))) + +(defun smarty-template-undo (begin end) + "Undo aborted template by deleting region and unexpanding the keyword." + (cond (smarty-template-invoked-by-hook + (goto-char end) + (insert " ") + (delete-region begin end) + (unexpand-abbrev)) + (t (delete-region begin end)))) + +(defun smarty-template-generic-function (label close-label field mandatory-count &optional infinite special-field) + "Generic function template 'label field1= field2=..." + (interactive) + (let ((start (point)) found here result-value elt continue field-count stop prompt) + (if smarty-template-invoked-by-hook + (setq found (smarty-after-ldelim)) + (insert smarty-left-delimiter) + (setq found t)) + (insert label) + (setq here (point-marker)) + (insert " ") + (when found + (setq elt field) + (setq continue t) + (setq field-count 0) + (setq stop nil) + (while (and elt continue) + (setq prompt (car elt)) + (when (not special-field) + (insert prompt "=")) + (setq result-value (smarty-template-field prompt nil t)) + (if (and (not result-value) + (< field-count mandatory-count)) + (progn (setq continue nil) + (delete-region start (point)) + (insert (concat label " ")) + (setq stop t)) + (if (not result-value) + (setq continue nil) + (setq here (point-marker)) + (insert " "))) + (setq field-count (+ 1 field-count)) + (setq elt (cdr elt))) + (when (and infinite continue) + (while continue + (setq result-value (smarty-template-field "var_name" "=" t here)) + (if (not result-value) + (setq continue nil) + (setq continue (smarty-template-field "var_value" nil t here)) + (setq here (point-marker)) + (insert " ")))) + (when (not stop) + (delete-region here (point)) + (if (> 0 mandatory-count) + (delete-char -1)) + (if special-field + (delete-char -1)) + (insert smarty-right-delimiter) + (setq here (point-marker)) + (if close-label + (insert smarty-left-delimiter "/" label smarty-right-delimiter)) + (goto-char here))))) + +(defun smarty-template-generic-modifier (label field mandatory-count) + "Generic modifier template '|label:field1:field2..." + (interactive) + (let ((start (point)) found here result-value elt continue field-count stop prompt) + (setq found (re-search-backward (concat (regexp-quote smarty-left-delimiter) "\\$\\(\\w+\\)" (regexp-quote "|")) nil t)) + (if found + (progn + (setq found (re-search-forward (regexp-quote smarty-right-delimiter) start t)) + (if (not found) + (progn + (goto-char start) + (insert label) + (setq here (point-marker)) + (setq elt field) + (setq continue t) + (setq field-count 0) + (setq stop nil) + (while (and elt continue) + (setq prompt (car elt)) + (insert ":") + (setq result-value (smarty-template-field prompt nil t)) + (if (and (not result-value) + (< field-count mandatory-count)) + (progn (setq continue nil) + (delete-region start (point)) + (insert (concat label " ")) + (setq stop t)) + (if (not result-value) + (setq continue nil) + (setq here (point-marker)) + (insert ":"))) + (setq field-count (+ 1 field-count)) + (setq elt (cdr elt))) + (when (not stop) + (delete-region here (point)) + (if (not (or (looking-at smarty-right-delimiter) + (looking-at "|"))) + (insert smarty-right-delimiter)))) + (goto-char start) + (insert label " "))) + (goto-char start) + (insert label " ")))) + +(defun smarty-template-capture-hook () + (smarty-hooked-abbrev 'smarty-template-capture)) +(defun smarty-template-config-load-hook () + (smarty-hooked-abbrev 'smarty-template-config-load)) +(defun smarty-template-else-hook () + (smarty-hooked-abbrev 'smarty-template-else)) +(defun smarty-template-elseif-hook () + (smarty-hooked-abbrev 'smarty-template-elseif)) +(defun smarty-template-foreach-hook () + (smarty-hooked-abbrev 'smarty-template-foreach)) +(defun smarty-template-foreachelse-hook () + (smarty-hooked-abbrev 'smarty-template-foreachelse)) +(defun smarty-template-if-hook () + (smarty-hooked-abbrev 'smarty-template-if)) +(defun smarty-template-include-hook () + (smarty-hooked-abbrev 'smarty-template-include)) +(defun smarty-template-include-php-hook () + (smarty-hooked-abbrev 'smarty-template-include-php)) +(defun smarty-template-insert-hook () + (smarty-hooked-abbrev 'smarty-template-insert)) +(defun smarty-template-ldelim-hook () + (smarty-hooked-abbrev 'smarty-template-ldelim)) +(defun smarty-template-literal-hook () + (smarty-hooked-abbrev 'smarty-template-literal)) +(defun smarty-template-php-hook () + (smarty-hooked-abbrev 'smarty-template-php)) +(defun smarty-template-rdelim-hook () + (smarty-hooked-abbrev 'smarty-template-rdelim)) +(defun smarty-template-section-hook () + (smarty-hooked-abbrev 'smarty-template-section)) +(defun smarty-template-sectionelse-hook () + (smarty-hooked-abbrev 'smarty-template-sectionelse)) +(defun smarty-template-strip-hook () + (smarty-hooked-abbrev 'smarty-template-strip)) + +(defun smarty-template-assign-hook () + (smarty-hooked-abbrev 'smarty-template-assign)) +(defun smarty-template-counter-hook () + (smarty-hooked-abbrev 'smarty-template-counter)) +(defun smarty-template-cycle-hook () + (smarty-hooked-abbrev 'smarty-template-cycle)) +(defun smarty-template-debug-hook () + (smarty-hooked-abbrev 'smarty-template-debug)) +(defun smarty-template-eval-hook () + (smarty-hooked-abbrev 'smarty-template-eval)) +(defun smarty-template-fetch-hook () + (smarty-hooked-abbrev 'smarty-template-fetch)) +(defun smarty-template-html-checkboxes-hook () + (smarty-hooked-abbrev 'smarty-template-html-checkboxes)) +(defun smarty-template-html-image-hook () + (smarty-hooked-abbrev 'smarty-template-html-image)) +(defun smarty-template-html-options-hook () + (smarty-hooked-abbrev 'smarty-template-html-options)) +(defun smarty-template-html-radios-hook () + (smarty-hooked-abbrev 'smarty-template-html-radios)) +(defun smarty-template-html-select-date-hook () + (smarty-hooked-abbrev 'smarty-template-html-select-date)) +(defun smarty-template-html-select-time-hook () + (smarty-hooked-abbrev 'smarty-template-html-select-time)) +(defun smarty-template-html-table-hook () + (smarty-hooked-abbrev 'smarty-template-html-table)) +(defun smarty-template-mailto-hook () + (smarty-hooked-abbrev 'smarty-template-mailto)) +(defun smarty-template-math-hook () + (smarty-hooked-abbrev 'smarty-template-math)) +(defun smarty-template-popup-hook () + (smarty-hooked-abbrev 'smarty-template-popup)) +(defun smarty-template-popup-init-hook () + (smarty-hooked-abbrev 'smarty-template-popup-init)) +(defun smarty-template-textformat-hook () + (smarty-hooked-abbrev 'smarty-template-textformat)) + +(defun smarty-template-capitalize-hook () + (smarty-hooked-abbrev 'smarty-template-capitalize)) +(defun smarty-template-cat-hook () + (smarty-hooked-abbrev 'smarty-template-cat)) +(defun smarty-template-count-characters-hook () + (smarty-hooked-abbrev 'smarty-template-count-characters)) +(defun smarty-template-count-paragraphs-hook () + (smarty-hooked-abbrev 'smarty-template-count-paragraphs)) +(defun smarty-template-count-sentences-hook () + (smarty-hooked-abbrev 'smarty-template-count-sentences)) +(defun smarty-template-count-words-hook () + (smarty-hooked-abbrev 'smarty-template-count-words)) +(defun smarty-template-date-format-hook () + (smarty-hooked-abbrev 'smarty-template-date-format)) +(defun smarty-template-default-hook () + (smarty-hooked-abbrev 'smarty-template-default)) +(defun smarty-template-escape-hook () + (smarty-hooked-abbrev 'smarty-template-escape)) +(defun smarty-template-indent-hook () + (smarty-hooked-abbrev 'smarty-template-indent)) +(defun smarty-template-lower-hook () + (smarty-hooked-abbrev 'smarty-template-lower)) +(defun smarty-template-nl2br-hook () + (smarty-hooked-abbrev 'smarty-template-nl2br)) +(defun smarty-template-regex-replace-hook () + (smarty-hooked-abbrev 'smarty-template-regex-replace)) +(defun smarty-template-replace-hook () + (smarty-hooked-abbrev 'smarty-template-replace)) +(defun smarty-template-spacify-hook () + (smarty-hooked-abbrev 'smarty-template-spacify)) +(defun smarty-template-string-format-hook () + (smarty-hooked-abbrev 'smarty-template-string-format)) +(defun smarty-template-vstrip-hook () + (smarty-hooked-abbrev 'smarty-template-vstrip)) +(defun smarty-template-strip-tags-hook () + (smarty-hooked-abbrev 'smarty-template-strip-tags)) +(defun smarty-template-truncate-hook () + (smarty-hooked-abbrev 'smarty-template-truncate)) +(defun smarty-template-upper-hook () + (smarty-hooked-abbrev 'smarty-template-upper)) +(defun smarty-template-wordwrap-hook () + (smarty-hooked-abbrev 'smarty-template-wordwrap)) + +(defun smarty-template-validate-hook () + (smarty-hooked-abbrev 'smarty-template-validate)) +(defun smarty-template-formtool-checkall-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-checkall)) +(defun smarty-template-formtool-copy-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-copy)) +(defun smarty-template-formtool-count-chars-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-count-chars)) +(defun smarty-template-formtool-init-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-init)) +(defun smarty-template-formtool-move-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-move)) +(defun smarty-template-formtool-moveall-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-moveall)) +(defun smarty-template-formtool-movedown-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-movedown)) +(defun smarty-template-formtool-moveup-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-moveup)) +(defun smarty-template-formtool-remove-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-remove)) +(defun smarty-template-formtool-rename-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-rename)) +(defun smarty-template-formtool-save-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-save)) +(defun smarty-template-formtool-selectall-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-selectall)) +(defun smarty-template-paginate-first-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-first)) +(defun smarty-template-paginate-last-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-last)) +(defun smarty-template-paginate-middle-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-middle)) +(defun smarty-template-paginate-next-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-next)) +(defun smarty-template-paginate-prev-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-prev)) + +(defun smarty-template-btosmilies-hook () + (smarty-hooked-abbrev 'smarty-template-btosmilies)) +(defun smarty-template-bbcodetohtml-hook () + (smarty-hooked-abbrev 'smarty-template-bbcodetohtml)) +(defun smarty-template-date-formatto-hook () + (smarty-hooked-abbrev 'smarty-template-date-formatto)) + +(defun smarty-template-capture () + "Insert a capture statement." + (interactive) + (smarty-template-generic-function "capture" t '("name" "assign") 0)) + +(defun smarty-template-config-load () + "Insert a config_load statement." + (interactive) + (smarty-template-generic-function "config_load" nil '("file" "section" "scope" "global") 1)) + +(defun smarty-template-else () + "Insert a else statement." + (interactive) + (smarty-template-generic-function "else" nil '() 0)) + +(defun smarty-template-elseif () + "Insert a elseif statement." + (interactive) + (smarty-template-generic-function "elseif" nil '("condition") 1 nil t)) + +(defun smarty-template-foreach () + "Insert a foreach statement." + (interactive) + (smarty-template-generic-function "foreach" t '("from" "item" "key" "name") 2)) + +(defun smarty-template-foreachelse () + "Insert a foreachelse statement." + (interactive) + (smarty-template-generic-function "foreachelse" nil '() 0)) + +(defun smarty-template-if () + "Insert a if statement." + (interactive) + (smarty-template-generic-function "if" t '("condition") 1 nil t)) + +(defun smarty-template-include () + "Insert a include statement." + (interactive) + (smarty-template-generic-function "include" nil '("file" "assign") 1 t)) + +(defun smarty-template-include-php () + "Insert a include_php statement." + (interactive) + (smarty-template-generic-function "include_php" nil '("file" "once" "assign") 1)) + +(defun smarty-template-insert () + "Insert a insert statement." + (interactive) + (smarty-template-generic-function "insert" nil '("name" "assign" "script") 1 t)) + +(defun smarty-template-ldelim () + "Insert a ldelim statement." + (interactive) + (smarty-template-generic-function "ldelim" nil '() 0)) + +(defun smarty-template-literal () + "Insert a literal statement." + (interactive) + (smarty-template-generic-function "literal" t '() 0)) + +(defun smarty-template-php () + "Insert a php statement." + (interactive) + (smarty-template-generic-function "php" t '() 0)) + +(defun smarty-template-rdelim () + "Insert a rdelim statement." + (interactive) + (smarty-template-generic-function "rdelim" nil '() 0)) + +(defun smarty-template-section () + "Insert a section statement." + (interactive) + (smarty-template-generic-function "section" t '("name" "loop" "start" "step" "max" "show") 2)) + +(defun smarty-template-sectionelse () + "Insert a sectionelse statement." + (interactive) + (smarty-template-generic-function "sectionelse" nil '() 0)) + +(defun smarty-template-strip () + "Insert a strip statement." + (interactive) + (smarty-template-generic-function "strip" t '() 0)) + + +(defun smarty-template-assign () + "Insert a assign statement." + (interactive) + (smarty-template-generic-function "assign" nil '("var" "value") 2)) + +(defun smarty-template-counter () + "Insert a counter statement." + (interactive) + (smarty-template-generic-function "counter" nil '("name" "start" "skip" "direction" "print" "assign") 0)) + +(defun smarty-template-cycle () + "Insert a cycle statement." + (interactive) + (smarty-template-generic-function "cycle" nil '("values" "name" "print" "advance" "delimiter" "assign" "reset") 1)) + +(defun smarty-template-debug () + "Insert a debug statement." + (interactive) + (smarty-template-generic-function "debug" nil '("output") 0)) + +(defun smarty-template-eval () + "Insert a eval statement." + (interactive) + (smarty-template-generic-function "eval" nil '("var" "assign") 1)) + +(defun smarty-template-fetch () + "Insert a fetch statement." + (interactive) + (smarty-template-generic-function "fetch" nil '("file" "assign") 1)) + +(defun smarty-template-html-checkboxes () + "Insert a html_checkboxes statement." + (interactive) + (smarty-template-generic-function "html_checkboxes" nil '("name" "values" "output" "selected" "options" "separator" "assign" "labels") 0)) + +(defun smarty-template-html-image () + "Insert a html_image statement." + (interactive) + (smarty-template-generic-function "html_image" nil '("file" "height" "width" "basedir" "alt" "href" "path_prefix") 1)) + +(defun smarty-template-html-options () + "Insert a html_options statement." + (interactive) + (smarty-template-generic-function "html_options" nil '("name" "values" "output" "selected" "options") 0)) + +(defun smarty-template-html-radios () + "Insert a html_radios statement." + (interactive) + (smarty-template-generic-function "html_radios" nil '("name" "values" "output" "selected" "options" "separator" "assign") 0)) + +(defun smarty-template-html-select-date () + "Insert a html_select_date statement." + (interactive) + (smarty-template-generic-function "html_select_date" nil '("prefix" "time" "start_year" "end_year" "display_days" "display_months" "display_years" "month_format" "day_format" "day_value_format" "year_as_text" "reverse_years" "field_array" "day_size" "month_size" "year_size" "all_extra" "day_extra" "month_extra" "year_extra" "field_order" "field_separator" "month_value_format" "year_empty" "month_empty" "day_empty") 0)) + +(defun smarty-template-html-select-time () + "Insert a html_select_time statement." + (interactive) + (smarty-template-generic-function "html_select_time" nil '("prefix" "time" "display_hours" "display_minutes" "display_seconds" "display_meridian" "use_24_hours" "minute_interval" "second_interval" "field_array" "all_extra" "hour_extra" "minute_extra" "second_extra" "meridian_extra") 0)) + +(defun smarty-template-html-table () + "Insert a html_table statement." + (interactive) + (smarty-template-generic-function "html_table" nil '("loop" "cols" "rows" "inner" "caption" "table_attr" "th_attr" "tr_attr" "td_attr" "trailpad" "hdir" "vdir") 1)) + +(defun smarty-template-mailto () + "Insert a mailto statement." + (interactive) + (smarty-template-generic-function "mailto" nil '("address" "text" "encode" "cc" "bcc" "subject" "newsgroups" "followupto" "extra") 1)) + +(defun smarty-template-math () + "Insert a math statement." + (interactive) + (smarty-template-generic-function "math" nil '("equation" "var" "format" "assign") 2 t)) + +(defun smarty-template-popup () + "Insert a popup statement." + (interactive) + (smarty-template-generic-function "popup" nil '("text" "trigger" "sticky" "caption" "fgcolor" "bgcolor" "textcolor" "capcolor" "closecolor" "textfont" "captionfont" "closefont" "textsize" "captionsize" "closesize" "width" "height" "left" "right" "center" "above" "below" "border" "offsetx" "offsety" "fgbackground" "bgbackground" "closetext" "noclose" "status" "autostatus" "autostatuscap" "inarray" "caparray" "capicon" "snapx" "snapy" "fixx" "fixy" "background" "padx" "pady" "fullhtml" "frame" "function" "delay" "hauto" "vauto") 1)) + +(defun smarty-template-popup-init () + "Insert a popup_init statement." + (interactive) + (smarty-template-generic-function "popup_init" nil '("src") 1)) + +(defun smarty-template-textformat () + "Insert a textformat statement." + (interactive) + (smarty-template-generic-function "textformat" t '("style" "indent" "indent_first" "indent_char" "wrap" "wrap_char" "wrap_cut" "assign") 0)) + +(defun smarty-template-capitalize () + "Insert a capitalize statement." + (interactive) + (smarty-template-generic-modifier "capitalize" '("upcase_numeric") 0)) + +(defun smarty-template-cat () + "Insert a cat statement." + (interactive) + (smarty-template-generic-modifier "cat" '("value") 0)) + +(defun smarty-template-count-characters () + "Insert a count_characters statement." + (interactive) + (smarty-template-generic-modifier "count_characters" '("include_whitespace") 0)) + +(defun smarty-template-count-paragraphs () + "Insert a count_paragraphs statement." + (interactive) + (smarty-template-generic-modifier "count_paragraphs" '() 0)) + +(defun smarty-template-count-sentences () + "Insert a count_sentences statement." + (interactive) + (smarty-template-generic-modifier "count_sentences" '() 0)) + +(defun smarty-template-count-words () + "Insert a count_words statement." + (interactive) + (smarty-template-generic-modifier "count_words" '() 0)) + +(defun smarty-template-date-format () + "Insert a date_format statement." + (interactive) + (smarty-template-generic-modifier "date_format" '("format" "default") 0)) + +(defun smarty-template-default () + "Insert a default statement." + (interactive) + (smarty-template-generic-modifier "default" '("value") 0)) + +(defun smarty-template-escape () + "Insert a escape statement." + (interactive) + (smarty-template-generic-modifier "escape" '("html|htmlall|url|urlpathinfo|quotes|hex|hexentity|javascript|mail" "charset") 0)) + +(defun smarty-template-indent () + "Insert a indent statement." + (interactive) + (smarty-template-generic-modifier "indent" '("value" "character") 0)) + +(defun smarty-template-lower () + "Insert a lower statement." + (interactive) + (smarty-template-generic-modifier "lower" '() 0)) + +(defun smarty-template-nl2br () + "Insert a nl2br statement." + (interactive) + (smarty-template-generic-modifier "nl2br" '() 0)) + +(defun smarty-template-regex-replace () + "Insert a regex_replace statement." + (interactive) + (smarty-template-generic-modifier "regex_replace" '("regexp" "string_to_replace") 2)) + +(defun smarty-template-replace () + "Insert a replace statement." + (interactive) + (smarty-template-generic-modifier "replace" '("string" "string_to_replace_with") 2)) + +(defun smarty-template-spacify () + "Insert a spacify statement." + (interactive) + (smarty-template-generic-modifier "spacify" '("character") 0)) + +(defun smarty-template-string-format () + "Insert a string_format statement." + (interactive) + (smarty-template-generic-modifier "string_format" '("format") 1)) + +(defun smarty-template-vstrip () + "Insert a strip statement." + (interactive) + (smarty-template-generic-modifier "strip" '() 0)) + +(defun smarty-template-strip-tags () + "Insert a strip_tags statement." + (interactive) + (smarty-template-generic-modifier "strip_tags" '("replace_by_space") 0)) + +(defun smarty-template-truncate () + "Insert a truncate statement." + (interactive) + (smarty-template-generic-modifier "truncate" '("count" "text_to_replace" "character_boundary" "middle_string") 0)) + +(defun smarty-template-upper () + "Insert a upper statement." + (interactive) + (smarty-template-generic-modifier "upper" '() 0)) + +(defun smarty-template-wordwrap () + "Insert a wordwrap statement." + (interactive) + (smarty-template-generic-modifier "wordwrap" '("count" "string" "character_boundary") 0)) + + +(defun smarty-template-validate () + "Insert a validate statement." + (interactive) + (smarty-template-generic-function "validate" nil '("field" "criteria" "message" "form" "transform" "trim" "empty" "halt" "assign" "append" "page") 3)) + +(defun smarty-template-formtool-checkall () + "Insert a formtool_checkall statement." + (interactive) + (smarty-template-generic-function "formtool_checkall" nil '("name" "class" "style") 1)) + +(defun smarty-template-formtool-copy () + "Insert a formtool_copy statement." + (interactive) + (smarty-template-generic-function "formtool_copy" nil '("from" "to" "save" "button_text" "all" "counter" "class" "style") 3)) + +(defun smarty-template-formtool-count-chars () + "Insert a formtool_count_chars statement." + (interactive) + (smarty-template-generic-function "formtool_count_chars" nil '("name" "limit" "alert") 3)) + +(defun smarty-template-formtool-init () + "Insert a formtool_init statement." + (interactive) + (smarty-template-generic-function "formtool_init" nil '("src") 1)) + +(defun smarty-template-formtool-move () + "Insert a formtool_move statement." + (interactive) + (smarty-template-generic-function "formtool_move" nil '("from" "to" "save_from" "save_to" "all" "count_to" "count_from" "class" "style") 4)) + +(defun smarty-template-formtool-moveall () + "Insert a formtool_moveall statement." + (interactive) + (smarty-template-generic-function "formtool_moveall" nil '("from" "to" "save_from" "save_to" "all" "count_to" "count_from" "class" "style") 4)) + +(defun smarty-template-formtool-movedown () + "Insert a formtool_movedown statement." + (interactive) + (smarty-template-generic-function "formtool_movedown" nil '("save" "name" "class" "style") 2)) + +(defun smarty-template-formtool-moveup () + "Insert a formtool_moveup statement." + (interactive) + (smarty-template-generic-function "formtool_moveup" nil '("save" "name" "class" "style") 2)) + +(defun smarty-template-formtool-remove () + "Insert a formtool_remove statement." + (interactive) + (smarty-template-generic-function "formtool_remove" nil '("from" "save" "all" "counter" "class" "style") 2)) + +(defun smarty-template-formtool-rename () + "Insert a formtool_rename statement." + (interactive) + (smarty-template-generic-function "formtool_rename" nil '("name" "from" "save" "class" "style") 3)) + +(defun smarty-template-formtool-save () + "Insert a formtool_save statement." + (interactive) + (smarty-template-generic-function "formtool_save" nil '("from" "name" "save") 3)) + +(defun smarty-template-formtool-selectall () + "Insert a formtool_selectall statement." + (interactive) + (smarty-template-generic-function "formtool_selectall" nil '("name" "class" "style") 1)) + +(defun smarty-template-paginate-first () + "Insert a paginate_first statement." + (interactive) + (smarty-template-generic-function "paginate_first" nil '("id" "text") 0)) + +(defun smarty-template-paginate-last () + "Insert a paginate_last statement." + (interactive) + (smarty-template-generic-function "paginate_last" nil '("id" "text") 0)) + +(defun smarty-template-paginate-middle () + "Insert a paginate_middle statement." + (interactive) + (smarty-template-generic-function "paginate_middle" nil '("id" "format" "prefix" "page_limit" "link_prefix" "link_suffix") 0)) + +(defun smarty-template-paginate-next () + "Insert a paginate_next statement." + (interactive) + (smarty-template-generic-function "paginate_next" nil '("id" "text") 0)) + +(defun smarty-template-paginate-prev () + "Insert a paginate_prev statement." + (interactive) + (smarty-template-generic-function "paginate_prev" nil '("id" "text") 0)) + + +(defun smarty-template-btosmilies () + "Insert a B2Smilies statement." + (interactive) + (smarty-template-generic-modifier "B2Smilies" '() 0)) + +(defun smarty-template-bbcodetohtml () + "Insert a bbcode2html statement." + (interactive) + (smarty-template-generic-modifier "bbcode2html" '() 0)) + +(defun smarty-template-date-formatto () + "Insert a date_format2 statement." + (interactive) + (smarty-template-generic-modifier "date_format2" '("format" "default") 0)) + +;; + +(defun smarty-resolve-env-variable (string) + "Resolve environment variables in STRING." + (while (string-match "\\(.*\\)${?\\(\\(\\w\\|_\\)+\\)}?\\(.*\\)" string) + (setq string (concat (match-string 1 string) + (getenv (match-string 2 string)) + (match-string 4 string)))) + string) + +(defun smarty-insert-string-or-file (string) + "Insert STRING or file contents if STRING is an existing file name." + (unless (equal string "") + (let ((file-name + (progn (string-match "^\\([^\n]+\\)" string) + (smarty-resolve-env-variable (match-string 1 string))))) + (if (file-exists-p file-name) + (forward-char (cadr (insert-file-contents file-name))) + (insert string))))) + +(defun smarty-template-insert-date () + "Insert date in appropriate format." + (interactive) + (insert + (cond + ;; 'american, 'european, 'scientific kept for backward compatibility + ((eq smarty-date-format 'american) (format-time-string "%m/%d/%Y" nil)) + ((eq smarty-date-format 'european) (format-time-string "%d.%m.%Y" nil)) + ((eq smarty-date-format 'scientific) (format-time-string "%Y/%m/%d" nil)) + (t (format-time-string smarty-date-format nil))))) + +(defun smarty-template-header (&optional file-title) + "Insert a Smarty file header." + (interactive) + (unless (equal smarty-file-header "") + (let (pos) + (save-excursion + (smarty-insert-string-or-file smarty-file-header) + (setq pos (point-marker))) + (smarty-template-replace-header-keywords + (point-min-marker) pos file-title)))) + +(defun smarty-template-footer () + "Insert a Smarty file footer." + (interactive) + (unless (equal smarty-file-footer "") + (let (pos) + (save-excursion + (setq pos (point-marker)) + (smarty-insert-string-or-file smarty-file-footer) + (unless (= (preceding-char) ?\n) + (insert "\n"))) + (smarty-template-replace-header-keywords pos (point-max-marker))))) + +(defun smarty-template-replace-header-keywords (beg end &optional file-title is-model) + "Replace keywords in header and footer." + (let () + (smarty-prepare-search-2 + (save-excursion + (goto-char beg) + (while (search-forward "<filename>" end t) + (replace-match (buffer-name) t t)) + (goto-char beg) + (while (search-forward "<copyright>" end t) + (replace-match smarty-copyright-string t t)) + (goto-char beg) + (while (search-forward "<author>" end t) + (replace-match "" t t) + (insert (user-full-name)) + (when user-mail-address (insert " <" user-mail-address ">"))) + (goto-char beg) + (while (search-forward "<login>" end t) + (replace-match (user-login-name) t t)) + (goto-char beg) + (while (search-forward "<company>" end t) + (replace-match smarty-company-name t t)) + (goto-char beg) + ;; Replace <RCS> with $, so that RCS for the source is + ;; not over-enthusiastic with replacements + (while (search-forward "<RCS>" end t) + (replace-match "$" nil t)) + (goto-char beg) + (while (search-forward "<date>" end t) + (replace-match "" t t) + (smarty-template-insert-date)) + (goto-char beg) + (while (search-forward "<year>" end t) + (replace-match (format-time-string "%Y" nil) t t)) + (goto-char beg) + (let (string) + (while + (re-search-forward "<\\(\\(\\w\\|\\s_\\)*\\) string>" end t) + (setq string (read-string (concat (match-string 1) ": "))) + (replace-match string t t))) + (goto-char beg) + (when (and (not is-model) (search-forward "<cursor>" end t)) + (replace-match "" t t)))))) + +(provide 'smarty-mode) +;;; smarty-mode.el ends here \ No newline at end of file diff --git a/emacs/nxhtml/autostart.el b/emacs/nxhtml/autostart.el new file mode 100644 index 0000000..44a6901 --- /dev/null +++ b/emacs/nxhtml/autostart.el @@ -0,0 +1,194 @@ +;;; autostart.el --- Load nxhtml +;; +;; Author: By: Lennart Borgman +;; Created: Fri Dec 15 2006 +;; Version: +;; Last-Updated: 2009-04-30 Thu +;; Keywords: +;; Compatibility: +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;; Fix-me: Split out the definitions from this file so it can be +;; loaded during byte compilation. + +;;(eval-when-compile (require 'web-vcs nil t)) +;;(eval-when-compile (require 'nxhtml-web-vcs nil t)) + +(message "Nxml/Nxhtml Autostart.el loading ...") + +(defconst nxhtml-autostart-trace nil) +(defsubst nxhtml-autostart-trace (format-string &rest args) + (when nxhtml-autostart-trace + (apply 'message format-string args))) + +(defconst nxhtml-load-time-start (float-time)) + +;; Add this dir to load-path +(add-to-list 'load-path + (file-name-directory (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name))) + +(require 'nxhtml-base) +(eval-and-compile (when (fboundp 'nxml-mode) + (load (expand-file-name "etc/schema/schema-path-patch" + nxhtml-install-dir)))) + +;; (defun nxhtml-custom-load-and-get-value (symbol) +;; (custom-load-symbol symbol) +;; (symbol-value symbol)) + +(defun nxhtml-list-loaded-features (use-message) + (interactive (list t)) + (let ((buf (when use-message ;(called-interactively-p) + (get-buffer-create "*nXhtml loaded features*")))) + (if buf + (with-current-buffer buf (erase-buffer)) + (message "") + (message "=== Loaded at nxhtml/autostart.el end:")) + (dolist (feature '( + as-external + html-chklnk + html-imenu + html-move + html-pagetoc + html-quote + html-site + html-toc + html-upl + html-wtoc + inlimg + mumamo + nxhtml-bug + nxhtml-menu + nxhtml-mode + nxhtml-mumamo + nxhtml-strval + nxhtml + nxhtml-js + nxml-where + outline-magic + rngalt + tidy-xhtml + xhtml-help + )) + (when (featurep feature) + (if buf + (with-current-buffer buf + (insert (format "(feature '%s)=%s\n" feature (featurep feature)))) + (message "(feature '%s)=%s" feature (featurep feature))))) + (if buf + (display-buffer buf) + (message "")))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Code that will run on loading this file + +(if (< emacs-major-version 23) + (unless (featurep 'autostart22) + (load (expand-file-name "autostart22" nxhtml-install-dir))) + ;; Check that the nxml-mode included with Emacs is used. There + ;; has been some problems on Debian with this. + (let ((nxml-mode-file (locate-library "nxml-mode")) + (help-file (locate-library "help"))) + (unless (string= (expand-file-name ".." help-file) + (expand-file-name "../.." nxml-mode-file)) + (error "Wrong nxml-mode=%s used, please use the one that comes with Emacs" nxml-mode-file)))) + +(let* ((util-dir (file-name-as-directory (expand-file-name "util" nxhtml-install-dir))) + (related-dir (file-name-as-directory (expand-file-name "related" nxhtml-install-dir))) + (nxhtml-dir (file-name-as-directory (expand-file-name "nxhtml" nxhtml-install-dir))) + ;;(company-dir (file-name-as-directory (expand-file-name "util/nxhtml-company-mode" nxhtml-install-dir))) + (tests-dir (file-name-as-directory (expand-file-name "tests" nxhtml-install-dir)))) + (add-to-list 'load-path nxhtml-dir) + (add-to-list 'load-path related-dir) + (add-to-list 'load-path util-dir) + (add-to-list 'load-path nxhtml-install-dir) + ;;(add-to-list 'load-path company-dir) + (add-to-list 'load-path tests-dir) + + (nxhtml-autostart-trace "... nXhtml loading %.1f seconds elapsed ..." (- (float-time) nxhtml-load-time-start)) + + ;; Autoloading etc + ;; (unless (featurep 'web-vcs) + ;; (load (expand-file-name "web-vcs" nxhtml-install-dir) (not nxhtml-autoload-web))) + + ;; (when (catch 'miss + ;; (dolist (file nxhtml-basic-files) + ;; (let ((dl-file (expand-file-name file nxhtml-install-dir))) + ;; (unless (file-exists-p dl-file) + ;; (throw 'miss t)))) + ;; nil) + ;; (nxhtml-setup-auto-download nxhtml-install-dir)) + + (unless (featurep 'web-autoload) + (load (expand-file-name "web-autoload" nxhtml-install-dir) (not nxhtml-autoload-web))) + + (when nxhtml-autoload-web + (ad-activate 'require t)) + + ;; Fix-me: Why must as-external be loaded? Why doesn't it work in batch? + ;;(unless noninteractive (require 'as-external)) + + (unless (featurep 'nxhtml-loaddefs) + (load (expand-file-name "nxhtml-loaddefs" nxhtml-install-dir) nxhtml-autoload-web)) + (nxhtml-autostart-trace "... nXhtml loading %.1f seconds elapsed ..." (- (float-time) nxhtml-load-time-start)) + + ;; Turn on `nxhtml-menu-mode' unconditionally + (nxhtml-autostart-trace "Turn on `nxhtml-menu-mode' unconditionally") + (nxhtml-menu-mode 1) + (nxhtml-autostart-trace "... nXhtml loading %.1f seconds elapsed ..." (- (float-time) nxhtml-load-time-start)) + + ;; Patch the rnc include paths + (when (fboundp 'rncpp-patch-xhtml-loader) (rncpp-patch-xhtml-loader)) + (nxhtml-autostart-trace "... nXhtml loading %.1f seconds elapsed ..." (- (float-time) nxhtml-load-time-start)) + + ;; Load nXhtml + (unless (featurep 'nxhtml-autoload) + (load (expand-file-name "nxhtml/nxhtml-autoload" nxhtml-install-dir)))) +(nxhtml-autostart-trace "... nXhtml loading %.1f seconds elapsed ..." (- (float-time) nxhtml-load-time-start)) + + +(unless (featurep 'nxhtml-autostart) + ;; Provide the feature here to avoid loading looping on error. + (provide 'nxhtml-autostart) + + ;; Tell what have been loaded of nXhtml: + (when nxhtml-autostart-trace (nxhtml-list-loaded-features nil)) + + ;; How long time did it all take? + (message "Nxml/Nxhtml Autostart.el loaded in %.1f seconds" (- (float-time) nxhtml-load-time-start))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; autostart.el ends here diff --git a/emacs/nxhtml/autostart22.el b/emacs/nxhtml/autostart22.el new file mode 100644 index 0000000..2376d43 --- /dev/null +++ b/emacs/nxhtml/autostart22.el @@ -0,0 +1,71 @@ +;;; autostart22.el --- Example of autostart file for Emacs22 +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-01-01 Thu +;; Version: +;; Last-Updated: 2009-01-05 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; This file is for Emacs 22 only. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Change this file according to the path of your nxml-mode dir. If +;; you do not use nxml-mode then just use autostart.el. +;; +;; NOTICE: You need to enter the path to your nxml-mode installation +;; below. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(let ((debug-on-error t)) + (if (/= emacs-major-version 22) + (message "This file (autostart22.el) is for Emacs 22 only") + + (defalias 'Custom-mode 'custom-mode) + + (let* ((this-file (or load-file-name buffer-file-name)) + (this-dir (file-name-directory this-file)) + ;; FIX-ME: Download nXml (since it is not included in Emacs + ;; 22) and place the path to rng-auto.el in your downloaded + ;; nXml HERE: + (rng-auto-file (or (locate-library "rng-auto.el") + "c:/emacs/u/081231/EmacsW32/nxhtml/nxml-mode-20041004/rng-auto.el"))) + (unless (file-exists-p rng-auto-file) + (error "Can't find rng-auto.el, please edit %s" this-file)) + (load rng-auto-file)))) + +(provide 'autostart22) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; autostart22.el ends here diff --git a/emacs/nxhtml/emacs22.cmd b/emacs/nxhtml/emacs22.cmd new file mode 100644 index 0000000..d50ac96 --- /dev/null +++ b/emacs/nxhtml/emacs22.cmd @@ -0,0 +1 @@ +c:\emacs\emacs-22.3\bin\emacs.exe -Q --debug-init -l autostart.el diff --git a/emacs/nxhtml/etc/img/pause/pause.jpg b/emacs/nxhtml/etc/img/pause/pause.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ff920756c42a4160ed9045de007bc95672dbbd5a GIT binary patch literal 25849 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ⅈs$~|9O`I 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/etc/img/pause/pause2.jpg b/emacs/nxhtml/etc/img/pause/pause2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6411344afe234c4ab8c791230f0445fb6a9aee58 GIT binary patch literal 26756 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 OV-Vp>?;XT_C;!=05DDY} literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/etc/schema/FDA-2009-N-0392-0396.1.doc b/emacs/nxhtml/etc/schema/FDA-2009-N-0392-0396.1.doc new file mode 100644 index 0000000000000000000000000000000000000000..aa2eff3d154395a93770f7c2f81d5cb062f0a8f7 GIT binary patch literal 47104 zcmeI534B!5*|<*vVGjg>2!i!0Dgi?XtBBQxeUVK>1wXe*GRX`~X5uUfC`v$3zKV)q z6~!eL+ak~!H^6FZs)!L>;+~4OL2Zp&ja6&3YW~lA?!7a2E=17k|JQ!ag=g-1w)ec} zJ?}YpN$s=U>wkXF5&M*DIaRe$UpIGD?HtEb*go6d&roVU+j8vd=H_NOd={|Ty8H)8 z;Qe3xK@GUDV_T(~4tqo@Q7LMcg^GV8OR26Ze?k6&OJ-j(TOUpO>DV??jW|cCK4Vfe z&mLu-K1`J2084XoxA@VPw(Se<)EkZDOBPu>x9wx@bx%29Ep5}xjjdLq&h=<cy~S}! zWfkS^$J)OB-M&h7p#)W?9Q1k;=l@~tAL`mqJgJ0R$Xb>|Ss%-F{~$9y0-ldFm$QE@ z;d@C0uEmx|nzPW3Yux#?ud~+@uXC~Ev)6Wb`x<-yPQqn!@D(dl?zO~U$a!}>?tPJu zbFt%b9y^q6yF4w$C-MG>i01cJivRI^+4(t?G!AslFC;RSxLnYWF6<jSH%@zK_3n5Z zu=UQ5TuM2A5#c&WKx?t{{afUb%Q4YESr&6$HtTw;RsE6hH(UFnigx;JelLrijvbjT zA4z8?`Y7dG%gI&U(NETPeKoQ_m;DKcDfNeVsqI+yU)%C>uWfy_*ZYS|J`$l`Mb8el zxYM!sZ8_We)6&|G-?k6Vb=!{AWmoJ7<#ryIF!sKjckbKA?X@lELtRVfBJrhaE2X1u z{b`lJca%W-u-u`!Ya_-qPcY^QFJ>!u*xF!WditbLsL=2P3ylfkSg|p-u*4tqN1|a* z)E^3_PY4w(^hP7b3{TKg>@D#IqsF+fCs^P!vZhQLJ9v2R$bso2hmXoNCix>iZ#ZI1 z_XNF0)|^nN#2A`8YUsf9ImA%r4+Ol~#*7KZu-wrjho#T)j_GK|Z1guKO&B|PSZ?k~ zgJ%xT9e&cVbXn$xjI(`2F*Qoci;eN2V1YLr9Fv|tHQSi&^9TH;#<(0~R({0i2}c$# z&Ne(HMyRwj6!8`s(U1}Kd5ywQd9XO_Df9=6jjXV@AmE8a{6+o(U9N#fs7PNG@f3NZ zi;b}NqL@Fd%NH?<LSbX#__;>b#DKRT8V*VFWwAiSU*<LDhP|Gsh+&{n=q>XXc)2`G zMkPfGf>eF}VxKn>HTI9$$Par&nv(Xq@sb~7>eQ)5*6@KwiMNoP1?)JpueVDP2$g%o zhZ>iWH7q%*h&OV*E{<fcC=?(z5eH?6gn|*oIhW&9H8sxRsLvBMrW!sE<@9;bi3n<8 zSV9Q;3nIo`Z-I{uzbBY&6og`>0mNPIkNS*~#q0+o{z9**H&R57Q3XaRS`i9Tworb= z8!pr0kH~qimaf0RDD`=RA!O>&T6mzSB>Vm#^-`jP8=;_Cd9nNj)R06*ePtVwQg4B- z;y_@rQSS4jrBl~Z7*Bz&-NHmwg-N{3gEAALH|!^OWIu`=D3ITbJU<j#7%|q(jw~+l z`90C_;u}R+X9l8v31f`&BDck!!1YG{Vwyy(z-yfCk9bRvn6#yJsCP6(dmwKUyanD; zX-)dt>Hc7$#~2$d4AUYCLM8bmDzz=8iv=WVGJp_hhUhX$2163otQ}8~g3%y!Rf&!k zkY2vmh>7C+BSuLmOaN~z914VrMWX_=jZ)v@h`Eh^MZ<nkUrJ0ILBmhm_7)W(MJk)H z`QD(HMuJ3gjLzv}gN7Hugi5U7T**0tXUm2D;vlMo>MllIB5W3L2Fcqp^<QkZ#;`XM z3Q!GF7_-ttgPnOKR}yVBl5JHQDpTT*>g!91)nDq5TJ>%=+JaDV&>xlND5Cb3XaP~8 zxFXpRNs0VHYM5xEWQJTu7MGMpX|Sc?P?102ji(tw1JTtGI?Xw6#4Jh#S&J0ojR-+o z>Xu`OK3MxvAHolM%d-udmLD0Q(XnEm;VCT*_`QW3{$??fn`o#Y6hMeU+E7H7J&~3X z3kH#HB!c12Nl!oH%-OSN&6zuO=44~el!<d^&6zr$wmg<lrs*s4hcQ5AE6+9-21DgE z)MA}+sROb?Y+9-Ez0q>7ms+;kqCbkhgu=xhTDgcw($qqha3T|_eCvWp3D(Y&k1@u8 z>XiM#g)X}w!JG|uzg8A44-rR*suZn6Kd^0JM9*Hef_>&8KQ@Dzu=W(TA#j>HV1 zu%j{fu+66E@&nST*)3TN9C<YlmQf^cAhMQvEu~xXg#F%#S(l}rs851p1uZoVvg=vs zMJ>HyZyAP|6iF|Pg$(HCLVk4<C$C!K5qeH~M{kaCmfxc*QEPzN>4@S;w#!0+D4l79 z{IOYPHWFPPe<Tuf9M9I5o7v8acmkrr1^#e>m<cI(Q6T0o9B5c2ibp4n)3oPEHAKFU zdSQ$TN6HjT1g$eIdTnJ%S9u~s^ry5OEK-4)IS)pbwj+5g#eSfL)Qbn{Si$WCFjMxC zSQu3{(@6-^F0ja(21B&ecs6~GX~t+OWf;Z$kUwyMYIM|>ol0~+ftCC40Z{!&3`0$y zCQUgK<HsoUlpu7<AQw2|T5AM!_ZPPWJ_N0k_lKS8UFZ!Uz_1aFVM0xdY_>K#6IwT< zi^D50Yc68;PpDqhTT&VdW1<3~{DjRhHC#6x$&?k*TI?a3Xk^hy!yz<kV2)wn`RHC@ zifCNam{m%ik#^S98B=BrG*c@=oOmu&fK^oQq5>~|1yV4rI;9GGi#=g|NIDOyfR2$K z$Ff!h6ij+US~D6Dl@=Jm)cZmKvnR4#8dN+Qi`TtGWV%8UL{!A~fU>mm6?%fj-f$=u z8E7Q=Jkr3W8IfOyBHE4+onH(mRNPeC&(aN3^s)eR5f(ckO`kH@US4Ez1UX|L&&Hvk z|BOhlh&dxq;Uo_Ww+Lq;hI=3#0`|QWgCKU#STvYUoeqpHUs|@PWr0WRFn%UZUdX^k zhzZ1)co);Eba~^_)j1?J6i32HXpA{plVeQ5k0aOUIu%BDz&5$3E5^ENXVVfP#W8c8 z)Inz1T{vE+sm5HVGbTAe?4cNT9LJL;Ox}nAxwX_w+S#=lAu&l8sg1Ar3wFF_Le@n| zxk+RJ*Tg7{X$y@Skfteg+dnJygvkvR><{ATl+p#$c|_wrBxZLeie~kl37^GLMi14L zZ<NNu;@aD-USw;TnS}C*(KD+`R4@{96^c$M;4csZYKziNWuezwYFZltSuIvBvnyJ= z_nrdj2`!^a^_JjtNXKD08rh^Ks(?{u6P=1B#v-_yV%8)-xc^a4J|ZskYP&=-R)Ta# zmSciY#^U59oEjaz$aGy}Itx;0UF)P2$~V1M+vDL7-M!gaq8lNkLS~5rZ8L3<WRcoH zyRGKxT~z7~CPW$t(d8pv(;*6lwW*Uj6vYxBJQ@p%mzv0VvT<9RkZ@5fXj%BEFNUnh zj*iv4NHoE;T1m<2T9ukkMDEaH?P^GGEn`;Q7fUaMabffqirJk_+#9q6XO08JZiKzq zU{nBA5s$!D07T}|HcR?8+<4u}>0C)7AKM}IYHLH>6{7z0#Z4o_;*!&Dyv5!^gp68X z<s%`yWV|A8u-H>9T0?4P13`DCNm0V6^h`!E{x(A<G$B5W3}Upks6>gvmK$tqBMB0b z^pRm4e=&ekt`chmhjK}E$Ma_8g9;ZTCgqeErQ^_&)}C$wqn3o{Y$=xb3!>fRTh~~; zViIXt$(Xgsu*Y9S#}s$d-EOw!*-JGr?nOMh%-WMnGz<pqX2T$dImT4nQav&;ldxL7 zD8E%2DZ3VyRFx?erwK3xY&Mi=T+ocyV_`xvs1_qE4a07Yv|Bw0utcOomWE2j+tL}* zK8w~Cx_Cc5ns&xyVncFLATtA&Xic4q_(CyyPFi5V&v=GfrMoGyx*ZH!#7}imPTeC& z6sBdC!B>1tX4R9YEaaynMLVqn2s|boKCX>@$j+3O5MCmxuz)_40Wmc%(TkSQ@RFht z_YhS?N5wXy#iWg5azwXWG~65wC!|k5$$*t?n1w_h5;yj&%<Mz#>^SFNtV~<us$@Ta z<ZX9C`~b;)yvJwi#hND3Qyb`e8Dl-#lc$)n=&b9oc3Mc&ISz`*sH>3j$aIIP*;9>j zT`2)SZvEm=Od1+-qLo&RQkZyjc3JkH%h63=u1(|@mq~_zQj0P&mSMVUSZuZtvvvEt zfl{(0#txrV``coO=~RLRrp2(ki{w@@*K|5PWgfrwowSxxP|NkxbrIKD(M;(PWMFD# zD?ZY6&Kw{FJ#&yyK;10Rg>Pt~BG4edhU8W!>zHN`Cq<5nbnFzRZsv+~88K>Ya}AAf zJEaN9@I>T319w5ZyqUJYO>So3m5F^l1Jh^@WXvX)HDl(CGfp;2f^?fQa`oUi2N#!| zENL?kr`;5ep-Ua?4G#8};E2)_1gIruEKTjThrgIdnQqg{P48%lNG1TJ@!Gu-e$JGb zO!UmM2FhpXhEBk_p;G2WXPq&3pmedNF-pKJr8L{5z+4bNPh@7I)RQzkCUEGW%vy~P zALyTBB2H#8VqqB~Q?0>;a>O2gm*D)#kY7)9Nt2S!@?ujuWd|OLdbqq;CWEBBiEfsv z40}rH(`Y%8YqJw72^D%|pl|ybmS~C@fRY^=X1Tbb*3p0`ABhq?+gL}H>Is4{L(-@h zS6$o4gcE2^by_9YdSvze(lSXO<DjjLr;xJAw(V3%2DKwi%a%4l@>WR17Ya}a=?o=N zal0_g^kzjenTB@w@W@1Z(s5V=LUV?hOp6_(u|x?c6~Z`D91c1oI!_%F>OkKS6+2{F ze$)F9DIyHBe909cqCBu1tP0cpy;->lO~IZ7LS)jO?!fI7)rxD56jKDoak0MAA<=4W z@kl03!|ExLqQvE=<6u^e5sfra?XQY=9K-OKRVj^`=249ALz(m-MGjfg743Is14D-~ z#B%8#omwcQv(s%0S;nV$rCqtDg_eXxA7mbn8Y+`{B(qa-Bxl5}BAF|UNl#@~w%E!L z8c-UbBQ~>a4JT#CY!}k=Q3P?(;#DImtGmF24ob&w`fA?7{j8ML^NEF_M)09<<;KQu z4#>RaVq+|Qd5Pcj6CAe)tjs0GK8aSQCoXZaw7N)LS?x?(knS3!FBIuh7RJH|r!eMW zRwNR`CDKCB{-Q(Hx>DQ%XW$ix>G8g)<`JgQkRW>Eis-;j7`H&QyF~^Hsa~0h&`yx# zlIb{)%=T(Gn<|u?T8^2SZ*eR2d@34)cOEKd<^km;E@_Q8mlV;wA0a_a3t+Y$Gdy~2 zR~iCJ=(V;&GN2%gm_t(|bThDgDlBTmoF6Xppx0JADPh`=sWNTYEXP>83pi2a1cO%~ z6&0XYkQfgjPSUemjUhHwRKl>FJel{=3EASXCwysz6pc~c96b({s9mST$=2PpcnsxC zNn%~B$h0O<P*Dc&B5O+g0Dhk2My{3ETc}C1zGcipKF|R%rDo-#;Iynnquo!^beURm z*#=r(ili|2Vn@aImK2Ew_d+y5d?=j<%MQBhO^c1%rfQR#RebDYd5Gd;YIUJ7roU4Z z6IWO2i^eAt-&vQ*0AZ#K*d{Z(R7$UIHqk_vZ>*ab9jpajvexSQ>22&5b~3gG2SW?N zywfL_t{cyNAb(KzwsXTCy7{Qpjb2ZmE{&6kAOsO|xb5^J46$uZ5Z}T>uCNBW`=1|* zg-sWeqF8RSZY)V&rc{OH_A(V<-juZLH^Gv;U~>c_KC2#{ntd1+4;w@XYm8vp5Nm?U zO4S;iND0gtMP~L&rQu4~DI=dk6mTjdCB~c~Yi2>`RPL<GuwP7_t`ARep?03pT+FaI z*OCj|X=X-bM1gBU?+-E+h{EV*h>~$HCnC8Z5~k3tvF#zsA;&nAnh8jTNL8jLrI+Fk zo-TovAw8|8hgk6pF@=dArgLN7i9p-2Ldo|kweh0n@jWfi9w}oEv@=R7rZZsAo$7+d zN;xkoqlXWAd_f<XRCCxdN4=Uoi!HiDPW8wG7bE>FnG?h*mRnxBTjb^)hYxVSoB7~2 z>FI6Lt=|J&kv=<TR*o?)w8$7bdU*PDe>93SGzmL`-JQuGWqv5U&=@*=_^6TTJ&Y;y zXHT3ned^59jAMM!Xz7?CL(0p`bMpNmyF1~=N+9aX;V!{3MoP~XPxeZVi}7Y48X8lo z@7L$G7~MCW@0Ff4eCWu5#^_<g2cI}JR~`=NF?;OfiH6ZDvDtH|?4+lE#|I<+TY~YN zX9|y_9S*&r4{U~C!%o-*``|Co0FCe^d<E$|{geqgFcgNvESLxLApjw`2Cjvh;8yqr zeEG>c`|4^R|J?(>y6Ng=`ro3!qQC=%51jkJ-08@^Yo^Z_SFOfR%Tyka{aqvPOxi!L z&2dTlS4?~<v440k-|&(1Ri^LNX}i?O4$JI_x@Y=E41U>pBz~pD=eRO{{Mr8X&f`b) z(lKQEtmC5+k*oMQD=z0bN+2QZj7W*z8#X1e-?NwAcOB)bVA_X?tH{5Ea^#aMhIYC* zaRu@GPp6HPJn1M`&1(O4;;MF;zS<#Asw3q&U#Wk)?nkkG4lIJza2JR^Y=NyHdhs}j zUi9q5lc_L*#~ydn&h|h(?1M*mDzF;f<*C5;;3?|xD`%T(dFK=7Wrw)aa%?}~nfIL; zP1<?ec_wM+4d<DEdB=*Zty0B>gD*XuhYn>+6rbwpbiC?3DTRG$NOGY2irUl*p}0^~ zNI$xNgw+4D1E{ksp5y=8nYq^O|LYP+O-V@=Tf7y14ZneV;Q@FR_QIR+7Bs+z@EJ5g z58A!m{%5j18!m*4APUQ14O|B|!A3Z-GyMXrgX`gEuoE7KzrefD1YbZJHf1ObgW(`H zW+cpnv*0}NKp9*NO^ppr^-T>;b+vU(4Rtkj)wR_-s;YOG|2FNY+)-IoxxTS#$C_0Y zjTMz(RW5e%tduVkc9DH)NKPyL@}(~)?a#XG<D`9QZqDm39d=aGe*Y7*llD7x%u3q7 ztpB4)`$@e5`EmDq?tXD>?o&zOzp-B=K4&j9RAjddR>Bpq0XD*B*aF+28g{`Gup9Qk zoA5q-09~>7heK~T7EXZCFcv1lBsd-Bz<f9dyif!|h`|kTEBq2R!GrKSsDUTJ?q6PE z`%hr^GoP{jIeY<GJZXIroC@eeV?%vI9se4Et$O}7)^fP65&fv)SN>J+XxO@OYr~Dz z*VbKGCw=ns*;|vO`DxMZiG6&6arBIt`q$A1(<_Vj;W!fa9z;7F$4S9m{}Q89f86!$ z*0&@-hxl$NPE88$)<?H~S1o=ve*H+1)i^i<=0Xt^!y;G=E8$w$0F`hzRKY#44YtD{ z;RE;>K7}u!8*kTSKzHZ|N5Szh0H(ogI34D~JeUvXK?#Il8$1ZVhicdfyWk0U72b!B zpdD`|q(fIY4En&4a4clQYG`Vde+?)=Z9PV!rl}r%sIL~CsHxupHT7Fr|NN$U{#|!d zea&?oxvu^?(?lTQ(LHnG5)&OsYO(lRvhO-d{ck9HfTLnf9Bv??<+!uH-SvN5cCugV zu1|M;AIx64^~I^-qeVVfLj$}I@^-}6&<q{%-?~5_7zQN}gb-W}x4|8-1*+h8@Ou!y z??u=Pufw0A9^Qrb;3N1uw8bw>gRamEGNB*zha4CJQg03QjkIF<-&k9>v+?2kH&w2$ zTT}P&iba7nb@dMyKD<V^+}nojOUM=Zi=52X;gEm)_@}|;&U%R-7wI^zKS2AMr0!0n z!+B?WQp6+s=F#MMlC*|!N%clJ=_gEGOAhDmKiu}gS)ZbvQZlE0xwZGB3+|1dA0RT$ zg%L0sPJ%ITDvX1(VIG_d1>l7uSO6D61j=C<EQiZsHCzX4;YL^wH^T<_CHw}q!49Z~ zC!qn}0eiggKHHzc7cim+d4p479883nPykIIzPY#Qg{D1^J@nXp4?VVL%VSMj_H5j< z@xBe~_N?3Z*p@w8)@^uf!&Mb~7d^)MvArUnx4T>wFTbMontI}vYErEd%H2wzE4wEV z3+LTh;kMds`)*FUK1o{%zdY~!r1S1p?ylve{GvUQ{(jbmeo5j<)+eXl4G|eGflJ{s zxDu|0Yv5+s0Jp&=xC?#_55dFm1Uv;#!!z&-ybbR{BXsYHO@<?&FJ!?$7y_eU4Ez`_ z051gK5?BJO;Ae0%Y=B!qY(Y~!-Fagj{dkSogX-EH)m8PIZdrF_edE%`O^xM^fySCm zOYu#6`L5)3KUZxd=iAHQO_K9Rc{e8Zk)!OJUVuYt$kAmNxKcDAQ~x@yBn7u-e0cH; zi4-`$;QV8f_B+nJBWd5=ex)4F_UzUaw`O#neQMJ6N%~IuPR$x5a=jhyg$H0e?1rb| zId}==&BH%KJ?w)9XoRn!x4c~m$H0kjCY%dCSOiO<0<MCe!EJCmY=XOBGdu#%Kp*A^ z49J7=a1JbkwXhC;1>0c{JPn->r|*Xh7y`L40#1UdFb{OUUt1&paQ&(qcQjTt)>PH( zkbez38f$7BYB$x^*EUo(tZ%5TsjI4~TT`>9rY=78LtdBsctDaodk;_8Pq8NlvlQ<7 zbk~>LQn)qLtshAmOZuwcoTU7@_03)XPW?Pl=4C{d4M$*qVFhm=uY^;0>-1C@bTs}v z9NwS0h9{22Cx`CG)3#v+a|bJ-5`GSMz;@UH4}#1sJO|Iii||EUvTXeK?0n=b_IKI& z&>2C?JI<?QTi(ZI<|lnuno4=N6LUd1mla#HMA8kYzS2g{g(3(*1eQVttb{Azf8nQa z6|9E4;7NE2o`z@OWq1|dgm<73{s~{gSI~yHh}%MU=mq`YcsK!u!w47&qahC_!7Ml% z=7GGuy%3hd3iw~R3GnP2n)L9lwx+3?e><A0nl?36GvZ&rV-1ab)sCuF75rl|pt5?E zTRzf$-R;NS-p@WUc^>+AM<nmN+yB{Fvy$3l-;qO;_S5?AN!l;H_`an5caBUR&%4{N z+n%`Xf!lt#J(s|gM2|N_WOygs4OQ?k{0`oL&)`ew*oS(9BOnjP!*n<Y{s+#5^B@2h z!4kL}Zh}hK2oJ-f@Fe^h_Q5;w0elQ6VtY=4N8xGs3%m_tlRkd?&#&xxWc%IQU-{K5 zx4*Le#%s-gzq)cM|L(r>?(%D|y!P&2T^ri3a`*H04q(m4<g7@NzPq;FwduD0?%H(M zhT9t7n}1CrJ-i4>FViQnIJ}7XanUu$aq{ohzNFeFob)CKiqAYQxpTy)vP8b`!{0#h z<$*L953`^E<m&`cSOizWYLGYdZ-d{!-S9Z<f+wH`{s?>F6Zj{zr$6ZiKZ0Bs3Ma$q z5QSxMIY__rbGQRG!pHA^{Kl)#zq<R;-`@M`=H0*DecKJYZ@6anH8)&w!)0Z=%NAUb z|LE?`H*D7ThMqrjWs+3I$I8?mprf=%&+SXO$5!szbJu=STa8Ow>M%JScP+VXgxd#9 z(hBnF)<Sn1c57AAoFm?<<kK<hL{8<3OrL~v99PGSoVP+1+ygt{LD&h8!&C4y?1k50 zAG`^lLduccWPmQv4+g;)I2H0>ER2KcFawIA92Uc6uoSL=8{yY*H{1gc!Nc$vybgbY zx8QwfYJ7XI`LFSXJ&*0#zNc|Z<Hp8~8(!FR?Zy}OY}j+<o+~$8xwJgAr(Dbdl5|Uc zKkM$Y)=82@ZeooyeNsQkHJqezq?1&GgfrW<tNn7^9OX-_$?+v=7V)`zfyR>@vkt@~ zF`L%F5f3$ga9woj_z5D@PvCPnjL)PDfe|nYCc#_?LlnwkHCzoh!c9;E&%ulE61)t1 zp&s6V_uzf_6#fAz_>`R>3kJi<@M92Pb1aO9888<vfg4~G+y(c*4tNlL56{8#@B+LA ze}zw=Nx(0V3BSgg#`-4Q{;Exto9Z^zR<c@OSyfxrR9VeEf$I9|HQXtvTvfZOdR6rf zQ)Aq1Z^ZE5By0;clXG}-|9`Ny>DD;6%^APYF~dy!ZrkA247Uw)+o&W>AwG8taB9{_ zk=5Y_zCHATzAy-KU<8bWQ(zX%gZbcxDEtQQh8^%2?1bI02VRC(;dR&te}#A9Z}16x z2LFU+=)m}*3uM5NFaQREj5|id$uJR4gPAZJ!VrUNK#%bnYMBwJZrD*Jt4);+)m05u z)$6OPWX-=d`nPJul7=M>iUqlxJm>gCz0#sKPZ~yxy6?jGT`kky<L7ieJQ0p~-1_3y z2Z`4?es}A``s`zq&R<cMJU@_Rkx0+2FK&I35;)Uy>yJ~Pb47mF!CKe=x56*sZnzJ& z!47yFcEMBdEIbD<!b|WmbUOwef+OKaFaQR@2p9>YU<^!vi7*T3qtyja02jd$xE9vH zTA*H=8XD{C7`$`irnd3n`lkDvHr=v`dw7dhmHHZeH11lT)MjEqK5qS=xnN0>Jlyhi z*Kd-%&<oR-kfRPu8$T{*4|H6fGI1OyUrFtn@S=YQ(l@t#Nzzl|anBb>O3wOr>zi92 zob`Xa$oW3FA0B}xU=KV6FTm^Y2D}GfLppN+Jt5PY4;aFF2F!%>;Cv{C5G;brU@26< zGPoIj30vSn*a<JeUTA<%;A`l>979Lw0f)mV7!Mb~EwB}S4d_TCw+HlnUlgT!N9~TP z+L}#OSa(`~C9S@4bp^w~YFNLhLE8Nv76cRWq8>!vnLg1HM}5VQ%UQ>9!p{!(PlRXR ztxwb2CC}%%>%*;&gHG9-6klk;)k*u#`jY&+>+@jx;cgGZ`wouBKSX3$1v}w!*adsw z8F&_Ip&s_Z8}L{73ciN4<GB9@9iR(jKzHZ|N5OG$JPd%rFcd~Z9*l*_a2lKi9w>z} zD2GL`5^jYpa1T5P55X>Y0$zYRFz5KhOmN@-{_3sOch+sKyYrSiufMbA&ehl7SyxkC zQ(d>BVXO6TiC7Ed=x#@DIl1L}uzGjble@i3y=MC4*WrPa4|jb#>qqkG)))8vT(>^B z_06r1PW{gn`Mn19un+zUAHd(?W9Z5pUpL6G=KFrcdH@WBQ7{?i!ue1P3*mBD4cEdi z;FoX@+za<XH9QKh!9Ms4{0%;YCg{vOVHfBJN5Wtj24i3>oCdRCHh5tfEQiZM<|3~J z(TT=-{XB?NzZd{q!1dMZH(?f-CaPTDq;LGL;Xd#hoWM0r>sPHe^}=1xcTDaSZ!c0G zc|4Eew6{t1EcH3&uB7vB`|P$C?*89h|86~X>x<idxb@KOFFN&Oq{!+fxE-8xxSQDD z2KGGeGi=LTZY{`M?hEh|ybN{lN7xH}vY01=DKHhLK>-wk7mDCUSPwVB1F#Ktfwtu| z<9f{a{pP<->o+Z5f6;nY|065ApFbhB!?HFD(o(QL9a4JvUP`}-mSxJRpPDtTjXE99 z?2zJ_)=wGE^SRTyQ#Xlg<N{^JCUGA;wxilCkPBN(Epz`fIt`w;?0(d6+L9e!_Q)an zQg!r&N&0g8Px>b9e>N@Ie{t(m((|Fj=d9lY>8rE-A0u<}Qjf2I)Z?ol_4pxt2~wX@ zZ`(oY=n1HS=iqsG0saJkhI)|a2<5x6Ux}3L<-6>BY6q6}_q&snop+q+yzSiiE|(>R z`I9rYA7Z=1elz<iJhss}L-k(qWpkeuDXQ=B7xq7v=RFrq-p({!H`V6Y6wk3K#f9?d zuf8|X%UP#SQg6>fElB-J-M$E~!d`d{UI(dfXI+2v!JDtY`MUf(&+3_7KSWXg8{%}^ z0^4TvGJVe6X+2cQ6xB8eu?{JnOiLq2RS(;$hz*n@SQbLdp6b_2Kk0p7yOc3Z4PE0) z8B;16a#U6A5TmO8l%uOUv_A&=uc=Hs7LKdJ2d}D4?G0Vl)TaJ7)Wv^G8Kn=M@UIrO z_Q`h_fBxHNy02cYHmlR_>MR<<JwGM)6w39#9F?#9Dx|zB00k<l!t59DAz`oba4gDJ z4(G$Fm@xIO_|D~+k87fQKzWQB!oP1H>k#5tJa5@2Cm*?V%H7$^&)d0jKmmu;FSgJr z|BymBl0-_$zMo?H*~<HuL~$Xpl^`;SEsDU#{0ninBo2~jU0Nm3DuGrBv`U~=0<98g zl|ZWmS|!jbfmR8$O5p#P1g=Q!sSaZ*@D|lgwT+i8u@yhmy3s0uA5a3*xh?!rbE=xI zy2O>Qotmkqgk-)WK-w~`B#+AU<`z#Xw|G+3`EbFMl(rs@l}zc_HUd%DKcf@W*u1|t z|D3t5E@}4JO!mC0h}dI#HpNi0*$zXo{*_r9Lro$NLFQUynWOx9A2;8}IuT13{`!@N zIUSkUGF&<Crw;!|8y<prxt&Vs)FxnVq;bR}hf`H&;>=PD^FC?*18Wt}S$iFifi(Oo zqSLk~T}P;+@>0~_)d(#oJ&&*2sVRCIt&ra^F{aa&)A>M0YJEoa(J2yggfa+~nvxt! zN){q^J5+`%)F^dk-W{rY$|y%#9Z733b50UQ=CguoA@O%nrw&RPHz>8##}i#@fx0>G zKGi>Efe!cC#5=j7Q<9V>6WXu;de@0+%vp!29xvx|O><l3;SPD7irwNlH8qet4o%6? zY3chMNLA{wm^?~-#F#J3x5}uaS8o_Rr@-Uu+||~9uTqXm%DsU{(bXv6q*?^4;V$4Y zW5rCN+6uph$3bp%^hCV9U<5k1oBG=W^{@{f;X4V{@NOrbpMj@%FZyY)-*sHU`%^37 z6y{1#g+U~K0vygW)4kyd?oHM}cb=P+XERsutlmnfgrCD5upR7YBIWNd+RsG3$o5O{ z3e>@?uopgrFQJdYeLdI?yWk0^f#=|Pcme(de}*?f?v3j|PbcdN3)yCAJ!i_{-&-yz zM$7dl=ghYE?_CDuEQUgs3Jck0Y1Khf4y|&r<nYZpk@6p-FL@N?fI45%e${oHvCdho z*DCzx_Ur$H!gV`f`IIh03+I%S@89X1T@T6auR@n0!(G0ix|-UrdQRnbchp~7tM)K% zDeiOP#hFV*ij;l7I86mO@Hs1FOZxIw#^&~NNlU&;OFoJC1wVD^Aa0NLrF_GCw|AdQ zlusq;u9PiNK9zDa`v;aMI??jEZwx1Sk#EJwBBGLfN}=m#89JZNbMAb$<2qUXf8_I< z$}V|e*nq!pf@`V&;&2yh{W)uKp}RZiDTO6~eCJEP^(5c>k#D}pcR%FY5Ay!MyaO!n zfy%pp@;;b;&k7$=-VKoF!{r%ac}`TG6_n?N-hf_2OAzfZ6HHzm)PF@=?sns<Dgy|v z2(J1AQ7EEN#{<#GXh#i%L68lSM|l@ro=21T*;HgfonW1l=gQ=ff@yFuTn{(ElkiuN zvP;EE`8z{8NZEVL>)G6^!umb>XR621J)3`4(cFwXPLh|b?8fWSDeB?3`mnczz3%Ld znEKPycIs00GT3{OSDM<X%dB%fUy;3~)?W03m0Ve2?e%--QudaymrA(TPI)k`om$Rb z8}<UHJ;UDR>`9#We<a~nSm9or{7l+8<VRR!aXITNK>T%~lVS2EYgr@(`4wGF<)8eD zZlr3>PSv`dN>1fS2mLGBlB!2*GGbc>E8!}O&q(8+aF}6Yrz5FI{@a42Vz!$U9kawM zu}Uf@S?fU+e0zILq`=2tpNS0SFGTXU%0fla!F&~WOi2Dtq<2h&zZ4hcPu)e*D$bDa z_^S#DERlV?!1{yAs$vWQB^Tc&a63}w?*>Ly#mR&eUHCSk+gErB`8%DFh^iP(P%$Il zCV1P5@q98_Rh&vV5$CrF+o@tUUsCo2#)k@#8|^vewJk*=e_aSu5T-26e3_MF&n!qm zldsW1^-&pE{uE>oDab(59!$zhb}bDk>kV^&*d7(J5w*0p&9$fw4V6lM4<xPI;k&0b zJSqN`(i7$F1FPXKu+x3!JESd*PzKI2V167D<xV3nLR;%sw)W4FeU&MRA6nWe>fLjP z3|aogn(Ldpx&Mg)V#(0IvZZ|1W+yCqH$D*BeZ~5(d+p+r5w)r9&etCeUH|o!KDlz$ z6fq()?IJ<iwiricT0D-*G~%dCyO21Yaimyrq^@l#AEh0-ubAGf^HJJ?I7&NQ$i6d< zR4Wd(rlmOYI>+;o*O@r-I=l1H#x6^Xab$Fj$C1&MI5N7r<7j)(veak9%Tk{~9Q7IQ zvZNifELA<?`Kana992Es`Dl00vQ%Wo<EY3aj*3io9PJNUmf3ycWtrWFIA-^8m!*Rh zhv=YajlIa9u5WHO>&jdo##Cj;wtb*4w6wj22&ALKbf~{rk!@xzUo!gq=rkp7T*_M- z@@B?rUpG~fpP}R}O?mS{o~D;~-;L7^C2wlT+ZWA~`ZI;xU&)&u{dmhv-oTKrX3CfM zw(_Qny!j(<Y08%xKb@YXuA4DPr5}BQk~b~o?TlOV2P^ri+OvIf)d$%_m3-ktp1PN3 z`ZI@(R7=hut>i0AZI}K;W%e7Z<cppc516jxO<n!j6~5RLJaVqumO4*$=sI7?7yjg{ zPSFk*D0v&;jq^O}??Vfee5~cZ62JPOyhLs46jbu${_>wh)y4sfm3-Yf|H4buPYW+m z@`ixCCG^Efm#TlBw@k?wLN1$gxsq>N$b0Hn&0DEfEm^7LOCsxjbd{1fNaTI>j>YTL ziM?-B@<zCP6=ds?w=4a<%Z0bAH&vyQH-|o+c!!cN5Xm>C<(p$Nohxs+$oI^yF59f+ zYew?MiF|)d-k|zuQI(P}49Q!S@})U>Z}O#~52y=HeL%^V5BDCmO;s(~rfNoRS2A52 zDchkIPJKwNpZt53!@G9!Uc0<eYmBSr<-teQi)Zar@(u5sqfaQA?v^iQ9O>Jm<Sl0T z^6C5$Pb+!D`NSU2DS1=&nh7r|`Qo9xC9!+q%j$@WURLr2*B8%uMO{9tPOU%dRV8oC z$X8Ie_1vfAJ8YSk?NfIQc}p$r`xmwJ*uN_IQufR9-&PaL-cj;>jTLj>Q`1JjujEau zTZjBjwORBxC2w71U)rcnjee};IqT(~Pt~@ipQ&yAn$#bMeXia*;tM5jYArwfE0ulG zSE@NLr6NW5Kw|r6Uotx-1sf{cve@fXYlx!fsIjgYDvx<_-DKLUGxcnHkU9Huw&bWZ z2zyC1EHTl|&2n6R?QLm5lQYH2rKYxPlh!sZwN2YAFIEPJE9`izw#i(*pILJ+_a0;h z-Aj4~_dG)S$<rVKMiLL6W?D*WO8a)HY2pFNVrO2qE9B=4?iI-Fdr05E8GgJ@y>q*^ zsj{?~`dEE;z`W;krX8kDYKjhH_MZ~DUT(M6lL+I{@-gp97;3V<w;|8n7LfZHl%kMr zxf>v(lD2AShgH2*qdd)Sc7K=j+_$SwzkTh}1m#I#{vMHKFtCwo5ChaELmbuQqjE%+ z>-wukxr$(|%eR(5hxV0e_pAHWvSo*j5H;$f?+uCT_6Q9`_*a&M%5)ia`RP(mw!R-Y z)+zJkc*n+Oo(oU;3E!4L59qg+wuE^Xj&~IIi>|p@?or8-$yu4K8_k^;X;riIL+~N% z&Xjp9R}JTESeISGwBtTj;<@pRq&<ltpZ4iP>%*)U($WsJh)#-=Z|Wrj2G{a+GlK)# zvU`#1>sQ|X_s?hfGPYdTL7gz*zCY%2>=sT)ndJO>kdT!iW6x?3EAte{z~(iOv>QN7 z#3vw<mod7G*bFPKY}PU~na;X1>v^mtr-iKftg|X*&9sGD!nzyl6|ALPt64LJp{{2w z`H*^&xd*&hH7qxG^xB9qi@$)#-xFgiclg?Hp?O~ND2rSx`7!@c%Kqov*UjWF`gj87 zbxfOB;fz`N5&n2iWTCDAiBrOj1UoM?>`|~WOOJq!vqO><l?UpI@v~(*P;VFI_;;+{ zouap&fAECntE}xmg+@HYagi}a)v^{VB>Q5YWZk;7N}yE&trBRJK&u2=CD1B?RtdC9 zpj85`5@?k`s|3DD0xgaIWjvkw($g>9lG8V1-HnX@vp@gM1dgS-j-AVZv^U6jUB;$9 zkTH5G$Q*#&r<XZ^TcA7K334BQE67;?evq;J!yse%ognxAp8^^CzX%fdXW$&;_hY}s zzc|V{857IgoE{@vYnexq{cZy~>$KTyas4AQCFPO4wlJ5_g-aw$GR&7E&h_)xRCNLp zkR^|`JvKMkm&2n$0_B11%eIv7g4t6iTrfrc+Ugnln9OC2<#>~IUgGJ`EQ+jc*wou1 zXPF{97QU}<14w+5Kfcb|NzzMGr^m}8`?8qF&9skU|NHnvgEL*7Nb66l1X?A~DuGrB zv`U~=0<98gl|ZWmS|!jbfmR88FA}iFpfZ+Y$f?KdGMJV7^>S}q?$gV?c^RwAI90~v zaxY%S_%d#nF}*wwAY*sACob;=$oO5x&2k@Jp5ZtG-0ug-IM0BiLB@{#LB_Ag!SOHv zvS1(#f)gMc2E*4ph#}7v=7QWim**~q!w8W3?sEP_)-u+XIRJS=T%Pm(F`NRY!cQO% z#=<xl4-;S_NchRDr@&O02B*Pvm;rKr7VFt?I?RDHU@n{qa{eorXKl;A@b9?DQ(f{7 zxIxL~E%$H>&yi4+11_07Jz|$jbf{g&RDE5wdG#c7W&J){Jx!itIEUQ|>(B(AUx~tZ zT{`hryPdwQ4<())xk!|kWvJu5bo0o!`|V2lDFl%=bExT$;@U=O04!%CeR<+%0_y_( zbedP!gL(GgzekY1NL=QC4mEv=b%ay`OB$Lh&&0{Rk<|TEQZLeZk|R-`n3Jy`w7g_} z2l;EIu;ib%U&+5+enykN*exl$EG_3Wab~7$TIr|I^5wb4QvE#Dg2Y9KxOEt_b!N)u z?;!?L7ai(_hj86@N#BlEbobxYHaW}Hy8XjQAcfj*LkBOhyKT3ar~^K`W=seb#7exu msCErzoFUJ%aY(l*+0L=g=ZsdLoOJK^sq41hwywV)3H(1eMpdE! literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/etc/schema/genshi-old.rnc b/emacs/nxhtml/etc/schema/genshi-old.rnc new file mode 100644 index 0000000..5384fe1 --- /dev/null +++ b/emacs/nxhtml/etc/schema/genshi-old.rnc @@ -0,0 +1,27 @@ +namespace py = "http://genshi.edgewall.org/" + +genshi.expr-type = xsd:string { minLength = "1" } +genshi.with-type = xsd:string { minLength = "1" } +genshi.choose-type = xsd:string +genshi.def-type = xsd:string +genshi.xpath-type = xsd:anyURI + +genshi.attrib = attribute py:if { genshi.expr-type }?, + attribute py:choose { genshi.choose-type }?, + attribute py:when { genshi.expr-type }?, + attribute py:otherwise { genshi.expr-type }?, + attribute py:for { genshi.expr-type }?, + attribute py:def { genshi.def-type }?, + attribute py:match { genshi.xpath-type }?, + attribute py:with { genshi.with-type }?, + attribute py:attrs { genshi.expr-type }?, + attribute py:content { genshi.expr-type }?, + attribute py:replace { genshi.expr-type }?, + attribute py:strip { genshi.expr-type }? + +genshi.if.attlist = attribute expr { genshi.expr-type } +genshi.for.attlist = attribute each { genshi.expr-type } +genshi.def.attlist = attribute each { genshi.expr-type } +genshi.with.attlist = attribute vars { genshi.with-type } + + diff --git a/emacs/nxhtml/etc/schema/genshi-schemas.xml b/emacs/nxhtml/etc/schema/genshi-schemas.xml new file mode 100644 index 0000000..89fe05f --- /dev/null +++ b/emacs/nxhtml/etc/schema/genshi-schemas.xml @@ -0,0 +1,3 @@ +<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0"> + <typeId id="XHTML" uri="qtmstr-xhtml.rnc" /> +</locatingRules> diff --git a/emacs/nxhtml/etc/schema/genshi.rnc b/emacs/nxhtml/etc/schema/genshi.rnc new file mode 100644 index 0000000..b9ddf76 --- /dev/null +++ b/emacs/nxhtml/etc/schema/genshi.rnc @@ -0,0 +1,84 @@ +default namespace = "http://genshi.edgewall.org/" +namespace py = "http://genshi.edgewall.org/" + +include "xinclude.rnc" + +# There's no way to just match the text part against a Genshi Python expression +# See: http://relaxng.org/compact-tutorial-20030326.html#id2814737 +python.expression = text + +genshi.expr-type = xsd:string { minLength = "1" } +genshi.xpath-type = xsd:anyURI + +genshi.attrib = + attribute py:if { genshi.expr-type }?, + attribute py:choose { text }?, + attribute py:when { genshi.expr-type }?, + attribute py:otherwise { text }?, + attribute py:for { genshi.expr-type }?, + attribute py:def { genshi.expr-type }?, + attribute py:match { genshi.xpath-type}?, + attribute py:with { genshi.expr-type }?, + attribute py:attrs { genshi.expr-type }?, + attribute py:content { text }?, + attribute py:replace { genshi.expr-type }?, + attribute py:strip { text }? + +genshi.if.attlist = attribute test { genshi.expr-type } +genshi.choose.attlist = attribute test { text } +genshi.when.attlist = attribute test { genshi.expr-type } +genshi.for.attlist = attribute each { genshi.expr-type } +genshi.def.attlist = attribute function { genshi.expr-type } +genshi.with.attlist = attribute vars { genshi.expr-type } +genshi.replace.attlist = attribute value { genshi.expr-type } +genshi.match.attlist = + attribute path { genshi.xpath-type }, + attribute buffer { "true" | "false" }?, + attribute once { "true" | "false" }?, + attribute recursive { "true" | "false" }? + +genshi.choose = + element py:choose { genshi.choose.attlist, + genshi.model + } +genshi.when = + element py:when { genshi.when.attlist, + genshi.model + } +genshi.otherwise = + element py:otherwise { + genshi.model + } +genshi.if = + element py:if { genshi.if.attlist, + genshi.model + } +genshi.for = + element py:for { genshi.for.attlist, + genshi.model + } +genshi.def = + element py:def { genshi.def.attlist, + genshi.model + } +genshi.with = + element py:with { genshi.with.attlist, + genshi.model + } +genshi.match = + element py:match { genshi.match.attlist, + genshi.model + } +genshi.replace = + element py:replace { genshi.replace.attlist, + genshi.model + } + +genshi.allowed.children = text + +genshi.class = genshi.if | genshi.choose | genshi.when | genshi.otherwise + | genshi.for | genshi.def | genshi.with | genshi.match | genshi.replace + | python.expression + | xi.include + +genshi.model = genshi.class* | genshi.allowed.children* \ No newline at end of file diff --git a/emacs/nxhtml/etc/schema/mjt.rnc b/emacs/nxhtml/etc/schema/mjt.rnc new file mode 100644 index 0000000..b37f01a --- /dev/null +++ b/emacs/nxhtml/etc/schema/mjt.rnc @@ -0,0 +1,74 @@ +include "xhtml-loader.rnc" + +MjtAll.attrib = + attribute mjt.def { Text.datatype }?, + attribute mjt.when { Text.datatype }?, + attribute mjt.otherwise { Text.datatype }?, + attribute mjt.for { Text.datatype }?, + attribute mjt.if { Text.datatype }?, + attribute mjt.elif { Text.datatype }?, + attribute mjt.else { Text.datatype }?, + attribute mjt.script { Text.datatype }?, + attribute mjt.choose { Text.datatype }?, + attribute mjt.replace { Text.datatype }?, + attribute mjt.content { Text.datatype }?, + attribute mjt.strip { Text.datatype }?, + attribute mjt.src { Text.datatype }?, + attribute mjt.style { Text.datatype }?, + attribute mjt.class { Text.datatype }?, + attribute mjt.id { Text.datatype }?, + attribute mjt.attrs { Text.datatype }?, + attribute mjt.task { Text.datatype }? + + +a.attlist &= + attribute mjt.onblur { Script.datatype }?, + attribute mjt.onfocus { Script.datatype }? +area.attlist &= + attribute mjt.onblur { Script.datatype }?, + attribute mjt.onfocus { Script.datatype }? +form.attlist &= + attribute mjt.onreset { Script.datatype }?, + attribute mjt.onsubmit { Script.datatype }? +body.attlist &= + attribute mjt.onload { Script.datatype }?, + attribute mjt.onunload { Script.datatype }? +label.attlist &= + attribute mjt.onblur { Script.datatype }?, + attribute mjt.onfocus { Script.datatype }? +input.attlist &= + attribute mjt.onblur { Script.datatype }?, + attribute mjt.onchange { Script.datatype }?, + attribute mjt.onfocus { Script.datatype }?, + attribute mjt.onselect { Script.datatype }? +select.attlist &= + attribute mjt.onblur { Script.datatype }?, + attribute mjt.onchange { Script.datatype }?, + attribute mjt.onfocus { Script.datatype }? +textarea.attlist &= + attribute mjt.onblur { Script.datatype }?, + attribute mjt.onchange { Script.datatype }?, + attribute mjt.onfocus { Script.datatype }?, + attribute mjt.onselect { Script.datatype }? +button.attlist &= + attribute mjt.onblur { Script.datatype }?, + attribute mjt.onfocus { Script.datatype }? + +MjtEvents.attrib = + attribute mjt.onclick { Script.datatype }?, + attribute mjt.ondblclick { Script.datatype }?, + attribute mjt.onmousedown { Script.datatype }?, + attribute mjt.onmouseup { Script.datatype }?, + attribute mjt.onmouseover { Script.datatype }?, + attribute mjt.onmousemove { Script.datatype }?, + attribute mjt.onmouseout { Script.datatype }?, + attribute mjt.onkeypress { Script.datatype }?, + attribute mjt.onkeydown { Script.datatype }?, + attribute mjt.onkeyup { Script.datatype }? + + +Common.attrib &= MjtAll.attrib +CommonIdRequired.attrib &= MjtAll.attrib + +Common.attrib &= MjtEvents.attrib +CommonIdRequired.attrib &= MjtEvents.attrib diff --git a/emacs/nxhtml/etc/schema/nxml-erb.patch b/emacs/nxhtml/etc/schema/nxml-erb.patch new file mode 100644 index 0000000..362913b --- /dev/null +++ b/emacs/nxhtml/etc/schema/nxml-erb.patch @@ -0,0 +1,37 @@ +--- nxml-mode-orig/xmltok.el 2005-10-16 15:32:53.000000000 -0400 ++++ nxml-mode-erb/xmltok.el 2006-09-01 01:02:55.000000000 -0400 +@@ -496,6 +496,9 @@ + (xmltok+ (xmltok-g markup-declaration "!") + (xmltok-g comment-first-dash "-" + (xmltok-g comment-open "-") opt) opt)) ++ (erb-section ++ (xmltok+ "%" ++ (xmltok-g erb-section-open "[^%]") opt)) + (cdata-section + (xmltok+ "!" + (xmltok-g marked-section-open "\\[") +@@ -526,6 +529,7 @@ + ;; by default + or cdata-section + or comment ++ or erb-section + or processing-instruction)) + (xmltok-defregexp + xmltok-attribute +@@ -693,6 +697,16 @@ + nil + "]]>") + 'not-well-formed))) ++ ((xmltok-after-lt start erb-section-open) ++ (setq xmltok-type ++ (if (re-search-forward "[^%]%>" nil t) ++ 'erb-section ++ (xmltok-add-error "No closing %>") ++ (xmltok-add-dependent 'xmltok-unclosed-reparse-p ++ nil ++ nil ++ "%>") ++ 'not-well-formed))) + ((xmltok-after-lt start processing-instruction-question) + (xmltok-scan-after-processing-instruction-open)) + ((xmltok-after-lt start comment-open) diff --git a/emacs/nxhtml/etc/schema/old-genshi.rnc b/emacs/nxhtml/etc/schema/old-genshi.rnc new file mode 100644 index 0000000..5a50385 --- /dev/null +++ b/emacs/nxhtml/etc/schema/old-genshi.rnc @@ -0,0 +1,31 @@ +namespace py = "http://genshi.edgewall.org/" + +genshi.expr-type = xsd:string { minLength = "1" } +genshi.with-type = xsd:string { minLength = "1" } +genshi.choose-type = xsd:string +genshi.def-type = xsd:string +genshi.xpath-type = xsd:anyURI + +genshi.attrib = attribute py:if { genshi.expr-type }?, + attribute py:choose { genshi.choose-type }?, + attribute py:when { genshi.expr-type }?, + attribute py:otherwise { genshi.expr-type }?, + attribute py:for { genshi.expr-type }?, + attribute py:def { genshi.def-type }?, + attribute py:match { genshi.xpath-type }?, + attribute py:with { genshi.with-type }?, + attribute py:attrs { genshi.expr-type }?, + attribute py:content { genshi.expr-type }?, + attribute py:replace { genshi.expr-type }?, + attribute py:strip { genshi.expr-type }? + +genshi.if.attlist = attribute test { genshi.expr-type } +genshi.for.attlist = attribute each { genshi.expr-type } +genshi.def.attlist = attribute function { genshi.expr-type } +genshi.with.attlist = attribute vars { genshi.with-type } +genshi.match.attlist = attribute path { genshi.xpath-type }, + attribute buffer { genshi.expr-type }?, + attribute once { genshi.expr-type }?, + attribute recursive { genshi.expr-type }? + + diff --git a/emacs/nxhtml/etc/schema/old-qtmstr-xhtml.rnc b/emacs/nxhtml/etc/schema/old-qtmstr-xhtml.rnc new file mode 100644 index 0000000..b5f84bd --- /dev/null +++ b/emacs/nxhtml/etc/schema/old-qtmstr-xhtml.rnc @@ -0,0 +1,61 @@ +namespace py = "http://genshi.edgewall.org/" +namespace xi = "http://www.w3.org/2001/XInclude" + +include "genshi.rnc" +include "xinclude.rnc" +include "xhtml-loader.rnc" + +start |= head|body|p|\div|h1|h2|h3|h4|h5|h6|hr|pre|dl|ol|ul|table|form + +Common.attrib &= genshi.attrib +head.attlist &= genshi.attrib +html.attlist &= genshi.attrib + +Head.class = base | isindex | link | meta | script | title | style | + if-head | for-head | def-head | with-head + +Head.model = Head.class* + +head.content &= Head.model* + +if-inline = element py:if { genshi.if.attlist, Inline.model } +if-block = element py:if { genshi.if.attlist, Block.model } +if-head = element py:if { genshi.if.attlist, Head.model } +for-inline = element py:for { genshi.for.attlist, Inline.model } +for-block = element py:for { genshi.for.attlist, Block.model } +for-head = element py:for { genshi.for.attlist, Head.model } +def-inline = element py:def { genshi.def.attlist, Inline.model } +def-block = element py:def { genshi.def.attlist, Block.model } +def-head = element py:def { genshi.def.attlist, Head.model } +with-inline = element py:with { genshi.with.attlist, Inline.model } +with-block = element py:with { genshi.with.attlist, Block.model } +with-head = element py:with { genshi.with.attlist, Head.model } +match-inline = element py:match { genshi.match.attlist, Inline.model } +match-block = element py:match { genshi.match.attlist, Block.model } +match-head = element py:match { genshi.match.attlist, Head.model } + +Inline.class |= if-inline | for-inline | def-inline | with-inline | match-inline +Block.class |= if-block | for-block | def-block | with-block | match-block + +xi-inline = element xi:include { + xinclude.include.attlist, + element xi:fallback { genshi.attrib, + (xi-inline | Inline.model)* + }? + } + +xi-block = element xi:include { xinclude.include.attlist, + element xi:fallback { genshi.attrib, + (xi-block | Block.model)* + }? + } + +xi-head = element xi:include { xinclude.include.attlist, + element xi:fallback { genshi.attrib, + (xi-head | Head.model)* + }? + } + +Inline.class |= xi-inline +Block.class |= xi-block +Head.class |= xi-head diff --git a/emacs/nxhtml/etc/schema/old-xinclude.rnc b/emacs/nxhtml/etc/schema/old-xinclude.rnc new file mode 100644 index 0000000..c45cf0c --- /dev/null +++ b/emacs/nxhtml/etc/schema/old-xinclude.rnc @@ -0,0 +1,11 @@ +namespace xi = "http://www.w3.org/2001/XInclude" +namespace local = "" + +xinclude.include.attlist = + attribute href { xsd:anyURI }?, + attribute parse { xsd:string }?, + attribute xpointer { xsd:string }?, + attribute encoding { xsd:string }?, + attribute accept { xsd:string }?, + attribute accept-language { xsd:string }? + diff --git a/emacs/nxhtml/etc/schema/qtmstr-xhtml-old.rnc b/emacs/nxhtml/etc/schema/qtmstr-xhtml-old.rnc new file mode 100644 index 0000000..61ab89e --- /dev/null +++ b/emacs/nxhtml/etc/schema/qtmstr-xhtml-old.rnc @@ -0,0 +1,58 @@ +namespace py = "http://genshi.edgewall.org/" +namespace xi = "http://www.w3.org/2001/XInclude" + +include "genshi.rnc" +include "xinclude.rnc" +include "xhtml-loader.rnc" + +start |= head|body|p|\div|h1|h2|h3|h4|h5|h6|hr|pre|dl|ol|ul|table|form + +Common.attrib &= genshi.attrib +head.attlist &= genshi.attrib +html.attlist &= genshi.attrib + +Head.class = base | isindex | link | meta | script | title | style | + if-head | for-head | def-head | with-head + +Head.model = Head.class* + +head.content &= Head.model* + +if-inline = element py:if { genshi.if.attlist, Inline.model } +if-block = element py:if { genshi.if.attlist, Block.model } +if-head = element py:if { genshi.if.attlist, Head.model } +for-inline = element py:for { genshi.for.attlist, Inline.model } +for-block = element py:for { genshi.for.attlist, Block.model } +for-head = element py:for { genshi.for.attlist, Head.model } +def-inline = element py:def { genshi.def.attlist, Inline.model } +def-block = element py:def { genshi.def.attlist, Block.model } +def-head = element py:def { genshi.def.attlist, Head.model } +with-inline = element py:with { genshi.with.attlist, Inline.model } +with-block = element py:with { genshi.with.attlist, Block.model } +with-head = element py:with { genshi.with.attlist, Head.model } + +Inline.class |= if-inline | for-inline | def-inline | with-inline +Block.class |= if-block | for-block | def-block | with-block + +xi-inline = element xi:include { + xinclude.include.attlist, + element xi:fallback { genshi.attrib, + (xi-inline | Inline.model)* + }? + } + +xi-block = element xi:include { xinclude.include.attlist, + element xi:fallback { genshi.attrib, + (xi-block | Block.model)* + }? + } + +xi-head = element xi:include { xinclude.include.attlist, + element xi:fallback { genshi.attrib, + (xi-head | Head.model)* + }? + } + +Inline.class |= xi-inline +Block.class |= xi-block +Head.class |= xi-head diff --git a/emacs/nxhtml/etc/schema/qtmstr-xhtml.rnc b/emacs/nxhtml/etc/schema/qtmstr-xhtml.rnc new file mode 100644 index 0000000..ff5d0a9 --- /dev/null +++ b/emacs/nxhtml/etc/schema/qtmstr-xhtml.rnc @@ -0,0 +1,66 @@ +default namespace = "http://www.w3.org/1999/xhtml" + +include "genshi.rnc" +include "xhtml-loader.rnc" { + start = html | head | head.content | body | frameset | frame | noframes | + Block.class | Inline.class | Table.class | Form.extra.class | genshi.class + html = element html { html.attlist, (genshi.model | (head, (body | frameset | genshi.model))) } + frameset = + element frameset { + frameset.attlist, + (((frameset | frame)+ & noframes?) | genshi.model) + } + noframes = element noframes { noframes.attlist, (body | genshi.model) } + title = element title { title.attlist, (text | genshi.model)* } + script = element script { script.attlist, (text | genshi.model)* } + style = element style { style.attlist, (text | genshi.model)* } + dl = element dl { dl.attlist, ((dt | dd)+ | genshi.model) } + ol = element ol { ol.attlist, (li+ | genshi.model) } + ul = element ul { ul.attlist, (li+ | genshi.model) } + dir = element dir { dir.attlist, (li.noblock+ | genshi.model) } + menu = element menu { menu.attlist, (li.noblock+ | genshi.model) } + select = element select { select.attlist, ((option | optgroup)+ | genshi.model) } + option = + element option { + Common.attrib, + attribute selected { "selected" }?, + attribute value { text }?, + (text | genshi.model)* + } + textarea = element textarea { textarea.attlist, (text & genshi.model)* } + optgroup = element optgroup { optgroup.attlist, (option+ | genshi.model) } + table = + element table { + table.attlist, + (caption? | genshi.model), + (col* | colgroup* | genshi.model), + (((thead? | genshi.model), + (tfoot? | genshi.model), + (tbody+ | genshi.model)) | (tr+ | genshi.model)) + } + colgroup = element colgroup { colgroup.attlist, (col* | genshi.model) } + tr = element tr { tr.attlist, ((th | td)+ | genshi.model) } + tbody = element tbody { tbody.attlist, (tr+ | genshi.model) } + thead = element thead { thead.attlist, (tr+ | genshi.model) } + tfoot = element tfoot { tfoot.attlist, (tr+ | genshi.model) } +} + +Table.class = caption | colgroup | col | tbody | thead | tfoot | th | tr | td +Form.extra.class = option | optgroup | legend + +Block.class |= genshi.class +Inline.class |= genshi.class +head.content &= genshi.class + +Core.attrib &= genshi.attrib +html.attlist &= genshi.attrib +head.attlist &= genshi.attrib +title.attlist &= genshi.attrib +base.attlist &= genshi.attrib +meta.attlist &= genshi.attrib +script.attlist &= genshi.attrib +param.attlist &= genshi.attrib +Edit.attrib &= genshi.attrib + +genshi.allowed.children |= html | head | head.content | body | frameset | frame + | noframes | Inline.class | Block.class | Table.class | Form.extra.class diff --git a/emacs/nxhtml/etc/schema/schema-path-patch.el b/emacs/nxhtml/etc/schema/schema-path-patch.el new file mode 100644 index 0000000..a6d59fc --- /dev/null +++ b/emacs/nxhtml/etc/schema/schema-path-patch.el @@ -0,0 +1,95 @@ +;;; schema-path-patch.el --- Patch schema paths +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-08T20:21:31+0200 Fri +;; Version: 0.2 +;; Last-Updated: 2008-08-19T00:21:25+0200 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; Cannot open load file: schema-path-patch. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Schemas here may include parts from nxml and need to know the path. +;; This file can be used to patch the paths. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(defvar rncpp-this-dir + (file-name-as-directory + (file-name-directory + (if load-file-name load-file-name buffer-file-name)))) + +(defun rncpp-get-nxml-schema-dir () + ;; First look for nxml-mode included with Emacs + (let ((schema-dir (file-name-as-directory + (expand-file-name "schema" data-directory)))) + (unless (file-directory-p schema-dir) + ;; This is an old nxml-mode, look for its schemas dir. + (let ((nxml-mode-dir (file-name-as-directory + (file-name-directory (locate-library "nxml-mode"))))) + (setq schema-dir (file-name-as-directory + (expand-file-name "schema" nxml-mode-dir))))) + (unless (file-directory-p schema-dir) + (error "Can't find schema-dir=%s" schema-dir)) + schema-dir)) + +;; Use xhtml-loader.rnc (an idea from Bryan Waite): +(defun rncpp-patch-xhtml-loader () + "Patch xhtml-loader.rnc so genshi and mjt rnc files works." + ;;(interactive) + (let* ((default-directory rncpp-this-dir) + (loader-path (expand-file-name "xhtml-loader.rnc")) + (loader-buf (find-buffer-visiting loader-path)) + (schema-dir (rncpp-get-nxml-schema-dir)) + (schema-relative-dir (file-relative-name schema-dir)) + (loader-string (concat "include \"" + schema-relative-dir + "xhtml.rnc\"\n"))) + (when loader-buf (kill-buffer loader-buf)) + (setq loader-buf (find-file-noselect loader-path)) + (with-current-buffer loader-buf + (unless (file-exists-p loader-path) + (insert loader-string)) + ;; Test if correct + (if (string= (buffer-substring-no-properties (point-min) (point-max)) + loader-string) + (message "xhtml-loader.rnc was ok") + (message "Patching xhtml-loader.rnc") + (delete-region (point-min) (point-max)) + (insert loader-string)) + (basic-save-buffer) + (kill-buffer (current-buffer))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; schema-path-patch.el ends here diff --git a/emacs/nxhtml/etc/schema/xinclude.rnc b/emacs/nxhtml/etc/schema/xinclude.rnc new file mode 100644 index 0000000..cbda979 --- /dev/null +++ b/emacs/nxhtml/etc/schema/xinclude.rnc @@ -0,0 +1,35 @@ +default namespace = "http://www.w3.org/2001/XInclude" +namespace xi = "http://www.w3.org/2001/XInclude" + +xi.include.attlist = + attribute href { xsd:anyURI }?, + attribute parse { "xml" | "text" }?, + attribute xpointer { xsd:string }?, + attribute encoding { xsd:string }?, + attribute accept { xsd:string }?, + attribute accept-language { xsd:string }? + +xi.include.attlist.extra = + attribute * - xi.include.attlist { text }* + +xi.include = + element xi:include { + xi.include.attlist, + xi.include.attlist.extra, + (xi.fallback? | xi.include.extra)* + } + +xi.include.extra = notAllowed + +xi.fallback.attlist = + attribute * { text }* + +xi.fallback = + element xi:fallback { + xi.fallback.attlist, + (xi.include | xi.fallback.extra)* + } + +xi.fallback.extra = notAllowed + +xi.class = xi.include | xi.fallback \ No newline at end of file diff --git a/emacs/nxhtml/etc/templates/rollover-2v.css b/emacs/nxhtml/etc/templates/rollover-2v.css new file mode 100644 index 0000000..ed10a41 --- /dev/null +++ b/emacs/nxhtml/etc/templates/rollover-2v.css @@ -0,0 +1,25 @@ +ROLLOVER_SPEC a { + /* Image */ + display: block; + background: transparent url("IMG_URL") 0 0 no-repeat; + overflow: hidden; + width: IMG_WIDTHpx; + /* Text placement and size, etc */ + CENTER_OR_PAD; + padding-top: PADDING_TOPpx; + font-size: FONT_SIZEpx; + padding-bottom: PADDING_BOTTOMpx; + text-decoration: none; + white-space: nowrap; + border: none; + margin: 0; +} +ROLLOVER_SPEC a:hover { + background-position: 0 -IMG_HEIGHT_2px; +} +ROLLOVER_SPEC li { + display: inline; + padding: 0; + margin: 0; + HOR_OR_VER; +} diff --git a/emacs/nxhtml/etc/uts39/idnchars.txt b/emacs/nxhtml/etc/uts39/idnchars.txt new file mode 100644 index 0000000..369f8f8 --- /dev/null +++ b/emacs/nxhtml/etc/uts39/idnchars.txt @@ -0,0 +1,894 @@ +# Recommended Identifier Profiles for IDN +# File: idnchars.txt +# Version: 2.0 +# Generated: 2006-08-15, 04:35:10 GMT +# Checkin: $Revision: 1.11 $ +# +# For documentation and usage, see http://www.unicode.org/reports/tr39/ +# +# Allowed as output characters + +002D ; output # (-) HYPHEN-MINUS +0030..0039 ; output # [10] (0..9) DIGIT ZERO..DIGIT NINE +0041..005A ; output # [26] (A..Z) LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z +0061..007A ; output # [26] (a..z) LATIN SMALL LETTER A..LATIN SMALL LETTER Z +00B7 ; output # (·) MIDDLE DOT +00E0..00F6 ; output # [23] (à ..ö) LATIN SMALL LETTER A WITH GRAVE..LATIN SMALL LETTER O WITH DIAERESIS +00F8..00FF ; output # [8] (ø..ÿ) LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS +0101 ; output # (Ä) LATIN SMALL LETTER A WITH MACRON +0103 ; output # (Ä) LATIN SMALL LETTER A WITH BREVE +0105 ; output # (Ä ) LATIN SMALL LETTER A WITH OGONEK +0107 ; output # (Ä) LATIN SMALL LETTER C WITH ACUTE +0109 ; output # (Ä) LATIN SMALL LETTER C WITH CIRCUMFLEX +010B ; output # (Ä) LATIN SMALL LETTER C WITH DOT ABOVE +010D ; output # (Ä) LATIN SMALL LETTER C WITH CARON +010F ; output # (Ä) LATIN SMALL LETTER D WITH CARON +0111 ; output # (Ä) LATIN SMALL LETTER D WITH STROKE +0113 ; output # (Ä) LATIN SMALL LETTER E WITH MACRON +0115 ; output # (Ä) LATIN SMALL LETTER E WITH BREVE +0117 ; output # (Ä) LATIN SMALL LETTER E WITH DOT ABOVE +0119 ; output # (Ä) LATIN SMALL LETTER E WITH OGONEK +011B ; output # (Ä) LATIN SMALL LETTER E WITH CARON +011D ; output # (Ä) LATIN SMALL LETTER G WITH CIRCUMFLEX +011F ; output # (Ä) LATIN SMALL LETTER G WITH BREVE +0121 ; output # (Ä¡) LATIN SMALL LETTER G WITH DOT ABOVE +0123 ; output # (Ä£) LATIN SMALL LETTER G WITH CEDILLA +0125 ; output # (Ä¥) LATIN SMALL LETTER H WITH CIRCUMFLEX +0127 ; output # (ħ) LATIN SMALL LETTER H WITH STROKE +0129 ; output # (Ä©) LATIN SMALL LETTER I WITH TILDE +012B ; output # (Ä«) LATIN SMALL LETTER I WITH MACRON +012D ; output # (Ä) LATIN SMALL LETTER I WITH BREVE +012F ; output # (į) LATIN SMALL LETTER I WITH OGONEK +0131 ; output # (ı) LATIN SMALL LETTER DOTLESS I +0135 ; output # (ĵ) LATIN SMALL LETTER J WITH CIRCUMFLEX +0137..0138 ; output # [2] (Ä·..ĸ) LATIN SMALL LETTER K WITH CEDILLA..LATIN SMALL LETTER KRA +013A ; output # (ĺ) LATIN SMALL LETTER L WITH ACUTE +013C ; output # (ļ) LATIN SMALL LETTER L WITH CEDILLA +013E ; output # (ľ) LATIN SMALL LETTER L WITH CARON +0142 ; output # (Å) LATIN SMALL LETTER L WITH STROKE +0144 ; output # (Å) LATIN SMALL LETTER N WITH ACUTE +0146 ; output # (Å) LATIN SMALL LETTER N WITH CEDILLA +0148 ; output # (Å) LATIN SMALL LETTER N WITH CARON +014B ; output # (Å) LATIN SMALL LETTER ENG +014D ; output # (Å) LATIN SMALL LETTER O WITH MACRON +014F ; output # (Å) LATIN SMALL LETTER O WITH BREVE +0151 ; output # (Å) LATIN SMALL LETTER O WITH DOUBLE ACUTE +0153 ; output # (Å) LATIN SMALL LIGATURE OE +0155 ; output # (Å) LATIN SMALL LETTER R WITH ACUTE +0157 ; output # (Å) LATIN SMALL LETTER R WITH CEDILLA +0159 ; output # (Å) LATIN SMALL LETTER R WITH CARON +015B ; output # (Å) LATIN SMALL LETTER S WITH ACUTE +015D ; output # (Å) LATIN SMALL LETTER S WITH CIRCUMFLEX +015F ; output # (Å) LATIN SMALL LETTER S WITH CEDILLA +0161 ; output # (Å¡) LATIN SMALL LETTER S WITH CARON +0163 ; output # (Å£) LATIN SMALL LETTER T WITH CEDILLA +0165 ; output # (Å¥) LATIN SMALL LETTER T WITH CARON +0167 ; output # (ŧ) LATIN SMALL LETTER T WITH STROKE +0169 ; output # (Å©) LATIN SMALL LETTER U WITH TILDE +016B ; output # (Å«) LATIN SMALL LETTER U WITH MACRON +016D ; output # (Å) LATIN SMALL LETTER U WITH BREVE +016F ; output # (ů) LATIN SMALL LETTER U WITH RING ABOVE +0171 ; output # (ű) LATIN SMALL LETTER U WITH DOUBLE ACUTE +0173 ; output # (ų) LATIN SMALL LETTER U WITH OGONEK +0175 ; output # (ŵ) LATIN SMALL LETTER W WITH CIRCUMFLEX +0177 ; output # (Å·) LATIN SMALL LETTER Y WITH CIRCUMFLEX +017A ; output # (ź) LATIN SMALL LETTER Z WITH ACUTE +017C ; output # (ż) LATIN SMALL LETTER Z WITH DOT ABOVE +017E ; output # (ž) LATIN SMALL LETTER Z WITH CARON +0183 ; output # (Æ) LATIN SMALL LETTER B WITH TOPBAR +0185 ; output # (Æ ) LATIN SMALL LETTER TONE SIX +0188 ; output # (Æ) LATIN SMALL LETTER C WITH HOOK +018C ; output # (Æ) LATIN SMALL LETTER D WITH TOPBAR +0192 ; output # (Æ) LATIN SMALL LETTER F WITH HOOK +0195 ; output # (Æ) LATIN SMALL LETTER HV +0199..019B ; output # [3] (Æ..Æ) LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE +019E ; output # (Æ) LATIN SMALL LETTER N WITH LONG RIGHT LEG +01A1 ; output # (Æ¡) LATIN SMALL LETTER O WITH HORN +01A3 ; output # (Æ£) LATIN SMALL LETTER OI +01A5 ; output # (Æ¥) LATIN SMALL LETTER P WITH HOOK +01A8 ; output # (ƨ) LATIN SMALL LETTER TONE TWO +01AD ; output # (Æ) LATIN SMALL LETTER T WITH HOOK +01B0 ; output # (Æ°) LATIN SMALL LETTER U WITH HORN +01B4 ; output # (Æ´) LATIN SMALL LETTER Y WITH HOOK +01B6 ; output # (ƶ) LATIN SMALL LETTER Z WITH STROKE +01BD ; output # (ƽ) LATIN SMALL LETTER TONE FIVE +01CE ; output # (Ç) LATIN SMALL LETTER A WITH CARON +01D0 ; output # (Ç) LATIN SMALL LETTER I WITH CARON +01D2 ; output # (Ç) LATIN SMALL LETTER O WITH CARON +01D4 ; output # (Ç) LATIN SMALL LETTER U WITH CARON +01D6 ; output # (Ç) LATIN SMALL LETTER U WITH DIAERESIS AND MACRON +01D8 ; output # (Ç) LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE +01DA ; output # (Ç) LATIN SMALL LETTER U WITH DIAERESIS AND CARON +01DC..01DD ; output # [2] (Ç..Ç) LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE..LATIN SMALL LETTER TURNED E +01DF ; output # (Ç) LATIN SMALL LETTER A WITH DIAERESIS AND MACRON +01E1 ; output # (Ç¡) LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON +01E3 ; output # (Ç£) LATIN SMALL LETTER AE WITH MACRON +01E5 ; output # (Ç¥) LATIN SMALL LETTER G WITH STROKE +01E7 ; output # (ǧ) LATIN SMALL LETTER G WITH CARON +01E9 ; output # (Ç©) LATIN SMALL LETTER K WITH CARON +01EB ; output # (Ç«) LATIN SMALL LETTER O WITH OGONEK +01ED ; output # (Ç) LATIN SMALL LETTER O WITH OGONEK AND MACRON +01EF..01F0 ; output # [2] (ǯ..Ç°) LATIN SMALL LETTER EZH WITH CARON..LATIN SMALL LETTER J WITH CARON +01F5 ; output # (ǵ) LATIN SMALL LETTER G WITH ACUTE +01F9 ; output # (ǹ) LATIN SMALL LETTER N WITH GRAVE +01FB ; output # (Ç») LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +01FD ; output # (ǽ) LATIN SMALL LETTER AE WITH ACUTE +01FF ; output # (Ç¿) LATIN SMALL LETTER O WITH STROKE AND ACUTE +0201 ; output # (È) LATIN SMALL LETTER A WITH DOUBLE GRAVE +0203 ; output # (È) LATIN SMALL LETTER A WITH INVERTED BREVE +0205 ; output # (È ) LATIN SMALL LETTER E WITH DOUBLE GRAVE +0207 ; output # (È) LATIN SMALL LETTER E WITH INVERTED BREVE +0209 ; output # (È) LATIN SMALL LETTER I WITH DOUBLE GRAVE +020B ; output # (È) LATIN SMALL LETTER I WITH INVERTED BREVE +020D ; output # (È) LATIN SMALL LETTER O WITH DOUBLE GRAVE +020F ; output # (È) LATIN SMALL LETTER O WITH INVERTED BREVE +0211 ; output # (È) LATIN SMALL LETTER R WITH DOUBLE GRAVE +0213 ; output # (È) LATIN SMALL LETTER R WITH INVERTED BREVE +0215 ; output # (È) LATIN SMALL LETTER U WITH DOUBLE GRAVE +0217 ; output # (È) LATIN SMALL LETTER U WITH INVERTED BREVE +0219 ; output # (È) LATIN SMALL LETTER S WITH COMMA BELOW +021B ; output # (È) LATIN SMALL LETTER T WITH COMMA BELOW +021F ; output # (È) LATIN SMALL LETTER H WITH CARON +0223 ; output # (È£) LATIN SMALL LETTER OU +0225 ; output # (È¥) LATIN SMALL LETTER Z WITH HOOK +0227 ; output # (ȧ) LATIN SMALL LETTER A WITH DOT ABOVE +0229 ; output # (È©) LATIN SMALL LETTER E WITH CEDILLA +022B ; output # (È«) LATIN SMALL LETTER O WITH DIAERESIS AND MACRON +022D ; output # (È) LATIN SMALL LETTER O WITH TILDE AND MACRON +022F ; output # (ȯ) LATIN SMALL LETTER O WITH DOT ABOVE +0231 ; output # (ȱ) LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON +0233 ; output # (ȳ) LATIN SMALL LETTER Y WITH MACRON +0253..0254 ; output # [2] (É..É) LATIN SMALL LETTER B WITH HOOK..LATIN SMALL LETTER OPEN O +0256..0257 ; output # [2] (É..É) LATIN SMALL LETTER D WITH TAIL..LATIN SMALL LETTER D WITH HOOK +0259 ; output # (É) LATIN SMALL LETTER SCHWA +025B ; output # (É) LATIN SMALL LETTER OPEN E +0260 ; output # (É ) LATIN SMALL LETTER G WITH HOOK +0263 ; output # (É£) LATIN SMALL LETTER GAMMA +0268..0269 ; output # [2] (ɨ..É©) LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER IOTA +026F ; output # (ɯ) LATIN SMALL LETTER TURNED M +0272 ; output # (ɲ) LATIN SMALL LETTER N WITH LEFT HOOK +0275 ; output # (ɵ) LATIN SMALL LETTER BARRED O +0280 ; output # (Ê) LATIN LETTER SMALL CAPITAL R +0283 ; output # (Ê) LATIN SMALL LETTER ESH +0288 ; output # (Ê) LATIN SMALL LETTER T WITH RETROFLEX HOOK +028A..028B ; output # [2] (Ê..Ê) LATIN SMALL LETTER UPSILON..LATIN SMALL LETTER V WITH HOOK +0292 ; output # (Ê) LATIN SMALL LETTER EZH +0294 ; output # (Ê) LATIN LETTER GLOTTAL STOP +0300..033F ; output # [64] (Ì..Ì¿) COMBINING GRAVE ACCENT..COMBINING DOUBLE OVERLINE +0342 ; output # (Í) COMBINING GREEK PERISPOMENI +0346..034E ; output # [9] (Í..Í) COMBINING BRIDGE ABOVE..COMBINING UPWARDS ARROW BELOW +0360..036F ; output # [16] (Í ..ͯ) COMBINING DOUBLE TILDE..COMBINING LATIN SMALL LETTER X +0390 ; output # (Î) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +03AC..03C1 ; output # [22] (ά..Ï) GREEK SMALL LETTER ALPHA WITH TONOS..GREEK SMALL LETTER RHO +03C3..03CE ; output # [12] (Ï..Ï) GREEK SMALL LETTER SIGMA..GREEK SMALL LETTER OMEGA WITH TONOS +0430..045F ; output # [48] (а..Ñ) CYRILLIC SMALL LETTER A..CYRILLIC SMALL LETTER DZHE +0461 ; output # (Ñ¡) CYRILLIC SMALL LETTER OMEGA +0463 ; output # (Ñ£) CYRILLIC SMALL LETTER YAT +0465 ; output # (Ñ¥) CYRILLIC SMALL LETTER IOTIFIED E +0467 ; output # (ѧ) CYRILLIC SMALL LETTER LITTLE YUS +0469 ; output # (Ñ©) CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS +046B ; output # (Ñ«) CYRILLIC SMALL LETTER BIG YUS +046D ; output # (Ñ) CYRILLIC SMALL LETTER IOTIFIED BIG YUS +046F ; output # (ѯ) CYRILLIC SMALL LETTER KSI +0471 ; output # (ѱ) CYRILLIC SMALL LETTER PSI +0473 ; output # (ѳ) CYRILLIC SMALL LETTER FITA +0475 ; output # (ѵ) CYRILLIC SMALL LETTER IZHITSA +0477 ; output # (Ñ·) CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0479 ; output # (ѹ) CYRILLIC SMALL LETTER UK +047B ; output # (Ñ») CYRILLIC SMALL LETTER ROUND OMEGA +047D ; output # (ѽ) CYRILLIC SMALL LETTER OMEGA WITH TITLO +047F ; output # (Ñ¿) CYRILLIC SMALL LETTER OT +0481 ; output # (Ò) CYRILLIC SMALL LETTER KOPPA +048B ; output # (Ò) CYRILLIC SMALL LETTER SHORT I WITH TAIL +048D ; output # (Ò) CYRILLIC SMALL LETTER SEMISOFT SIGN +048F ; output # (Ò) CYRILLIC SMALL LETTER ER WITH TICK +0491 ; output # (Ò) CYRILLIC SMALL LETTER GHE WITH UPTURN +0493 ; output # (Ò) CYRILLIC SMALL LETTER GHE WITH STROKE +0495 ; output # (Ò) CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK +0497 ; output # (Ò) CYRILLIC SMALL LETTER ZHE WITH DESCENDER +0499 ; output # (Ò) CYRILLIC SMALL LETTER ZE WITH DESCENDER +049B ; output # (Ò) CYRILLIC SMALL LETTER KA WITH DESCENDER +049D ; output # (Ò) CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE +049F ; output # (Ò) CYRILLIC SMALL LETTER KA WITH STROKE +04A1 ; output # (Ò¡) CYRILLIC SMALL LETTER BASHKIR KA +04A3 ; output # (Ò£) CYRILLIC SMALL LETTER EN WITH DESCENDER +04A5 ; output # (Ò¥) CYRILLIC SMALL LIGATURE EN GHE +04A7 ; output # (Ò§) CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK +04A9 ; output # (Ò©) CYRILLIC SMALL LETTER ABKHASIAN HA +04AB ; output # (Ò«) CYRILLIC SMALL LETTER ES WITH DESCENDER +04AD ; output # (Ò) CYRILLIC SMALL LETTER TE WITH DESCENDER +04AF ; output # (Ò¯) CYRILLIC SMALL LETTER STRAIGHT U +04B1 ; output # (Ò±) CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE +04B3 ; output # (Ò³) CYRILLIC SMALL LETTER HA WITH DESCENDER +04B5 ; output # (Òµ) CYRILLIC SMALL LIGATURE TE TSE +04B7 ; output # (Ò·) CYRILLIC SMALL LETTER CHE WITH DESCENDER +04B9 ; output # (Ò¹) CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE +04BB ; output # (Ò») CYRILLIC SMALL LETTER SHHA +04BD ; output # (Ò½) CYRILLIC SMALL LETTER ABKHASIAN CHE +04BF..04C0 ; output # [2] (Ò¿..Ó) CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER..CYRILLIC LETTER PALOCHKA +04C2 ; output # (Ó) CYRILLIC SMALL LETTER ZHE WITH BREVE +04C4 ; output # (Ó) CYRILLIC SMALL LETTER KA WITH HOOK +04C6 ; output # (Ó) CYRILLIC SMALL LETTER EL WITH TAIL +04C8 ; output # (Ó) CYRILLIC SMALL LETTER EN WITH HOOK +04CA ; output # (Ó) CYRILLIC SMALL LETTER EN WITH TAIL +04CC ; output # (Ó) CYRILLIC SMALL LETTER KHAKASSIAN CHE +04CE ; output # (Ó) CYRILLIC SMALL LETTER EM WITH TAIL +04D1 ; output # (Ó) CYRILLIC SMALL LETTER A WITH BREVE +04D3 ; output # (Ó) CYRILLIC SMALL LETTER A WITH DIAERESIS +04D5 ; output # (Ó) CYRILLIC SMALL LIGATURE A IE +04D7 ; output # (Ó) CYRILLIC SMALL LETTER IE WITH BREVE +04D9 ; output # (Ó) CYRILLIC SMALL LETTER SCHWA +04DB ; output # (Ó) CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS +04DD ; output # (Ó) CYRILLIC SMALL LETTER ZHE WITH DIAERESIS +04DF ; output # (Ó) CYRILLIC SMALL LETTER ZE WITH DIAERESIS +04E1 ; output # (Ó¡) CYRILLIC SMALL LETTER ABKHASIAN DZE +04E3 ; output # (Ó£) CYRILLIC SMALL LETTER I WITH MACRON +04E5 ; output # (Ó¥) CYRILLIC SMALL LETTER I WITH DIAERESIS +04E7 ; output # (Ó§) CYRILLIC SMALL LETTER O WITH DIAERESIS +04E9 ; output # (Ó©) CYRILLIC SMALL LETTER BARRED O +04EB ; output # (Ó«) CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS +04ED ; output # (Ó) CYRILLIC SMALL LETTER E WITH DIAERESIS +04EF ; output # (Ó¯) CYRILLIC SMALL LETTER U WITH MACRON +04F1 ; output # (Ó±) CYRILLIC SMALL LETTER U WITH DIAERESIS +04F3 ; output # (Ó³) CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE +04F5 ; output # (Óµ) CYRILLIC SMALL LETTER CHE WITH DIAERESIS +04F9 ; output # (Ó¹) CYRILLIC SMALL LETTER YERU WITH DIAERESIS +0501 ; output # (Ô) CYRILLIC SMALL LETTER KOMI DE +0503 ; output # (Ô) CYRILLIC SMALL LETTER KOMI DJE +0505 ; output # (Ô ) CYRILLIC SMALL LETTER KOMI ZJE +0507 ; output # (Ô) CYRILLIC SMALL LETTER KOMI DZJE +0509 ; output # (Ô) CYRILLIC SMALL LETTER KOMI LJE +050B ; output # (Ô) CYRILLIC SMALL LETTER KOMI NJE +050D ; output # (Ô) CYRILLIC SMALL LETTER KOMI SJE +050F ; output # (Ô) CYRILLIC SMALL LETTER KOMI TJE +0561..0586 ; output # [38] (Õ¡..Ö) ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LETTER FEH +0591..05A1 ; output # [17] (Ö..Ö¡) HEBREW ACCENT ETNAHTA..HEBREW ACCENT PAZER +05A3..05B9 ; output # [23] (Ö£..Ö¹) HEBREW ACCENT MUNAH..HEBREW POINT HOLAM +05BB..05BD ; output # [3] (Ö»..Ö½) HEBREW POINT QUBUTS..HEBREW POINT METEG +05BF ; output # (Ö¿) HEBREW POINT RAFE +05C1..05C2 ; output # [2] (×..×) HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C4 ; output # (×) HEBREW MARK UPPER DOT +05D0..05EA ; output # [27] (×..ת) HEBREW LETTER ALEF..HEBREW LETTER TAV +05F0..05F2 ; output # [3] (×°..ײ) HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD +0621..063A ; output # [26] (Ø¡..غ) ARABIC LETTER HAMZA..ARABIC LETTER GHAIN +0641..0655 ; output # [21] (Ù..Ù) ARABIC LETTER FEH..ARABIC HAMZA BELOW +0660..0669 ; output # [10] (Ù ..Ù©) ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE +0670..0674 ; output # [5] (Ù°..Ù´) ARABIC LETTER SUPERSCRIPT ALEF..ARABIC LETTER HIGH HAMZA +0679..068D ; output # [21] (Ù¹..Ú) ARABIC LETTER TTEH..ARABIC LETTER DDAHAL +068F..06D3 ; output # [69] (Ú..Û) ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +06D5..06DC ; output # [8] (Û..Û) ARABIC LETTER AE..ARABIC SMALL HIGH SEEN +06DF..06E8 ; output # [10] (Û..Û¨) ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH NOON +06EA..06ED ; output # [4] (Ûª..Û) ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM +06F0..06FC ; output # [13] (Û°..Û¼) EXTENDED ARABIC-INDIC DIGIT ZERO..ARABIC LETTER GHAIN WITH DOT BELOW +0710..072C ; output # [29] (Ü..ܬ) SYRIAC LETTER ALAPH..SYRIAC LETTER TAW +0730..073F ; output # [16] (Ü°..Ü¿) SYRIAC PTHAHA ABOVE..SYRIAC RWAHA +0780..07B1 ; output # [50] (Þ..Þ±) THAANA LETTER HAA..THAANA LETTER NAA +0901..0903 ; output # [3] (à¤..à¤) DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN VISARGA +0905..0939 ; output # [53] (ठ..ह) DEVANAGARI LETTER A..DEVANAGARI LETTER HA +093C..094D ; output # [18] (़..à¥) DEVANAGARI SIGN NUKTA..DEVANAGARI SIGN VIRAMA +0950..0954 ; output # [5] (à¥..à¥) DEVANAGARI OM..DEVANAGARI ACUTE ACCENT +0960..0963 ; output # [4] (ॠ..ॣ) DEVANAGARI LETTER VOCALIC RR..DEVANAGARI VOWEL SIGN VOCALIC LL +0966..096F ; output # [10] (०..९) DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE +0981..0983 ; output # [3] (à¦..à¦) BENGALI SIGN CANDRABINDU..BENGALI SIGN VISARGA +0985..098C ; output # [8] (ঠ..à¦) BENGALI LETTER A..BENGALI LETTER VOCALIC L +098F..0990 ; output # [2] (à¦..à¦) BENGALI LETTER E..BENGALI LETTER AI +0993..09A8 ; output # [22] (à¦..ন) BENGALI LETTER O..BENGALI LETTER NA +09AA..09B0 ; output # [7] (প..র) BENGALI LETTER PA..BENGALI LETTER RA +09B2 ; output # (ল) BENGALI LETTER LA +09B6..09B9 ; output # [4] (শ..হ) BENGALI LETTER SHA..BENGALI LETTER HA +09BC ; output # (়) BENGALI SIGN NUKTA +09BE..09C4 ; output # [7] (া..à§) BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN VOCALIC RR +09C7..09C8 ; output # [2] (à§..à§) BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09CB..09CD ; output # [3] (à§..à§) BENGALI VOWEL SIGN O..BENGALI SIGN VIRAMA +09D7 ; output # (à§) BENGALI AU LENGTH MARK +09E0..09E3 ; output # [4] (ৠ..ৣ) BENGALI LETTER VOCALIC RR..BENGALI VOWEL SIGN VOCALIC LL +09E6..09F1 ; output # [12] (০..ৱ) BENGALI DIGIT ZERO..BENGALI LETTER RA WITH LOWER DIAGONAL +0A02 ; output # (à¨) GURMUKHI SIGN BINDI +0A05..0A0A ; output # [6] (ਠ..à¨) GURMUKHI LETTER A..GURMUKHI LETTER UU +0A0F..0A10 ; output # [2] (à¨..à¨) GURMUKHI LETTER EE..GURMUKHI LETTER AI +0A13..0A28 ; output # [22] (à¨..ਨ) GURMUKHI LETTER OO..GURMUKHI LETTER NA +0A2A..0A30 ; output # [7] (ਪ..ਰ) GURMUKHI LETTER PA..GURMUKHI LETTER RA +0A32 ; output # (ਲ) GURMUKHI LETTER LA +0A35 ; output # (ਵ) GURMUKHI LETTER VA +0A38..0A39 ; output # [2] (ਸ..ਹ) GURMUKHI LETTER SA..GURMUKHI LETTER HA +0A3C ; output # (਼) GURMUKHI SIGN NUKTA +0A3E..0A42 ; output # [5] (ਾ..à©) GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN UU +0A47..0A48 ; output # [2] (à©..à©) GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A4B..0A4D ; output # [3] (à©..à©) GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +0A5C ; output # (à©) GURMUKHI LETTER RRA +0A66..0A74 ; output # [15] (੦..à©´) GURMUKHI DIGIT ZERO..GURMUKHI EK ONKAR +0A81..0A83 ; output # [3] (àª..àª) GUJARATI SIGN CANDRABINDU..GUJARATI SIGN VISARGA +0A85..0A8B ; output # [7] (ઠ..àª) GUJARATI LETTER A..GUJARATI LETTER VOCALIC R +0A8D ; output # (àª) GUJARATI VOWEL CANDRA E +0A8F..0A91 ; output # [3] (àª..àª) GUJARATI LETTER E..GUJARATI VOWEL CANDRA O +0A93..0AA8 ; output # [22] (àª..ન) GUJARATI LETTER O..GUJARATI LETTER NA +0AAA..0AB0 ; output # [7] (પ..ર) GUJARATI LETTER PA..GUJARATI LETTER RA +0AB2..0AB3 ; output # [2] (લ..ળ) GUJARATI LETTER LA..GUJARATI LETTER LLA +0AB5..0AB9 ; output # [5] (વ..હ) GUJARATI LETTER VA..GUJARATI LETTER HA +0ABC..0AC5 ; output # [10] (઼..à« ) GUJARATI SIGN NUKTA..GUJARATI VOWEL SIGN CANDRA E +0AC7..0AC9 ; output # [3] (à«..à«) GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN CANDRA O +0ACB..0ACD ; output # [3] (à«..à«) GUJARATI VOWEL SIGN O..GUJARATI SIGN VIRAMA +0AD0 ; output # (à«) GUJARATI OM +0AE0 ; output # (à« ) GUJARATI LETTER VOCALIC RR +0AE6..0AEF ; output # [10] (૦..૯) GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE +0B01..0B03 ; output # [3] (à¬..à¬) ORIYA SIGN CANDRABINDU..ORIYA SIGN VISARGA +0B05..0B0C ; output # [8] (ଠ..à¬) ORIYA LETTER A..ORIYA LETTER VOCALIC L +0B0F..0B10 ; output # [2] (à¬..à¬) ORIYA LETTER E..ORIYA LETTER AI +0B13..0B28 ; output # [22] (à¬..ନ) ORIYA LETTER O..ORIYA LETTER NA +0B2A..0B30 ; output # [7] (ପ..ର) ORIYA LETTER PA..ORIYA LETTER RA +0B32..0B33 ; output # [2] (ଲ..ଳ) ORIYA LETTER LA..ORIYA LETTER LLA +0B36..0B39 ; output # [4] (ଶ..ହ) ORIYA LETTER SHA..ORIYA LETTER HA +0B3C..0B43 ; output # [8] (଼..à) ORIYA SIGN NUKTA..ORIYA VOWEL SIGN VOCALIC R +0B47..0B48 ; output # [2] (à..à) ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B4B..0B4D ; output # [3] (à..à) ORIYA VOWEL SIGN O..ORIYA SIGN VIRAMA +0B56..0B57 ; output # [2] (à..à) ORIYA AI LENGTH MARK..ORIYA AU LENGTH MARK +0B5F..0B61 ; output # [3] (à..à¡) ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL +0B66..0B6F ; output # [10] (à¦..à¯) ORIYA DIGIT ZERO..ORIYA DIGIT NINE +0B82..0B83 ; output # [2] (à®..à®) TAMIL SIGN ANUSVARA..TAMIL SIGN VISARGA +0B85..0B8A ; output # [6] (à® ..à®) TAMIL LETTER A..TAMIL LETTER UU +0B8E..0B90 ; output # [3] (à®..à®) TAMIL LETTER E..TAMIL LETTER AI +0B92..0B95 ; output # [4] (à®..à®) TAMIL LETTER O..TAMIL LETTER KA +0B99..0B9A ; output # [2] (à®..à®) TAMIL LETTER NGA..TAMIL LETTER CA +0B9C ; output # (à®) TAMIL LETTER JA +0B9E..0B9F ; output # [2] (à®..à®) TAMIL LETTER NYA..TAMIL LETTER TTA +0BA3..0BA4 ; output # [2] (ண..த) TAMIL LETTER NNA..TAMIL LETTER TA +0BA8..0BAA ; output # [3] (ந..ப) TAMIL LETTER NA..TAMIL LETTER PA +0BAE..0BB5 ; output # [8] (à®®..வ) TAMIL LETTER MA..TAMIL LETTER VA +0BB7..0BB9 ; output # [3] (à®·..ஹ) TAMIL LETTER SSA..TAMIL LETTER HA +0BBE..0BC2 ; output # [5] (ா..à¯) TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN UU +0BC6..0BC8 ; output # [3] (à¯..à¯) TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BCA..0BCD ; output # [4] (à¯..à¯) TAMIL VOWEL SIGN O..TAMIL SIGN VIRAMA +0BD7 ; output # (à¯) TAMIL AU LENGTH MARK +0BE7..0BEF ; output # [9] (௧..௯) TAMIL DIGIT ONE..TAMIL DIGIT NINE +0C01..0C03 ; output # [3] (à°..à°) TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C05..0C0C ; output # [8] (à° ..à°) TELUGU LETTER A..TELUGU LETTER VOCALIC L +0C0E..0C10 ; output # [3] (à°..à°) TELUGU LETTER E..TELUGU LETTER AI +0C12..0C28 ; output # [23] (à°..à°¨) TELUGU LETTER O..TELUGU LETTER NA +0C2A..0C33 ; output # [10] (à°ª..à°³) TELUGU LETTER PA..TELUGU LETTER LLA +0C35..0C39 ; output # [5] (à°µ..à°¹) TELUGU LETTER VA..TELUGU LETTER HA +0C3E..0C44 ; output # [7] (à°¾..à±) TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN VOCALIC RR +0C46..0C48 ; output # [3] (à±..à±) TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C4A..0C4D ; output # [4] (à±..à±) TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +0C55..0C56 ; output # [2] (à±..à±) TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C60..0C61 ; output # [2] (à± ..ౡ) TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C66..0C6F ; output # [10] (౦..౯) TELUGU DIGIT ZERO..TELUGU DIGIT NINE +0C82..0C83 ; output # [2] (à²..à²) KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0C85..0C8C ; output # [8] (ಠ..à²) KANNADA LETTER A..KANNADA LETTER VOCALIC L +0C8E..0C90 ; output # [3] (à²..à²) KANNADA LETTER E..KANNADA LETTER AI +0C92..0CA8 ; output # [23] (à²..ನ) KANNADA LETTER O..KANNADA LETTER NA +0CAA..0CB3 ; output # [10] (ಪ..ಳ) KANNADA LETTER PA..KANNADA LETTER LLA +0CB5..0CB9 ; output # [5] (ವ..ಹ) KANNADA LETTER VA..KANNADA LETTER HA +0CBE..0CC4 ; output # [7] (ಾ..à³) KANNADA VOWEL SIGN AA..KANNADA VOWEL SIGN VOCALIC RR +0CC6..0CC8 ; output # [3] (à³..à³) KANNADA VOWEL SIGN E..KANNADA VOWEL SIGN AI +0CCA..0CCD ; output # [4] (à³..à³) KANNADA VOWEL SIGN O..KANNADA SIGN VIRAMA +0CD5..0CD6 ; output # [2] (à³..à³) KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0CE0..0CE1 ; output # [2] (à³ ..ೡ) KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL +0CE6..0CEF ; output # [10] (೦..೯) KANNADA DIGIT ZERO..KANNADA DIGIT NINE +0D02..0D03 ; output # [2] (à´..à´) MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D05..0D0C ; output # [8] (à´ ..à´) MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L +0D0E..0D10 ; output # [3] (à´..à´) MALAYALAM LETTER E..MALAYALAM LETTER AI +0D12..0D28 ; output # [23] (à´..à´¨) MALAYALAM LETTER O..MALAYALAM LETTER NA +0D2A..0D39 ; output # [16] (à´ª..à´¹) MALAYALAM LETTER PA..MALAYALAM LETTER HA +0D3E..0D43 ; output # [6] (à´¾..àµ) MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN VOCALIC R +0D46..0D48 ; output # [3] (àµ..àµ) MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D4A..0D4D ; output # [4] (àµ..àµ) MALAYALAM VOWEL SIGN O..MALAYALAM SIGN VIRAMA +0D57 ; output # (àµ) MALAYALAM AU LENGTH MARK +0D60..0D61 ; output # [2] (ൠ..ൡ) MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL +0D66..0D6F ; output # [10] (൦..൯) MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE +0D82..0D83 ; output # [2] (à¶..à¶) SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0D85..0D96 ; output # [18] (ච..à¶) SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA +0D9A..0DB1 ; output # [24] (à¶..න) SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA +0DB3..0DBB ; output # [9] (ඳ..ර) SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA +0DBD ; output # (ල) SINHALA LETTER DANTAJA LAYANNA +0DC0..0DC6 ; output # [7] (à·..à·) SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA +0DCA ; output # (à·) SINHALA SIGN AL-LAKUNA +0DCF..0DD4 ; output # [6] (à·..à·) SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6 ; output # (à·) SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8..0DDF ; output # [8] (à·..à·) SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DF2..0DF3 ; output # [2] (à·²..à·³) SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0E01..0E32 ; output # [50] (à¸..า) THAI CHARACTER KO KAI..THAI CHARACTER SARA AA +0E34..0E3A ; output # [7] (ิ..ฺ) THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E40..0E4E ; output # [15] (à¹..à¹) THAI CHARACTER SARA E..THAI CHARACTER YAMAKKAN +0E50..0E59 ; output # [10] (à¹..à¹) THAI DIGIT ZERO..THAI DIGIT NINE +0E81..0E82 ; output # [2] (àº..àº) LAO LETTER KO..LAO LETTER KHO SUNG +0E84 ; output # (àº) LAO LETTER KHO TAM +0E87..0E88 ; output # [2] (àº..àº) LAO LETTER NGO..LAO LETTER CO +0E8A ; output # (àº) LAO LETTER SO TAM +0E8D ; output # (àº) LAO LETTER NYO +0E94..0E97 ; output # [4] (àº..àº) LAO LETTER DO..LAO LETTER THO TAM +0E99..0E9F ; output # [7] (àº..àº) LAO LETTER NO..LAO LETTER FO SUNG +0EA1..0EA3 ; output # [3] (ມ..ຣ) LAO LETTER MO..LAO LETTER LO LING +0EA5 ; output # (ລ) LAO LETTER LO LOOT +0EA7 ; output # (ວ) LAO LETTER WO +0EAA..0EAB ; output # [2] (ສ..ຫ) LAO LETTER SO SUNG..LAO LETTER HO SUNG +0EAD..0EB2 ; output # [6] (àº..າ) LAO LETTER O..LAO VOWEL SIGN AA +0EB4..0EB9 ; output # [6] (ິ..ູ) LAO VOWEL SIGN I..LAO VOWEL SIGN UU +0EBB..0EBD ; output # [3] (ົ..ຽ) LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN NYO +0EC0..0EC4 ; output # [5] (à»..à») LAO VOWEL SIGN E..LAO VOWEL SIGN AI +0EC6 ; output # (à») LAO KO LA +0EC8..0ECD ; output # [6] (à»..à») LAO TONE MAI EK..LAO NIGGAHITA +0ED0..0ED9 ; output # [10] (à»..à») LAO DIGIT ZERO..LAO DIGIT NINE +0F00 ; output # (à¼) TIBETAN SYLLABLE OM +0F18..0F19 ; output # [2] (à¼..à¼) TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F20..0F29 ; output # [10] (༠..༩) TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE +0F35 ; output # (༵) TIBETAN MARK NGAS BZUNG NYI ZLA +0F37 ; output # (༷) TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F39 ; output # (༹) TIBETAN MARK TSA -PHRU +0F3E..0F42 ; output # [5] (༾..à½) TIBETAN SIGN YAR TSHES..TIBETAN LETTER GA +0F44..0F47 ; output # [4] (à½..à½) TIBETAN LETTER NGA..TIBETAN LETTER JA +0F49..0F4C ; output # [4] (à½..à½) TIBETAN LETTER NYA..TIBETAN LETTER DDA +0F4E..0F51 ; output # [4] (à½..à½) TIBETAN LETTER NNA..TIBETAN LETTER DA +0F53..0F56 ; output # [4] (à½..à½) TIBETAN LETTER NA..TIBETAN LETTER BA +0F58..0F5B ; output # [4] (à½..à½) TIBETAN LETTER MA..TIBETAN LETTER DZA +0F5D..0F68 ; output # [12] (à½..ཨ) TIBETAN LETTER WA..TIBETAN LETTER A +0F6A ; output # (ཪ) TIBETAN LETTER FIXED-FORM RA +0F71..0F72 ; output # [2] (ཱ..ི) TIBETAN VOWEL SIGN AA..TIBETAN VOWEL SIGN I +0F74 ; output # (ུ) TIBETAN VOWEL SIGN U +0F7A..0F80 ; output # [7] (ེ..à¾) TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN REVERSED I +0F82..0F84 ; output # [3] (à¾..à¾) TIBETAN SIGN NYI ZLA NAA DA..TIBETAN MARK HALANTA +0F86..0F8B ; output # [6] (à¾..à¾) TIBETAN SIGN LCI RTAGS..TIBETAN SIGN GRU MED RGYINGS +0F90..0F92 ; output # [3] (à¾..à¾) TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER GA +0F94..0F97 ; output # [4] (à¾..à¾) TIBETAN SUBJOINED LETTER NGA..TIBETAN SUBJOINED LETTER JA +0F99..0F9C ; output # [4] (à¾..à¾) TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER DDA +0F9E..0FA1 ; output # [4] (à¾..ྡ) TIBETAN SUBJOINED LETTER NNA..TIBETAN SUBJOINED LETTER DA +0FA3..0FA6 ; output # [4] (ྣ..ྦ) TIBETAN SUBJOINED LETTER NA..TIBETAN SUBJOINED LETTER BA +0FA8..0FAB ; output # [4] (ྨ..ྫ) TIBETAN SUBJOINED LETTER MA..TIBETAN SUBJOINED LETTER DZA +0FAD..0FB8 ; output # [12] (à¾..ྸ) TIBETAN SUBJOINED LETTER WA..TIBETAN SUBJOINED LETTER A +0FBA..0FBC ; output # [3] (ྺ..ྼ) TIBETAN SUBJOINED LETTER FIXED-FORM WA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +0FC6 ; output # (à¿) TIBETAN SYMBOL PADMA GDAN +1000..1021 ; output # [34] (á..á¡) MYANMAR LETTER KA..MYANMAR LETTER A +1023..1027 ; output # [5] (á£..á§) MYANMAR LETTER I..MYANMAR LETTER E +1029..102A ; output # [2] (á©..áª) MYANMAR LETTER O..MYANMAR LETTER AU +102C..1032 ; output # [7] (á¬..á²) MYANMAR VOWEL SIGN AA..MYANMAR VOWEL SIGN AI +1036..1039 ; output # [4] (á¶..á¹) MYANMAR SIGN ANUSVARA..MYANMAR SIGN VIRAMA +1040..1049 ; output # [10] (á..á) MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE +1050..1059 ; output # [10] (á..á) MYANMAR LETTER SHA..MYANMAR VOWEL SIGN VOCALIC LL +10A0..10C5 ; output # [38] (á ..á ) GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE +10D0..10F0 ; output # [33] (á..á°) GEORGIAN LETTER AN..GEORGIAN LETTER HAE +10F7..10F8 ; output # [2] (á·..á¸) GEORGIAN LETTER YN..GEORGIAN LETTER ELIFI +1200..1206 ; output # [7] (á..á) ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE HO +1208..1246 ; output # [63] (á..á) ETHIOPIC SYLLABLE LA..ETHIOPIC SYLLABLE QO +1248 ; output # (á) ETHIOPIC SYLLABLE QWA +124A..124D ; output # [4] (á..á) ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE +1250..1256 ; output # [7] (á..á) ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO +1258 ; output # (á) ETHIOPIC SYLLABLE QHWA +125A..125D ; output # [4] (á..á) ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE +1260..1286 ; output # [39] (á ..á) ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XO +1288 ; output # (á) ETHIOPIC SYLLABLE XWA +128A..128D ; output # [4] (á..á) ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE +1290..12AE ; output # [31] (á..á®) ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KO +12B0 ; output # (á°) ETHIOPIC SYLLABLE KWA +12B2..12B5 ; output # [4] (á²..áµ) ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE +12B8..12BE ; output # [7] (á¸..á¾) ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO +12C0 ; output # (á) ETHIOPIC SYLLABLE KXWA +12C2..12C5 ; output # [4] (á..á ) ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE +12C8..12CE ; output # [7] (á..á) ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE WO +12D0..12D6 ; output # [7] (á..á) ETHIOPIC SYLLABLE PHARYNGEAL A..ETHIOPIC SYLLABLE PHARYNGEAL O +12D8..12EE ; output # [23] (á..á®) ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE YO +12F0..130E ; output # [31] (á°..á) ETHIOPIC SYLLABLE DA..ETHIOPIC SYLLABLE GO +1310 ; output # (á) ETHIOPIC SYLLABLE GWA +1312..1315 ; output # [4] (á..á) ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE +1318..131E ; output # [7] (á..á) ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE GGO +1320..1346 ; output # [39] (á ..á) ETHIOPIC SYLLABLE THA..ETHIOPIC SYLLABLE TZO +1348..135A ; output # [19] (á..á) ETHIOPIC SYLLABLE FA..ETHIOPIC SYLLABLE FYA +1369..1371 ; output # [9] (á©..á±) ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE +13A0..13F4 ; output # [85] (á ..á´) CHEROKEE LETTER A..CHEROKEE LETTER YV +1401..166C ; output # [620] (á..á¬) CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA +166F..1676 ; output # [8] (á¯..á¶) CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS NNGAA +1780..17A2 ; output # [35] (á..á¢) KHMER LETTER KA..KHMER LETTER QA +17A5..17A7 ; output # [3] (á¥..á§) KHMER INDEPENDENT VOWEL QI..KHMER INDEPENDENT VOWEL QU +17A9..17B3 ; output # [11] (á©..á³) KHMER INDEPENDENT VOWEL QUU..KHMER INDEPENDENT VOWEL QAU +17B6..17D0 ; output # [27] (á¶..á) KHMER VOWEL SIGN AA..KHMER SIGN SAMYOK SANNYA +17D2 ; output # (á) KHMER SIGN COENG +17D7 ; output # (á) KHMER SIGN LEK TOO +17DC ; output # (á) KHMER SIGN AVAKRAHASANYA +17E0..17E9 ; output # [10] (á ..á©) KHMER DIGIT ZERO..KHMER DIGIT NINE +1810..1819 ; output # [10] (á ..á ) MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE +1820..1877 ; output # [88] (á ..á¡·) MONGOLIAN LETTER A..MONGOLIAN LETTER MANCHU ZHA +1880..18A9 ; output # [42] (á¢..ᢩ) MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI DAGALGA +1E01 ; output # (á¸) LATIN SMALL LETTER A WITH RING BELOW +1E03 ; output # (á¸) LATIN SMALL LETTER B WITH DOT ABOVE +1E05 ; output # (Ḡ) LATIN SMALL LETTER B WITH DOT BELOW +1E07 ; output # (á¸) LATIN SMALL LETTER B WITH LINE BELOW +1E09 ; output # (á¸) LATIN SMALL LETTER C WITH CEDILLA AND ACUTE +1E0B ; output # (á¸) LATIN SMALL LETTER D WITH DOT ABOVE +1E0D ; output # (á¸) LATIN SMALL LETTER D WITH DOT BELOW +1E0F ; output # (á¸) LATIN SMALL LETTER D WITH LINE BELOW +1E11 ; output # (á¸) LATIN SMALL LETTER D WITH CEDILLA +1E13 ; output # (á¸) LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW +1E15 ; output # (á¸) LATIN SMALL LETTER E WITH MACRON AND GRAVE +1E17 ; output # (á¸) LATIN SMALL LETTER E WITH MACRON AND ACUTE +1E19 ; output # (á¸) LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW +1E1B ; output # (á¸) LATIN SMALL LETTER E WITH TILDE BELOW +1E1D ; output # (á¸) LATIN SMALL LETTER E WITH CEDILLA AND BREVE +1E1F ; output # (á¸) LATIN SMALL LETTER F WITH DOT ABOVE +1E21 ; output # (ḡ) LATIN SMALL LETTER G WITH MACRON +1E23 ; output # (ḣ) LATIN SMALL LETTER H WITH DOT ABOVE +1E25 ; output # (ḥ) LATIN SMALL LETTER H WITH DOT BELOW +1E27 ; output # (ḧ) LATIN SMALL LETTER H WITH DIAERESIS +1E29 ; output # (ḩ) LATIN SMALL LETTER H WITH CEDILLA +1E2B ; output # (ḫ) LATIN SMALL LETTER H WITH BREVE BELOW +1E2D ; output # (á¸) LATIN SMALL LETTER I WITH TILDE BELOW +1E2F ; output # (ḯ) LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE +1E31 ; output # (ḱ) LATIN SMALL LETTER K WITH ACUTE +1E33 ; output # (ḳ) LATIN SMALL LETTER K WITH DOT BELOW +1E35 ; output # (ḵ) LATIN SMALL LETTER K WITH LINE BELOW +1E37 ; output # (ḷ) LATIN SMALL LETTER L WITH DOT BELOW +1E39 ; output # (ḹ) LATIN SMALL LETTER L WITH DOT BELOW AND MACRON +1E3B ; output # (ḻ) LATIN SMALL LETTER L WITH LINE BELOW +1E3D ; output # (ḽ) LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW +1E3F ; output # (ḿ) LATIN SMALL LETTER M WITH ACUTE +1E41 ; output # (á¹) LATIN SMALL LETTER M WITH DOT ABOVE +1E43 ; output # (á¹) LATIN SMALL LETTER M WITH DOT BELOW +1E45 ; output # (á¹ ) LATIN SMALL LETTER N WITH DOT ABOVE +1E47 ; output # (á¹) LATIN SMALL LETTER N WITH DOT BELOW +1E49 ; output # (á¹) LATIN SMALL LETTER N WITH LINE BELOW +1E4B ; output # (á¹) LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW +1E4D ; output # (á¹) LATIN SMALL LETTER O WITH TILDE AND ACUTE +1E4F ; output # (á¹) LATIN SMALL LETTER O WITH TILDE AND DIAERESIS +1E51 ; output # (á¹) LATIN SMALL LETTER O WITH MACRON AND GRAVE +1E53 ; output # (á¹) LATIN SMALL LETTER O WITH MACRON AND ACUTE +1E55 ; output # (á¹) LATIN SMALL LETTER P WITH ACUTE +1E57 ; output # (á¹) LATIN SMALL LETTER P WITH DOT ABOVE +1E59 ; output # (á¹) LATIN SMALL LETTER R WITH DOT ABOVE +1E5B ; output # (á¹) LATIN SMALL LETTER R WITH DOT BELOW +1E5D ; output # (á¹) LATIN SMALL LETTER R WITH DOT BELOW AND MACRON +1E5F ; output # (á¹) LATIN SMALL LETTER R WITH LINE BELOW +1E61 ; output # (ṡ) LATIN SMALL LETTER S WITH DOT ABOVE +1E63 ; output # (á¹£) LATIN SMALL LETTER S WITH DOT BELOW +1E65 ; output # (á¹¥) LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE +1E67 ; output # (ṧ) LATIN SMALL LETTER S WITH CARON AND DOT ABOVE +1E69 ; output # (ṩ) LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE +1E6B ; output # (ṫ) LATIN SMALL LETTER T WITH DOT ABOVE +1E6D ; output # (á¹) LATIN SMALL LETTER T WITH DOT BELOW +1E6F ; output # (ṯ) LATIN SMALL LETTER T WITH LINE BELOW +1E71 ; output # (á¹±) LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW +1E73 ; output # (á¹³) LATIN SMALL LETTER U WITH DIAERESIS BELOW +1E75 ; output # (á¹µ) LATIN SMALL LETTER U WITH TILDE BELOW +1E77 ; output # (á¹·) LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW +1E79 ; output # (á¹¹) LATIN SMALL LETTER U WITH TILDE AND ACUTE +1E7B ; output # (á¹») LATIN SMALL LETTER U WITH MACRON AND DIAERESIS +1E7D ; output # (á¹½) LATIN SMALL LETTER V WITH TILDE +1E7F ; output # (ṿ) LATIN SMALL LETTER V WITH DOT BELOW +1E81 ; output # (áº) LATIN SMALL LETTER W WITH GRAVE +1E83 ; output # (áº) LATIN SMALL LETTER W WITH ACUTE +1E85 ; output # (Ạ) LATIN SMALL LETTER W WITH DIAERESIS +1E87 ; output # (áº) LATIN SMALL LETTER W WITH DOT ABOVE +1E89 ; output # (áº) LATIN SMALL LETTER W WITH DOT BELOW +1E8B ; output # (áº) LATIN SMALL LETTER X WITH DOT ABOVE +1E8D ; output # (áº) LATIN SMALL LETTER X WITH DIAERESIS +1E8F ; output # (áº) LATIN SMALL LETTER Y WITH DOT ABOVE +1E91 ; output # (áº) LATIN SMALL LETTER Z WITH CIRCUMFLEX +1E93 ; output # (áº) LATIN SMALL LETTER Z WITH DOT BELOW +1E95..1E99 ; output # [5] (áº..áº) LATIN SMALL LETTER Z WITH LINE BELOW..LATIN SMALL LETTER Y WITH RING ABOVE +1EA1 ; output # (ạ) LATIN SMALL LETTER A WITH DOT BELOW +1EA3 ; output # (ả) LATIN SMALL LETTER A WITH HOOK ABOVE +1EA5 ; output # (ấ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA7 ; output # (ầ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA9 ; output # (ẩ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EAB ; output # (ẫ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE +1EAD ; output # (áº) LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAF ; output # (ắ) LATIN SMALL LETTER A WITH BREVE AND ACUTE +1EB1 ; output # (ằ) LATIN SMALL LETTER A WITH BREVE AND GRAVE +1EB3 ; output # (ẳ) LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE +1EB5 ; output # (ẵ) LATIN SMALL LETTER A WITH BREVE AND TILDE +1EB7 ; output # (ặ) LATIN SMALL LETTER A WITH BREVE AND DOT BELOW +1EB9 ; output # (ẹ) LATIN SMALL LETTER E WITH DOT BELOW +1EBB ; output # (ẻ) LATIN SMALL LETTER E WITH HOOK ABOVE +1EBD ; output # (ẽ) LATIN SMALL LETTER E WITH TILDE +1EBF ; output # (ế) LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC1 ; output # (á») LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC3 ; output # (á») LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC5 ; output # (á» ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE +1EC7 ; output # (á») LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC9 ; output # (á») LATIN SMALL LETTER I WITH HOOK ABOVE +1ECB ; output # (á») LATIN SMALL LETTER I WITH DOT BELOW +1ECD ; output # (á») LATIN SMALL LETTER O WITH DOT BELOW +1ECF ; output # (á») LATIN SMALL LETTER O WITH HOOK ABOVE +1ED1 ; output # (á») LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED3 ; output # (á») LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED5 ; output # (á») LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED7 ; output # (á») LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE +1ED9 ; output # (á») LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1EDB ; output # (á») LATIN SMALL LETTER O WITH HORN AND ACUTE +1EDD ; output # (á») LATIN SMALL LETTER O WITH HORN AND GRAVE +1EDF ; output # (á») LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE +1EE1 ; output # (ỡ) LATIN SMALL LETTER O WITH HORN AND TILDE +1EE3 ; output # (ợ) LATIN SMALL LETTER O WITH HORN AND DOT BELOW +1EE5 ; output # (ụ) LATIN SMALL LETTER U WITH DOT BELOW +1EE7 ; output # (ủ) LATIN SMALL LETTER U WITH HOOK ABOVE +1EE9 ; output # (ứ) LATIN SMALL LETTER U WITH HORN AND ACUTE +1EEB ; output # (ừ) LATIN SMALL LETTER U WITH HORN AND GRAVE +1EED ; output # (á») LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE +1EEF ; output # (ữ) LATIN SMALL LETTER U WITH HORN AND TILDE +1EF1 ; output # (á»±) LATIN SMALL LETTER U WITH HORN AND DOT BELOW +1EF3 ; output # (ỳ) LATIN SMALL LETTER Y WITH GRAVE +1EF5 ; output # (ỵ) LATIN SMALL LETTER Y WITH DOT BELOW +1EF7 ; output # (á»·) LATIN SMALL LETTER Y WITH HOOK ABOVE +1EF9 ; output # (ỹ) LATIN SMALL LETTER Y WITH TILDE +1F00..1F07 ; output # [8] (á¼..á¼) GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F10..1F15 ; output # [6] (á¼..á¼) GREEK SMALL LETTER EPSILON WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F20..1F27 ; output # [8] (á¼ ..ἧ) GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI +1F30..1F37 ; output # [8] (á¼°..á¼·) GREEK SMALL LETTER IOTA WITH PSILI..GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI +1F40..1F45 ; output # [6] (á½..á½ ) GREEK SMALL LETTER OMICRON WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F50..1F57 ; output # [8] (á½..á½) GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F60..1F67 ; output # [8] (á½ ..ὧ) GREEK SMALL LETTER OMEGA WITH PSILI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F70 ; output # (á½°) GREEK SMALL LETTER ALPHA WITH VARIA +1F72 ; output # (á½²) GREEK SMALL LETTER EPSILON WITH VARIA +1F74 ; output # (á½´) GREEK SMALL LETTER ETA WITH VARIA +1F76 ; output # (ὶ) GREEK SMALL LETTER IOTA WITH VARIA +1F78 ; output # (ὸ) GREEK SMALL LETTER OMICRON WITH VARIA +1F7A ; output # (ὺ) GREEK SMALL LETTER UPSILON WITH VARIA +1F7C ; output # (á½¼) GREEK SMALL LETTER OMEGA WITH VARIA +1FB0..1FB1 ; output # [2] (á¾°..á¾±) GREEK SMALL LETTER ALPHA WITH VRACHY..GREEK SMALL LETTER ALPHA WITH MACRON +1FB6 ; output # (ᾶ) GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FC6 ; output # (á¿) GREEK SMALL LETTER ETA WITH PERISPOMENI +1FD0..1FD2 ; output # [3] (á¿..á¿) GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD6..1FD7 ; output # [2] (á¿..á¿) GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FE0..1FE2 ; output # [3] (á¿ ..á¿¢) GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE4..1FE7 ; output # [4] (ῤ..ῧ) GREEK SMALL LETTER RHO WITH PSILI..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FF6 ; output # (ῶ) GREEK SMALL LETTER OMEGA WITH PERISPOMENI +2132 ; output # (â²) TURNED CAPITAL F +3005..3007 ; output # [3] (ã ..ã) IDEOGRAPHIC ITERATION MARK..IDEOGRAPHIC NUMBER ZERO +3041..3096 ; output # [86] (ã..ã) HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE +3099..309A ; output # [2] (ã..ã) COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309D..309E ; output # [2] (ã..ã) HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK +30A1..30FE ; output # [94] (ã¡..ã¾) KATAKANA LETTER SMALL A..KATAKANA VOICED ITERATION MARK +3105..312C ; output # [40] (ã ..ã¬) BOPOMOFO LETTER B..BOPOMOFO LETTER GN +31A0..31B7 ; output # [24] (ã ..ã·) BOPOMOFO LETTER BU..BOPOMOFO FINAL LETTER H +31F0..31FF ; output # [16] (ã°..ã¿) KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO +3447 ; output # (ã) CJK UNIFIED IDEOGRAPH-3447 +3473 ; output # (ã³) CJK UNIFIED IDEOGRAPH-3473 +34E4 ; output # (ã¤) CJK UNIFIED IDEOGRAPH-34E4 +3577 ; output # (ã·) CJK UNIFIED IDEOGRAPH-3577 +359E ; output # (ã) CJK UNIFIED IDEOGRAPH-359E +35A1 ; output # (ã¡) CJK UNIFIED IDEOGRAPH-35A1 +35AD ; output # (ã) CJK UNIFIED IDEOGRAPH-35AD +35BF ; output # (ã¿) CJK UNIFIED IDEOGRAPH-35BF +35CE ; output # (ã) CJK UNIFIED IDEOGRAPH-35CE +35F3 ; output # (ã³) CJK UNIFIED IDEOGRAPH-35F3 +35FE ; output # (ã¾) CJK UNIFIED IDEOGRAPH-35FE +360E ; output # (ã) CJK UNIFIED IDEOGRAPH-360E +361A ; output # (ã) CJK UNIFIED IDEOGRAPH-361A +3918 ; output # (ã¤) CJK UNIFIED IDEOGRAPH-3918 +3960 ; output # (㥠) CJK UNIFIED IDEOGRAPH-3960 +396E ; output # (㥮) CJK UNIFIED IDEOGRAPH-396E +39CF..39D0 ; output # [2] (ã§..ã§) CJK UNIFIED IDEOGRAPH-39CF..CJK UNIFIED IDEOGRAPH-39D0 +39DF ; output # (ã§) CJK UNIFIED IDEOGRAPH-39DF +39F8 ; output # (㧸) CJK UNIFIED IDEOGRAPH-39F8 +39FE ; output # (㧾) CJK UNIFIED IDEOGRAPH-39FE +3A18 ; output # (ã¨) CJK UNIFIED IDEOGRAPH-3A18 +3A52 ; output # (ã©) CJK UNIFIED IDEOGRAPH-3A52 +3A67 ; output # (㩧) CJK UNIFIED IDEOGRAPH-3A67 +3A73 ; output # (㩳) CJK UNIFIED IDEOGRAPH-3A73 +3B39 ; output # (㬹) CJK UNIFIED IDEOGRAPH-3B39 +3B4E ; output # (ã) CJK UNIFIED IDEOGRAPH-3B4E +3C6E ; output # (ã±®) CJK UNIFIED IDEOGRAPH-3C6E +3CE0 ; output # (ã³ ) CJK UNIFIED IDEOGRAPH-3CE0 +3DE7 ; output # (ã·§) CJK UNIFIED IDEOGRAPH-3DE7 +3DEB ; output # (ã·«) CJK UNIFIED IDEOGRAPH-3DEB +3E74 ; output # (ã¹´) CJK UNIFIED IDEOGRAPH-3E74 +3ED0 ; output # (ã») CJK UNIFIED IDEOGRAPH-3ED0 +4056 ; output # (ä) CJK UNIFIED IDEOGRAPH-4056 +4065 ; output # (ä¥) CJK UNIFIED IDEOGRAPH-4065 +406A ; output # (äª) CJK UNIFIED IDEOGRAPH-406A +40BB ; output # (ä») CJK UNIFIED IDEOGRAPH-40BB +40DF ; output # (ä) CJK UNIFIED IDEOGRAPH-40DF +4137 ; output # (ä·) CJK UNIFIED IDEOGRAPH-4137 +415F ; output # (ä ) CJK UNIFIED IDEOGRAPH-415F +4337 ; output # (ä·) CJK UNIFIED IDEOGRAPH-4337 +43AC ; output # (ä¬) CJK UNIFIED IDEOGRAPH-43AC +43B1 ; output # (ä±) CJK UNIFIED IDEOGRAPH-43B1 +43DD ; output # (ä) CJK UNIFIED IDEOGRAPH-43DD +44D6 ; output # (ä) CJK UNIFIED IDEOGRAPH-44D6 +44EA ; output # (äª) CJK UNIFIED IDEOGRAPH-44EA +4606 ; output # (ä) CJK UNIFIED IDEOGRAPH-4606 +464C ; output # (ä) CJK UNIFIED IDEOGRAPH-464C +4661 ; output # (ä¡) CJK UNIFIED IDEOGRAPH-4661 +4723 ; output # (ä£) CJK UNIFIED IDEOGRAPH-4723 +4729 ; output # (ä©) CJK UNIFIED IDEOGRAPH-4729 +477C ; output # (ä¼) CJK UNIFIED IDEOGRAPH-477C +478D ; output # (ä) CJK UNIFIED IDEOGRAPH-478D +47F4 ; output # (ä´) CJK UNIFIED IDEOGRAPH-47F4 +48B5 ; output # (䢵) CJK UNIFIED IDEOGRAPH-48B5 +48BC ; output # (䢼) CJK UNIFIED IDEOGRAPH-48BC +48C5 ; output # (ä£ ) CJK UNIFIED IDEOGRAPH-48C5 +48D3 ; output # (ä£) CJK UNIFIED IDEOGRAPH-48D3 +4947 ; output # (ä¥) CJK UNIFIED IDEOGRAPH-4947 +497A ; output # (䥺) CJK UNIFIED IDEOGRAPH-497A +497D ; output # (䥽) CJK UNIFIED IDEOGRAPH-497D +4982..4983 ; output # [2] (ä¦..ä¦) CJK UNIFIED IDEOGRAPH-4982..CJK UNIFIED IDEOGRAPH-4983 +4985..4986 ; output # [2] (ä¦ ..ä¦) CJK UNIFIED IDEOGRAPH-4985..CJK UNIFIED IDEOGRAPH-4986 +499B ; output # (ä¦) CJK UNIFIED IDEOGRAPH-499B +499F ; output # (ä¦) CJK UNIFIED IDEOGRAPH-499F +49B6..49B7 ; output # [2] (䦶..䦷) CJK UNIFIED IDEOGRAPH-49B6..CJK UNIFIED IDEOGRAPH-49B7 +49D1 ; output # (ä§) CJK UNIFIED IDEOGRAPH-49D1 +4A12 ; output # (ä¨) CJK UNIFIED IDEOGRAPH-4A12 +4AB8 ; output # (䪸) CJK UNIFIED IDEOGRAPH-4AB8 +4C77 ; output # (ä±·) CJK UNIFIED IDEOGRAPH-4C77 +4C7D ; output # (ä±½) CJK UNIFIED IDEOGRAPH-4C7D +4C81 ; output # (ä²) CJK UNIFIED IDEOGRAPH-4C81 +4C85 ; output # (ä² ) CJK UNIFIED IDEOGRAPH-4C85 +4C9F..4CA3 ; output # [5] (ä²..ä²£) CJK UNIFIED IDEOGRAPH-4C9F..CJK UNIFIED IDEOGRAPH-4CA3 +4CB3 ; output # (ä²³) CJK UNIFIED IDEOGRAPH-4CB3 +4D08 ; output # (ä´) CJK UNIFIED IDEOGRAPH-4D08 +4D13..4D19 ; output # [7] (ä´..ä´) CJK UNIFIED IDEOGRAPH-4D13..CJK UNIFIED IDEOGRAPH-4D19 +4DAE ; output # (䶮) CJK UNIFIED IDEOGRAPH-4DAE +4E00..9FA5 ; output # [20902] (ä¸..é¾¥) CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FA5 +A000..A48C ; output # [1165] (ê..ê) YI SYLLABLE IT..YI SYLLABLE YYR +AC00..D7A3 ; output # [11172] (ê°..í£) HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH +FA0E..FA0F ; output # [2] (ï¨..ï¨) CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F +FA11 ; output # (ï¨) CJK COMPATIBILITY IDEOGRAPH-FA11 +FA13..FA14 ; output # [2] (ï¨..ï¨) CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14 +FA1F ; output # (ï¨) CJK COMPATIBILITY IDEOGRAPH-FA1F +FA21 ; output # (﨡) CJK COMPATIBILITY IDEOGRAPH-FA21 +FA23..FA24 ; output # [2] (﨣..﨤) CJK COMPATIBILITY IDEOGRAPH-FA23..CJK COMPATIBILITY IDEOGRAPH-FA24 +FA27..FA29 ; output # [3] (﨧..﨩) CJK COMPATIBILITY IDEOGRAPH-FA27..CJK COMPATIBILITY IDEOGRAPH-FA29 +2070E ; output # (ð ) CJK UNIFIED IDEOGRAPH-2070E +20731 ; output # (ð ±) CJK UNIFIED IDEOGRAPH-20731 +20779 ; output # (ð ¹) CJK UNIFIED IDEOGRAPH-20779 +20C53 ; output # (ð ±) CJK UNIFIED IDEOGRAPH-20C53 +20C78 ; output # (𠱸) CJK UNIFIED IDEOGRAPH-20C78 +20C96 ; output # (ð ²) CJK UNIFIED IDEOGRAPH-20C96 +20CCF ; output # (ð ³) CJK UNIFIED IDEOGRAPH-20CCF +20CD5 ; output # (ð ³) CJK UNIFIED IDEOGRAPH-20CD5 +20D15 ; output # (ð ´) CJK UNIFIED IDEOGRAPH-20D15 +20D7C ; output # (ð µ¼) CJK UNIFIED IDEOGRAPH-20D7C +20D7F ; output # (𠵿) CJK UNIFIED IDEOGRAPH-20D7F +20E0E..20E0F ; output # [2] (ð ¸..ð ¸) CJK UNIFIED IDEOGRAPH-20E0E..CJK UNIFIED IDEOGRAPH-20E0F +20E77 ; output # (ð ¹·) CJK UNIFIED IDEOGRAPH-20E77 +20E9D ; output # (ð º) CJK UNIFIED IDEOGRAPH-20E9D +20EA2 ; output # (𠺢) CJK UNIFIED IDEOGRAPH-20EA2 +20ED7 ; output # (ð ») CJK UNIFIED IDEOGRAPH-20ED7 +20EF9..20EFA ; output # [2] (ð »¹..𠻺) CJK UNIFIED IDEOGRAPH-20EF9..CJK UNIFIED IDEOGRAPH-20EFA +20F2D..20F2E ; output # [2] (ð ¼..ð ¼®) CJK UNIFIED IDEOGRAPH-20F2D..CJK UNIFIED IDEOGRAPH-20F2E +20F4C ; output # (ð ½) CJK UNIFIED IDEOGRAPH-20F4C +20FB4 ; output # (ð ¾´) CJK UNIFIED IDEOGRAPH-20FB4 +20FBC ; output # (ð ¾¼) CJK UNIFIED IDEOGRAPH-20FBC +20FEA ; output # (𠿪) CJK UNIFIED IDEOGRAPH-20FEA +2105C ; output # (ð¡) CJK UNIFIED IDEOGRAPH-2105C +2106F ; output # (ð¡¯) CJK UNIFIED IDEOGRAPH-2106F +21075..21076 ; output # [2] (ð¡µ..ð¡¶) CJK UNIFIED IDEOGRAPH-21075..CJK UNIFIED IDEOGRAPH-21076 +2107B ; output # (ð¡») CJK UNIFIED IDEOGRAPH-2107B +210C1 ; output # (ð¡) CJK UNIFIED IDEOGRAPH-210C1 +210C9 ; output # (ð¡) CJK UNIFIED IDEOGRAPH-210C9 +211D9 ; output # (ð¡) CJK UNIFIED IDEOGRAPH-211D9 +220C7 ; output # (ð¢) CJK UNIFIED IDEOGRAPH-220C7 +227B5 ; output # (ð¢µ) CJK UNIFIED IDEOGRAPH-227B5 +22AD5 ; output # (ð¢«) CJK UNIFIED IDEOGRAPH-22AD5 +22B43 ; output # (ð¢) CJK UNIFIED IDEOGRAPH-22B43 +22BCA ; output # (ð¢¯) CJK UNIFIED IDEOGRAPH-22BCA +22C51 ; output # (ð¢±) CJK UNIFIED IDEOGRAPH-22C51 +22C55 ; output # (ð¢±) CJK UNIFIED IDEOGRAPH-22C55 +22CC2 ; output # (ð¢³) CJK UNIFIED IDEOGRAPH-22CC2 +22D08 ; output # (ð¢´) CJK UNIFIED IDEOGRAPH-22D08 +22D4C ; output # (ð¢µ) CJK UNIFIED IDEOGRAPH-22D4C +22D67 ; output # (𢵧) CJK UNIFIED IDEOGRAPH-22D67 +22EB3 ; output # (𢺳) CJK UNIFIED IDEOGRAPH-22EB3 +23CB7 ; output # (𣲷) CJK UNIFIED IDEOGRAPH-23CB7 +244D3 ; output # (ð¤) CJK UNIFIED IDEOGRAPH-244D3 +24DB8 ; output # (𤶸) CJK UNIFIED IDEOGRAPH-24DB8 +24DEA ; output # (𤷪) CJK UNIFIED IDEOGRAPH-24DEA +2512B ; output # (ð¥«) CJK UNIFIED IDEOGRAPH-2512B +26258 ; output # (ð¦) CJK UNIFIED IDEOGRAPH-26258 +267CC ; output # (ð¦) CJK UNIFIED IDEOGRAPH-267CC +269F2 ; output # (𦧲) CJK UNIFIED IDEOGRAPH-269F2 +269FA ; output # (𦧺) CJK UNIFIED IDEOGRAPH-269FA +27A3E ; output # (𧨾) CJK UNIFIED IDEOGRAPH-27A3E +2815D ; output # (ð¨ ) CJK UNIFIED IDEOGRAPH-2815D +28207 ; output # (ð¨) CJK UNIFIED IDEOGRAPH-28207 +282E2 ; output # (ð¨¢) CJK UNIFIED IDEOGRAPH-282E2 +28CCA ; output # (ð¨³) CJK UNIFIED IDEOGRAPH-28CCA +28CCD ; output # (ð¨³) CJK UNIFIED IDEOGRAPH-28CCD +28CD2 ; output # (ð¨³) CJK UNIFIED IDEOGRAPH-28CD2 +29D98 ; output # (ð©¶) CJK UNIFIED IDEOGRAPH-29D98 + +# Total code points: 37201 + +# Not allowed at start of identifier + +0300..033F ; nonstarting # [64] (Ì..Ì¿) COMBINING GRAVE ACCENT..COMBINING DOUBLE OVERLINE +0342 ; nonstarting # (Í) COMBINING GREEK PERISPOMENI +0345..034E ; nonstarting # [10] (Í ..Í) COMBINING GREEK YPOGEGRAMMENI..COMBINING UPWARDS ARROW BELOW +0360..036F ; nonstarting # [16] (Í ..ͯ) COMBINING DOUBLE TILDE..COMBINING LATIN SMALL LETTER X +0591..05A1 ; nonstarting # [17] (Ö..Ö¡) HEBREW ACCENT ETNAHTA..HEBREW ACCENT PAZER +05A3..05B9 ; nonstarting # [23] (Ö£..Ö¹) HEBREW ACCENT MUNAH..HEBREW POINT HOLAM +05BB..05BD ; nonstarting # [3] (Ö»..Ö½) HEBREW POINT QUBUTS..HEBREW POINT METEG +05BF ; nonstarting # (Ö¿) HEBREW POINT RAFE +05C1..05C2 ; nonstarting # [2] (×..×) HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C4 ; nonstarting # (×) HEBREW MARK UPPER DOT +064B..0655 ; nonstarting # [11] (Ù..Ù) ARABIC FATHATAN..ARABIC HAMZA BELOW +0670 ; nonstarting # (Ù°) ARABIC LETTER SUPERSCRIPT ALEF +06D6..06DC ; nonstarting # [7] (Û..Û) ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN +06DF..06E4 ; nonstarting # [6] (Û..Û¤) ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA +06E7..06E8 ; nonstarting # [2] (Û§..Û¨) ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +06EA..06ED ; nonstarting # [4] (Ûª..Û) ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM +0711 ; nonstarting # (Ü) SYRIAC LETTER SUPERSCRIPT ALAPH +0730..073F ; nonstarting # [16] (Ü°..Ü¿) SYRIAC PTHAHA ABOVE..SYRIAC RWAHA +07A6..07B0 ; nonstarting # [11] (Þ¦..Þ°) THAANA ABAFILI..THAANA SUKUN +0901..0903 ; nonstarting # [3] (à¤..à¤) DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN VISARGA +093C ; nonstarting # (़) DEVANAGARI SIGN NUKTA +093E..094D ; nonstarting # [16] (ा..à¥) DEVANAGARI VOWEL SIGN AA..DEVANAGARI SIGN VIRAMA +0951..0954 ; nonstarting # [4] (à¥..à¥) DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT +0962..0963 ; nonstarting # [2] (ॢ..ॣ) DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL +0981..0983 ; nonstarting # [3] (à¦..à¦) BENGALI SIGN CANDRABINDU..BENGALI SIGN VISARGA +09BC ; nonstarting # (়) BENGALI SIGN NUKTA +09BE..09C4 ; nonstarting # [7] (া..à§) BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN VOCALIC RR +09C7..09C8 ; nonstarting # [2] (à§..à§) BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09CB..09CD ; nonstarting # [3] (à§..à§) BENGALI VOWEL SIGN O..BENGALI SIGN VIRAMA +09D7 ; nonstarting # (à§) BENGALI AU LENGTH MARK +09E2..09E3 ; nonstarting # [2] (ৢ..ৣ) BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL +0A02 ; nonstarting # (à¨) GURMUKHI SIGN BINDI +0A3C ; nonstarting # (਼) GURMUKHI SIGN NUKTA +0A3E..0A42 ; nonstarting # [5] (ਾ..à©) GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN UU +0A47..0A48 ; nonstarting # [2] (à©..à©) GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A4B..0A4D ; nonstarting # [3] (à©..à©) GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +0A70..0A71 ; nonstarting # [2] (à©°..ੱ) GURMUKHI TIPPI..GURMUKHI ADDAK +0A81..0A83 ; nonstarting # [3] (àª..àª) GUJARATI SIGN CANDRABINDU..GUJARATI SIGN VISARGA +0ABC ; nonstarting # (઼) GUJARATI SIGN NUKTA +0ABE..0AC5 ; nonstarting # [8] (ા..à« ) GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN CANDRA E +0AC7..0AC9 ; nonstarting # [3] (à«..à«) GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN CANDRA O +0ACB..0ACD ; nonstarting # [3] (à«..à«) GUJARATI VOWEL SIGN O..GUJARATI SIGN VIRAMA +0B01..0B03 ; nonstarting # [3] (à¬..à¬) ORIYA SIGN CANDRABINDU..ORIYA SIGN VISARGA +0B3C ; nonstarting # (଼) ORIYA SIGN NUKTA +0B3E..0B43 ; nonstarting # [6] (ା..à) ORIYA VOWEL SIGN AA..ORIYA VOWEL SIGN VOCALIC R +0B47..0B48 ; nonstarting # [2] (à..à) ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B4B..0B4D ; nonstarting # [3] (à..à) ORIYA VOWEL SIGN O..ORIYA SIGN VIRAMA +0B56..0B57 ; nonstarting # [2] (à..à) ORIYA AI LENGTH MARK..ORIYA AU LENGTH MARK +0B82 ; nonstarting # (à®) TAMIL SIGN ANUSVARA +0BBE..0BC2 ; nonstarting # [5] (ா..à¯) TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN UU +0BC6..0BC8 ; nonstarting # [3] (à¯..à¯) TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BCA..0BCD ; nonstarting # [4] (à¯..à¯) TAMIL VOWEL SIGN O..TAMIL SIGN VIRAMA +0BD7 ; nonstarting # (à¯) TAMIL AU LENGTH MARK +0C01..0C03 ; nonstarting # [3] (à°..à°) TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C3E..0C44 ; nonstarting # [7] (à°¾..à±) TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN VOCALIC RR +0C46..0C48 ; nonstarting # [3] (à±..à±) TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C4A..0C4D ; nonstarting # [4] (à±..à±) TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +0C55..0C56 ; nonstarting # [2] (à±..à±) TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C82..0C83 ; nonstarting # [2] (à²..à²) KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0CBE..0CC4 ; nonstarting # [7] (ಾ..à³) KANNADA VOWEL SIGN AA..KANNADA VOWEL SIGN VOCALIC RR +0CC6..0CC8 ; nonstarting # [3] (à³..à³) KANNADA VOWEL SIGN E..KANNADA VOWEL SIGN AI +0CCA..0CCD ; nonstarting # [4] (à³..à³) KANNADA VOWEL SIGN O..KANNADA SIGN VIRAMA +0CD5..0CD6 ; nonstarting # [2] (à³..à³) KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0D02..0D03 ; nonstarting # [2] (à´..à´) MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D3E..0D43 ; nonstarting # [6] (à´¾..àµ) MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN VOCALIC R +0D46..0D48 ; nonstarting # [3] (àµ..àµ) MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D4A..0D4D ; nonstarting # [4] (àµ..àµ) MALAYALAM VOWEL SIGN O..MALAYALAM SIGN VIRAMA +0D57 ; nonstarting # (àµ) MALAYALAM AU LENGTH MARK +0D82..0D83 ; nonstarting # [2] (à¶..à¶) SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0DCA ; nonstarting # (à·) SINHALA SIGN AL-LAKUNA +0DCF..0DD4 ; nonstarting # [6] (à·..à·) SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6 ; nonstarting # (à·) SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8..0DDF ; nonstarting # [8] (à·..à·) SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DF2..0DF3 ; nonstarting # [2] (à·²..à·³) SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0E31 ; nonstarting # (ั) THAI CHARACTER MAI HAN-AKAT +0E34..0E3A ; nonstarting # [7] (ิ..ฺ) THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E47..0E4E ; nonstarting # [8] (à¹..à¹) THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN +0EB1 ; nonstarting # (ັ) LAO VOWEL SIGN MAI KAN +0EB4..0EB9 ; nonstarting # [6] (ິ..ູ) LAO VOWEL SIGN I..LAO VOWEL SIGN UU +0EBB..0EBC ; nonstarting # [2] (ົ..ຼ) LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO +0EC8..0ECD ; nonstarting # [6] (à»..à») LAO TONE MAI EK..LAO NIGGAHITA +0F18..0F19 ; nonstarting # [2] (à¼..à¼) TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F35 ; nonstarting # (༵) TIBETAN MARK NGAS BZUNG NYI ZLA +0F37 ; nonstarting # (༷) TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F39 ; nonstarting # (༹) TIBETAN MARK TSA -PHRU +0F3E..0F3F ; nonstarting # [2] (༾..༿) TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES +0F71..0F72 ; nonstarting # [2] (ཱ..ི) TIBETAN VOWEL SIGN AA..TIBETAN VOWEL SIGN I +0F74 ; nonstarting # (ུ) TIBETAN VOWEL SIGN U +0F76 ; nonstarting # (ྲྀ) TIBETAN VOWEL SIGN VOCALIC R +0F78 ; nonstarting # (ླྀ) TIBETAN VOWEL SIGN VOCALIC L +0F7A..0F80 ; nonstarting # [7] (ེ..à¾) TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN REVERSED I +0F82..0F84 ; nonstarting # [3] (à¾..à¾) TIBETAN SIGN NYI ZLA NAA DA..TIBETAN MARK HALANTA +0F86..0F87 ; nonstarting # [2] (à¾..à¾) TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS +0F90..0F97 ; nonstarting # [8] (à¾..à¾) TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER JA +0F99..0FBC ; nonstarting # [36] (à¾..ྼ) TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +0FC6 ; nonstarting # (à¿) TIBETAN SYMBOL PADMA GDAN +102C..1032 ; nonstarting # [7] (á¬..á²) MYANMAR VOWEL SIGN AA..MYANMAR VOWEL SIGN AI +1036..1039 ; nonstarting # [4] (á¶..á¹) MYANMAR SIGN ANUSVARA..MYANMAR SIGN VIRAMA +1056..1059 ; nonstarting # [4] (á..á) MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC LL +17B6..17D0 ; nonstarting # [27] (á¶..á) KHMER VOWEL SIGN AA..KHMER SIGN SAMYOK SANNYA +17D2 ; nonstarting # (á) KHMER SIGN COENG +18A9 ; nonstarting # (ᢩ) MONGOLIAN LETTER ALI GALI DAGALGA +3099..309A ; nonstarting # [2] (ã..ã) COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + +# Total code points: 524 diff --git a/emacs/nxhtml/etc/viper-tut/0intro b/emacs/nxhtml/etc/viper-tut/0intro new file mode 100644 index 0000000..3a37e33 --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/0intro @@ -0,0 +1,59 @@ +Viper tutorial #0: Introduction + +This Viper tutorial is based on the vi tutorial VILEARN. Some things +works differently in Emacs and corresponding parts of the tutorial has +been changed for this. There has also been added some basic +information about Emacs that are useful to get started if you already +are a vi user. + +This tutorial is a hands-on-tutorial for Viper. If you want more +information about Viper, please read the VIPER-MANUAL. + +Note that if you are using Viper you probably still want to know quite +a bit about Emacs to use Emacs efficiently. Therefore you can also +run the Emacs tutorial from here - with special support for +Viper. This is part 6 below. You should run this part also to get to +know which Emacs standard key bindings are shadowed by Viper. + +The tutorial consists of these parts: + + 0 Introduction + (this file) + + 1 Basic Editing + Covers the handful of commands required to both navigate all + five tutorials and do basic editing. + + 2 Moving Efficiently + Covers all of the cursor positioning commands. These are the + commands used later as arguments to editing commands. + + 3 Cutting and Pasting + Introduces the first compound commands, numbering, and copy + buffers. + + 4 Inserting Techniques + Continues the discussion of compound commands, while completing + the list of insertion commands first discussed in tutorial one. + + 5 Tricks and Timesavers + This is less a tutorial than a description of common vi commands + which don't fit correctly into normal logic. + + 6 Emacs Tutorial for Viper Users + Even Viper users use a lot of keys from Emacs. Therefore you can + run the Emacs tutorial here too. It will show you which keys in + the tutorial that are changed because you are using Viper. This + depends of which Viper state you are in, vi state or some insert + state. If you switch Viper state the tutorial will immediately + show which keys are affected. + + +BUGS +Vilearn has the remark that it "Still doesn't cover variables, ex +commands, or tags. At least one more tutorial is necessary for a +complete introduction to vi." - I do not think you have to learn those +parts to use Viper. There are other ways to do these things in Emacs! + +For more information about vilearn see the the README-FILE. + diff --git a/emacs/nxhtml/etc/viper-tut/1basics b/emacs/nxhtml/etc/viper-tut/1basics new file mode 100644 index 0000000..aea1fc5 --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/1basics @@ -0,0 +1,187 @@ +Viper tutorial #1: The Basics + +This lesson lasts 10-15 minutes and teaches simple editing. Lines +which begin with >>> mark exercises you should try. When you +want to exit this tutorial type 'Z''Z' (type capital Z, twice). + +When you type commands in vi they do not appear on the screen. If the +letters you type unexpectedly appear on the screen, press the ESC key. + + +BASIC CURSOR MOVEMENT +--------------------- +To move through the tutorial use C-d (control d) and C-u (control u). + + C-d Move DOWN one half-screen + (depress the control key and type d) + + C-u Move UP one half-screen + (depress the control key and type u) + +* EMACS-NOTICE: C-u is normally used in Emacs for UNIVERSAL-ARGUMENT. + You can in most cases use DIGIT-ARGUMENT instead. + +>>> Now type C-d (control d) and C-u (control u) to move down and back up. + +When you are done reading a screen, you are expected to type C-d to move +down to the next screen. You must remember to type C-d throughout the +tutorial. + +To move the cursor line by line, or character by character, use the +four keys 'h', 'j', 'k', and 'l'. + + 'h' Move left one character + 'j' Move down one line + 'k' Move up one line + 'l' Move right one character + +You will notice that these keys are in a straight line on the +keyboard. Study the diagram below showing the function of h, j, k, l. + + UP + ....... ....... ....... ....... + : : : : : : : : + LEFT : h : : j : : k : : l : RIGHT + :.....: :.....: :.....: :.....: + + DOWN + +>>> Now type 'j' or 'k' a few times to bring the cursor to this line. + +>>> Try moving off the right end of a line using 'l' . Notice that +>>> vi will not allow you to move off the end of the line using 'l' . +>>> Likewise, you cannot use 'h' and 'l' on a blank line. + +>>> Try moving past the bottom of the screen using 'j' . Notice how +>>> how the screen scrolls downward. + +>>> Now practice using 'k' to move up, and 'h' to move left. + + +DELETION +-------- +To delete characters and lines, use 'x' and 'd''d'. + + 'x' X-OUT one character + 'd''d' DELETE one line + +To undo your changes, use 'u'. + + 'u' UNDO last change only + +>>> Delete this SCRAP line. Move to this line with 'j' or 'k' , now type 'd''d' . +>>> Try undoing the deletion with 'u' . + +>>> Move to this line and x-out the Y's with 'x' : "whY ask whY?" + +>>> Try undoing the deletion with 'u' . Try typing 'u' several times. +>>> Notice that 'u' only undoes the last change. + +* EMACS-NOTICE: In Viper you can use the repeat command '.' (just a dot) + to undo more changes. This goes in both direction, ie undoing and + redoing. Typing just 'u' changes direction. + +Here are more lines on which to practice deleting and undoing (use: 'd''d' 'x' 'u' ) + + Emacs is a nice creation. Emacs is a nice creation. + Emacs is a nice creation. Emacs is a nice creation. + Emacs is a nice creation. Emacs is a nice creation. + + +QUIT COMMANDS +------------- +(DO NOT QUIT the tutorial at this time.) + +To quit a file without saving any changes you have made (for instance, +with the 'd''d' or 'x' commands) use :q!<RETURN> . To quit and save your +changes, use 'Z''Z' . When you are editing your own files, you normally +use 'Z''Z' to quit. + + :q!<RETURN> QUIT without saving changes + (type a colon, then the letter q, then an + exclamation point, and press RETURN) + + 'Z''Z' Exit and save any changes + (type capital Z, twice) + + + +INSERTION +--------- +You enter insert mode with 'i' or 'o' . Anything you type during insert +mode appears on the screen. When you are done inserting, press ESC +to exit insert mode. Type C-[ (control [ ), if you do not have an ESC key. + + 'o' OPEN a line for inserting text + 'i' INSERT starting at the cursor + + ESC ESCAPE from insert mode + +During insert mode, use your erase character (usually backspace or +delete) to delete mistakes. The characters you delete will remain on +the screen until you press ESC. + +>>> Insert your name and phone number below the next blank line. To do this: +>>> Open a line below using 'o' . +>>> Type your first and last name. Press RETURN. +>>> Then type your phone number and press ESC. +>>> Use 'x' to erase part of your phone number. + +>>> Type the date below your phone number. To do this: +>>> Open another line using 'o' . +>>> Type the date and press ESC. + +>>> Type 'u' to undo the insertion. + +>>> Insert a nickname between your first and last names, using 'i'. To do this: +>>> Move the cursor to the spot between your names using 'h', 'j', 'k', 'l'. +>>> Press 'i' . +>>> Type the nickname, use DELETE or BACKSPACE to erase any typos. +>>> Then press ESC. + +On some computers, a line may be longer than the width of the screen. +This means that a very long line may appear to be two lines on the +screen. This happens when you keep typing without pressing RETURN at +the edge of the screen. To avoid any confusion when you're inserting +text, be sure to press RETURN before reaching the right edge of the +screen. + + +SUMMARY +------- +These are the vi commands you should know after tutorial #1: + + C-d Move DOWN one half-screen + (depress the control key and type d) + + C-u Move UP one half-screen + (depress the control key and type u) + + 'h' Move left one character + 'j' Move down one line + 'k' Move up one line + 'l' Move right one character + + 'd''d' DELETE one line + 'x' X-OUT one character + + 'u' UNDO last change + + :q!<RETURN> QUIT without saving changes + (type a colon, then the letter q, then an + exclamation point, and press RETURN) + + 'Z''Z' Exit and save any changes + (type capital Z, twice) + + 'o' OPEN a line for inserting text + 'i' INSERT starting at the cursor + + ESC ESCAPE from insert mode + + +You are now prepared to do simple editing on your own files. Practice +using vi for a few days. Then take the second vi tutorial to learn +more powerful and useful vi commands. + +Copyright (c) 1992 Jill Kliger and Wesley Craig. All Rights Reserved. diff --git a/emacs/nxhtml/etc/viper-tut/2moving b/emacs/nxhtml/etc/viper-tut/2moving new file mode 100644 index 0000000..8e4148e --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/2moving @@ -0,0 +1,269 @@ +Viper tutorial #2: Moving Through Files Efficiently + +This lesson lasts 15-20 minutes. The material taught here is used in +tutorial #3: Cutting and Pasting. Lines which begin with >>> mark +exercises you should try. When you want to exit this tutorial type 'Z''Z'. + + +WORDS +----- +There are many ways to move from one word to another. Consider these: + + 'w' Move to the beginning of the next WORD + 'e' Move to the END of the next word + 'b' Move BACK to the beginning to the previous word + +For 'w', 'e', and 'b', a word is delimited by any non-alphanumeric +character. The capitalized versions, 'W', 'E', and 'B', also move from word +to word. The difference is that for 'W', 'E', and 'B', a word is delimited +by any blank space. + +>>> Try out 'w', 'b', 'e', on the lines provided below. +>>> Next practice using 'B', 'W', 'b', 'E' on the lines provided below. + + EX-PER-IMENT on these lines;test moving back &forth. + EX-PER-IMENT on these lines;test moving back &forth. + + +ON THE LINE +----------- +You can move immediately to any point on the current line. + + '$' Move to the end of the line + '^' Move to the first non-white character on the line + + '0' Move to the first column on the line (column zero) + #'|' Move to an exact column on the line (column #) e.g. 5| 12| + +>>> Experiment with '$' and '^' on the line provided below. Notice +>>> that '^' moves to the first non-white character, not the beginning. + + This is a PRACTICE LINE. There is white space at the front. END + +'0' (zero) will always take you to the far left edge of the screen. + +#'|' (number vertical-bar) is for moving to an explicit column on a line. +Just type any number 1-80 and press | . For example: 5| 20| 30| +Note that you can't move beyond the last column on a line. + + +FINDING CHARACTERS +------------------ +Often you want to move to a specific letter or character on a line. + + 'f' char FIND the next occurrence of char on the line + 't' char Move 'TIL the next occurrence of char on the line + + 'F' char FIND the previous occurrence of char on the line + 'T' char Move 'TIL the previous occurrence of char on the line + + ';' Repeat the last f, t, F, or T + ',' Reverse the last f, t, F, or T + +'f' and 'F' land on the character. 't' and 'T' land next to the character. +'f' and 't' move forward, while 'F' and 'T' move backward. + +If the specified character is not on the line, vi will beep. + +>>> Move to the beginning of the line below, and try out these commands: +>>> 'f'e 'f'E ';' ';' ',' ',' 't'@ 'T'P 't'e 't'E ',' ';' ',' ';' + + "PRACTICE line?" "Each and Every?" "Find thE char@cter and move to it.END + + +MATCHING +-------- +vi has a handy way to determine if (), {}, and [] pairs match up. + + '%' Move to matching () or {} or [] + +>>> On the practice lines below, move your cursor over a (,),{,},[, or ]. +>>> Then type '%' . + + [TRY THIS. ((Whether) the pairs match up is the question.) [One] + pair is incomplete]. Can you tell {which one? ]} END + + +WINDOW POSITIONS +---------------- +You can move the cursor to the top, middle, or bottom of the vi window. + + 'H' Move to the HIGHEST position in the window + 'M' Move to the MIDDLE position in the window + 'L' Move to the LOWEST position in the window + +>>> Try out these commands: type H then M and L and then M again. + + +MARKING LOCATIONS +----------------- +You can mark positions in the file and return to them. + + 'm' char MARK this location and name it char + ''' char (quote character) return to line named char + '''''' (quote quote) return from last movement + +char can be any lower case letter, a-z. A mark persists until you: + 1) use the same char to mark another location + or 2) delete the marked line + +>>> Move to this line and type ma to mark it a +>>> Move to this line and type mb to mark it b +>>> Move to this line and type mz to mark it z +>>> Type 'a to return to line a +>>> Type 'b to return to line b +>>> Type 'z to return to line z + +Certain commands can move you large distances. These commands cause +your last position to be remembered in the special mark named ' (quote). +To move to this special mark, just type '' (quote quote). + +>>> Try this: 'b to return to line b, and then '' to return here. + + +GO TO A LINE +------------ + + 'G' GO to the last line in the file + #'G' GO to line #. (e.g., 3G , 5G , 124G ) + +Read these directions carefully: +>>> Type '1''G' to go to the top of the file, and then '''''' (quote quote) +>>> to return here. +>>> Now try 'G' to go to the end of the file, and then '''''' to return here. + + +BLOCKS OF TEXT +-------------- +It is often convenient to move through files jumping from one block of +text to the next. To do this use braces and parentheses: + + '{' (left brace) Move to the beginning of a paragraph + '}' (right brace) Move to the end of a paragraph + + '(' (left paren) Move to the beginning of a sentence + ')' (right paren) Move to the beginning of the next sentence + +>>> Experiment with '}' and '{' on the two paragraphs provided below. +>>> Note that paragraphs are separated by a blank line. + + EXPERIMENT on this first paragraph. The quick brown fox jumped + over the seven lazy dogs. The fox must have been very large to + jump over seven dogs! + + EXPERIMENT on this second paragraph. The quick brown dog + jumped over the seven lazy foxes. The dog didn't have to be nearly + as large, since foxes aren't too big. + +>>> Try out ')' and '(' on the two paragraphs provided above. +>>> Notice that sentences are separated by two blank spaces. + +C programmers find it useful to move by sections, since sections may be +delimited by a left brace in the first column. By placing the opening +brace of a C subroutine in the first column, you can move to the top of +the next subroutine, using '[''[' and ']'']' . + + '[''[' Move to the beginning of a section + ']'']' Move to the end of a section + +Note that if vi does not find a left brace at the far left, it will +move to the top or bottom of the file. + +>>> Now try ']'']' then ']'']' and '[''[' on the subroutines provided below: + +main() +{ + helloworld(); +} + +helloworld() +{ + printf( "Hello world\n" ); +} + + +SEARCHING +--------- +This enables you to jump to the next occurrence of a string in a file. +To initially find the string use: + + '/'string Find string looking forward + '?'string Find string looking backward + +To find additional occurrences of the string type: + + 'n' Repeat last / or ? command + 'N' Reverse last / or ? command + +vi may search past the bottom of the file and then start again at the top. +(Or, vi may search past the top and then start again at the bottom.) + +>>> You are going to search for a string, find the next three +>>> occurrences. Then flip directions and find the string until you +>>> return to this location. To do this: +>>> Type '/''t''h''e' then press RETURN. +>>> Type 'n' three times. +>>> Type 'N' until you return to this location. + +* EMACS-NOTICE: Emacs has very powerful SEARCH-COMMANDS which you may + want to use in parallell to those above. One of the first you want + to try is probably C-s (ISEARCH-FORWARD). + + +SUMMARY +------- + + 'w' Move to the beginning of the next WORD + 'e' Move to the END of the next word + 'b' Move BACK to the beginning to the previous word + + '$' Move to the end of the line + '^' Move to the first non-white character on the line + + '0' Move to the first column on the line (column zero) + #'|' Move to an exact column on the line (column #) e.g. 5| 12| + + 'f' char FIND the next occurrence of char on the line + 't' char Move 'TIL the next occurrence of char on the line + + 'F' char FIND the previous occurrence of char on the line + 'T' char Move 'TIL the previous occurrence of char on the line + + ';' Repeat the last f, t, F, or T + ',' Reverse the last f, t, F, or T + + '%' Show matching () or {} or [] + + 'H' Move to the HIGHEST position in the window + 'M' Move to the MIDDLE position in the window + 'L' Move to the LOWEST position in the window + + 'm' char MARK this location and name it char + ''' char (quote character) return to line named char + '''''' (quote quote) return from last movement + + 'G' GO to the last line in the file + #'G' GO to line #. (e.g., 3G , 5G , 175G ) + + '{' (left brace) Move to the beginning of a paragraph + '}' (right brace) Move to the end of a paragraph + + '(' (left paren) Move to the beginning of a sentence + ')' (right paren) Move to the beginning of the next sentence + + '[''[' Move to the beginning of a section + ']'']' Move to the end of a section + + '/'string Find string looking forward + '?'string Find string looking backward + + 'n' Repeat last / or ? command + 'N' Reverse last / or ? command + +You should now be able to move around files very efficiently. These +commands are especially useful if you are using vi over a slow modem. +Practice the material in this lesson for a few days and then take +either the third vi tutorial to learn how to copy, cut, and paste, or +the forth vi tutorial to learn additional insertion techniques. + +Copyright (c) 1992 Jill Kliger and Wesley Craig. All Rights Reserved. diff --git a/emacs/nxhtml/etc/viper-tut/3cutpaste b/emacs/nxhtml/etc/viper-tut/3cutpaste new file mode 100644 index 0000000..6d531d9 --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/3cutpaste @@ -0,0 +1,318 @@ +Viper tutorial #3: Copying, Cutting, and Pasting + +This lesson lasts 15-20 minutes. This tutorial assumes full knowledge +of tutorial #1, and familiarity with tutorial #2. Lines which begin +with >>> mark exercises you should try. + +When you want to exit this tutorial type 'Z''Z' to exit and save your +changes. Or type :q!<RETURN> to exit without saving changes. +Remember that typing u will UNDO your last change. + + +CUTTING TEXT +------------ +The delete command can be combined with any of the movement commands +taught throughout tutorial #2. The resulting command is of the form: + + 'd'movement DELETE to where the movement command specifies + +Consider the following examples: + + 'd''w' DELETE to the beginning of the next WORD + 'd''$' DELETE to the end of the line + 'd'')' DELETE to the beginning of the next sentence + 'd''t'e DELETE 'TIL the next e + 'd''d' DELETE a line (dd is a special case of the d command) + +>>> Experiment with 'd''w' 'd''$' 'd'')' 'd''t'e 'd''d' on the paragraph provided below: + + PRACTICE here. Now is the time for all good users to learn the + editor. The quick brown fox jumped over the seven lazy fish. Now + is the time for all good users to learn the editor. The quick + brown computer jumped over the seven lazy users. END PRACTICE + +* EMACS-NOTICE: In Viper you can also use 'r' and 'R' for Emacs region and + Viper line extended region. This is very convenient together with + CUA-MODE where the region is visible (it is usually called the + selected text or something similar in other applications). + + +PASTING TEXT +------------ +When text is deleted it is put into a buffer which contains the most +recently deleted text. To paste the contents of this buffer elsewhere +in the file use the p or P command. + + 'P' (upper p) PUT the contents of the buffer before the cursor + 'p' (lower p) PUT the contents of the buffer after the cursor + +>>> Try this sequence of commands on the practice lines below: +>>> 'd''d' to delete one line +>>> 'j' to move down a line +>>> 'p' (lower p) to PUT the deleted text after the cursor +>>> '}' to move to the end of the paragraph +>>> 'P' (upper p) to PUT the deleted text before the cursor + + PRACTICE line. Cut and Paste this line to the bottom of the + paragraph. Here is some filler, feel free to cut and paste the + text in this practice region. Remember that u undoes the last + action. END OF PRACTICE + +>>> Try this sequence of commands at the beginning of a word: +>>> 'd''w' 'w' 'P' + +The fastest way to swap two letters is to type: 'x''p' + +>>> Use xp to correct the misspelled words below: + + PRACTICE. Thier weird quiet recieved an inconvenient shriek. + Thier belief is that to recieve grief from nieghbors outwieghs + all else. Biege skies lead to wierd science. END. + + +NUMBERING +--------- +Consider cutting and pasting 3 words. Based on previous exercises you +would type 'd''w' , move to the new location, and type 'p' , and repeat +this procedure twice more. There is an easier way to do this: + +>>> Using the practice lines below, try the following sequence of commands: +>>> Move to the beginning of the first sentence. +>>> Type 'd''3''w' to DELETE 3 WORDS. +>>> Type 'w' to move ahead one WORD. +>>> Type 'P' (upper p) to PUT the three words before the cursor. + + PRACTICE Numbering vi commands is easy to do. Now is the time for + all good users to learn the editor. The quick brown fox jumped + over the seven lazy dogs. Numbering vi commands is easy to do. + Now is the time for all good users to learn the editor. END PRACTICE + +>>> Type 'd''2''d' to DELETE 2 lines, using the practice paragraph above. +>>> Move to the top of the paragraph. +>>> Type 'p' (lower p) to PUT the two lines after of the cursor. + +Numbering also works for movement commands. + +>>> Now try '4''w' to move ahead 4 WORDs, on the lines provided above. +>>> Then use '3''b' to move BACK 3 words. + +When you type '4''w' THINK "4 words", when you type d4w think "delete 4 +words". In general, we can write + + #movement repeat movement # times + d#movement DELETE to where the #movement command specifies + + +COPYING TEXT +------------ +The YANK command works just like the DELETE command, except 'y' is used +instead of 'd' . + + 'y'movement YANK to where the movement command specifies + +YANK and DELETE are identical except that YANK only copies the specified +text into the buffer. + +>>> Try this sequence of commands on the practice lines below: +>>> 'y''y' to YANK a line (yy is a special case of the y command) +>>> '3''j' to move down 3 lines +>>> 'p' (lower p) to PUT the yanked text after the cursor + + PRACTICE line. Copy and Paste this line to the bottom of the + paragraph. Here is some filler, feel free to copy and paste the + text in this practice region. Remember that u undoes the last + action. END OF PRACTICE + +Please note that copy, cutting, and pasting large blocks of text may +significantly alter the tutorial file. Remember that you can always get +a new copy of the tutorial file and that u UNDOes your last change. + +Here are some examples which show the similarity between y and d . + + 'y''w' YANK to the beginning of the next WORD + 'y''$' YANK to the end of the line + 'y'')' YANK to the beginning of the next sentence + 'y''t'e YANK 'TIL the next e + 'y''y' YANK a line + +Here are some more examples using commands from tutorial #2. + + 'y''L' YANK from here to the lowest point of the window + 'y''/'and YANK from here to the word "and" + 'y''2''}' YANK 2 paragraphs + 'y''''a YANK from here to the marked line "a" (mark line first) + +>>> Experiment with 'y''w' 'y''t'e 'y''4''w' 'y''2''}' 'y''3''y' and 'y''$' on the paragraph +>>> provided below. Copy text AND use 'p' or 'P' to paste it. + + PRACTICE line. Copy and Paste this line to the bottom of the + paragraph. Here is some filler, feel free to copy and paste + the text in this practice region. Remember that u undoes the + last action. END OF PRACTICE + + +NUMBERED BUFFERS +---------------- +In all of the previous pasting exercises you've used the "un-named" +buffer. The un-named buffer contains the text you most recently cut or +copied. When you make a new cut or copy, the old contents of the +un-named buffer are moved to one of the "numbered" buffers. The +buffers are numbered 1-9. Each time you cut or copy text, + + vi saves your current cut or copy in a buffer #1 + vi saves your 2nd to last cut or copy in a buffer #2 + The cut or copy before that is saved in a buffer #3 ... + vi saves your 8th oldest cut or copy in a buffer #8 + vi saves your 9th oldest cut or copy in a buffer #9 + +Note that buffer #1 is the same as the un-named buffer. Here's how to +paste from the numbered buffers: + + "#P (upper p) PUT contents of buffer # before the cursor + "#p (lower p) PUT contents of buffer # after the cursor + +For example: + + "1p PUT buffer 1 after the cursor + "7p PUT buffer 7 after the cursor + +>>> Delete this 1st line with dd +>>> Delete this 2nd line with dd +>>> Delete this 3rd block with d2d +>>> (2nd half of block 3) +>>> Delete this 4th block with dd +>>> Now type "1p "2p "3p "4p + +If you are using vi and have made accidental deletions, just PUT the +contents of each numbered buffer to recover the deleted text. + + +NAMED BUFFERS +------------- +vi maintains the un-named and numbered buffers automatically. You can +maintain your own buffers named a-z. That is, you can cut or copy text +into buffer x and later paste the text from buffer x. + + '"'aDELETE DELETE text into buffer a + "aYANK YANK text into buffer a + "aPUT PUT text from buffer a + +Note, don't actually type 'DELETE', 'YANK', or 'PUT'; type one of the +DELETE commands, YANK commands, or PUT commands. See the examples below: + + "ad} DELETE paragraph into buffer a + "by3y YANK 3 lines into buffer b + "cy200G YANK to line 200 into buffer c + "dp PUT buffer d after the cursor + "zP PUT buffer z before the cursor + +The contents of a named buffer are lost if: + 1) you store new text in a buffer with the same name + or 2) you quit vi (using 'Z''Z' or :q!<RETURN> ) + +>>> Delete this START line into buffer a by typing "add +>>> Paste buffer a by typing "ap + +>>> Delete this INTERMEDIATE line into buffer b by typing "bdd +>>> Paste buffer b by typing "bp + +To put new material into buffer a +>>> Delete this FINAL line into buffer a by typing "add +>>> Paste buffer a by typing "ap + + +SAVING WITHOUT QUITTING +----------------------- +With ZZ you save changes and kill the current buffer. (In vi you also +exit with 'Z''Z'.) With :w you can save and not quit vi. It is a safe +practice to save changes to a file regularly. This reduces re-typing +in the event your computer crashes. + + :w<RETURN> WRITE contents of the file (without quitting) + (type a colon, type w , then press the RETURN key) + +>>> Try :w now. Note the message at the bottom of the screen. + + +PASTING BETWEEN FILES +--------------------- + +* EMACS-NOTICE: In Emacs there are no problems editing several + files. You can however do it in the more complicated vi way below if + you really want to ;-) + +This is an extremely useful procedure in vi. Only one new command is +required for pasting between files, the EDIT command + + :e filename<RETURN> Begin EDITing the file called "filename" + +The EDIT command allows you to edit another file without quitting vi. +This is useful since named buffers are lost when you quit vi. + +Let's say you want to copy 6 lines from the file called "3temp" into +this file which is named "3cutpaste": +(Note that "3temp" has already been created for you) + + 1) WRITE "3cutpaste". vi will not allow :w (press RETURN) + you to edit another file without first + saving any changes you've made. + + 2) EDIT "3temp" without quitting vi. :e 3temp (press RETURN) + + 3) YANK 6 lines from "3temp". "ay6y + + 4) Return to "3cutpaste". :e 3cutpaste (press RETURN) + + 5) PUT from buffer a "ap + +Note that the un-named and numbered buffers are lost when the EDIT +command is used. Only named buffers are preserved with EDIT. + +>>> Follow the 5-step procedure outlined above. Don't be concerned +>>> with remembering all 5 steps, the instructions are repeated in +>>> "3temp". Paste the text from "3temp" near this line of this file, +>>> "3cutpaste". + +You can use this 5-step procedure on any two files, with any cutting or +copying action (here, y6y is the example). + + +SUMMARY +------- + + #movement repeat movement # times + * EMACS-NOTICE: You may also use 'r' or 'R' in Viper. + + 'd'movement DELETE to where "movement" command specifies + 'd'#movement DELETE to where the #movement command specifies + (e.g. 'd''w' 'd''3''w' ) + + 'y'movement YANK to where "movement" command specifies + 'y'#movement YANK to where the #movement command specifies + (e.g. 'y''w' 'y''3''w' ) + + 'P' (upper p) PUT the contents of the buffer before the cursor + 'p' (lower p) PUT the contents of the buffer after the cursor + + '"'#P (upper p) PUT contents of buffer # before the cursor + '"'#p (lower p) PUT contents of buffer # after the cursor + (e.g. '"''2''p' '"''7''P' ) + + '"'aDELETE DELETE text into buffer a + '"'aYANK YANK text into buffer a + '"'aPUT PUT text from named buffer a + (Note, don't actually type 'DELETE', 'YANK', or 'PUT'; + type one of the DELETE commands, YANK commands, or PUT + commands, e.g. '"''a''d''}' '"''b''y''3''y' '"''c''y''2''0''0''G' '"''d''p' '"''z''P' ) + + :w<RETURN> WRITE contents of the file (without quitting) + (type a colon, type w , then press the RETURN key) + + :e filename<RETURN> Begin EDITing the file called "filename" + + +You are now prepared to handle all cutting, copying and pasting tasks +which may arise. If you practice what you've learned you'll find editing +in vi to be fast and convenient. + +Copyright (c) 1992 Jill Kliger and Wesley Craig. All Rights Reserved. diff --git a/emacs/nxhtml/etc/viper-tut/4inserting b/emacs/nxhtml/etc/viper-tut/4inserting new file mode 100644 index 0000000..ab2c6a5 --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/4inserting @@ -0,0 +1,180 @@ +Viper tutorial #4: Insertion Techniques + +This lesson lasts 5-10 minutes. This tutorial assumes full knowledge +of tutorial #1, and familiarity with tutorial #2. Lines which begin +with >>> mark exercises you should try. When you want to exit this +tutorial type 'Z''Z' . + + +SIMPLE INSERTION +---------------- +You spend most of your time in vi inserting text. As you might expect, +there are several commands to begin insertion. + + 'o' OPEN a line below the cursor + 'O' OPEN a line above the cursor + + 'i' INSERT starting before the cursor + 'I' INSERT at the beginning of the line + + 'a' APPEND starting after the cursor + 'A' APPEND at the end of the line + +Remember to type ESC to leave insert mode. If you don't have an ESC key +type C-[ (control [ ). + + ESC ESCAPE from insert mode + +>>> Move the cursor to this line. Type 'O' , enter your name. Press ESC. +>>> Next type 'o' , enter the date. Press ESC. + +Note that 'O' opens the line above and puts you in insert mode, +while 'o' opens the line below and also puts you in insert mode. + +>>> Type 'a' on any line above, enter your name. Press ESC. Do the +>>> same for 'A'. + +>>> Read the following. Your goal is to take the sentence fragment below: + + BROWN FOX OVER THE SEVEN LAZY + +>>> and convert it to + + THE QUICK BROWN FOX JUMPED OVER THE SEVEN LAZY DOGS. + +>>> To do this type: +>>> 'I' to insert THE QUICK (then press ESC) +>>> move the cursor to after the X in FOX +>>> 'a' to insert JUMPED (then press ESC) +>>> 'A' to insert DOGS. (then press ESC) +>>> Now move to the sentence fragment and make the changes outlined above. + + +JOINING LINES +------------- +Often it is convenient to join two short lines into one line. There +are several ways to do this. The easiest is the J command. Other +methods will be explored in tutorial #5. + + 'J' JOIN two lines + +>>> Go to the first line in the block below. Type J. Type J again. + + Example: NOW IS THE TIME + the walrus said + TO THINK OF MANY THINGS + +In the event that joining lines creates a line which exceeds the width +of the screen, you can break the line by typing i and pressing RETURN. + + +SUBSTITUTING TEXT +----------------- +Substituting combines the delete command and the insert command into a +single step. + + #'s' SUBSTITUTE for # characters + #'S' SUBSTITUTE for # whole lines + + +In order to substitute text you have to know how much text you want to +delete. Consider the following examples: + + '3''s' SUBSTITUTE the next 3 characters for what will be typed + '7''s' SUBSTITUTE the next 7 characters for what will be typed + +>>> Change the SAMPLE DEFINITION below. To do this: +>>> move the cursor to the T in TWO +>>> type '3's +>>> type FOUR then press ESC + + SAMPLE DEFINITION: A string quartet is defined to be + a group of TWO musicians. + + +REPLACING TEXT +-------------- +The 'r' and 'R' commands allow you to directly type over existing text. + + 'r' REPLACE character (NO need to press ESC) + 'R' enter over-type mode + +>>> Correct each of the TYPOs on the sample line below. To do this: +>>> move the cursor to the misspelled character +>>> type 'r' +>>> type the correct character + + SAMPLE: maintanence conveniance complience applience dilagent + +>>> Use the over-type command, 'R' , on the sample line above. +>>> Type 'R' then type the name of a local restaurant. Press ESC. + + +CHANGING TEXT +------------- +The change command combines insertion, deletion, and the movement +commands. (Recall that the movement commands were taught in tutorial +#2.) Change is probably more useful than replace or substitute. The +general form of the change command is: + + 'c'movement CHANGE to where the movement command specifies + +Consider the following examples: + + 'c''w' CHANGE to the beginning of the next WORD + 'c''$' CHANGE to the end of the line + 'c'')' CHANGE to the beginning of the next sentence + 'c''t'e CHANGE 'TIL the next e + 'c''3''w' CHANGE the next 3 WORDS + 'c''c' CHANGE a line (cc is a special case of the c command) + 'c''}' CHANGE to the end of the paragraph + +>>> Follow these steps: +>>> 1. move to the desired location in the practice paragraph below +>>> 2. type 'c''w' (change to the beginning of the next WORD) +>>> 3. type your name +>>> 4. press ESC + + PRACTICE here. Now is the time for all good users to learn the + editor. The quick red fox jumped over the seven lazy fish. Now + is the time for all good users to learn the editor. The quick + brown computer jumped over the seven lazy users. END PRACTICE + +>>> Experiment by using a variety of options for step #2. Try +>>> out 'c''$' 'c'')' 'c''t'e 'c''3''w' 'c''c' 'c''}' on the practice paragraph above. + +Note that the change command follows the same pattern as the delete +and yank commands which were explored in tutorial #3. + + +SUMMARY +------- + + 'o' OPEN a line below the cursor + 'O' OPEN a line above the cursor + + 'i' INSERT starting before the cursor + 'I' INSERT at the beginning of the line + + 'a' APPEND starting after the cursor + 'A' APPEND at the end of the line + + ESC ESCAPE from insert mode + + 'J' JOIN two lines + + #'s' SUBSTITUTE for # characters + #'S' SUBSTITUTE for # whole lines + + 'r' REPLACE character (NO need to press ESC) + 'R' enter over-type mode + + 'c'movement CHANGE to where the movement commands specifies + (e.g. 'c''3''w' 'c''$' 'c''c' ) + + +These commands should improve your ability to insert text efficiently. +The next tutorials deal with advanced commands and tricks which can +further speed up your editing. + +Copyright (c) 1992 Jill Kliger and Wesley Craig. All Rights Reserved. diff --git a/emacs/nxhtml/etc/viper-tut/5tricks b/emacs/nxhtml/etc/viper-tut/5tricks new file mode 100644 index 0000000..c1e414e --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/5tricks @@ -0,0 +1,229 @@ +Viper tutorial #5: Tricks and Timesavers + +This lesson lasts 10-15 minutes. You should have a strong +understanding of tutorials #1-3 before working through these timesaving +techniques. Lines which begin with >>> mark exercises you should +try. When you want to exit this tutorial type 'Z''Z' . + + +CASE CONVERSION +--------------- +When you want to change an upper-case character to a lower-case +character (or lower-case to upper-case) there is a single command which +does both: + + '~' (tilde) Convert case of current character + +>>> Move the cursor to be OVER the first character in the example +>>> line below. Press '~' until you have changed the case of the +>>> entire line. ( '~' will advance to the right automatically). + + bOB WENT TO pARIS, fRANCE, TO SEE THE #1 CYCLING EVENT. end. + +Note that '~' only affects alphabetic characters. + + +UNDOING +------- +* EMACS-NOTICE: Uppercase U does the same thing as lowercase u in + Viper so this part of the tutorial which was about U has been + removed. + + +REPEAT LAST COMMAND +------------------- +Often you want to make the same change at multiple locations in the +file. To help accomplish this, vi remembers your previous action. + + '.' (dot) repeat last change + +>>> Go through the example below changing "FISH" to "TOAD": +>>> Go to the "F" in the first instance of "FISH" +>>> To change the word: type 'c''w' then type TOAD then press ESC +>>> Move the cursor to "F" in the second occurence of "FISH" +>>> Type '.' (dot) +>>> Move the cursor to "F" in the final occurence of "FISH" +>>> Type '.' (dot) +>>> Now move the cursor to each occurence of "CROW"; Type '.' (dot) + + EXAMPLE: The FISH fed the cat. The CROW fed the cat. Example + text is FISH to make interesting. The man fed the CROW. The + worm fed the FISH. Example text is hard to make CROW. END. + +>>> Go through the example above deleting all occurences of "TOAD": +>>> Move to the beginning of the EXAMPLE paragraph above. +>>> Type '/''T''O''A''D' and press RETURN (recall tutorial #2) +>>> Delete the word by typing 'd''w' +>>> Type 'n' to move to the next occurence of "TOAD" +>>> Type '.' (dot) to repeat the dw command +>>> Use 'n''.' to delete the remaining "TOAD"s + +Note that '.' only repeats changes, not cursor movements. + +* EMACS-NOTICE: In Emacs '.' also repeat undo and redo. + +* EMACS-NOTICE: Emacs KEYBOARD-MACROS are very powerful for repeating + whole sequences of keyboard commands. + + +WINDOW ACTIONS +-------------- +You are already familiar with the C-u (depress the control key and +type u) and C-d commands from tutorial #1. + + C-d Move DOWN one half-screen + C-u Move UP one half-screen + +There are several related commands: + + C-f Move FORWARD one full-screen + C-b Move BACKWARD one full-screen + + C-e Move the window down one line without moving cursor + C-y Move the window up one line without moving cursor + +The C-e and C-y commands may seem obscure; however, notice that on +the keyboard, e and y are close to d and u respectively. This +should help you remember that C-e moves DOWN, and C-y moves UP. + +Recall the 'H' 'M' 'L' (HIGH MIDDLE LOW) window commands from Tutorial 2. +Consider a scenario where you want to yank from the current line to a +line near the top of the window. You could use C-e and C-y to +position the text in the window before you use the yH command. + +The 'z' command also moves the window without moving your cursor: + + 'z'<RETURN> Position the current line to top of window + 'z''.' Position the current line to middle of window + 'z''-' Position the current line to bottom of window + +>>> Move to this line. Type 'z' and press RETURN. Notice that +>>> this text and the cursor have moved to the top of the window. +>>> Try 'z''-' and 'z''.' also. + + +FILE AND DISPLAY CONTROL +------------------------ + +* EMACS-NOTICE: In vi C-g shows the status of the current file, but + C-g in Emacs in most situation stops what Emacs is doing. To get + information about the current file you can use C-c C-g instead when + Viper is in vi state. + +* EMACS-NOTICE: In vi C-l refreshes the screen, but C-l in Emacs calls + the command recenter. + + +SUSPENDING VI +------------- +* EMACS-NOTICE: In vi C-z suspends vi. However in Viper C-z is by + default the VIPER-TOGGLE-KEY. To suspend or iconify Emacs use C-x + C-z. + + +BANG COMMAND +------------ +* EMACS-NOTICE: Emacs has builtin commands to sort etc. + +The exclamation point, '!' (aka BANG), command allows you to feed text +to any Unix command. The output of the Unix command replaces the +original text. Here is a useful Unix command to use from within vi: + + !}fmt Format the paragraph, joining and filling lines to + produce output lines of up to 72 characters + +>>> Move to the example paragraph below. Type !}fmt and press +>>> RETURN. Notice the paragraph will be reformatted such that +>>> the lines are of approximately equal length. + + EXAMPLE: + So we grow together, + Like to a double cherry, seeming parted, + But yet an union in partition; + Two lovely berries moulded on one stem; + So, with two seeming bodies, but one heart; + END. + +Another useful command is: + + !}sort Sort lines of a paragraph alphabetically + +>>> Move to the example text below. Type !}sort and press RETURN. + + OBERON king of the fairies. + PUCK or Robin Goodfellow. + HERMIA daughter to Egeus, in love with Lysander. + HELENA in love with Demetrius. + LYSANDER in love with Hermia. + DEMETRIUS in love with Hermia. + +Remember, any Unix command may be used this way. + + +SHIFTING TEXT +------------- +It is possible to shift large blocks of text right and left with the '>' +and '<' commands. + + '>'movement Shift right to where the movement command specifies + '<'movement Shift left to where the movement command specifies + +These commands work like the 'd' command. For example: + + '>''}' Shift right to the end of the paragraph + '<''}' Shift left to the end of the paragraph + '>''>' Shift the current line right + '<''<' Shift the current line left + +>>> Move the cursor to the first line of the paragraph below. +>>> Type '>''>' and '<''<' to shift the line back and forth. Next +>>> try '>''}' to shift the paragraph to the right, then '<''}' to shift +>>> it left, then type '.' until all four lines start at the left edge. + + THIS IS THE FIRST LINE OF EXAMPLE TEXT + IS + EXAMPLE + TEXT END + + +SUMMARY +------- + + '~' (tilde) Convert case of current character + + 'U' * EMACS-NOTICE: Same as lowercase u undo in Viper. + + '.' (dot) repeat last change + + C-d Move DOWN one half-screen + (depress the control key and type d) + + C-u Move UP one half-screen + (depress the control key and type u) + + C-f Move FORWARD one full-screen + C-b Move BACKWARD one full-screen + + C-e Move the window down one line without moving cursor + C-y Move the window up one line without moving cursor + + 'z'<RETURN> Position the current line to top of window + 'z''.' Position the current line to middle of window + 'z''-' Position the current line to bottom of window + + C-c C-g Show status of current file + C-l Recenter + + '!'}fmt Format the paragraph, joining and filling lines to + produce output lines of up to 72 characters + + '!'}sort Sort lines of a paragraph alphabetically + + '>'movement Shift right to where the movement command specifies + '<'movement Shift left to where the movement command specifies + + +These commands should significantly speed up your editing. Have a nice +day. Tutorial 6 contains even more nifty commands. + +Copyright (c) 1992 Jill Kliger and Wesley Craig. All Rights Reserved. diff --git a/emacs/nxhtml/etc/viper-tut/README b/emacs/nxhtml/etc/viper-tut/README new file mode 100644 index 0000000..dd39176 --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/README @@ -0,0 +1,49 @@ +Viper Tutorial README +===================== + +To install the Viper tutorial you must do two things: + +1) Put viper-tutorial.el in your Emacs load-path. + +2) Put the tutorial files (0intro, 1basics etc) in subdirectory to + where you put viper-tutorial.el with the name viper-tut. + Optionally you may put those file any where and customize the + option viper-tut-directory. + +The tutorial is started by + + M-x viper-tutorial RET + + + + +Viper tutorial is based on vilearn version 1.0 which was downloaded +from http://vilearn.org. + +Below is the original readme from vilearn. Note that the only part +that applies here is the copyright notice. + +--------------------------------------------------- +This is version 1.0 of vilearn, an interactive vi tutorial. + +Copyright (c) 1992 Jill Kliger and Wesley Craig. All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appears in all copies and that +the copyright notice, this permission notice, and an explicit record of +any local changes, appear in supporting documentation. This software +is supplied as is without expressed or implied warranties of any kind. + +To install, edit the Makefile and type + + make install + +We have a mailing list, vilearn-admins@terminator.rs.itd.umich.edu. To +be added to the list, send mail to vilearn-admins-request. The list is +intended to discuss the tutorials, coordinate projects relating to +them, and provide help to those who may need it. + +Wesley Craig & Jill Kliger +1317 Packard Street vilearn@terminator.rs.itd.umich.edu +Ann Arbor, MI 48104 diff --git a/emacs/nxhtml/etc/viper-tut/outline b/emacs/nxhtml/etc/viper-tut/outline new file mode 100644 index 0000000..9eaa3e4 --- /dev/null +++ b/emacs/nxhtml/etc/viper-tut/outline @@ -0,0 +1,131 @@ + +* +* tutorial 1 FILENAME: 1basics +* basics +* + +C-d down +C-u up + +h left +j down +k up +l right + +dd delete line +x x-out character + +u undo + +:q! force quit +ZZ good bye + +o open +i insert + +* +* tutorial 2 FILENAME: 2moving +* objects, finds & marks +* + +w W word +b B back +e E end + +{ } paragraph +( ) sentence +[ ] sections + +$ end of line +^ first non-white +| column +0 beginning of line + +f F find +t T to +; repeat fFtT +, reverse fFtT + +G goto + +H high +M middle +L low + +n N next +? / regex + +% match + +' move to marked line +m mark + + +* +* tutorial 3 FILENAME: 3cutpaste & 3temp +* +* cutting, pasting, buffers, and files +* + +d D deletes +y Y yank +p P put +" buffer +:e edit + +* +* tutorial 4 FILENAME: 4inserting +* insertion +* + +a A append +c C change +i I insert +o O open +r R replace +s S substitute + +J join + +* +* tutorial 5 FILENAME: 5tricks +* tricks +* + +~ case + +u U undo + +. do again + +C-b back +C-f forward +C-e down line +C-y up line +z zero + +C-g status +C-l refresh + +C-z suspend + +C-t pop tag proposed +C-] follow tag proposed + +! command + +< > shift + +* +* tutorial 6 PROPOSED +* commands from hell +* + +: colon commands +Q quit +C-r redraw +@ execute buffer as macro +& like :& + +C-t shift (insert) +C-d unshift (insert) diff --git a/emacs/nxhtml/nxhtml-base.el b/emacs/nxhtml/nxhtml-base.el new file mode 100644 index 0000000..d768a5e --- /dev/null +++ b/emacs/nxhtml/nxhtml-base.el @@ -0,0 +1,150 @@ +;;; nxhtml-base.el --- The very, very basic vars... +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2010-01-13 Wed +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Things that always must be loaded and that are often necessary when +;; byte compiling. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +;;(eval-when-compile (require 'web-vcs nil t)) +(eval-when-compile (require 'flymake-js nil t)) +(eval-when-compile (require 'flymake-css nil t)) +(eval-when-compile (require 'flymake-java-1 nil t)) + +(defconst nxhtml-menu:version "2.08") +(setq message-log-max t) +(setq debug-on-error t) + +(defconst nxhtml-install-dir + (file-name-directory (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + "Installation directory for nXhtml.") + +(define-minor-mode nxhtml-autoload-web + "If on download elisp files from web when they are needed. +If t then during `require' nXhtml elisp files can be downloaded +from the nXhtml repository on the web. This will currently +download the development sources, latest version. + +Other files that are used by a command may also be downloaded. + +Note that files are not updated automatically. You have to use +`nxhtml-update-existing-files' for that." + :global t + ;;:lighter (propertize " nX" 'face 'font-lock-comment-face) + :lighter " nX" + :group 'nxhtml) + +(defun nxhtml-autoload (fun src &optional docstring interactive type) + "Generalized `autoload'. May setup autoload from the web. +If `nxhtml-autoload-web' is t then setup autoloading from the web. +Otherwise setup for normal local autoloading." + (if nxhtml-autoload-web + (progn + ;; Do not require this until we really need it. + (require 'web-autoload) + (web-autoload fun src docstring interactive type)) + (let ((file src)) + (when (listp file) + (setq file (file-name-nondirectory (nth 2 file)))) + (autoload fun file docstring interactive type)))) + +;; Fix-me: web autoload defcustoms. +;; +;; I have no good idea how to fix this. It looks like I have to +;; defadvice `custom-load-symbol'. I thought that should not be +;; necessary since it does (require load) on line 605 but the web +;; autoload does not start. Why? Hm, you never know since it is inside +;; a (condition-case nil ...). +;; +;; Ah, found it. The require is only done if custom loads contains a +;; symbol, not a string. So I changed this to a symbol instead in +;; nxhtml-loaddefs.el. Maybe `load' instead of `require' should be +;; advised? + +;; What a hell is this below? Have things been rewritten in custom or +;; did I mix somethintg? +(defun nxhtml-custom-autoload (symbol load &optional noset) + "Like `custom-autoload', but also run :set for defcustoms etc." + ;; Fix-me: is-boundp is currently always t because of the order in + ;; loaddefs. Hm, so this worked just by chance... + (let* ((is-boundp (prog1 (boundp symbol) + (custom-autoload symbol load noset))) + (standard (get symbol 'standard-value)) + (saved (get symbol 'saved-value)) + ;; Fix-me: property custom-set etc are not available + (custom-set (get symbol 'custom-set)) + (custom-initialize (get symbol 'custom-initialize)) + (set (or custom-set 'custom-set-default))) ;; Fix-me: initialize + (setq custom-set t) ;; Not available here + (when (or custom-initialize + (and saved + (not (equal (car saved) (symbol-value symbol))) + custom-set)) + (funcall set symbol (car saved)) + (custom-load-symbol symbol)))) + +(defun flymake-init-load-flymakemsg () + (require 'flymakemsg)) + +(define-minor-mode nxhtml-flymake-setup + "Let nXhtml add some addtions to flymake. +This adds support for CSS and JavaScript files. + +It also adds showing of errors in minibuffer when point is on +them. + +If you turn this off you must restart Emacs for it to take +effect." + :group 'nxhtml + :group 'flymake + (when nxhtml-flymake-setup + (flymake-js-load) + (flymake-css-load) + (flymake-java-1-load) + (add-hook 'flymake-mode-hook 'flymake-init-load-flymakemsg))) + + +(provide 'nxhtml-base) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-base.el ends here diff --git a/emacs/nxhtml/nxhtml-loaddefs.el b/emacs/nxhtml/nxhtml-loaddefs.el new file mode 100644 index 0000000..bfa98ee --- /dev/null +++ b/emacs/nxhtml/nxhtml-loaddefs.el @@ -0,0 +1,4490 @@ +;; Autoloads for nXthml +;; +;; This file should be updated by `nxhtmlmaint-get-file-autoloads', +;; `nxhtmlmaint-get-dir-autoloads' or `nxhtmlmaint-get-all-autoloads'. +(eval-when-compile (require 'nxhtml-base)) +(eval-when-compile (require 'web-vcs)) + +;;;### (autoloads (cancel-secondary-selection set-secondary-selection +;;;;;; anchored-transpose) "anchored-transpose" "util/anchored-transpose.el" +;;;;;; (19333 54924)) +;;; Generated autoloads from util/anchored-transpose.el +(web-autoload-require 'anchored-transpose 'lp '(nxhtml-download-root-url nil) "util/anchored-transpose" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'anchored-transpose `(lp '(nxhtml-download-root-url nil) "util/anchored-transpose" nxhtml-install-dir) "\ +Transpose portions of the region around an anchor phrase. + +`this phrase but not that word' can be transposed into +`that word but not this phrase' + +I want this phrase but not that word. + |----------------------------|. .This is the entire phrase. + |-------|. . . . . . .This is the anchor phrase. + +First select the entire phrase and type \\[anchored-transpose]. +This set the secondary selection. + +Then select the anchor phrase and type \\[anchored-transpose] +again. Alternatively you can do the selections like this: + +I want this phrase but not that word. + |----------| |---------| Separate phrase selection. + +By default the anchor phrase will automatically include +any surrounding whitespace even if you don't explicitly select +it. Also, it won't include certain trailing punctuation. See +`anchored-transpose-do-fuzzy' for details. A prefix arg prior to +either selection means `no fuzzy logic, use selections +literally'. + +You can select the regions to be swapped separately in any +order. + +After swapping both primary and secondary selection are still +active. They will be canceled after second next command if you +do not swap regions again. (Second because this allow you to +adjust the regions and try again.) + +You can also swap text between different buffers this way. + +Typing \\[anchored-transpose] with nothing selected clears any +prior selection, ie secondary selection. + +\(fn BEG1 END1 FLG1 &optional BEG2 END2 FLG2 WIN2)" t nil) + +(nxhtml-autoload 'set-secondary-selection `(lp '(nxhtml-download-root-url nil) "util/anchored-transpose" nxhtml-install-dir) "\ +Set the secondary selection to the current region. +This must be bound to a mouse drag event. + +\(fn BEG END)" t nil) + +(nxhtml-autoload 'cancel-secondary-selection `(lp '(nxhtml-download-root-url nil) "util/anchored-transpose" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (appmenu-mode appmenu-add appmenu) "appmenu" "util/appmenu.el" +;;;;;; (19275 63380)) +;;; Generated autoloads from util/appmenu.el +(web-autoload-require 'appmenu 'lp '(nxhtml-download-root-url nil) "util/appmenu" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'appmenu 'custom-loads))) (if (member '"appmenu" loads) nil (put 'appmenu 'custom-loads (cons '"appmenu" loads)))) + +(nxhtml-autoload 'appmenu-add `(lp '(nxhtml-download-root-url nil) "util/appmenu" nxhtml-install-dir) "\ +Add entry to `appmenu-alist'. +Add an entry to this list with ID, PRIORITY, TEST, TITLE and +DEFINITION as explained there. + +\(fn ID PRIORITY TEST TITLE DEFINITION)" nil nil) + +(defvar appmenu-mode nil "\ +Non-nil if Appmenu mode is enabled. +See the command `appmenu-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `appmenu-mode'.") + +(nxhtml-custom-autoload 'appmenu-mode 'appmenu nil) + +(nxhtml-autoload 'appmenu-mode `(lp '(nxhtml-download-root-url nil) "util/appmenu" nxhtml-install-dir) "\ +Use a context sensitive popup menu. +AppMenu (appmenu.el) is a framework for creating cooperative +context sensitive popup menus with commands from different major +and minor modes. Using this different modes may cooperate about +the use of popup menus. + +There is also the command `appmenu-as-help' that shows the key +bindings at current point in the help buffer. + +The popup menu and the help buffer version are on these keys: + +\\{appmenu-mode-map} + +The variable `appmenu-alist' is where the popup menu entries +comes from. + +If there is a `keymap' property at point then relevant bindings +from this is also shown in the popup menu. + +You can write functions that use whatever information you want in +Emacs to construct these entries. Since this information is only +collected when the popup menu is shown you do not have to care as +much about computation time as for entries in the menu bar. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (as-external-mode as-external-for-wiki as-external-for-mail-mode +;;;;;; as-external-for-xhtml as-external) "as-external" "util/as-external.el" +;;;;;; (19292 49706)) +;;; Generated autoloads from util/as-external.el +(web-autoload-require 'as-external 'lp '(nxhtml-download-root-url nil) "util/as-external" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'as-external 'custom-loads))) (if (member '"as-external" loads) nil (put 'as-external 'custom-loads (cons '"as-external" loads)))) + +(nxhtml-autoload 'as-external-for-xhtml `(lp '(nxhtml-download-root-url nil) "util/as-external" nxhtml-install-dir) "\ +Setup for Firefox addon It's All Text to edit XHTML. +It's All Text is a Firefox add-on for editing textareas with an +external editor. +See URL `https://addons.mozilla.org/en-US/firefox/addon/4125'. + +In this case Emacs is used to edit textarea fields on a web page. +The text will most often be part of a web page later, like on a +blog. Therefore turn on these: + +- `nxhtml-mode' since some XHTML tags may be allowed. +- `nxhtml-validation-header-mode' since it is not a full page. +- `wrap-to-fill-column-mode' to see what you are writing. +- `html-write-mode' to see it even better. + +Also bypass the question for line end conversion when using +emacsw32-eol. + +\(fn)" t nil) + +(nxhtml-autoload 'as-external-for-mail-mode `(lp '(nxhtml-download-root-url nil) "util/as-external" nxhtml-install-dir) "\ +Setup for Firefox addon It's All Text to edit mail. +Set normal mail comment markers in column 1 (ie >). + +Set `fill-column' to 90 and enable `wrap-to-fill-column-mode' so +that it will look similar to how it will look in the sent plain +text mail. + +See also `as-external-mode'. + +\(fn)" t nil) + +(nxhtml-autoload 'as-external-for-wiki `(lp '(nxhtml-download-root-url nil) "util/as-external" nxhtml-install-dir) "\ +Setup for Firefox addon It's All Text to edit MediaWikis. + +\(fn)" t nil) + +(defvar as-external-mode nil "\ +Non-nil if As-External mode is enabled. +See the command `as-external-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `as-external-mode'.") + +(nxhtml-custom-autoload 'as-external-mode 'as-external nil) + +(nxhtml-autoload 'as-external-mode `(lp '(nxhtml-download-root-url nil) "util/as-external" nxhtml-install-dir) "\ +If non-nil check if Emacs is called as external editor. +When Emacs is called as an external editor for example to edit +text areas on a web page viewed with Firefox this library tries +to help to setup the buffer in a useful way. It may for example +set major and minor modes for the buffer. + +This can for example be useful when blogging or writing comments +on blogs. + +See `as-external-alist' for more information. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (buffer-bg-set-color) "buffer-bg" "util/buffer-bg.el" +;;;;;; (19254 64104)) +;;; Generated autoloads from util/buffer-bg.el +(web-autoload-require 'buffer-bg 'lp '(nxhtml-download-root-url nil) "util/buffer-bg" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'buffer-bg-set-color `(lp '(nxhtml-download-root-url nil) "util/buffer-bg" nxhtml-install-dir) "\ +Add an overlay with background color COLOR to buffer BUFFER. +If COLOR is nil remove previously added overlay. + +\(fn COLOR BUFFER)" t nil) + +;;;*** + +;;;### (autoloads (chartg-make-chart chartg-complete) "chartg" "util/chartg.el" +;;;;;; (19278 15746)) +;;; Generated autoloads from util/chartg.el +(web-autoload-require 'chartg 'lp '(nxhtml-download-root-url nil) "util/chartg" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'chartg-complete `(lp '(nxhtml-download-root-url nil) "util/chartg" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'chartg-make-chart `(lp '(nxhtml-download-root-url nil) "util/chartg" nxhtml-install-dir) "\ +Try to make a new chart. +If region is active then make a new chart from data in the +selected region. + +Else if current buffer is in `chartg-mode' then do it from the +chart specifications in this buffer. Otherwise create a new +buffer and initialize it with `chartg-mode'. + +If the chart specifications are complete enough to make a chart +then do it and show the resulting chart image. If not then tell +user what is missing. + +NOTE: This is beta, no alpha code. It is not ready. + +Below are some examples. To test them mark an example and do + + M-x chartg-make-chart + +* Example, simple x-y chart: + + Output-file: \"~/temp-chart.png\" + Size: 200 200 + Data: 3 8 5 | 10 20 30 + Type: line-chartg-xy + +* Example, pie: + + Output-file: \"~/temp-depression.png\" + Size: 400 200 + Data: + 2,160,000 + 3,110,000 + 1,510,000 + 73,600 + 775,000 + 726,000 + 8,180,000 + 419,000 + Type: pie-3-dimensional + Chartg-title: \"Depression hits on Google\" + Legends: + \"SSRI\" + | \"Psychotherapy\" + | \"CBT\" + | \"IPT\" + | \"Psychoanalysis\" + | \"Mindfulness\" + | \"Meditation\" + | \"Exercise\" + + +* Example, pie: + + Output-file: \"~/temp-panic.png\" + Size: 400 200 + Data: + 979,000 + 969,000 + 500,000 + 71,900 + 193,000 + 154,000 + 2,500,000 + 9,310,000 + Type: pie-3-dimensional + Chartg-title: \"Depression hits on Google\" + Legends: + \"SSRI\" + | \"Psychotherapy\" + | \"CBT\" + | \"IPT\" + | \"Psychoanalysis\" + | \"Mindfulness\" + | \"Meditation\" + | \"Exercise\" + + +* Example using raw: + + Output-file: \"~/temp-chartg-slipsen-kostar.png\" + Size: 400 130 + Data: 300 1000 30000 + Type: bar-chartg-horizontal + Chartg-title: \"Vad killen i slips tjänar jämfört med dig och mig\" + Google-chartg-raw: \"&chds=0,30000&chco=00cd00|ff4500|483d8b&chxt=y,x&chxl=0:|Killen+i+slips|Partiledarna|Du+och+jag&chf=bg,s,ffd700\" + + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (css-color-test css-color-global-mode css-color-mode +;;;;;; css-color) "css-color" "util/css-color.el" (19386 34254)) +;;; Generated autoloads from util/css-color.el +(web-autoload-require 'css-color 'lp '(nxhtml-download-root-url nil) "util/css-color" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'css-color 'custom-loads))) (if (member '"css-color" loads) nil (put 'css-color 'custom-loads (cons '"css-color" loads)))) + +(nxhtml-autoload 'css-color-mode `(lp '(nxhtml-download-root-url nil) "util/css-color" nxhtml-install-dir) "\ +Show hex color literals with the given color as background. +In this mode hexadecimal colour specifications like #6600ff are +displayed with the specified colour as background. + +Certain keys are bound to special colour editing commands when +point is at a hexadecimal colour: + +\\{css-color-map} + +\(fn &optional ARG)" t nil) + +(defvar css-color-global-mode nil "\ +Non-nil if Css-Color-Global mode is enabled. +See the command `css-color-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `css-color-global-mode'.") + +(nxhtml-custom-autoload 'css-color-global-mode 'css-color nil) + +(nxhtml-autoload 'css-color-global-mode `(lp '(nxhtml-download-root-url nil) "util/css-color" nxhtml-install-dir) "\ +Toggle Css-Color mode in every possible buffer. +With prefix ARG, turn Css-Color-Global mode on if and only if +ARG is positive. +Css-Color mode is enabled in all buffers where +`css-color-turn-on-in-buffer' would do it. +See `css-color-mode' for more information on Css-Color mode. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'css-color-test `(lp '(nxhtml-download-root-url nil) "util/css-color" nxhtml-install-dir) "\ +Test colors interactively. +The colors are displayed in the echo area. You can specify the +colors as any viable css color. Example: + + red + #f00 + #0C0 + #b0ff00 + hsla(100, 50%, 25%) + rgb(255,100,120) + +\(fn FG-COLOR BG-COLOR)" t nil) + +;;;*** + +;;;### (autoloads (css-palette-global-mode css-palette css-palette-mode) +;;;;;; "css-palette" "util/css-palette.el" (19235 1650)) +;;; Generated autoloads from util/css-palette.el +(web-autoload-require 'css-palette 'lp '(nxhtml-download-root-url nil) "util/css-palette" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'css-palette-mode `(lp '(nxhtml-download-root-url nil) "util/css-palette" nxhtml-install-dir) "\ +Minor mode for palettes in CSS. + +The mode `css-palette-mode' acts on the first COLORS declaration in your + file of the form: + +COLORS: +\( +c0 \"#6f5d25\" ;tainted sand +c1 \"#000000\" ;Black +c2 \"#cca42b\" ;goldenslumber +c3 \"#6889cb\" ;far off sky +c4 \"#fff\" ;strange aeons +) + +Such declarations should appear inside a block comment, in order + to be parsed properly by the LISP reader. + +Type \\[css-palette-update-all], and any occurence of + + color: #f55; /*[c3]*/ + +will be updated with + + color: #6899cb; /*[c3]*/ + +The following commands are available to insert key-value pairs + and palette declarations: + \\{css-palette-mode-map} + +You can extend or redefine the types of palettes by defining a + new palette specification of the form (PATTERN REGEXP + REF-FOLLOWS-VALUE), named according to the naming scheme + css-palette:my-type, where + +PATTERN is a pattern containing two (%s) format directives which + will be filled in with the variable and its value, + +REGEXP is a regular expression to match a value - variable + pattern, + +and REF-FOLLOWS-VALUE defined whether or not the reference comes + after the value. This allows for more flexibility. + +Note that, although the w3c spec at URL + `http://www.w3.org/TR/CSS2/syndata.html#comments' says that + comments \" may occur anywhere between tokens, and their + contents have no influence on the rendering\", Internet + Explorer does not think so. Better keep all your comments after + a \"statement\", as per the default. This means `css-palette' + is ill-suited for use within shorthands. + +See variable `css-palette:colors' for an example of a palette + type. + +The extension mechanism means that palette types can be used to + contain arbitrary key-value mappings. + +Besides the colors palette, css-palette defines the palette + definition variables `css-palette:colors-outside' and + `css-palette:files', for colors with the reference outside and + for file url()'s respectively. + +You can fine-control which palette types css-palette should look + at via the variable `css-palette-types'. + +\(fn &optional ARG)" t nil) + +(let ((loads (get 'css-palette 'custom-loads))) (if (member '"css-palette" loads) nil (put 'css-palette 'custom-loads (cons '"css-palette" loads)))) + +(defvar css-palette-global-mode nil "\ +Non-nil if Css-Palette-Global mode is enabled. +See the command `css-palette-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `css-palette-global-mode'.") + +(nxhtml-custom-autoload 'css-palette-global-mode 'css-palette nil) + +(nxhtml-autoload 'css-palette-global-mode `(lp '(nxhtml-download-root-url nil) "util/css-palette" nxhtml-install-dir) "\ +Toggle Css-Palette mode in every possible buffer. +With prefix ARG, turn Css-Palette-Global mode on if and only if +ARG is positive. +Css-Palette mode is enabled in all buffers where +`css-palette-turn-on-in-buffer' would do it. +See `css-palette-mode' for more information on Css-Palette mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (cusnu-export-my-skin-options customize-for-new-user) +;;;;;; "cus-new-user" "util/cus-new-user.el" (19173 56140)) +;;; Generated autoloads from util/cus-new-user.el +(web-autoload-require 'cus-new-user 'lp '(nxhtml-download-root-url nil) "util/cus-new-user" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'customize-for-new-user `(lp '(nxhtml-download-root-url nil) "util/cus-new-user" nxhtml-install-dir) "\ +Show special customization page for new user. + +\(fn &optional NAME)" t nil) + +(nxhtml-autoload 'cusnu-export-my-skin-options `(lp '(nxhtml-download-root-url nil) "util/cus-new-user" nxhtml-install-dir) "\ +Export to file FILE custom options in `cusnu-my-skin-options'. +The options is exported to elisp code that other users can run to +set the options that you have added to `cusnu-my-skin-options'. + +For more information about this see `cusnu-export-cust-group'. + +\(fn FILE)" t nil) + +;;;*** + +;;;### (autoloads (ediff-url) "ediff-url" "util/ediff-url.el" (19362 +;;;;;; 34258)) +;;; Generated autoloads from util/ediff-url.el +(web-autoload-require 'ediff-url 'lp '(nxhtml-download-root-url nil) "util/ediff-url" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'ediff-url `(lp '(nxhtml-download-root-url nil) "util/ediff-url" nxhtml-install-dir) "\ +Compare current buffer to a web URL using `ediff-buffers'. +Check URL using `ediff-url-redirects' before fetching the file. + +This is for checking downloaded file. A the file may have a comment +telling the download URL of thise form in the header: + + ;; URL: http://the-server.net/the-path/the-file.el + +If not the user is asked for the URL. + +\(fn URL)" t nil) + +;;;*** + +;;;### (autoloads (ffip-find-file-in-dirtree ffip-set-current-project) +;;;;;; "ffip" "util/ffip.el" (19257 25432)) +;;; Generated autoloads from util/ffip.el +(web-autoload-require 'ffip 'lp '(nxhtml-download-root-url nil) "util/ffip" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'ffip-set-current-project `(lp '(nxhtml-download-root-url nil) "util/ffip" nxhtml-install-dir) "\ +Setup ffip project NAME with top directory ROOT of type TYPE. +ROOT can either be just a directory or a list of directory where +the first used just for prompting purposes and the files in the +rest are read into the ffip project. + +Type is a type in `ffip-project-file-types'. + +\(fn NAME ROOT TYPE)" nil nil) + +(nxhtml-autoload 'ffip-find-file-in-dirtree `(lp '(nxhtml-download-root-url nil) "util/ffip" nxhtml-install-dir) "\ +Find files in directory tree ROOT. + +\(fn ROOT)" t nil) + +;;;*** + +;;;### (autoloads (fold-dwim-turn-on-outline-and-hide-all fold-dwim-turn-on-hs-and-hide +;;;;;; fold-dwim-unhide-hs-and-outline fold-dwim-mode fold-dwim-toggle +;;;;;; fold-dwim) "fold-dwim" "util/fold-dwim.el" (19218 42180)) +;;; Generated autoloads from util/fold-dwim.el +(web-autoload-require 'fold-dwim 'lp '(nxhtml-download-root-url nil) "util/fold-dwim" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'fold-dwim 'custom-loads))) (if (member '"fold-dwim" loads) nil (put 'fold-dwim 'custom-loads (cons '"fold-dwim" loads)))) + +(nxhtml-autoload 'fold-dwim-toggle `(lp '(nxhtml-download-root-url nil) "util/fold-dwim" nxhtml-install-dir) "\ +Toggle visibility or some other visual things. +Try toggling different visual things in this order: + +- Images shown at point with `inlimg-mode' +- Text at point prettified by `html-write-mode'. + +For the rest it unhides if possible, otherwise hides in this +order: + +- `org-mode' header or something else using that outlines. +- Maybe `fold-dwim-toggle-selective-display'. +- `Tex-fold-mode' things. +- In html if `outline-minor-mode' and after heading hide content. +- `hs-minor-mode' things. +- `outline-minor-mode' things. (Turns maybe on this.) + +It uses `fold-dwim-show' to show any hidden text at point; if no +hidden fold is found, try `fold-dwim-hide' to hide the +construction at the cursor. + +Note: Also first turn on `fold-dwim-mode' to get the keybinding +for this function from it. + +\(fn)" t nil) + +(defvar fold-dwim-mode nil "\ +Non-nil if Fold-Dwim mode is enabled. +See the command `fold-dwim-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `fold-dwim-mode'.") + +(nxhtml-custom-autoload 'fold-dwim-mode 'fold-dwim nil) + +(nxhtml-autoload 'fold-dwim-mode `(lp '(nxhtml-download-root-url nil) "util/fold-dwim" nxhtml-install-dir) "\ +Key binding for `fold-dwim-toggle'. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'fold-dwim-unhide-hs-and-outline `(lp '(nxhtml-download-root-url nil) "util/fold-dwim" nxhtml-install-dir) "\ +Unhide everything hidden by Hide/Show and Outline. +Ie everything hidden by `hs-minor-mode' and +`outline-minor-mode'. + +\(fn)" t nil) + +(nxhtml-autoload 'fold-dwim-turn-on-hs-and-hide `(lp '(nxhtml-download-root-url nil) "util/fold-dwim" nxhtml-install-dir) "\ +Turn on minor mode `hs-minor-mode' and hide. +If major mode is derived from `nxml-mode' call `hs-hide-block' +else call `hs-hide-all'. + +\(fn)" t nil) + +(nxhtml-autoload 'fold-dwim-turn-on-outline-and-hide-all `(lp '(nxhtml-download-root-url nil) "util/fold-dwim" nxhtml-install-dir) "\ +Turn on `outline-minor-mode' and call `hide-body'. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (foldit-global-mode foldit-mode foldit) "foldit" +;;;;;; "util/foldit.el" (19275 63380)) +;;; Generated autoloads from util/foldit.el +(web-autoload-require 'foldit 'lp '(nxhtml-download-root-url nil) "util/foldit" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'foldit 'custom-loads))) (if (member '"foldit" loads) nil (put 'foldit 'custom-loads (cons '"foldit" loads)))) + +(nxhtml-autoload 'foldit-mode `(lp '(nxhtml-download-root-url nil) "util/foldit" nxhtml-install-dir) "\ +Minor mode providing visual aids for folding. +Shows some hints about what you have hidden and how to reveal it. + +Supports `hs-minor-mode', `outline-minor-mode' and major modes +derived from `outline-mode'. + +\(fn &optional ARG)" t nil) + +(defvar foldit-global-mode nil "\ +Non-nil if Foldit-Global mode is enabled. +See the command `foldit-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `foldit-global-mode'.") + +(nxhtml-custom-autoload 'foldit-global-mode 'foldit nil) + +(nxhtml-autoload 'foldit-global-mode `(lp '(nxhtml-download-root-url nil) "util/foldit" nxhtml-install-dir) "\ +Toggle Foldit mode in every possible buffer. +With prefix ARG, turn Foldit-Global mode on if and only if +ARG is positive. +Foldit mode is enabled in all buffers where +`(lambda nil (foldit-mode 1))' would do it. +See `foldit-mode' for more information on Foldit mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (gimpedit-can-edit gimpedit-edit-buffer gimpedit-edit-file +;;;;;; gimpedit) "gimpedit" "util/gimpedit.el" (19275 63380)) +;;; Generated autoloads from util/gimpedit.el +(web-autoload-require 'gimpedit 'lp '(nxhtml-download-root-url nil) "util/gimpedit" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'gimpedit 'custom-loads))) (if (member '"gimpedit" loads) nil (put 'gimpedit 'custom-loads (cons '"gimpedit" loads)))) + +(nxhtml-autoload 'gimpedit-edit-file `(lp '(nxhtml-download-root-url nil) "util/gimpedit" nxhtml-install-dir) "\ +Edit IMAGE-FILE with GIMP. +See also `gimpedit-edit-file'. + +\(fn IMAGE-FILE &optional EXTRA-ARGS)" t nil) + +(nxhtml-autoload 'gimpedit-edit-buffer `(lp '(nxhtml-download-root-url nil) "util/gimpedit" nxhtml-install-dir) "\ +Edit image file in current buffer with GIMP. +See also `gimpedit-edit-file'. + +You may also be interested in gimpedit-mode with which you can edit +gimp files from within Emacs using GIMP's scripting +possibilities. See + + URL `http://www.emacswiki.org/emacs/GimpMode' + +\(fn)" t nil) + +(nxhtml-autoload 'gimpedit-can-edit `(lp '(nxhtml-download-root-url nil) "util/gimpedit" nxhtml-install-dir) "\ +Not documented + +\(fn FILE-NAME)" nil nil) + +;;;*** + +;;;### (autoloads (gpl-mode) "gpl" "util/gpl.el" (18795 27308)) +;;; Generated autoloads from util/gpl.el +(web-autoload-require 'gpl 'lp '(nxhtml-download-root-url nil) "util/gpl" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'gpl-mode `(lp '(nxhtml-download-root-url nil) "util/gpl" nxhtml-install-dir) "\ +Mode for font-locking and editing color palettes of the GPL format. + +Such palettes are used and produced by free software applications +such as the GIMP, Inkscape, Scribus, Agave and on-line tools such +as http://colourlovers.com. + +You can also use +URL `http://niels.kicks-ass.org/public/elisp/css-palette.el' to import +such palette into a css-file as hexadecimal color palette. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (hfyview-frame hfyview-window hfyview-region hfyview-buffer +;;;;;; hfyview-quick-print-in-files-menu) "hfyview" "util/hfyview.el" +;;;;;; (19400 17335)) +;;; Generated autoloads from util/hfyview.el +(web-autoload-require 'hfyview 'lp '(nxhtml-download-root-url nil) "util/hfyview" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(defvar hfyview-quick-print-in-files-menu nil "\ +Add Quick print entries to File menu if non-nil. +If you set this to nil you have to restart Emacs to get rid of +the Quick Print entry.") + +(nxhtml-custom-autoload 'hfyview-quick-print-in-files-menu 'hfyview nil) + +(nxhtml-autoload 'hfyview-buffer `(lp '(nxhtml-download-root-url nil) "util/hfyview" nxhtml-install-dir) "\ +Convert buffer to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window. + +\(fn ARG)" t nil) + +(nxhtml-autoload 'hfyview-region `(lp '(nxhtml-download-root-url nil) "util/hfyview" nxhtml-install-dir) "\ +Convert region to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window. + +\(fn ARG)" t nil) + +(nxhtml-autoload 'hfyview-window `(lp '(nxhtml-download-root-url nil) "util/hfyview" nxhtml-install-dir) "\ +Convert window to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window. + +\(fn ARG)" t nil) + +(nxhtml-autoload 'hfyview-frame `(lp '(nxhtml-download-root-url nil) "util/hfyview" nxhtml-install-dir) "\ +Convert frame to html preserving faces and show in web browser. +Make an XHTML view of the current Emacs frame. Put it in a buffer +named *hfyview-frame* and show that buffer in a web browser. + +If WHOLE-BUFFERS is non-nil then the whole content of the buffers +is shown in the XHTML page, otherwise just the part that is +visible currently on the frame. + +If you turn on the minor mode `hfyview-frame-mode' you can also +get the minibuffer/echo area in the output. See this mode for +details. + +With command prefix also show html source in other window. + +\(fn WHOLE-BUFFERS)" t nil) + +;;;*** + +;;;### (autoloads (hl-needed-mode hl-needed) "hl-needed" "util/hl-needed.el" +;;;;;; (19394 16942)) +;;; Generated autoloads from util/hl-needed.el +(web-autoload-require 'hl-needed 'lp '(nxhtml-download-root-url nil) "util/hl-needed" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'hl-needed 'custom-loads))) (if (member '"hl-needed" loads) nil (put 'hl-needed 'custom-loads (cons '"hl-needed" loads)))) + +(defvar hl-needed-mode nil "\ +Non-nil if Hl-Needed mode is enabled. +See the command `hl-needed-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `hl-needed-mode'.") + +(nxhtml-custom-autoload 'hl-needed-mode 'hl-needed nil) + +(nxhtml-autoload 'hl-needed-mode `(lp '(nxhtml-download-root-url nil) "util/hl-needed" nxhtml-install-dir) "\ +Try to highlight current line and column when needed. +This is a global minor mode. It can operate in some different +ways: + +- Highlighting can be on always, see `hl-needed-always'. + +Or, it can be turned on depending on some conditions. In this +case highlighting is turned off after each command and turned on +again in the current window when either: + +- A new window was selected, see `hl-needed-on-new-window'. +- A new buffer was selected, see `hl-needed-on-new-buffer'. +- Window configuration was changed, see `hl-needed-on-config-change'. +- Buffer was scrolled see `hl-needed-on-scrolling'. +- A window was clicked with the mouse, see `hl-needed-on-mouse'. + +After this highlighting may be turned off again, normally after a +short delay, see `hl-needed-flash'. + +If either highlighting was not turned on or was turned off again +it will be turned on when + +- Emacs has been idle for `hl-needed-idle-time' seconds. + +See also `hl-needed-not-in-modes' and `hl-needed-currently-fun'. + +Note 1: For columns to be highlighted vline.el must be available. + +Note 2: This mode depends on `hl-line-mode' and `vline-mode' and +tries to cooperate with them. If you turn on either of these that +overrides the variables for turning on the respective +highlighting here. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (html-write-mode html-write) "html-write" "util/html-write.el" +;;;;;; (19275 63380)) +;;; Generated autoloads from util/html-write.el +(web-autoload-require 'html-write 'lp '(nxhtml-download-root-url nil) "util/html-write" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'html-write 'custom-loads))) (if (member '"html-write" loads) nil (put 'html-write 'custom-loads (cons '"html-write" loads)))) + +(nxhtml-autoload 'html-write-mode `(lp '(nxhtml-download-root-url nil) "util/html-write" nxhtml-install-dir) "\ +Minor mode for convenient display of some HTML tags. +When this mode is on a tag in `html-write-tag-list' is displayed as +the inner text of the tag with a face corresponding to the tag. +By default for example <i>...</i> is displayed as italic and +<a>...</a> is displayed as an underlined clickable link. + +Only non-nested tags are hidden. The idea is just that it should +be easier to read and write, not that it should look as html +rendered text. + +See the customization group `html-write' for more information about +faces. + +The following keys are defined when you are on a tag handled by +this minor mode: + +\\{html-write-keymap} + +IMPORTANT: Most commands you use works also on the text that is +hidden. The movement commands is an exception, but as soon as +you edit the buffer you may also change the hidden parts. + +Hint: Together with `wrap-to-fill-column-mode' this can make it +easier to see what text you are actually writing in html parts of +a web file. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (inlimg-toggle-slicing inlimg-toggle-display inlimg-global-mode +;;;;;; inlimg-mode inlimg) "inlimg" "util/inlimg.el" (19269 33008)) +;;; Generated autoloads from util/inlimg.el +(web-autoload-require 'inlimg 'lp '(nxhtml-download-root-url nil) "util/inlimg" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'inlimg 'custom-loads))) (if (member '"inlimg" loads) nil (put 'inlimg 'custom-loads (cons '"inlimg" loads)))) + +(nxhtml-autoload 'inlimg-mode `(lp '(nxhtml-download-root-url nil) "util/inlimg" nxhtml-install-dir) "\ +Display images inline. +Search buffer for image tags. Display found images. + +Image tags are setup per major mode in `inlimg-mode-specs'. + +Images are displayed on a line below the tag referencing them. +The whole image or a slice of it may be displayed, see +`inlimg-slice'. Margins relative text are specified in +`inlimg-margins'. + +See also the commands `inlimg-toggle-display' and +`inlimg-toggle-slicing'. + +Note: This minor mode uses `font-lock-mode'. + +\(fn &optional ARG)" t nil) + +(defvar inlimg-global-mode nil "\ +Non-nil if Inlimg-Global mode is enabled. +See the command `inlimg-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `inlimg-global-mode'.") + +(nxhtml-custom-autoload 'inlimg-global-mode 'inlimg nil) + +(nxhtml-autoload 'inlimg-global-mode `(lp '(nxhtml-download-root-url nil) "util/inlimg" nxhtml-install-dir) "\ +Toggle Inlimg mode in every possible buffer. +With prefix ARG, turn Inlimg-Global mode on if and only if +ARG is positive. +Inlimg mode is enabled in all buffers where +`inlimg--global-turn-on' would do it. +See `inlimg-mode' for more information on Inlimg mode. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'inlimg-toggle-display `(lp '(nxhtml-download-root-url nil) "util/inlimg" nxhtml-install-dir) "\ +Toggle display of image at point POINT. +See also the command `inlimg-mode'. + +\(fn POINT)" t nil) + +(nxhtml-autoload 'inlimg-toggle-slicing `(lp '(nxhtml-download-root-url nil) "util/inlimg" nxhtml-install-dir) "\ +Toggle slicing of image at point POINT. +See also the command `inlimg-mode'. + +\(fn POINT)" t nil) + +;;;*** + +;;;### (autoloads (majmodpri majmodpri-apply-priorities majmodpri-apply +;;;;;; majmodpri-sort-lists) "majmodpri" "util/majmodpri.el" (19407 +;;;;;; 18407)) +;;; Generated autoloads from util/majmodpri.el +(web-autoload-require 'majmodpri 'lp '(nxhtml-download-root-url nil) "util/majmodpri" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'majmodpri-sort-lists `(lp '(nxhtml-download-root-url nil) "util/majmodpri" nxhtml-install-dir) "\ +Sort the list used when selecting major mode. +Only sort those lists choosen in `majmodpri-lists-to-sort'. +Sort according to priorities in `majmodpri-mode-priorities'. +Keep the old order in the list otherwise. + +The lists can be sorted when loading elisp libraries, see +`majmodpri-sort-after-load'. + +See also `majmodpri-apply-priorities'. + +\(fn)" t nil) + +(nxhtml-autoload 'majmodpri-apply `(lp '(nxhtml-download-root-url nil) "util/majmodpri" nxhtml-install-dir) "\ +Sort major mode lists and apply to existing buffers. +Note: This function is suitable to add to +`desktop-after-read-hook'. It will restore the multi major modes +in buffers. + +\(fn)" nil nil) + +(nxhtml-autoload 'majmodpri-apply-priorities `(lp '(nxhtml-download-root-url nil) "util/majmodpri" nxhtml-install-dir) "\ +Apply major mode priorities. +First run `majmodpri-sort-lists' and then if CHANGE-MODES is +non-nil apply to existing file buffers. If interactive ask +before applying. + +\(fn CHANGE-MODES)" t nil) + +(let ((loads (get 'majmodpri 'custom-loads))) (if (member '"majmodpri" loads) nil (put 'majmodpri 'custom-loads (cons '"majmodpri" loads)))) + +;;;*** + +;;;### (autoloads (markchars-global-mode markchars-mode markchars) +;;;;;; "markchars" "util/markchars.el" (19372 5886)) +;;; Generated autoloads from util/markchars.el +(web-autoload-require 'markchars 'lp '(nxhtml-download-root-url nil) "util/markchars" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'markchars 'custom-loads))) (if (member '"markchars" loads) nil (put 'markchars 'custom-loads (cons '"markchars" loads)))) + +(nxhtml-autoload 'markchars-mode `(lp '(nxhtml-download-root-url nil) "util/markchars" nxhtml-install-dir) "\ +Mark special characters. +Which characters to mark are defined by `markchars-keywords'. + +The default is to mark non-IDN, non-ascii chars with a magenta +underline. + +For information about IDN chars see `idn-is-recommended'. + +If you change anything in the customization group `markchars' you +must restart this minor mode for the changes to take effect. + +\(fn &optional ARG)" t nil) + +(defvar markchars-global-mode nil "\ +Non-nil if Markchars-Global mode is enabled. +See the command `markchars-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `markchars-global-mode'.") + +(nxhtml-custom-autoload 'markchars-global-mode 'markchars nil) + +(nxhtml-autoload 'markchars-global-mode `(lp '(nxhtml-download-root-url nil) "util/markchars" nxhtml-install-dir) "\ +Toggle Markchars mode in every possible buffer. +With prefix ARG, turn Markchars-Global mode on if and only if +ARG is positive. +Markchars mode is enabled in all buffers where +`(lambda nil (markchars-mode 1))' would do it. +See `markchars-mode' for more information on Markchars mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (mlinks-global-mode mlinks-mode mlinks) "mlinks" +;;;;;; "util/mlinks.el" (19364 56214)) +;;; Generated autoloads from util/mlinks.el +(web-autoload-require 'mlinks 'lp '(nxhtml-download-root-url nil) "util/mlinks" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'mlinks 'custom-loads))) (if (member '"mlinks" loads) nil (put 'mlinks 'custom-loads (cons '"mlinks" loads)))) + +(nxhtml-autoload 'mlinks-mode `(lp '(nxhtml-download-root-url nil) "util/mlinks" nxhtml-install-dir) "\ +Recognizes certain parts of a buffer as hyperlinks. +The hyperlinks are created in different ways for different major +modes with the help of the functions in the list +`mlinks-mode-functions'. + +The hyperlinks can be hilighted when point is over them. Use +`mlinks-toggle-hilight' to toggle this feature for the current +buffer. + +All keybindings in this mode are by default done under the prefi§x +key + + C-c RET + +which is supposed to be a kind of mnemonic for link (alluding to +the RET key commonly used in web browser to follow a link). +\(Unfortunately this breaks the rules in info node `Key Binding +Conventions'.) Below are the key bindings defined by this mode: + +\\{mlinks-mode-map} + +For some major modes `mlinks-backward-link' and +`mlinks-forward-link' will take you to the previous/next link. +By default the link moved to will be active, see +`mlinks-active-links'. + +\(fn &optional ARG)" t nil) + +(defvar mlinks-global-mode nil "\ +Non-nil if Mlinks-Global mode is enabled. +See the command `mlinks-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `mlinks-global-mode'.") + +(nxhtml-custom-autoload 'mlinks-global-mode 'mlinks nil) + +(nxhtml-autoload 'mlinks-global-mode `(lp '(nxhtml-download-root-url nil) "util/mlinks" nxhtml-install-dir) "\ +Toggle Mlinks mode in every possible buffer. +With prefix ARG, turn Mlinks-Global mode on if and only if +ARG is positive. +Mlinks mode is enabled in all buffers where +`mlinks-turn-on-in-buffer' would do it. +See `mlinks-mode' for more information on Mlinks mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (mumamo-multi-major-modep mumamo-list-defined-multi-major-modes +;;;;;; mumamo-mark-for-refontification mumamo-hi-lock-faces mumamo +;;;;;; mumamo-add-to-defined-multi-major-modes define-mumamo-multi-major-mode) +;;;;;; "mumamo" "util/mumamo.el" (19412 26290)) +;;; Generated autoloads from util/mumamo.el +(web-autoload-require 'mumamo 'lp '(nxhtml-download-root-url nil) "util/mumamo" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'define-mumamo-multi-major-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo" nxhtml-install-dir) "\ +Define a function that turn on support for multiple major modes. +Define a function FUN-SYM that set up to divide the current +buffer into chunks with different major modes. + +The documentation string for FUN-SYM should contain the special +documentation in the string SPEC-DOC, general documentation for +functions of this type and information about chunks. + +The new function will use the definitions in CHUNKS (which is +called a \"chunk family\") to make the dividing of the buffer. + +The function FUN-SYM can be used to setup a buffer instead of a +major mode function: + +- The function FUN-SYM can be called instead of calling a major + mode function when you want to use multiple major modes in a + buffer. + +- The defined function can be used instead of a major mode + function in for example `auto-mode-alist'. + +- As the very last thing FUN-SYM will run the hook FUN-SYM-hook, + just as major modes do. + +- There is also a general hook, `mumamo-turn-on-hook', which is + run when turning on mumamo with any of these functions. This + is run right before the hook specific to any of the functions + above that turns on the multiple major mode support. + +- The multi major mode FUN-SYM has a keymap named FUN-SYM-map. + This overrides the major modes' keymaps since it is handled as + a minor mode keymap. + +- There is also a special mumamo keymap, `mumamo-map' that is + active in every buffer with a multi major mode. This is also + handled as a minor mode keymap and therefor overrides the major + modes' keymaps. + +- However when this support for multiple major mode is on the + buffer is divided into chunks, each with its own major mode. + +- The chunks are fontified according the major mode assigned to + them for that. + +- Indenting is also done according to the major mode assigned to + them for that. + +- The actual major mode used in the buffer is changed to the one + in the chunk when moving point between these chunks. + +- When major mode is changed the hooks for the new major mode, + `after-change-major-mode-hook' and `change-major-mode-hook' are + run. + +- There will be an alias for FUN-SYM called mumamo-alias-FUN-SYM. + This can be used to check whic multi major modes have been + defined. + +** A little bit more technical description: + +The dividing of a buffer into chunks is done during fontification +by `mumamo-get-chunk-at'. + +The name of the function is saved in in the buffer local variable +`mumamo-multi-major-mode' when the function is called. + +All functions defined by this macro is added to the list +`mumamo-defined-multi-major-modes'. + +Basically Mumamo handles only major modes that uses jit-lock. +However as a special effort also `nxml-mode' and derivatives +thereof are handled. Since it seems impossible to me to restrict +those major modes fontification to only a chunk without changing +`nxml-mode' the fontification is instead done by +`html-mode'/`sgml-mode' for chunks using `nxml-mode' and its +derivates. + +CHUNKS is a list where each entry have the format + + (CHUNK-DEF-NAME MAIN-MAJOR-MODE SUBMODE-CHUNK-FUNCTIONS) + +CHUNK-DEF-NAME is the key name by which the entry is recognized. +MAIN-MAJOR-MODE is the major mode used when there is no chunks. +If this is nil then `major-mode' before turning on this mode will +be used. + +SUBMODE-CHUNK-FUNCTIONS is a list of the functions that does the +chunk division of the buffer. They are tried in the order they +appear here during the chunk division process. + +If you want to write new functions for chunk divisions then +please see `mumamo-find-possible-chunk'. You can perhaps also +use `mumamo-quick-static-chunk' which is more easy-to-use +alternative. See also the file mumamo-fun.el where there are +many routines for chunk division. + +When you write those new functions you may want to use some of +the functions for testing chunks: + + `mumamo-test-create-chunk-at' `mumamo-test-create-chunks-at-all' + `mumamo-test-easy-make' `mumamo-test-fontify-region' + +These are in the file mumamo-test.el. + +\(fn FUN-SYM SPEC-DOC CHUNKS)" nil (quote macro)) + +(nxhtml-autoload 'mumamo-add-to-defined-multi-major-modes `(lp '(nxhtml-download-root-url nil) "util/mumamo" nxhtml-install-dir) "\ +Not documented + +\(fn ENTRY)" nil nil) + +(let ((loads (get 'mumamo 'custom-loads))) (if (member '"mumamo" loads) nil (put 'mumamo 'custom-loads (cons '"mumamo" loads)))) + +(let ((loads (get 'mumamo-hi-lock-faces 'custom-loads))) (if (member '"mumamo" loads) nil (put 'mumamo-hi-lock-faces 'custom-loads (cons '"mumamo" loads)))) + +(nxhtml-autoload 'mumamo-mark-for-refontification `(lp '(nxhtml-download-root-url nil) "util/mumamo" nxhtml-install-dir) "\ +Mark region between MIN and MAX for refontification. + +\(fn MIN MAX)" nil nil) + +(nxhtml-autoload 'mumamo-list-defined-multi-major-modes `(lp '(nxhtml-download-root-url nil) "util/mumamo" nxhtml-install-dir) "\ +List currently defined multi major modes. +If SHOW-DOC is non-nil show the doc strings added when defining +them. (This is not the full doc string. To show the full doc +string you can click on the multi major mode in the list.) + +If SHOW-CHUNKS is non-nil show the names of the chunk dividing +functions each multi major mode uses. + +If MATCH then show only multi major modes whos names matches. + +\(fn SHOW-DOC SHOW-CHUNKS MATCH)" t nil) + +(nxhtml-autoload 'mumamo-multi-major-modep `(lp '(nxhtml-download-root-url nil) "util/mumamo" nxhtml-install-dir) "\ +Return t if VALUE is a multi major mode function. + +\(fn VALUE)" nil nil) + +;;;*** + +;;;### (autoloads (python-rst-mumamo-mode latex-haskell-mumamo-mode +;;;;;; latex-clojure-mumamo-mode markdown-html-mumamo-mode xsl-sgml-mumamo-mode +;;;;;; xsl-nxml-mumamo-mode mako-html-mumamo-mode org-mumamo-mode +;;;;;; asp-html-mumamo-mode noweb2-mumamo-mode mumamo-noweb2 csound-sgml-mumamo-mode +;;;;;; laszlo-nxml-mumamo-mode metapost-mumamo-mode ruby-heredoc-mumamo-mode +;;;;;; python-heredoc-mumamo-mode cperl-heredoc-mumamo-mode perl-heredoc-mumamo-mode +;;;;;; php-heredoc-mumamo-mode sh-heredoc-mumamo-mode eruby-javascript-mumamo-mode +;;;;;; eruby-html-mumamo-mode eruby-mumamo-mode jsp-html-mumamo-mode +;;;;;; gsp-html-mumamo-mode ssjs-html-mumamo-mode smarty-html-mumamo-mode +;;;;;; mjt-html-mumamo-mode genshi-html-mumamo-mode django-html-mumamo-mode +;;;;;; embperl-html-mumamo-mode mason-html-mumamo-mode nxml-mumamo-mode +;;;;;; html-mumamo-mode mumamo-define-html-file-wide-keys) "mumamo-fun" +;;;;;; "util/mumamo-fun.el" (19410 22971)) +;;; Generated autoloads from util/mumamo-fun.el +(web-autoload-require 'mumamo-fun 'lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'mumamo-define-html-file-wide-keys `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Define keys in multi major mode keymap for html files. + +\(fn)" nil nil) + +(nxhtml-autoload 'html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for (X)HTML with main mode `html-mode'. +This covers inlined style and javascript and PHP." t) + +(nxhtml-autoload 'nxml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for (X)HTML with main mode `nxml-mode'. +This covers inlined style and javascript and PHP. + +See also `mumamo-alt-php-tags-mode'." t) + +(nxhtml-autoload 'mason-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Mason using main mode `html-mode'. +This covers inlined style and javascript." t) + +(nxhtml-autoload 'embperl-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Embperl files with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'django-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Django with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'genshi-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Genshi with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'mjt-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for MJT with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'smarty-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Smarty with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'ssjs-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for SSJS with main mode `html-mode'. +This covers inlined style and javascript." t) + +(nxhtml-autoload 'gsp-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for GSP with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'jsp-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for JSP with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'eruby-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major mode for eRuby with unspecified main mode. +Current major-mode will be used as the main major mode." t) + +(nxhtml-autoload 'eruby-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for eRuby with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'eruby-javascript-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for eRuby with main mode `javascript-mode'." t) + +(nxhtml-autoload 'sh-heredoc-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for sh heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." t) + +(nxhtml-autoload 'php-heredoc-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for PHP heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." t) + +(nxhtml-autoload 'perl-heredoc-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." t) + +(nxhtml-autoload 'cperl-heredoc-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." t) + +(nxhtml-autoload 'python-heredoc-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." t) + +(nxhtml-autoload 'ruby-heredoc-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Ruby heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." t) + +(nxhtml-autoload 'metapost-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for MetaPost." t) + +(nxhtml-autoload 'laszlo-nxml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for OpenLaszlo." t) + +(nxhtml-autoload 'csound-sgml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on mutiple major modes for CSound orc/sco Modes." t) + +(let ((loads (get 'mumamo-noweb2 'custom-loads))) (if (member '"mumamo-fun" loads) nil (put 'mumamo-noweb2 'custom-loads (cons '"mumamo-fun" loads)))) + +(nxhtml-autoload 'noweb2-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Multi major mode for noweb files." t) + +(nxhtml-autoload 'asp-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for ASP with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'org-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for `org-mode' files with main mode `org-mode'. +** Note about HTML subchunks: +Unfortunately this only allows `html-mode' (not `nxhtml-mode') in +sub chunks." t) + +(nxhtml-autoload 'mako-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Mako with main mode `html-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'xsl-nxml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multi major mode for XSL with main mode `nxml-mode'. +This covers inlined style and javascript." t) + +(nxhtml-autoload 'xsl-sgml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multi major mode for XSL with main mode `sgml-mode'. +This covers inlined style and javascript." t) + +(nxhtml-autoload 'markdown-html-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multi major markdown mode in buffer. +Main major mode will be `markdown-mode'. +Inlined html will be in `html-mode'. + +You need `markdown-mode' which you can download from URL +`http://jblevins.org/projects/markdown-mode/'." t) + +(nxhtml-autoload 'latex-clojure-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multi major mode latex+clojure. +Main major mode will be `latex-mode'. +Subchunks will be in `clojure-mode'. + +You will need `clojure-mode' which you can download from URL +`http://github.com/jochu/clojure-mode/tree'." t) + +(nxhtml-autoload 'latex-haskell-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multi major mode latex+haskell. +Main major mode will be `latex-mode'. +Subchunks will be in `haskell-mode'. + +You will need `haskell-mode' which you can download from URL +`http://projects.haskell.org/haskellmode-emacs/'." t) + +(nxhtml-autoload 'python-rst-mumamo-mode `(lp '(nxhtml-download-root-url nil) "util/mumamo-fun" nxhtml-install-dir) "\ +Turn on multiple major modes for Python with RestructuredText docstrings." t) + +;;;*** + +;;;### (autoloads (mumamo-add-region-from-string mumamo-add-region) +;;;;;; "mumamo-regions" "util/mumamo-regions.el" (19275 63380)) +;;; Generated autoloads from util/mumamo-regions.el +(web-autoload-require 'mumamo-regions 'lp '(nxhtml-download-root-url nil) "util/mumamo-regions" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'mumamo-add-region `(lp '(nxhtml-download-root-url nil) "util/mumamo-regions" nxhtml-install-dir) "\ +Add a mumamo region from selection. +Mumamo regions are like another layer of chunks above the normal chunks. +They does not affect the normal chunks, but they overrides them. + +To create a mumamo region first select a visible region and then +call this function. + +If the buffer is not in a multi major mode a temporary multi +major mode will be created applied to the buffer first. +To get out of this and get back to a single major mode just use + + M-x normal-mode + +\(fn)" t nil) + +(nxhtml-autoload 'mumamo-add-region-from-string `(lp '(nxhtml-download-root-url nil) "util/mumamo-regions" nxhtml-install-dir) "\ +Add a mumamo region from string at point. +Works as `mumamo-add-region' but for string or comment at point. + +Buffer must be fontified. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (n-back-game n-back) "n-back" "util/n-back.el" +;;;;;; (19278 15746)) +;;; Generated autoloads from util/n-back.el +(web-autoload-require 'n-back 'lp '(nxhtml-download-root-url nil) "util/n-back" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'n-back 'custom-loads))) (if (member '"n-back" loads) nil (put 'n-back 'custom-loads (cons '"n-back" loads)))) + +(nxhtml-autoload 'n-back-game `(lp '(nxhtml-download-root-url nil) "util/n-back" nxhtml-install-dir) "\ +Emacs n-Back game. +This game is supposed to increase your working memory and fluid +intelligence. + +In this game something is shown for half a second on the screen +and maybe a sound is played. You should then answer if parts of +it is the same as you have seen or heard before. This is +repeated for about 20 trials. + +You answer with the keys shown in the bottom window. + +In the easiest version of the game you should answer if you have +just seen or heard what is shown now. By default the game gets +harder as you play it with success. Then first the number of +items presented in a trial grows. After that it gets harder by +that you have to somehow remember not the last item, but the item +before that (or even earlier). That is what \"n-Back\" stands +for. + +Note that remember does not really mean remember clearly. The +game is for training your brain getting used to keep those things +in the working memory, maybe as a cross-modal unit. You are +supposed to just nearly be able to do what you do in the game. +And you are supposed to have fun, that is what your brain like. + +You should probably not overdue this. Half an hour a day playing +might be an optimal time according to some people. + +The game is shamelessly modeled after Brain Workshop, see URL +`http://brainworkshop.sourceforge.net/' just for the fun of +getting it into Emacs. The game resembles but it not the same as +that used in the report by Jaeggi mentioned at the above URL. + +Not all features in Brain Workshop are implemented here, but some +new are maybe ... - and you have it available here in Emacs. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (nxhtmltest-run nxhtmltest-run-indent) "nxhtmltest-suites" +;;;;;; "tests/nxhtmltest-suites.el" (19360 6294)) +;;; Generated autoloads from tests/nxhtmltest-suites.el +(web-autoload-require 'nxhtmltest-suites 'lp '(nxhtml-download-root-url nil) "tests/nxhtmltest-suites" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'nxhtmltest-run-indent `(lp '(nxhtml-download-root-url nil) "tests/nxhtmltest-suites" nxhtml-install-dir) "\ +Run indentation tests. + +\(fn)" t nil) + +(nxhtml-autoload 'nxhtmltest-run `(lp '(nxhtml-download-root-url nil) "tests/nxhtmltest-suites" nxhtml-install-dir) "\ +Run all tests defined for nXhtml. +Currently there are only tests using ert.el defined. + +Note that it is currently expected that the following tests will +fail (they corresponds to known errors in nXhtml/Emacs): + + `nxhtml-ert-nxhtml-changes-jump-back-10549' + `nxhtml-ert-nxhtml-changes-jump-back-7014' + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (nxhtmltest-run-Q) "nxhtmltest-Q" "tests/nxhtmltest-Q.el" +;;;;;; (19264 36684)) +;;; Generated autoloads from tests/nxhtmltest-Q.el +(web-autoload-require 'nxhtmltest-Q 'lp '(nxhtml-download-root-url nil) "tests/nxhtmltest-Q" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'nxhtmltest-run-Q `(lp '(nxhtml-download-root-url nil) "tests/nxhtmltest-Q" nxhtml-install-dir) "\ +Run all tests defined for nXhtml in fresh Emacs. +See `nxhtmltest-run' for more information about the tests. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (ert-run-tests-interactively ert-deftest) "ert" +;;;;;; "tests/ert.el" (19173 56140)) +;;; Generated autoloads from tests/ert.el +(web-autoload-require 'ert 'lp '(nxhtml-download-root-url nil) "tests/ert" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'ert-deftest `(lp '(nxhtml-download-root-url nil) "tests/ert" nxhtml-install-dir) "\ +Define NAME (a symbol) as a test. + +\(fn NAME () [:documentation DOCSTRING] [:expected-result TYPE] BODY...)" nil (quote macro)) + +(nxhtml-autoload 'ert-run-tests-interactively `(lp '(nxhtml-download-root-url nil) "tests/ert" nxhtml-install-dir) "\ +Run the tests specified by SELECTOR and display the results in a buffer. + +\(fn SELECTOR &optional OUTPUT-BUFFER-NAME MESSAGE-FN)" t nil) + +;;;*** + +;;;### (autoloads (ocr-user-mode) "ocr-user" "util/ocr-user.el" (19290 +;;;;;; 21626)) +;;; Generated autoloads from util/ocr-user.el +(web-autoload-require 'ocr-user 'lp '(nxhtml-download-root-url nil) "util/ocr-user" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'ocr-user-mode `(lp '(nxhtml-download-root-url nil) "util/ocr-user" nxhtml-install-dir) "\ +Color up digits three by three. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (ourcomments-warning ourcomments-M-x-menu-mode +;;;;;; ourcomments-paste-with-convert-mode use-custom-style info-open-file +;;;;;; replace-read-files rdir-query-replace ldir-query-replace +;;;;;; grep-query-replace emacs-Q-nxhtml emacs-Q emacs--no-desktop +;;;;;; emacs--debug-init emacs-buffer-file emacs emacs-restart ourcomments-ido-ctrl-tab +;;;;;; ourcomments-ido-buffer-raise-frame ourcomments-ido-buffer-other-frame +;;;;;; ourcomments-ido-buffer-other-window describe-symbol describe-defstruct +;;;;;; describe-custom-group narrow-to-comment buffer-narrowed-p +;;;;;; describe-command ourcomments-ediff-files find-emacs-other-file +;;;;;; ourcomments-insert-date-and-time describe-timers ourcomments-copy+paste-set-point +;;;;;; better-fringes-mode describe-key-and-map-briefly ourcomments-move-end-of-line +;;;;;; ourcomments-move-beginning-of-line ourcomments-mark-whole-buffer-or-field +;;;;;; fill-dwim unfill-individual-paragraphs unfill-region unfill-paragraph +;;;;;; define-toggle-old define-toggle popup-menu-at-point ourcomments-indirect-fun) +;;;;;; "ourcomments-util" "util/ourcomments-util.el" (19411 29548)) +;;; Generated autoloads from util/ourcomments-util.el +(web-autoload-require 'ourcomments-util 'lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'ourcomments-indirect-fun `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Get the alias symbol for function FUN if any. + +\(fn FUN)" nil nil) + +(nxhtml-autoload 'popup-menu-at-point `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Popup the given menu at point. +This is similar to `popup-menu' and MENU and PREFIX has the same +meaning as there. The position for the popup is however where +the window point is. + +\(fn MENU &optional PREFIX)" nil nil) + +(nxhtml-autoload 'define-toggle `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Declare SYMBOL as a customizable variable with a toggle function. +The purpose of this macro is to define a defcustom and a toggle +function suitable for use in a menu. + +The arguments have the same meaning as for `defcustom' with these +restrictions: + +- The :type keyword cannot be used. Type is always 'boolean. +- VALUE must be t or nil. + +DOC and ARGS are just passed to `defcustom'. + +A `defcustom' named SYMBOL with doc-string DOC and a function +named SYMBOL-toggle is defined. The function toggles the value +of SYMBOL. It takes no parameters. + +To create a menu item something similar to this can be used: + + (define-key map [SYMBOL] + (list 'menu-item \"Toggle nice SYMBOL\" + 'SYMBOL-toggle + :button '(:toggle . SYMBOL))) + +\(fn SYMBOL VALUE DOC &rest ARGS)" nil (quote macro)) + +(nxhtml-autoload 'define-toggle-old `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Not documented + +\(fn SYMBOL VALUE DOC &rest ARGS)" nil (quote macro)) + +(nxhtml-autoload 'unfill-paragraph `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Unfill the current paragraph. + +\(fn)" t nil) + +(nxhtml-autoload 'unfill-region `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Unfill the current region. + +\(fn)" t nil) + +(nxhtml-autoload 'unfill-individual-paragraphs `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Unfill individual paragraphs in the current region. + +\(fn)" t nil) + +(nxhtml-autoload 'fill-dwim `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Fill or unfill paragraph or region. +With prefix ARG fill only current line. + +\(fn ARG)" t nil) + +(nxhtml-autoload 'ourcomments-mark-whole-buffer-or-field `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Mark whole buffer or editable field at point. + +\(fn)" t nil) + +(nxhtml-autoload 'ourcomments-move-beginning-of-line `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Move point to beginning of line or indentation. +See `beginning-of-line' for ARG. + +If `line-move-visual' is non-nil then the visual line beginning +is first tried. + +If in a widget field stay in that. + +\(fn ARG)" t nil) + +(nxhtml-autoload 'ourcomments-move-end-of-line `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Move point to end of line or after last non blank char. +See `end-of-line' for ARG. + +Similar to `ourcomments-move-beginning-of-line' but for end of +line. + +\(fn ARG)" t nil) + +(nxhtml-autoload 'describe-key-and-map-briefly `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Try to print names of keymap from which KEY fetch its definition. +Look in current active keymaps and find keymap variables with the +same value as the keymap where KEY is bound. Print a message +with those keymap variable names. Return a list with the keymap +variable symbols. + +When called interactively prompt for KEY. + +INSERT and UNTRANSLATED should normall be nil (and I am not sure +what they will do ;-). + +\(fn &optional KEY INSERT UNTRANSLATED)" t nil) + +(defvar better-fringes-mode nil "\ +Non-nil if Better-Fringes mode is enabled. +See the command `better-fringes-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `better-fringes-mode'.") + +(nxhtml-custom-autoload 'better-fringes-mode 'ourcomments-util nil) + +(nxhtml-autoload 'better-fringes-mode `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Choose another fringe bitmap color and bottom angle. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'ourcomments-copy+paste-set-point `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Set point for copy+paste here. +Enable temporary minor mode `ourcomments-copy+paste-mode'. +However if point for copy+paste already is set then cancel it and +disable the minor mode. + +The purpose of this command is to make it easy to grab a piece of +text and paste it at current position. After this command you +should select a piece of text to copy and then call the command +`ourcomments-copy+paste'. + +\(fn)" t nil) + +(nxhtml-autoload 'describe-timers `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Show timers with readable time format. + +\(fn)" t nil) + +(nxhtml-autoload 'ourcomments-insert-date-and-time `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Insert date and time. +See option `ourcomments-insert-date-and-time' for how to +customize it. + +\(fn)" t nil) + +(nxhtml-autoload 'find-emacs-other-file `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Find corresponding file to source or installed elisp file. +If you have checked out and compiled Emacs yourself you may have +Emacs lisp files in two places, the checked out source tree and +the installed Emacs tree. If buffer contains an Emacs elisp file +in one of these places then find the corresponding elisp file in +the other place. Return the file name of this file. + +Rename current buffer using your `uniquify-buffer-name-style' if +it is set. + +When DISPLAY-FILE is non-nil display this file in other window +and go to the same line number as in the current buffer. + +\(fn DISPLAY-FILE)" t nil) + +(nxhtml-autoload 'ourcomments-ediff-files `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +In directory DEF-DIR run `ediff-files' on files FILE-A and FILE-B. +The purpose of this function is to make it eaiser to start +`ediff-files' from a shell through Emacs Client. + +This is used in EmacsW32 in the file ediff.cmd where Emacs Client +is called like this: + + @%emacs_client% -e \"(setq default-directory \\\"%emacs_cd%\\\")\" + @%emacs_client% -n -e \"(ediff-files \\\"%f1%\\\" \\\"%f2%\\\")\" + +It can of course be done in a similar way with other shells. + +\(fn DEF-DIR FILE-A FILE-B)" nil nil) + +(nxhtml-autoload 'describe-command `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Like `describe-function', but prompts only for interactive commands. + +\(fn COMMAND)" t nil) + +(nxhtml-autoload 'buffer-narrowed-p `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Return non-nil if the current buffer is narrowed. + +\(fn)" nil nil) + +(nxhtml-autoload 'narrow-to-comment `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'describe-custom-group `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Describe customization group SYMBOL. + +\(fn SYMBOL)" t nil) + +(nxhtml-autoload 'describe-defstruct `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Not documented + +\(fn SYMBOL)" t nil) + +(nxhtml-autoload 'describe-symbol `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Show information about SYMBOL. +Show SYMBOL plist and whether is is a variable or/and a +function. + +\(fn SYMBOL)" t nil) + +(nxhtml-autoload 'ourcomments-ido-buffer-other-window `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Show buffer in other window. + +\(fn)" t nil) + +(nxhtml-autoload 'ourcomments-ido-buffer-other-frame `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Show buffer in other frame. + +\(fn)" t nil) + +(nxhtml-autoload 'ourcomments-ido-buffer-raise-frame `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Raise frame showing buffer. + +\(fn)" t nil) + +(defvar ourcomments-ido-ctrl-tab nil "\ +Non-nil if Ourcomments-Ido-Ctrl-Tab mode is enabled. +See the command `ourcomments-ido-ctrl-tab' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `ourcomments-ido-ctrl-tab'.") + +(nxhtml-custom-autoload 'ourcomments-ido-ctrl-tab 'ourcomments-util nil) + +(nxhtml-autoload 'ourcomments-ido-ctrl-tab `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Enable buffer switching using C-Tab with function `ido-mode'. +This changes buffer switching with function `ido-mode' the +following way: + +- You can use C-Tab. + +- You can show the selected buffer in three ways independent of + how you entered function `ido-mode' buffer switching: + + * S-return: other window + * C-return: other frame + * M-return: raise frame + +Those keys are selected to at least be a little bit reminiscent +of those in for example common web browsers. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'emacs-restart `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Restart Emacs and start `server-mode' if on before. + +\(fn)" t nil) + +(nxhtml-autoload 'emacs `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Start a new Emacs with default parameters. +Additional ARGS are passed to the new Emacs. + +See also `ourcomments-started-emacs-use-output-buffer'. + +\(fn &rest ARGS)" t nil) + +(nxhtml-autoload 'emacs-buffer-file `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Start a new Emacs showing current buffer file. +Go to the current line and column in that file. +If there is no buffer file then instead start with `dired'. + +This calls the function `emacs' with argument --no-desktop and +the file or a call to dired. + +\(fn)" t nil) + +(nxhtml-autoload 'emacs--debug-init `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Start a new Emacs with --debug-init parameter. +This calls the function `emacs' with added arguments ARGS. + +\(fn &rest ARGS)" t nil) + +(nxhtml-autoload 'emacs--no-desktop `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Start a new Emacs with --no-desktop parameter. +This calls the function `emacs' with added arguments ARGS. + +\(fn &rest ARGS)" t nil) + +(nxhtml-autoload 'emacs-Q `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Start a new Emacs with -Q parameter. +Start new Emacs without any customization whatsoever. +This calls the function `emacs' with added arguments ARGS. + +\(fn &rest ARGS)" t nil) + +(nxhtml-autoload 'emacs-Q-nxhtml `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Start new Emacs with -Q and load nXhtml. +This calls the function `emacs' with added arguments ARGS. + +\(fn &rest ARGS)" t nil) + +(nxhtml-autoload 'grep-query-replace `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Do `query-replace-regexp' of FROM with TO, on all files in *grep*. +Third arg DELIMITED (prefix arg) means replace only word-delimited matches. +If you exit (\\[keyboard-quit], RET or q), you can resume the query replace +with the command \\[tags-loop-continue]. + +\(fn FROM TO &optional DELIMITED)" t nil) + +(nxhtml-autoload 'ldir-query-replace `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Replace FROM with TO in FILES in directory DIR. +This runs `query-replace-regexp' in files matching FILES in +directory DIR. + +See `tags-query-replace' for DELIMETED and more information. + +\(fn FROM TO FILES DIR &optional DELIMITED)" t nil) + +(nxhtml-autoload 'rdir-query-replace `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Replace FROM with TO in FILES in directory tree ROOT. +This runs `query-replace-regexp' in files matching FILES in +directory tree ROOT. + +See `tags-query-replace' for DELIMETED and more information. + +\(fn FROM TO FILE-REGEXP ROOT &optional DELIMITED)" t nil) + +(nxhtml-autoload 'replace-read-files `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Read files arg for replace. + +\(fn REGEXP &optional REPLACE)" nil nil) + +(nxhtml-autoload 'info-open-file `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Open an info file in `Info-mode'. + +\(fn INFO-FILE)" t nil) + +(nxhtml-autoload 'use-custom-style `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Setup like in `Custom-mode', but without things specific to Custom. + +\(fn)" nil nil) + +(defvar ourcomments-paste-with-convert-mode nil "\ +Non-nil if Ourcomments-Paste-With-Convert mode is enabled. +See the command `ourcomments-paste-with-convert-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `ourcomments-paste-with-convert-mode'.") + +(nxhtml-custom-autoload 'ourcomments-paste-with-convert-mode 'ourcomments-util nil) + +(nxhtml-autoload 'ourcomments-paste-with-convert-mode `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Pasted text may be automatically converted in this mode. +The functions in `ourcomments-paste-with-convert-hook' are run +after commands in `ourcomments-paste-with-convert-commands' if any +of the functions returns non-nil that text is inserted instead of +the original text. + +For exampel when this mode is on and you paste an html link in an +`org-mode' buffer it will be directly converted to an org style +link. (This is the default behaviour.) + +Tip: The Firefox plugin Copy as HTML Link is handy, see URL + `https://addons.mozilla.org/en-US/firefox/addon/2617'. + +Note: This minor mode will defadvice the paste commands. + +\(fn &optional ARG)" t nil) + +(defvar ourcomments-M-x-menu-mode nil "\ +Non-nil if Ourcomments-M-X-Menu mode is enabled. +See the command `ourcomments-M-x-menu-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `ourcomments-M-x-menu-mode'.") + +(nxhtml-custom-autoload 'ourcomments-M-x-menu-mode 'ourcomments-util nil) + +(nxhtml-autoload 'ourcomments-M-x-menu-mode `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Add commands started from Emacs menus to M-x history. +The purpose of this is to make it easier to redo them and easier +to learn how to do them from the command line (which is often +faster if you know how to do it). + +Only commands that are not already in M-x history are added. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'ourcomments-warning `(lp '(nxhtml-download-root-url nil) "util/ourcomments-util" nxhtml-install-dir) "\ +Not documented + +\(fn FORMAT-STRING &rest ARGS)" nil nil) + +;;;*** + +;;;### (autoloads (major-modep major-or-multi-majorp) "ourcomments-widgets" +;;;;;; "util/ourcomments-widgets.el" (19275 63380)) +;;; Generated autoloads from util/ourcomments-widgets.el +(web-autoload-require 'ourcomments-widgets 'lp '(nxhtml-download-root-url nil) "util/ourcomments-widgets" nxhtml-install-dir 'nxhtml-byte-compile-file) + + (nxhtml-autoload 'command "ourcomments-widgets") + +(nxhtml-autoload 'major-or-multi-majorp `(lp '(nxhtml-download-root-url nil) "util/ourcomments-widgets" nxhtml-install-dir) "\ +Return t if VALUE is a major or multi major mode function. + +\(fn VALUE)" nil nil) + +(nxhtml-autoload 'major-modep `(lp '(nxhtml-download-root-url nil) "util/ourcomments-widgets" nxhtml-install-dir) "\ +Return t if VALUE is a major mode function. + +\(fn VALUE)" nil nil) + (nxhtml-autoload 'major-mode-function "ourcomments-widgets") + +;;;*** + +;;;### (autoloads (pause-start-in-new-emacs pause-mode pause) "pause" +;;;;;; "util/pause.el" (19335 58922)) +;;; Generated autoloads from util/pause.el +(web-autoload-require 'pause 'lp '(nxhtml-download-root-url nil) "util/pause" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'pause 'custom-loads))) (if (member '"pause" loads) nil (put 'pause 'custom-loads (cons '"pause" loads)))) + +(defvar pause-mode nil "\ +Non-nil if Pause mode is enabled. +See the command `pause-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `pause-mode'.") + +(nxhtml-custom-autoload 'pause-mode 'pause nil) + +(nxhtml-autoload 'pause-mode `(lp '(nxhtml-download-root-url nil) "util/pause" nxhtml-install-dir) "\ +This minor mode tries to make you take a break. +It will jump up and temporary stop your work - even if you are +not in Emacs. If you are in Emacs it will however try to be +gentle and wait until you have been idle with the keyboard for a +short while. (If you are not in Emacs it can't be gentle. How +could it?) + +Then it will show you a special screen with a link to a yoga +exercise you can do when you pause. + +After the pause you continue your work where you were +interrupted. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'pause-start-in-new-emacs `(lp '(nxhtml-download-root-url nil) "util/pause" nxhtml-install-dir) "\ +Start pause with interval AFTER-MINUTES in a new Emacs instance. +The new Emacs instance will be started with -Q. However if +`custom-file' is non-nil it will be loaded so you can still +customize pause. + +One way of using this function may be to put in your .emacs +something like + + ;; for just one Emacs running pause + (when server-mode (pause-start-in-new-emacs 15)) + +See `pause-start' for more info. + +\(fn AFTER-MINUTES)" t nil) + +;;;*** + +;;;### (autoloads (global-pointback-mode pointback-mode) "pointback" +;;;;;; "util/pointback.el" (19023 47096)) +;;; Generated autoloads from util/pointback.el +(web-autoload-require 'pointback 'lp '(nxhtml-download-root-url nil) "util/pointback" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'pointback-mode `(lp '(nxhtml-download-root-url nil) "util/pointback" nxhtml-install-dir) "\ +Restore previous window point when switching back to a buffer. + +\(fn &optional ARG)" t nil) + +(defvar global-pointback-mode nil "\ +Non-nil if Global-Pointback mode is enabled. +See the command `global-pointback-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-pointback-mode'.") + +(nxhtml-custom-autoload 'global-pointback-mode 'pointback nil) + +(nxhtml-autoload 'global-pointback-mode `(lp '(nxhtml-download-root-url nil) "util/pointback" nxhtml-install-dir) "\ +Toggle Pointback mode in every possible buffer. +With prefix ARG, turn Global-Pointback mode on if and only if +ARG is positive. +Pointback mode is enabled in all buffers where +`pointback-on' would do it. +See `pointback-mode' for more information on Pointback mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (popcmp-completing-read popcmp-completion-style +;;;;;; popcmp) "popcmp" "util/popcmp.el" (19365 33760)) +;;; Generated autoloads from util/popcmp.el +(web-autoload-require 'popcmp 'lp '(nxhtml-download-root-url nil) "util/popcmp" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'popcmp 'custom-loads))) (if (member '"popcmp" loads) nil (put 'popcmp 'custom-loads (cons '"popcmp" loads)))) + +(defvar popcmp-completion-style (cond (t 'popcmp-popup)) "\ +Completion style. +The currently available completion styles are: + +- popcmp-popup: Use OS popup menus (default). +- emacs-default: Emacs default completion. +- Company Mode completion. +- anything: The Anything elisp lib completion style. + +The style of completion set here is not implemented for all +completions. The scope varies however with which completion +style you have choosen. + +For information about Company Mode and how to use it see URL +`http://www.emacswiki.org/emacs/CompanyMode'. + +For information about Anything and how to use it see URL +`http://www.emacswiki.org/emacs/Anything'. + +See also the options `popcmp-short-help-beside-alts' and +`popcmp-group-alternatives' which are also availabe when popup +completion is available.") + +(nxhtml-custom-autoload 'popcmp-completion-style 'popcmp nil) + +(nxhtml-autoload 'popcmp-completing-read `(lp '(nxhtml-download-root-url nil) "util/popcmp" nxhtml-install-dir) "\ +Read a string in the minubuffer with completion, or popup a menu. +This function can be used instead `completing-read'. The main +purpose is to provide a popup style menu for completion when +completion is tighed to text at point in a buffer. If a popup +menu is used it will be shown at window point. Whether a popup +menu or minibuffer completion is used is governed by +`popcmp-completion-style'. + +The variables PROMPT, TABLE, PREDICATE, REQUIRE-MATCH, +INITIAL-INPUT, POP-HIST, DEF and INHERIT-INPUT-METHOD all have the +same meaning is for `completing-read'. + +ALT-HELP should be nil or a hash variable or an association list +with the completion alternative as key and a short help text as +value. You do not need to supply help text for all alternatives. +The use of ALT-HELP is set by `popcmp-short-help-beside-alts'. + +ALT-SETS should be nil or an association list that has as keys +groups and as second element an alternative that should go into +this group. + +\(fn PROMPT TABLE &optional PREDICATE REQUIRE-MATCH INITIAL-INPUT POP-HIST DEF INHERIT-INPUT-METHOD ALT-HELP ALT-SETS)" nil nil) + +;;;*** + +;;;### (autoloads (rebind-keys-mode rebind) "rebind" "util/rebind.el" +;;;;;; (19292 11678)) +;;; Generated autoloads from util/rebind.el +(web-autoload-require 'rebind 'lp '(nxhtml-download-root-url nil) "util/rebind" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'rebind 'custom-loads))) (if (member '"rebind" loads) nil (put 'rebind 'custom-loads (cons '"rebind" loads)))) + +(defvar rebind-keys-mode nil "\ +Non-nil if Rebind-Keys mode is enabled. +See the command `rebind-keys-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `rebind-keys-mode'.") + +(nxhtml-custom-autoload 'rebind-keys-mode 'rebind nil) + +(nxhtml-autoload 'rebind-keys-mode `(lp '(nxhtml-download-root-url nil) "util/rebind" nxhtml-install-dir) "\ +Rebind keys as defined in `rebind-keys'. +The key bindings will override almost all other key bindings +since it is put on emulation level, like for example ``cua-mode' +and `viper-mode'. + +This is for using for example C-a to mark the whole buffer (or a +field). There are some predifined keybindings for this. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (rnc-mode) "rnc-mode" "util/rnc-mode.el" (18775 +;;;;;; 60004)) +;;; Generated autoloads from util/rnc-mode.el +(web-autoload-require 'rnc-mode 'lp '(nxhtml-download-root-url nil) "util/rnc-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'rnc-mode `(lp '(nxhtml-download-root-url nil) "util/rnc-mode" nxhtml-install-dir) "\ +Major mode for editing RELAX NG Compact Syntax schemas. +\\{rnc-mode-map} + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (search-form) "search-form" "util/search-form.el" +;;;;;; (19275 63380)) +;;; Generated autoloads from util/search-form.el +(web-autoload-require 'search-form 'lp '(nxhtml-download-root-url nil) "util/search-form" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'search-form `(lp '(nxhtml-download-root-url nil) "util/search-form" nxhtml-install-dir) "\ +Display a form for search and replace. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (sex-mode sex) "sex-mode" "util/sex-mode.el" (19218 +;;;;;; 42182)) +;;; Generated autoloads from util/sex-mode.el +(web-autoload-require 'sex-mode 'lp '(nxhtml-download-root-url nil) "util/sex-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'sex 'custom-loads))) (if (member '"sex-mode" loads) nil (put 'sex 'custom-loads (cons '"sex-mode" loads)))) + +(defvar sex-mode nil "\ +Non-nil if Sex mode is enabled. +See the command `sex-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `sex-mode'.") + +(nxhtml-custom-autoload 'sex-mode 'sex-mode nil) + +(nxhtml-autoload 'sex-mode `(lp '(nxhtml-download-root-url nil) "util/sex-mode" nxhtml-install-dir) "\ +Open certain files in external programs. +See `sex-get-file-open-cmd' for how to determine which files to +open by external applications. Note that this selection is +nearly the same as in `org-mode'. The main difference is that +the fallback always is to open a file in Emacs. (This is +necessary to avoid to disturb many of Emacs operations.) + +This affects all functions that opens files, like `find-file', +`find-file-noselect' etc. + +However it does not affect files opened through Emacs client. + +Urls can also be handled, see `sex-handle-urls'. + +When opening a file with the shell a (temporary) dummy buffer is +created in Emacs with major mode `sex-file-mode' and an external +program is called to handle the file. How this dummy buffer is +handled is governed by `sex-keep-dummy-buffer'. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (sml-modeline-mode sml-modeline) "sml-modeline" +;;;;;; "util/sml-modeline.el" (19362 49086)) +;;; Generated autoloads from util/sml-modeline.el +(web-autoload-require 'sml-modeline 'lp '(nxhtml-download-root-url nil) "util/sml-modeline" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'sml-modeline 'custom-loads))) (if (member '"sml-modeline" loads) nil (put 'sml-modeline 'custom-loads (cons '"sml-modeline" loads)))) + +(defvar sml-modeline-mode nil "\ +Non-nil if Sml-Modeline mode is enabled. +See the command `sml-modeline-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `sml-modeline-mode'.") + +(nxhtml-custom-autoload 'sml-modeline-mode 'sml-modeline nil) + +(nxhtml-autoload 'sml-modeline-mode `(lp '(nxhtml-download-root-url nil) "util/sml-modeline" nxhtml-install-dir) "\ +Show buffer size and position like scrollbar in mode line. +You can customize this minor mode, see option `sml-modeline-mode'. + +Note: If you turn this mode on then you probably want to turn off +option `scroll-bar-mode'. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (tabkey2-emma-without-tabkey2 tabkey2-mode tabkey2) +;;;;;; "tabkey2" "util/tabkey2.el" (19277 65356)) +;;; Generated autoloads from util/tabkey2.el +(web-autoload-require 'tabkey2 'lp '(nxhtml-download-root-url nil) "util/tabkey2" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'tabkey2 'custom-loads))) (if (member '"tabkey2" loads) nil (put 'tabkey2 'custom-loads (cons '"tabkey2" loads)))) + +(defvar tabkey2-mode nil "\ +Non-nil if Tabkey2 mode is enabled. +See the command `tabkey2-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `tabkey2-mode'.") + +(nxhtml-custom-autoload 'tabkey2-mode 'tabkey2 nil) + +(nxhtml-autoload 'tabkey2-mode `(lp '(nxhtml-download-root-url nil) "util/tabkey2" nxhtml-install-dir) "\ +More fun with Tab key number two (completion etc). +This global minor mode by default binds Tab in a way that let you +do completion with Tab in all buffers (where it is possible). + +The Tab key is easy to type on your keyboard. Then why not use +it for completion, something that is very useful? Shells usually +use Tab for completion so many are used to it. This was the idea +of Smart Tabs and this is a generalization of that idea. + +However in Emacs the Tab key is usually used for indentation. +The idea here is that if Tab has been pressed once for +indentation, then as long as point stays further Tab keys might +as well do completion. + +So you kind of do Tab-Tab for first completion (and then just +Tab for further completions as long as point is not moved). + +And there is even kind of Tab-Tab-Tab completion: If completion +fails the next completion function will be the one you try with +next Tab. (You get some notification of this, of course.) + +See `tabkey2-first' for more information about usage. + +Note: If you do not want the Tab-Tab behaviour above, but still +want an easy way to reach the available completion functions, +then you can instead of turning on tabkey2-mode enter this in +your .emacs: + + (global-set-key [f8] 'tabkey2-cycle-completion-functions) + +After hitting f8 you will then be in the same state as after the +first in tabkey2-mode. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'tabkey2-emma-without-tabkey2 `(lp '(nxhtml-download-root-url nil) "util/tabkey2" nxhtml-install-dir) "\ +Not documented + +\(fn)" nil nil) + +;;;*** + +;;;### (autoloads (tyda-mode) "tyda" "util/tyda.el" (19275 63380)) +;;; Generated autoloads from util/tyda.el +(web-autoload-require 'tyda 'lp '(nxhtml-download-root-url nil) "util/tyda" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(defvar tyda-mode nil "\ +Non-nil if Tyda mode is enabled. +See the command `tyda-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `tyda-mode'.") + +(nxhtml-custom-autoload 'tyda-mode 'tyda nil) + +(nxhtml-autoload 'tyda-mode `(lp '(nxhtml-download-root-url nil) "util/tyda" nxhtml-install-dir) "\ +Minor mode for key bindings for `tyda-lookup-word'. +It binds Alt-Mouse-1 just as the Tyda add-on does in Firefox. +Here are all key bindings + +\\{tyda-mode-map} + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (udev-call-first-step) "udev" "util/udev.el" (19412 +;;;;;; 25976)) +;;; Generated autoloads from util/udev.el +(web-autoload-require 'udev 'lp '(nxhtml-download-root-url nil) "util/udev" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'udev-call-first-step `(lp '(nxhtml-download-root-url nil) "util/udev" nxhtml-install-dir) "\ +Set up and call first step. +Set up buffer LOG-BUFFER to be used for log messages and +controling of the execution of the functions in list STEPS which +are executed one after another. + +Write HEADER at the end of LOG-BUFFER. + +Call first step. + +If FINISH-FUN non-nil it should be a function. This is called +after last step with LOG-BUFFER as parameter. + +\(fn LOG-BUFFER STEPS HEADER FINISH-FUN)" nil nil) + +;;;*** + +;;;### (autoloads (udev-ecb-customize-startup udev-ecb-update) "udev-ecb" +;;;;;; "util/udev-ecb.el" (19256 5410)) +;;; Generated autoloads from util/udev-ecb.el +(web-autoload-require 'udev-ecb 'lp '(nxhtml-download-root-url nil) "util/udev-ecb" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'udev-ecb-update `(lp '(nxhtml-download-root-url nil) "util/udev-ecb" nxhtml-install-dir) "\ +Fetch and install ECB from the devel sources. +To determine where to store the sources see `udev-ecb-dir'. +For how to start ECB see `udev-ecb-load-ecb'. + +\(fn)" t nil) + +(nxhtml-autoload 'udev-ecb-customize-startup `(lp '(nxhtml-download-root-url nil) "util/udev-ecb" nxhtml-install-dir) "\ +Customize ECB dev nXhtml startup group. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (udev-rinari-update) "udev-rinari" "util/udev-rinari.el" +;;;;;; (19256 5410)) +;;; Generated autoloads from util/udev-rinari.el +(web-autoload-require 'udev-rinari 'lp '(nxhtml-download-root-url nil) "util/udev-rinari" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'udev-rinari-update `(lp '(nxhtml-download-root-url nil) "util/udev-rinari" nxhtml-install-dir) "\ +Fetch and install Rinari from the devel sources. +To determine where to store the sources and how to start rinari +see `udev-rinari-dir' and `udev-rinari-load-rinari'. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (viper-tutorial) "viper-tut" "util/viper-tut.el" +;;;;;; (19388 44990)) +;;; Generated autoloads from util/viper-tut.el +(web-autoload-require 'viper-tut 'lp '(nxhtml-download-root-url nil) "util/viper-tut" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'viper-tutorial `(lp '(nxhtml-download-root-url nil) "util/viper-tut" nxhtml-install-dir) "\ +Run a tutorial for Viper. + +A simple classic tutorial in 5 parts that have been used by many +people starting to learn vi keys. You may learn enough to start +using `viper-mode' in Emacs. + +Some people find that vi keys helps against repetetive strain +injury, see URL + + `http://www.emacswiki.org/emacs/RepeatedStrainInjury'. + +Note: There might be a few clashes between vi key binding and +Emacs standard key bindings. You will be notified about those in +the tutorial. Even more, if your own key bindings comes in +between you will be notified about that too. + +\(fn PART &optional DONT-ASK-FOR-REVERT)" t nil) + +;;;*** + +;;;### (autoloads (vline-global-mode vline-mode) "vline" "util/vline.el" +;;;;;; (19157 2168)) +;;; Generated autoloads from util/vline.el +(web-autoload-require 'vline 'lp '(nxhtml-download-root-url nil) "util/vline" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'vline-mode `(lp '(nxhtml-download-root-url nil) "util/vline" nxhtml-install-dir) "\ +Display vertical line mode. + +\(fn &optional ARG)" t nil) + +(defvar vline-global-mode nil "\ +Non-nil if Vline-Global mode is enabled. +See the command `vline-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `vline-global-mode'.") + +(nxhtml-custom-autoload 'vline-global-mode 'vline nil) + +(nxhtml-autoload 'vline-global-mode `(lp '(nxhtml-download-root-url nil) "util/vline" nxhtml-install-dir) "\ +Display vertical line mode as globally. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (whelp) "whelp" "util/whelp.el" (19277 65356)) +;;; Generated autoloads from util/whelp.el +(web-autoload-require 'whelp 'lp '(nxhtml-download-root-url nil) "util/whelp" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'whelp 'custom-loads))) (if (member '"whelp" loads) nil (put 'whelp 'custom-loads (cons '"whelp" loads)))) + +;;;*** + +;;;### (autoloads (wikipedia-draft-buffer wikipedia-draft-page wikipedia-draft +;;;;;; wikipedia-mode) "wikipedia-mode" "related/wikipedia-mode.el" +;;;;;; (19277 65356)) +;;; Generated autoloads from related/wikipedia-mode.el +(web-autoload-require 'wikipedia-mode 'lp '(nxhtml-download-root-url nil) "related/wikipedia-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'wikipedia-mode `(lp '(nxhtml-download-root-url nil) "related/wikipedia-mode" nxhtml-install-dir) "\ +Major mode for editing wikimedia style wikis. +Major mode for editing articles written in the markup language +used by Wikipedia, the free on-line +encyclopedia (see URL `http://www.wikipedia.org'). + +There are several ways to use wikipedia-mode: + +- You can simply cut and paste articles between Emacs and your + web browser's text box. +- If you are using Firefox you can use the It's All Text add-on + for Firefox. +- You can use MozEx, a Mozilla/Firefox web browser extension that + allows you to call Emacs from a text + box (see URL `http://mozex.mozdev.org/'). +- Another way is to use the PERL script ee-helper, which allows + you to up and download wiki texts. + +Wikipedia articles are usually unfilled: newline characters are not +used for breaking paragraphs into lines. Unfortunately, Emacs does not +handle word wrapping yet. As a workaround, wikipedia-mode turns on +longlines-mode automatically. In case something goes wrong, the +following commands may come in handy: + +\\[wikipedia-fill-article] fills the buffer. +\\[wikipedia-unfill-article] unfills the buffer. +Be warned that function can be dead slow, better use wikipedia-unfill-paragraph-or-region. +\\[wikipedia-unfill-paragraph-or-region] unfills the paragraph +\\[wikipedia-unfill-paragraph-simple] doehe same but simpler. + + + +The following commands put in markup structures. + +\\[wikipedia-insert-bold-italic] bold+italic +\\[wikipedia-insert-bold] bold text +\\[wikipedia-insert-italics] italics +\\[wikipedia-insert-nowiki] no wiki markup +\\[wikipedia-insert-link-wiki] inserts a link + +The following commands are also defined: +\\[wikipedia-insert-user] inserts user name +\\[wikipedia-insert-signature] inserts ~~~~ +\\[wikipedia-insert-enumerate] inserts enumerate type structures +\\[wikipedia-insert-itemize] inserts itemize type structures +\\[wikipedia-insert-hline] inserts a hline + +The draft functionality +\\[wikipedia-draft] +\\[wikipedia-draft-region] +\\[wikipedia-draft-view-draft] +\\[wikipedia-draft-page] +\\[wikipedia-draft-buffer] + +Replying and sending functionality +\\[wikipedia-reply-at-point-simple] +\\[wikipedia-draft-reply] + + +The register functionality +\\[wikipedia-copy-page-to-register] +\\[defun wikipedia-insert-page-to-register] + + +Some simple editing commands. +\\[wikipedia-enhance-indent] +\\[wikipedia-yank-prefix] +\\[wikipedia-unfill-paragraph-or-region] + + + +\\[wikipedia-terminate-paragraph] starts a new list item or paragraph in a context-aware manner. + +\(fn)" t nil) + +(nxhtml-autoload 'wikipedia-draft `(lp '(nxhtml-download-root-url nil) "related/wikipedia-mode" nxhtml-install-dir) "\ +Open a temporary buffer in wikipedia mode for editing an + wikipedia draft, which an arbitrary piece of data. After + finishing the editing either use \\[wikipedia-draft-buffer] to + send the data into the wikipedia-draft-data-file, or send the + buffer using `wikipedia-draft-send-to-mozex' and insert it later + into a wikipedia article. + +\(fn)" t nil) + +(nxhtml-autoload 'wikipedia-draft-page `(lp '(nxhtml-download-root-url nil) "related/wikipedia-mode" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'wikipedia-draft-buffer `(lp '(nxhtml-download-root-url nil) "related/wikipedia-mode" nxhtml-install-dir) "\ +Wikipedia-draft-buffer sends the contents of the current (temporary) +buffer to the wikipedia-draft-buffer, see the variable +wikipedia-draft-data-file. + +\(fn)" t nil) + +(defvar wikipedia-draft-send-archive t "\ +*Archive the reply.") + +;;;*** + +;;;### (autoloads (visual-basic-mode) "visual-basic-mode" "related/visual-basic-mode.el" +;;;;;; (19235 1650)) +;;; Generated autoloads from related/visual-basic-mode.el +(web-autoload-require 'visual-basic-mode 'lp '(nxhtml-download-root-url nil) "related/visual-basic-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'visual-basic-mode `(lp '(nxhtml-download-root-url nil) "related/visual-basic-mode" nxhtml-install-dir) "\ +A mode for editing Microsoft Visual Basic programs. +Features automatic indentation, font locking, keyword capitalization, +and some minor convenience functions. +Commands: +\\{visual-basic-mode-map} + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (tt-mode) "tt-mode" "related/tt-mode.el" (18603 +;;;;;; 15792)) +;;; Generated autoloads from related/tt-mode.el +(web-autoload-require 'tt-mode 'lp '(nxhtml-download-root-url nil) "related/tt-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'tt-mode `(lp '(nxhtml-download-root-url nil) "related/tt-mode" nxhtml-install-dir) "\ +Major mode for editing Template Toolkit files. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (smarty-mode smarty) "smarty-mode" "related/smarty-mode.el" +;;;;;; (19235 1650)) +;;; Generated autoloads from related/smarty-mode.el +(web-autoload-require 'smarty-mode 'lp '(nxhtml-download-root-url nil) "related/smarty-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'smarty 'custom-loads))) (if (member '"smarty-mode" loads) nil (put 'smarty 'custom-loads (cons '"smarty-mode" loads)))) + +(nxhtml-autoload 'smarty-mode `(lp '(nxhtml-download-root-url nil) "related/smarty-mode" nxhtml-install-dir) "\ +Smarty Mode +*********** + +Smarty Mode is a GNU XEmacs major mode for editing Smarty templates. + +1 Introduction +************** + +Smarty-Mode is a mode allowing easy edit of Smarty templates: +highlight, templates, navigation into source files... + + + +Features (new features in bold) : + + * Completion + + * Customizable + + * Highlight + + * Menu + + * Stuttering + + * Templates + - Built-in Functions + + - User Functions + + - Variable Modifiers + + - Plugin (Functions) + * BlockRepeatPlugin + + * ClipCache + + * Smarty Formtool + + * Smarty Paginate + + * Smarty Validate + + - Plugin (Variable Modifiers) + * AlternativeDateModifierPlugin + + * B2Smilies + + * BBCodePlugin + + - Fonctions Non-Smarty + + + +This manual describes Smarty Mode version 0.0.5. + +2 Installation +************** + +2.1 Requirements +================ + +Smarty Mode is a XEmacs major mode that needs the following +software/packages: + + * XEmacs (http://www.xemacs.org/). + + * `font-lock' mode generaly installed with XEmacs. + + * `assoc' mode generaly installed with XEmacs. + + * `easymenu' mode generaly installed with XEmacs. + + * `hippie-exp' mode generaly installed with XEmacs. + +Before continuing, you must be sure to have all this packages +installed. + +2.2 Download +============ + +Two internet address to download Smarty Mode : + + * Principal: Smarty-Mode 0.0.5 + (http://deboutv.free.fr/lisp/smarty/download/smarty-0.0.5.tar.gz) + (http://deboutv.free.fr/lisp/smarty/) + + * Secondary: Smarty-Mode 0.0.5 + (http://www.morinie.fr/lisp/smarty/download/smarty-0.0.5.tar.gz) + (http://www.morinie.fr/lisp/smarty/) + + * Old releases: Smarty-Mode + (http://deboutv.free.fr/lisp/smarty/download.php) + (http://deboutv.free.fr/lisp/smarty/) + +2.3 Installation +================ + +2.3.1 Installation +------------------ + +To install Smarty Mode you need to choose an installation directory +\(for example `/usr/local/share/lisp' or `c:lisp'). The administrator +must have the write rights on this directory. + +With your favorite unzip software, unzip the archive in the +installation directory. + +Example: + cd /usr/local/share/lisp + tar zxvf smarty-0.0.5.tar.gz +Now you have a `smarty' directory in the installation directory. This +directory contains 2 files `smarty-mode.el' and `smarty-mode.elc' and +another directory `docs' containing the documentation. + +You need to configure XEmacs. open you initialization file `init.el' +\(open the file or start XEmacs then choose the Options menu and Edit +Init File). Add the following lines (the installation directory in +this example is `/usr/local/share/lisp') : + + (setq load-path + (append (list \"/usr/local/share/lisp/\") load-path)) + (nxhtml-autoload 'smarty-mode \"smarty-mode\" \"Smarty Mode\" t) + +2.3.2 Update +------------ + +The update is easy. You need to unzip the archive in the installation +directory to remove the old release. + +Example: + cd /usr/local/share/lisp + rm -rf smarty + tar zxvf smarty-0.0.5.tar.gz + +2.4 Invoke Smarty-Mode +====================== + +You have two possibilities to invoke the Smarty Mode. + + - Manually: At each file opening you need to launch Smarty Mode + with the following command: + + `M-x smarty-mode' + + - Automatically: Add the following linesin your initialization + file `init.el' : + + (setq auto-mode-alist + (append + '((\"\\.tpl$\" . smarty-mode)) + auto-mode-alist)) + + +3 Customization +*************** + +This chapter describes the differents parameters and functions that +you can change to customize Smarty Mode. To do that, open a Smarty +file, click on the Smarty menu and choose Options then Browse +Options.... + +3.1 Parameters +============== + +3.1.1 Mode +---------- + +Smarty Mode has 2 modes allowing to simplify the writing of Smarty +templates. You can enable/disable each mode individually. + +`smarty-electric-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable automatic generation of template. + If `nil'; template generators can still be invoked through key + bindings and menu. Is indicated in the modeline by \"/e\" after + the mode name and can be toggled by `smarty-electric-mode'. + +`smarty-stutter-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable the stuttering. Is indicated in the + modeline by \"/s\" after the mode name and can be toggled by + `smarty-stutter-mode'. + +3.1.2 Menu +---------- + +Smarty Mode has also 1 menu that you can enable/disable. The menu +Sources is specific to each Smarty files opened. + +`smarty-source-file-menu' + Type: boolean + Default value: `t' + Description: If `t'; the Sources menu is enabled. This menu + contains the list of Smarty file located in the current + directory. The Sources menu scans the directory when a file is + opened. + +3.1.3 Menu +---------- + +`smarty-highlight-plugin-functions' + Type: boolean + Default value: `t' + Description: If `t'; the functions described in the smarty + plugins are highlighted. + +3.1.4 Templates +--------------- + +3.1.4.1 Header +.............. + +`smarty-file-header' + Type: string + Default value: `\"\"' + Description: String or file to insert as file header. If the + string specifies an existing file name the contents of the file + is inserted; otherwise the string itself is inserted as file + header. + Type `C-j' for newlines. + The follonwing keywords are supported: + <filename>: replaced by the file name. + <author>: replaced by the user name and email address. + <login>: replaced by `user-login-name'. + <company>: replaced by `smarty-company-name' content. + <date>: replaced by the current date. + <year>: replaced by the current year. + <copyright>: replaced by `smarty-copyright-string' content. + <cursor>: final cursor position. + +`smarty-file-footer' + Type: string + Default value: `\"\"' + Description: String or file to insert as file footer. See + `smarty-file-header' + +`smarty-company-name' + Type: string + Default value: `\"\"' + Description: Name of the company to insert in file header. + +`smarty-copyright-string' + Type: string + Default value: `\"\"' + Description: Coryright string to insert in file header. + +`smarty-date-format' + Type: string + Default value: `\"%Y-%m-%d\"' + Description: Date format. + +`smarty-modify-date-prefix-string' + Type: string + Default value: `\"\"' + Description: Prefix string of modification date in Smarty file + header. + +`smarty-modify-date-on-saving' + Type: bool + Default value: `nil' + Description: If `t'; update the modification date when the + buffer is saved. + +3.1.5 Miscellaneous +------------------- + +`smarty-left-delimiter' + Type: string + Default value: `\"\"' + Description: Left escaping delimiter for Smarty templates. + +`smarty-right-delimiter' + Type: string + Default value: `\"\"' + Description: Right escaping delimiter for Smarty templates. + +`smarty-intelligent-tab' + Type: bool + Default value: `t' + Description: If `t'; TAB does indentation; completion and insert + tabulations. If `nil'; TAB does only indentation. + +`smarty-word-completion-in-minibuffer' + Type: bool + Default value: `t' + Description: If `t'; enable completion in the minibuffer. + +`smarty-word-completion-case-sensitive' + Type: bool + Default value: `nil' + Description: If `t'; completion is case sensitive. + +3.2 Functions +============= + +3.2.1 Mode +---------- + +`smarty-electric-mode' + Menu: Smarty -> Options -> Mode -> Electric Mode + Keybinding: `C-c C-m C-e' + Description: This functions is used to enable/disable the + electric mode. + +`smarty-stutter-mode' + Menu: Smarty -> Options -> Mode -> Stutter Mode + Keybinding: `C-c C-m C-s' + Description: This function is used to enable/disable the stutter + mode. + +4 Menus +******* + +There are 2 menus: Smarty and Sources. All theses menus can be +accessed from the menubar or from the right click. This chapter +describes each menus. + +4.1 Smarty +========== + +This is the main menu of Smarty Mode. It allows an easy access to the +main features of the Smarty Mode: Templates (see *Note Templates::) +and Options (see *Note Customization::). + +This menu contains also 3 functions that are discussed in the next +part. + +4.1.1 Functions +--------------- + +`smarty-show-messages' + Menu: Smarty -> Show Messages + Keybinding: `C-c M-m' + Description: This function opens the *Messages* buffer to + display previous error messages. + +`smarty-doc-mode' + Menu: Smarty -> Smarty Mode Documentation + Keybinding: `C-c C-h' + Description: This function opens the *Help* buffer and prints in + it the Smarty Mode documentation. + +`smarty-version' + Menu: Smarty -> Version + Keybinding: `C-c C-v' + Description: This function displays in the minibuffer the + current Smarty Mode version with the timestamp. + +4.2 Sources +=========== + +The Sources menu shows the Smarty files in the current directory. If +you add or delete a file in the current directory, you need to +refresh the menu. + +4.2.1 Customization +------------------- + +`smarty-source-file-menu' + Type: boolean + Default value: `t' + Description: If `t'; the Sources menu is enabled. This menu + contains the list of Smarty file located in the current + directory. The Sources menu scans the directory when a file is + opened. + +4.2.2 Functions +--------------- + +`smarty-add-source-files-menu' + Menu: Sources -> *Rescan* + Keybinding: `C-c C-s C-u' + Description: This function is used to refresh the Sources menu. + +5 Stuttering +************ + +The stutter mode is a mode that affects a function to a key. For +example, when you use the `ENTER' key, the associated function will +create a new line and indent it. + +5.1 Customization +================= + +`smarty-stutter-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable the stuttering. Is indicated in the + modeline by \"/s\" after the mode name and can be toggled by + `smarty-stutter-mode'. + +5.2 Functions +============= + +`SPACE' + If in comment, indent the comment and add new line if necessary. + In other case, add a space. + +`(' + If the previous character is a `(', the `((' will be replaced by + `['. + If the previous character is a `[', the `[(' will be replaced by + `{'. + In other case, insert a `('. + +`)' + If the previous character is a `)', the `))' will be replaced by + `]'. + If the previous character is a `]', the `])' will be replaced by + `}'. + In other case, insert a `)'. + +6 Templates +*********** + +In the Smarty Mode, the Smarty functions (like if, while, for, fopen, +fclose) are predefined in functions called \"Templates\". + +Each template can be invoked by the function name or by using the +<SPACE> key after the Smarty function name in the buffer (Note, using +`M-<SPACE>' disable the template). + +A template can be aborted by using the `C-g' or by lefting empty the +tempate prompt (in the minibuffer). + +6.1 Customization +================= + +`smarty-electric-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable automatic generation of template. + If `nil'; template generators can still be invoked through key + bindings and menu. Is indicated in the modeline by \"/e\" after + the mode name and can be toggled by `smarty-electric-mode'. + +For a complete description of the template customizable variables, +see *Note Cu01-Pa01-Template:: + +6.2 Functions +============= + +6.2.1 Smarty Functions +---------------------- + +For Smarty functions, see PDF or HTML documentation. + +6.2.2 Non-Smarty Functions +-------------------------- + +`smarty-template-header' + Menu: Smarty -> Templates -> Insert Header + Keybinding: `C-c C-t C-h' + Description: This function is used to insert a header in the + current buffer. + +`smarty-template-footer' + Menu: Smarty -> Templates -> Insert Footer + Keybinding: `C-c C-t C-f' + Description: This function is used to insert a footer in the + current buffer. + +`smarty-template-insert-date' + Menu: Smarty -> Templates -> Insert Date + Keybinding: `C-c C-t C-d i' + Description: This function is used to insert the date in the + current buffer. + +`smarty-template-modify' + Menu: Smarty -> Templates -> Modify Date + Keybinding: `C-c C-t C-d m' + Description: This function is used to modify the last + modification date in the current buffer. + +7 Bugs, Help +************ + + * To report bugs: Bugtracker + (http://bugtracker.morinie.fr/lisp/set_project.php?project_id=2) + + * To obtain help you can post on the dedicated forum: Forum + (http://forum.morinie.fr/lisp/) + +8 Key bindings +************** + +\\{smarty-mode-map} + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (php-mode php-file-patterns php) "php-mode" "related/php-mode.el" +;;;;;; (19218 42180)) +;;; Generated autoloads from related/php-mode.el +(web-autoload-require 'php-mode 'lp '(nxhtml-download-root-url nil) "related/php-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'php 'custom-loads))) (if (member '"php-mode" loads) nil (put 'php 'custom-loads (cons '"php-mode" loads)))) + +(defvar php-file-patterns '("\\.php[s34]?\\'" "\\.phtml\\'" "\\.inc\\'") "\ +List of file patterns for which to automatically invoke `php-mode'.") + +(nxhtml-custom-autoload 'php-file-patterns 'php-mode nil) + +(nxhtml-autoload 'php-mode `(lp '(nxhtml-download-root-url nil) "related/php-mode" nxhtml-install-dir) "\ +Major mode for editing PHP code. + +\\{php-mode-map} + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (global-mozadd-mirror-mode mozadd-mirror-mode global-mozadd-refresh-edited-on-save-mode +;;;;;; mozadd-refresh-edited-on-save-mode) "mozadd" "related/mozadd.el" +;;;;;; (19235 1650)) +;;; Generated autoloads from related/mozadd.el +(web-autoload-require 'mozadd 'lp '(nxhtml-download-root-url nil) "related/mozadd" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'mozadd-refresh-edited-on-save-mode `(lp '(nxhtml-download-root-url nil) "related/mozadd" nxhtml-install-dir) "\ +Refresh mozadd edited file in Firefox when saving file. +The mozadd edited file is the file in the last buffer visited in +`mozadd-mirror-mode'. + +You can use this for example when you edit CSS files. + +The mozadd edited file must be shown in Firefox and visible. + +\(fn &optional ARG)" t nil) + +(defvar global-mozadd-refresh-edited-on-save-mode nil "\ +Non-nil if Global-Mozadd-Refresh-Edited-On-Save mode is enabled. +See the command `global-mozadd-refresh-edited-on-save-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-mozadd-refresh-edited-on-save-mode'.") + +(nxhtml-custom-autoload 'global-mozadd-refresh-edited-on-save-mode 'mozadd nil) + +(nxhtml-autoload 'global-mozadd-refresh-edited-on-save-mode `(lp '(nxhtml-download-root-url nil) "related/mozadd" nxhtml-install-dir) "\ +Toggle Mozadd-Refresh-Edited-On-Save mode in every possible buffer. +With prefix ARG, turn Global-Mozadd-Refresh-Edited-On-Save mode on if and only if +ARG is positive. +Mozadd-Refresh-Edited-On-Save mode is enabled in all buffers where +`(lambda nil (when (or (derived-mode-p (quote css-mode)) (mozadd-html-buffer-file-p)) (mozadd-refresh-edited-on-save-mode 1)))' would do it. +See `mozadd-refresh-edited-on-save-mode' for more information on Mozadd-Refresh-Edited-On-Save mode. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'mozadd-mirror-mode `(lp '(nxhtml-download-root-url nil) "related/mozadd" nxhtml-install-dir) "\ +Mirror content of current file buffer immediately in Firefox. +When you turn on this mode the file will be opened in Firefox. +Every change you make in the buffer will trigger a redraw in +Firefox - regardless of if you save the file or not. + +For the mirroring to work the edited file must be shown in +Firefox and visible. + +If `nxml-where-mode' is on the marks will also be shown in +Firefox as CSS outline style. You can customize the style +through the option `mozadd-xml-path-outline-style'. + +See also `mozadd-refresh-edited-on-save-mode'. + +\(fn &optional ARG)" t nil) + +(defvar global-mozadd-mirror-mode nil "\ +Non-nil if Global-Mozadd-Mirror mode is enabled. +See the command `global-mozadd-mirror-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-mozadd-mirror-mode'.") + +(nxhtml-custom-autoload 'global-mozadd-mirror-mode 'mozadd nil) + +(nxhtml-autoload 'global-mozadd-mirror-mode `(lp '(nxhtml-download-root-url nil) "related/mozadd" nxhtml-install-dir) "\ +Toggle Mozadd-Mirror mode in every possible buffer. +With prefix ARG, turn Global-Mozadd-Mirror mode on if and only if +ARG is positive. +Mozadd-Mirror mode is enabled in all buffers where +`(lambda nil (when (mozadd-html-buffer-file-p) (mozadd-mirror-mode 1)))' would do it. +See `mozadd-mirror-mode' for more information on Mozadd-Mirror mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (inferior-moz-mode moz-minor-mode) "moz" "related/moz.el" +;;;;;; (19048 2102)) +;;; Generated autoloads from related/moz.el +(web-autoload-require 'moz 'lp '(nxhtml-download-root-url nil) "related/moz" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'moz-minor-mode `(lp '(nxhtml-download-root-url nil) "related/moz" nxhtml-install-dir) "\ +MozRepl minor mode for interaction with Firefox. +With no argument, this command toggles the mode. +Non-null prefix argument turns on the mode. +Null prefix argument turns off the mode. + +When this minor mode is enabled, some commands become available +to send current code area (as understood by c-mark-function) or +region or buffer to an inferior MozRepl process (which will be +started as needed). + +The following keys are bound in this minor mode: + +\\{moz-minor-mode-map} + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'inferior-moz-mode `(lp '(nxhtml-download-root-url nil) "related/moz" nxhtml-install-dir) "\ +Major mode for interacting with Firefox via MozRepl. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (iss-mumamo-mode) "iss-mumamo" "related/iss-mumamo.el" +;;;;;; (19294 54042)) +;;; Generated autoloads from related/iss-mumamo.el +(web-autoload-require 'iss-mumamo 'lp '(nxhtml-download-root-url nil) "related/iss-mumamo" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'iss-mumamo-mode `(lp '(nxhtml-download-root-url nil) "related/iss-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes Inno Setup .iss files. +The main major mode will be `iss-mode'. +The [code] section, if any, will be in `pascal-mode'." t) + +;;;*** + +;;;### (autoloads (iss-mode) "iss-mode" "related/iss-mode.el" (19294 +;;;;;; 54042)) +;;; Generated autoloads from related/iss-mode.el +(web-autoload-require 'iss-mode 'lp '(nxhtml-download-root-url nil) "related/iss-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'iss-mode `(lp '(nxhtml-download-root-url nil) "related/iss-mode" nxhtml-install-dir) "\ +Major mode for editing InnoSetup script files. Upon startup iss-mode-hook is run. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (flymake-js-load flymake-js) "flymake-js" "related/flymake-js.el" +;;;;;; (19218 42180)) +;;; Generated autoloads from related/flymake-js.el +(web-autoload-require 'flymake-js 'lp '(nxhtml-download-root-url nil) "related/flymake-js" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'flymake-js 'custom-loads))) (if (member '"flymake-js" loads) nil (put 'flymake-js 'custom-loads (cons '"flymake-js" loads)))) + +(nxhtml-autoload 'flymake-js-load `(lp '(nxhtml-download-root-url nil) "related/flymake-js" nxhtml-install-dir) "\ +Not documented + +\(fn)" nil nil) + +;;;*** + +;;;### (autoloads (flymake-java-1-load) "flymake-java-1" "related/flymake-java-1.el" +;;;;;; (19264 27004)) +;;; Generated autoloads from related/flymake-java-1.el +(web-autoload-require 'flymake-java-1 'lp '(nxhtml-download-root-url nil) "related/flymake-java-1" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'flymake-java-1-load `(lp '(nxhtml-download-root-url nil) "related/flymake-java-1" nxhtml-install-dir) "\ +Not documented + +\(fn)" nil nil) + +;;;*** + +;;;### (autoloads (flymake-css-load) "flymake-css" "related/flymake-css.el" +;;;;;; (19292 11678)) +;;; Generated autoloads from related/flymake-css.el +(web-autoload-require 'flymake-css 'lp '(nxhtml-download-root-url nil) "related/flymake-css" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'flymake-css-load `(lp '(nxhtml-download-root-url nil) "related/flymake-css" nxhtml-install-dir) "\ +Not documented + +\(fn)" nil nil) + +;;;*** + +;;;### (autoloads (django-mode) "django" "related/django.el" (19411 +;;;;;; 8520)) +;;; Generated autoloads from related/django.el +(web-autoload-require 'django 'lp '(nxhtml-download-root-url nil) "related/django" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'django-mode `(lp '(nxhtml-download-root-url nil) "related/django" nxhtml-install-dir) "\ +Simple Django mode for use with mumamo. +This mode only provides syntax highlighting. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (csharp-mode csharp-mode-hook) "csharp-mode" "related/csharp-mode.el" +;;;;;; (19410 9973)) +;;; Generated autoloads from related/csharp-mode.el +(web-autoload-require 'csharp-mode 'lp '(nxhtml-download-root-url nil) "related/csharp-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(add-to-list 'auto-mode-alist '("\\.cs$" . csharp-mode)) + +(defvar csharp-mode-hook nil "\ +*Hook called by `csharp-mode'.") + +(nxhtml-custom-autoload 'csharp-mode-hook 'csharp-mode t) + +(nxhtml-autoload 'csharp-mode `(lp '(nxhtml-download-root-url nil) "related/csharp-mode" nxhtml-install-dir) "\ +Major mode for editing C# code. This mode is derived from CC Mode to +support C#. + +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `csharp-mode-hook'. + +This mode will automatically add a regexp for Csc.exe error and warning +messages to the `compilation-error-regexp-alist'. + +Key bindings: +\\{csharp-mode-map} + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (winring-rename-configuration winring-delete-configuration +;;;;;; winring-jump-to-configuration winring-prev-configuration +;;;;;; winring-next-configuration winring-duplicate-configuration +;;;;;; winring-new-configuration) "winring" "util/winring.el" (19392 +;;;;;; 30980)) +;;; Generated autoloads from util/winring.el +(web-autoload-require 'winring 'lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'winring-new-configuration `(lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir) "\ +Save the current window configuration and create an empty new one. +The buffer shown in the new empty configuration is defined by +`winring-new-config-buffer-name'. + +With \\[universal-argument] prompt for the new configuration's name. +Otherwise, the function in `winring-name-generator' will be called to +get the new configuration's name. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'winring-duplicate-configuration `(lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir) "\ +Push the current window configuration on the ring, and duplicate it. + +With \\[universal-argument] prompt for the new configuration's name. +Otherwise, the function in `winring-name-generator' will be called to +get the new configuration's name. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'winring-next-configuration `(lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir) "\ +Switch to the next window configuration for this frame. + +\(fn)" t nil) + +(nxhtml-autoload 'winring-prev-configuration `(lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir) "\ +Switch to the previous window configuration for this frame. + +\(fn)" t nil) + +(nxhtml-autoload 'winring-jump-to-configuration `(lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir) "\ +Go to the named window configuration. + +\(fn)" t nil) + +(nxhtml-autoload 'winring-delete-configuration `(lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir) "\ +Delete the current configuration and switch to the next one. +With \\[universal-argument] prompt for named configuration to delete. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'winring-rename-configuration `(lp '(nxhtml-download-root-url nil) "util/winring" nxhtml-install-dir) "\ +Rename the current configuration to NAME. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (winsav-switch-config winsav-save-full-config winsav-save-mode +;;;;;; winsav winsav-put-window-tree) "winsav" "util/winsav.el" +;;;;;; (19295 38082)) +;;; Generated autoloads from util/winsav.el +(web-autoload-require 'winsav 'lp '(nxhtml-download-root-url nil) "util/winsav" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'winsav-put-window-tree `(lp '(nxhtml-download-root-url nil) "util/winsav" nxhtml-install-dir) "\ +Put window structure SAVED-TREE into WINDOW. +Restore a structure SAVED-TREE returned from +`winsav-get-window-tree' into window WINDOW. + +If COPY-WIN-OVL is non-nil then overlays having a 'window +property pointing to one of the windows in SAVED-TREE where this +window still is shown will be copied to a new overlay with +'window property pointing to the corresponding new window. + +If WIN-OVL-ALL-BUFS is non-nil then all buffers will be searched +for overlays with a 'window property of the kind above. + +At the very end of this function the hook `winsav-after-put' is +run. + +\(fn SAVED-TREE WINDOW &optional COPY-WIN-OVL WIN-OVL-ALL-BUFS)" nil nil) + +(let ((loads (get 'winsav 'custom-loads))) (if (member '"winsav" loads) nil (put 'winsav 'custom-loads (cons '"winsav" loads)))) + +(defvar winsav-save-mode nil "\ +Non-nil if Winsav-Save mode is enabled. +See the command `winsav-save-mode' for a description of this minor mode.") + +(nxhtml-custom-autoload 'winsav-save-mode 'winsav nil) + +(nxhtml-autoload 'winsav-save-mode `(lp '(nxhtml-download-root-url nil) "util/winsav" nxhtml-install-dir) "\ +Toggle winsav configuration saving mode. +With numeric ARG, turn winsav saving on if ARG is positive, off +otherwise. + +When this mode is turned on, winsav configurations are saved from +one session to another. A winsav configuration consists of +frames, windows and visible buffers configurations plus +optionally buffers and files managed by the functions used by +option `desktop-save-mode' + +By default this is integrated with `desktop-save-mode'. If +`desktop-save-mode' is on and `winsav-handle-also-desktop' is +non-nil then save and restore also desktop. + +See the command `winsav-switch-config' for more information and +other possibilities. + +Note: If you want to avoid saving when you exit just turn off +this minor mode. + +For information about what is saved and restored and how to save +and restore additional information see the function +`winsav-save-configuration'. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'winsav-save-full-config `(lp '(nxhtml-download-root-url nil) "util/winsav" nxhtml-install-dir) "\ +Saved current winsav configuration in directory DIRNAME. +Then change to this configuration. + +See also `winsav-switch-config'. + +\(fn DIRNAME)" nil nil) + +(nxhtml-autoload 'winsav-switch-config `(lp '(nxhtml-download-root-url nil) "util/winsav" nxhtml-install-dir) "\ +Change to winsav configuration in directory DIRNAME. +If DIRNAME is the current winsav configuration directory then +offer to save it or restore it from saved values. + +Otherwise, before switching offer to save the current winsav +configuration. Then finally switch to the new winsav +configuration, creating it if it does not exist. + +If option `desktop-save-mode' is on then buffers and files are also +restored and saved the same way. + +See also option `winsav-save-mode' and command +`winsav-tell-configuration'. + +\(fn DIRNAME)" t nil) + +;;;*** + +;;;### (autoloads (winsav-rotate winsize-set-mode-line-colors winsize-save-window-configuration +;;;;;; winsize-balance-siblings resize-windows) "winsize" "util/winsize.el" +;;;;;; (19292 49706)) +;;; Generated autoloads from util/winsize.el +(web-autoload-require 'winsize 'lp '(nxhtml-download-root-url nil) "util/winsize" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'resize-windows `(lp '(nxhtml-download-root-url nil) "util/winsize" nxhtml-install-dir) "\ +Start window resizing. +During resizing a window is selected. You can move its +borders. In the default configuration the arrow keys moves the +right or bottom border if they are there. To move the opposite +border use S-arrowkeys. + +You can also do other window operations, like splitting, deleting +and balancing the sizes. The keybindings below describes the key +bindings during resizing:\\<winsize-keymap> + + `balance-windows' \\[balance-windows] + `winsize-balance-siblings' \\[winsize-balance-siblings] + `fit-window-to-buffer' \\[fit-window-to-buffer] + `shrink-window-if-larger-than-buffer' \\[shrink-window-if-larger-than-buffer] + + `winsav-rotate' \\[winsav-rotate] + + `winsize-move-border-up' \\[winsize-move-border-up] + `winsize-move-border-down' \\[winsize-move-border-down] + `winsize-move-border-left' \\[winsize-move-border-left] + `winsize-move-border-right' \\[winsize-move-border-right] + + `winsize-to-border-or-window-left' \\[winsize-to-border-or-window-left] + `winsize-to-border-or-window-up' \\[winsize-to-border-or-window-up] + `winsize-to-border-or-window-right' \\[winsize-to-border-or-window-right] + `winsize-to-border-or-window-down' \\[winsize-to-border-or-window-down] + + Note that you can also use your normal keys for + `forward-char', `backward-char', `next-line', `previous-line' + and what you have on HOME and END to move in the windows. That + might sometimes be necessary to directly select a + window. (You may however also use `other-window' or click + with the mouse, see below.) + + `delete-window' \\[delete-window] + `delete-other-windows' \\[delete-other-windows] + `split-window-vertically' \\[split-window-vertically] + `split-window-horizontally' \\[split-window-horizontally] + `other-window' \\[other-window] + + `winsize-save-window-configuration' \\[winsize-save-window-configuration] + `winsize-next-window-configuration' \\[winsize-next-window-configuration] + `winsize-previous-window-configuration' \\[winsize-previous-window-configuration] + + `mouse-set-point' \\[mouse-set-point] + + `winsize-quit' \\[winsize-quit] + `winsize-stop-go-back' \\[winsize-stop-go-back] + `winsize-stop' \\[winsize-stop] + `winsize-stop-and-execute' \\[winsize-stop-and-execute] + + `winsize-help' \\[winsize-help] + `describe-key' \\[describe-key] + `describe-key-briefly' \\[describe-key-briefly] + (All the normal help keys work, and at least those above will + play well with resizing.) + +Nearly all other keys exits window resizing and they are also +executed. However, the key sequences in `winsize-let-me-use' and +dito for commands there are also executed without exiting +resizing. + +The colors of the modelines are changed to those given in +`winsize-mode-line-colors' to indicate that you are resizing +windows. To make this indication more prominent the text in the +selected window is marked with the face hold in the variable +`winsize-selected-window-face'. + +The option `winsize-juris-way' decides how the borders to move +are selected. If this option is non-nil then the right or bottom +border are the ones that are moved with the arrow keys and the +opposite border with shift arrow keys. + +If `winsize-juris-way' is nil then the following apply: + +As you select other borders or move to new a window the mouse +pointer is moved inside the selected window to show which borders +are beeing moved. The mouse jumps a little bit to make its +position more visible. You can turn this off by customizing +`winsize-make-mouse-prominent'. + +Which borders initially are choosen are controlled by the +variable `winsize-autoselect-borders'. + +** Example: Border selection, movements and windows. + + Suppose you have a frame divided into windows like in the + figure below. If window B is selected when you start resizing + then (with default settings) the borders marked with 'v' and + 'h' will be the ones that the arrow keys moves. To indicate + this the mouse pointer is placed in the right lower corner of + the selected window B. + + +----------+-----------+--------+ + | | v | + | | v | + | A | _B_ v | + | | v | + | | v | + | | x v | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + Now if you press M-<left> then the picture below shows what has + happened. Note that the selected vertical border is now the one + between A and B. The mouse pointer has moved to the + corresponding corner in the window B, which is still selected. + + +----------+-----------+--------+ + | v | | + | v | | + | A v _B_ | | + | v | | + | v | | + | v x | | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + Press M-<left> once again. This gives this picture: + + +----------+-----------+--------+ + | v | | + | v | | + | _A_ v B | | + | v | | + | v | | + | x v | | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + Note that the window A is now selected. However there is no + border that could be moved to the left of this window (which + would otherwise be chosen now) so the border between A and B is + still the one that <left> and <right> moves. The mouse has + moved to A. + + If we now delete window A the new situation will look like + this: + + +----------+-----------+--------+ + | | | + | | | + | _B_ | | + | | | + | | | + | x | | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + + +>>>> testing stuff >>>> +`help-mode-hook' +`temp-buffer-show-function' +`view-exit-action' +<<<<<<<<<<<<<<<<<<<<<<< + +\(fn)" t nil) + +(nxhtml-autoload 'winsize-balance-siblings `(lp '(nxhtml-download-root-url nil) "util/winsize" nxhtml-install-dir) "\ +Make current window siblings the same height or width. +It works the same way as `balance-windows', but only for the +current window and its siblings. + +\(fn)" t nil) + +(nxhtml-autoload 'winsize-save-window-configuration `(lp '(nxhtml-download-root-url nil) "util/winsize" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'winsize-set-mode-line-colors `(lp '(nxhtml-download-root-url nil) "util/winsize" nxhtml-install-dir) "\ +Turn mode line colors on if ON is non-nil, otherwise off. + +\(fn ON)" nil nil) + +(nxhtml-autoload 'winsav-rotate `(lp '(nxhtml-download-root-url nil) "util/winsize" nxhtml-install-dir) "\ +Rotate window configuration on selected frame. +MIRROR should be either 'mirror-left-right, 'mirror-top-bottom or +nil. In the first case the window configuration is mirrored +vertically and in the second case horizontally. If MIRROR is nil +the configuration is not mirrored. + +If TRANSPOSE is non-nil then the window structure is transposed +along the diagonal from top left to bottom right (in analogy with +matrix transosition). + +If called interactively MIRROR will is 'mirror-left-right by +default, but 'mirror-top-bottom if called with prefix. TRANSPOSE +is t. This mean that the window configuration will be turned one +quarter clockwise (or counter clockwise with prefix). + +\(fn MIRROR TRANSPOSE)" t nil) + +;;;*** + +;;;### (autoloads (wrap-to-fill-column-mode wrap-to-fill-left-marg-modes +;;;;;; wrap-to-fill-left-marg wrap-to-fill) "wrap-to-fill" "util/wrap-to-fill.el" +;;;;;; (19306 50510)) +;;; Generated autoloads from util/wrap-to-fill.el +(web-autoload-require 'wrap-to-fill 'lp '(nxhtml-download-root-url nil) "util/wrap-to-fill" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'wrap-to-fill 'custom-loads))) (if (member '"wrap-to-fill" loads) nil (put 'wrap-to-fill 'custom-loads (cons '"wrap-to-fill" loads)))) + +(defvar wrap-to-fill-left-marg nil "\ +Left margin handling for `wrap-to-fill-column-mode'. +Used by `wrap-to-fill-column-mode'. If nil then center the +display columns. Otherwise it should be a number which will be +the left margin.") + +(nxhtml-custom-autoload 'wrap-to-fill-left-marg 'wrap-to-fill t) + +(defvar wrap-to-fill-left-marg-modes '(text-mode fundamental-mode) "\ +Major modes where `wrap-to-fill-left-margin' may be nil.") + +(nxhtml-custom-autoload 'wrap-to-fill-left-marg-modes 'wrap-to-fill t) + +(nxhtml-autoload 'wrap-to-fill-column-mode `(lp '(nxhtml-download-root-url nil) "util/wrap-to-fill" nxhtml-install-dir) "\ +Use `fill-column' display columns in buffer windows. +By default the display columns are centered, but see the option +`wrap-to-fill-left-marg'. + +Fix-me: +Note 1: When turning this on `visual-line-mode' is also turned on. This +is not reset when turning off this mode. + +Note 2: The text properties 'wrap-prefix and 'wrap-to-fill-prefix +is set by this mode to indent continuation lines. + +Key bindings added by this minor mode: + +\\{wrap-to-fill-column-mode-map} + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (xhtml-help xhtml-help-show-tag-ref xhtml-help-tag-at-point +;;;;;; xhtml-help-show-css-ref) "xhtml-help" "nxhtml/xhtml-help.el" +;;;;;; (19364 56214)) +;;; Generated autoloads from nxhtml/xhtml-help.el +(web-autoload-require 'xhtml-help 'lp '(nxhtml-download-root-url nil) "nxhtml/xhtml-help" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'xhtml-help-show-css-ref `(lp '(nxhtml-download-root-url nil) "nxhtml/xhtml-help" nxhtml-install-dir) "\ +Show CSS reference for CSS property name at point. + +\(fn)" t nil) + +(nxhtml-autoload 'xhtml-help-tag-at-point `(lp '(nxhtml-download-root-url nil) "nxhtml/xhtml-help" nxhtml-install-dir) "\ +Get xhtml tag name at or before point. + +\(fn)" nil nil) + +(nxhtml-autoload 'xhtml-help-show-tag-ref `(lp '(nxhtml-download-root-url nil) "nxhtml/xhtml-help" nxhtml-install-dir) "\ +Show xhtml reference for tag name at or before point. + +\(fn)" t nil) + +(let ((loads (get 'xhtml-help 'custom-loads))) (if (member '"xhtml-help" loads) nil (put 'xhtml-help 'custom-loads (cons '"xhtml-help" loads)))) + +;;;*** + +;;;### (autoloads (tidy-build-menu tidy) "tidy-xhtml" "nxhtml/tidy-xhtml.el" +;;;;;; (19364 56214)) +;;; Generated autoloads from nxhtml/tidy-xhtml.el +(web-autoload-require 'tidy-xhtml 'lp '(nxhtml-download-root-url nil) "nxhtml/tidy-xhtml" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'tidy 'custom-loads))) (if (member '"tidy-xhtml" loads) nil (put 'tidy 'custom-loads (cons '"tidy-xhtml" loads)))) + +(nxhtml-autoload 'tidy-build-menu `(lp '(nxhtml-download-root-url nil) "nxhtml/tidy-xhtml" nxhtml-install-dir) "\ +Set up the tidy menu in MAP. +Used to set up a Tidy menu in your favourite mode. + +\(fn &optional MAP)" t nil) + +;;;*** + +;;;### (autoloads (rngalt-set-validation-header) "rngalt" "nxhtml/rngalt.el" +;;;;;; (19365 33760)) +;;; Generated autoloads from nxhtml/rngalt.el +(web-autoload-require 'rngalt 'lp '(nxhtml-download-root-url nil) "nxhtml/rngalt" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'rngalt-set-validation-header `(lp '(nxhtml-download-root-url nil) "nxhtml/rngalt" nxhtml-install-dir) "\ +Not documented + +\(fn START-OF-DOC)" nil nil) + +;;;*** + +;;;### (autoloads (nxml-where-global-mode nxml-where-mode nxml-where) +;;;;;; "nxml-where" "nxhtml/nxml-where.el" (19365 33760)) +;;; Generated autoloads from nxhtml/nxml-where.el +(web-autoload-require 'nxml-where 'lp '(nxhtml-download-root-url nil) "nxhtml/nxml-where" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'nxml-where 'custom-loads))) (if (member '"nxml-where" loads) nil (put 'nxml-where 'custom-loads (cons '"nxml-where" loads)))) + +(nxhtml-autoload 'nxml-where-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxml-where" nxhtml-install-dir) "\ +Shows path in mode line. + +\(fn &optional ARG)" t nil) + +(defvar nxml-where-global-mode nil "\ +Non-nil if Nxml-Where-Global mode is enabled. +See the command `nxml-where-global-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `nxml-where-global-mode'.") + +(nxhtml-custom-autoload 'nxml-where-global-mode 'nxml-where nil) + +(nxhtml-autoload 'nxml-where-global-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxml-where" nxhtml-install-dir) "\ +Toggle Nxml-Where mode in every possible buffer. +With prefix ARG, turn Nxml-Where-Global mode on if and only if +ARG is positive. +Nxml-Where mode is enabled in all buffers where +`nxml-where-turn-on-in-nxml-child' would do it. +See `nxml-where-mode' for more information on Nxml-Where mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads (nxhtml-features-check nxhtml-customize nxhtml) +;;;;;; "nxhtml" "nxhtml/nxhtml.el" (19412 25954)) +;;; Generated autoloads from nxhtml/nxhtml.el +(web-autoload-require 'nxhtml 'lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'nxhtml 'custom-loads))) (if (member '"nxhtml" loads) nil (put 'nxhtml 'custom-loads (cons '"nxhtml" loads)))) + +(nxhtml-autoload 'nxhtml-customize `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml" nxhtml-install-dir) "\ +Customize nXhtml. + +\(fn)" t nil) + +(nxhtml-autoload 'nxhtml-features-check `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml" nxhtml-install-dir) "\ +Check if external modules used by nXhtml are found. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (mako-nxhtml-mumamo-mode asp-nxhtml-mumamo-mode +;;;;;; eruby-nxhtml-mumamo-mode jsp-nxhtml-mumamo-mode gsp-nxhtml-mumamo-mode +;;;;;; smarty-nxhtml-mumamo-mode mjt-nxhtml-mumamo-mode genshi-nxhtml-mumamo-mode +;;;;;; mason-nxhtml-mumamo-mode django-nxhtml-mumamo-mode embperl-nxhtml-mumamo-mode +;;;;;; nxhtml-mumamo-mode) "nxhtml-mumamo" "nxhtml/nxhtml-mumamo.el" +;;;;;; (19389 57826)) +;;; Generated autoloads from nxhtml/nxhtml-mumamo.el +(web-autoload-require 'nxhtml-mumamo 'lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for (X)HTML with main mode `nxhtml-mode'. +This covers inlined style and javascript and PHP. + +See also `mumamo-alt-php-tags-mode'." t) + +(nxhtml-autoload 'embperl-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for Embperl files with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'django-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for Django with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'mason-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for Mason using main mode `nxhtml-mode'. +This covers inlined style and javascript." t) + +(nxhtml-autoload 'genshi-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for Genshi with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'mjt-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for MJT with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'smarty-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for Smarty with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'gsp-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for GSP with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'jsp-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for JSP with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'eruby-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for eRuby with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'asp-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for ASP with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +(nxhtml-autoload 'mako-nxhtml-mumamo-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mumamo" nxhtml-install-dir) "\ +Turn on multiple major modes for Mako with main mode `nxhtml-mode'. +This also covers inlined style and javascript." t) + +;;;*** + +;;;### (autoloads (nxhtml-validation-header-mode nxhtml-short-tag-help +;;;;;; nxhtml-mode) "nxhtml-mode" "nxhtml/nxhtml-mode.el" (19412 +;;;;;; 25947)) +;;; Generated autoloads from nxhtml/nxhtml-mode.el +(web-autoload-require 'nxhtml-mode 'lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(when (fboundp 'nxml-mode) +(nxhtml-autoload 'nxhtml-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mode" nxhtml-install-dir) "\ +Major mode for editing XHTML documents. +It is based on `nxml-mode' and adds some features that are useful +when editing XHTML files.\\<nxhtml-mode-map> + +To see an overview in html format do \\[nxhtml-overview]. + +* Note: Please observe that when loading nXhtml some file + associations are done, see `nxhtml-setup-file-assoc'. + +The nXhtml menu is added by this mode (or actually the minor +mode `nxhtml-menu-mode') and gives quick access and an overview +of some other important features. These includes: + +- multiple major modes, see `define-mumamo-multi-major-mode' +- easy uploading and viewing of files, see for example + `html-upl-upload-file' +- validation in XHTML part for php etc, see + `nxhtml-validation-header-mode' (you probably also want to know about + `nxhtml-toggle-visible-warnings' for this!) +- converting of html to xhtml, see `tidy-buffer' + +The XML menu contains functionality added by `nxml-mode' (on +which this major mode is based). There is also a popup menu +added to the [apps] key. + +The most important features are probably completion and +validation, which is inherited from `nxml-mode' with some small +addtions. In very many situation you can use completion. To +access it type \\[nxml-complete]. Completion has been enhanced in +the following way: + +- If region is active and visible then completion will surround the + region with the chosen tag's start and end tag. However only the + starting point is checked for validity. If something is wrong after + insertion you will however immediately see it if you have validation + on. +- It can in some cases give assistance with attribute values. +- Completion can be customized, see the menus XHTML - Completion: + * You can use a menu popup style completion. + * You can have alternatives grouped. + * You can get a short help text shown for each alternative. +- There does not have to be a '<' before point for tag name + completion. (`nxml-mode' requires a '<' before point for tag name + completion.) +- Completes xml version and encoding. +- Completes in an empty buffer, ie inserts a skeleton. + +Some smaller, useful, but easy-to-miss features: + +* Following links. The href and src attribute names are + underlined and a special keymap is bound to + them:\\<mlinks-mode-map> + + \\[mlinks-backward-link], \\[mlinks-forward-link] Move + between underlined href/src attributes + + \\[mlinks-goto], Mouse-1 Follow link inside Emacs + (if possible) + + It is even a little bit quicker when the links are in an active + state (marked with the face `isearch'):\\<mlinks-active-hilight-keymap> + + \\[mlinks-backward-link], \\[mlinks-forward-link] Move + between underlined href/src attributes + \\[mlinks-goto], Mouse-1 Follow link inside Emacs (if possible) + + If the link is not into a file that you can edit (a mailto link + for example) you will be prompted for an alternative action. + +* Creating links. To make it easier to create links to id/name + attribute in different files there are two special + functions:\\<nxhtml-mode-map> + + \\[nxhtml-save-link-to-here] copy link to id/name (you must + be in the tag to get the link) + \\[nxhtml-paste-link-as-a-tag] paste this as an a-tag. + +Here are all key bindings in nxhtml-mode itself: + +\\{nxhtml-mode-map} + +The minor mode `nxhtml-menu-mode' adds some bindings: + +\\{nxhtml-menu-mode-map} + +Notice that other minor mode key bindings may also be active, as +well as emulation modes. Do \\[describe-bindings] to get a list +of all active key bindings. Also, *VERY IMPORTANT*, if mumamo is +used in the buffer each mumamo chunk has a different major mode +with different key bindings. You can however still see all +bindings with \\[describe-bindings], but you have to do that with +point in the mumamo chunk you want to know the key bindings in. + +--------- +* Note: Some of the features supported by this mode are optional + and available only if other Emacs modules are found. Use + \\[nxhtml-features-check] to get a list of these optional + features and modules needed. You should however have no problem + with this if you have followed the installation instructions + for nXhtml. + +\(fn)" t nil)) + +(nxhtml-autoload 'nxhtml-short-tag-help `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mode" nxhtml-install-dir) "\ +Display description of tag TAG. If TAG is omitted, try tag at point. + +\(fn TAG)" t nil) + +(when (fboundp 'nxml-mode) +(nxhtml-autoload 'nxhtml-validation-header-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-mode" nxhtml-install-dir) "\ +If on use a Fictive XHTML Validation Header for the buffer. +See `nxhtml-set-validation-header' for information about Fictive XHTML Validation Headers. + +This mode may be turned on automatically in two ways: +- If you try to do completion of a XHTML tag or attribute then + `nxthml-mode' may ask you if you want to turn this mode on if + needed. +- You can also choose to have it turned on automatically whenever + a mumamo multi major mode is used, see + `nxhtml-validation-header-if-mumamo' for further information. + +\(fn &optional ARG)" t nil)) + +;;;*** + +;;;### (autoloads (nxhtml-overview nxhtml-menu-mode nxhtml-browse-region +;;;;;; nxhtml-browse-file nxhtml-edit-with-gimp) "nxhtml-menu" "nxhtml/nxhtml-menu.el" +;;;;;; (19412 26360)) +;;; Generated autoloads from nxhtml/nxhtml-menu.el +(web-autoload-require 'nxhtml-menu 'lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-menu" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'nxhtml-edit-with-gimp `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-menu" nxhtml-install-dir) "\ +Edit with GIMP buffer or file at point. + +\(fn)" t nil) + +(nxhtml-autoload 'nxhtml-browse-file `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-menu" nxhtml-install-dir) "\ +View file in web browser. + +\(fn FILE)" t nil) + +(nxhtml-autoload 'nxhtml-browse-region `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-menu" nxhtml-install-dir) "\ +View region in web browser. + +\(fn)" t nil) + +(defvar nxhtml-menu-mode nil "\ +Non-nil if Nxhtml-Menu mode is enabled. +See the command `nxhtml-menu-mode' for a description of this minor mode.") + +(nxhtml-custom-autoload 'nxhtml-menu-mode 'nxhtml-menu nil) + +(nxhtml-autoload 'nxhtml-menu-mode `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-menu" nxhtml-install-dir) "\ +Minor mode to turn on some key and menu bindings. +See `nxhtml-mode' for more information. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'nxhtml-overview `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-menu" nxhtml-install-dir) "\ +Show a HTML page with an overview of nXhtml. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (nxhtml-report-bug) "nxhtml-bug" "nxhtml/nxhtml-bug.el" +;;;;;; (19277 65354)) +;;; Generated autoloads from nxhtml/nxhtml-bug.el +(web-autoload-require 'nxhtml-bug 'lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-bug" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'nxhtml-report-bug `(lp '(nxhtml-download-root-url nil) "nxhtml/nxhtml-bug" nxhtml-install-dir) "\ +Report a bug in nXhtml. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (html-wtoc) "html-wtoc" "nxhtml/html-wtoc.el" (19364 +;;;;;; 56214)) +;;; Generated autoloads from nxhtml/html-wtoc.el +(web-autoload-require 'html-wtoc 'lp '(nxhtml-download-root-url nil) "nxhtml/html-wtoc" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'html-wtoc 'custom-loads))) (if (member '"html-wtoc" loads) nil (put 'html-wtoc 'custom-loads (cons '"html-wtoc" loads)))) + +;;;*** + +;;;### (autoloads (html-upl-ediff-file html-upl-edit-remote-file-with-toc +;;;;;; html-upl-edit-remote-file html-upl-upload-file html-upl-remote-dired +;;;;;; html-upl-upload-site html-upl-upload-site-with-toc html-upl) +;;;;;; "html-upl" "nxhtml/html-upl.el" (19364 56214)) +;;; Generated autoloads from nxhtml/html-upl.el +(web-autoload-require 'html-upl 'lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'html-upl 'custom-loads))) (if (member '"html-upl" loads) nil (put 'html-upl 'custom-loads (cons '"html-upl" loads)))) + +(nxhtml-autoload 'html-upl-upload-site-with-toc `(lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'html-upl-upload-site `(lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'html-upl-remote-dired `(lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir) "\ +Start dired for remote directory or its parent/ancestor. + +\(fn DIRNAME)" t nil) + +(nxhtml-autoload 'html-upl-upload-file `(lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir) "\ +Upload a single file in a site. +For the definition of a site see `html-site-current'. + +\(fn FILENAME)" t nil) + +(nxhtml-autoload 'html-upl-edit-remote-file `(lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'html-upl-edit-remote-file-with-toc `(lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'html-upl-ediff-file `(lp '(nxhtml-download-root-url nil) "nxhtml/html-upl" nxhtml-install-dir) "\ +Run ediff on local and remote file. +FILENAME could be either the remote or the local file. + +\(fn FILENAME)" t nil) + +;;;*** + +;;;### (autoloads (html-toc) "html-toc" "nxhtml/html-toc.el" (19364 +;;;;;; 56214)) +;;; Generated autoloads from nxhtml/html-toc.el +(web-autoload-require 'html-toc 'lp '(nxhtml-download-root-url nil) "nxhtml/html-toc" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'html-toc 'custom-loads))) (if (member '"html-toc" loads) nil (put 'html-toc 'custom-loads (cons '"html-toc" loads)))) + +(defconst html-toc-menu-map (let ((map (make-sparse-keymap))) (define-key map [html-toc-browse-frames-file] (list 'menu-item "Browse Frames File" 'html-toc-browse-frames-file)) (define-key map [html-toc-write-frames-file] (list 'menu-item "Write Frames File" 'html-toc-write-frames-file)) (define-key map [html-toc-write-toc-file] (list 'menu-item "Write TOC File for Frames" 'html-toc-write-toc-file)) (define-key map [html-toc-sep1] (list 'menu-item "--")) (define-key map [html-toc-edit-pages-file] (list 'menu-item "Edit List of Pages for TOC" 'html-site-edit-pages-file)) (define-key map [html-toc-create-pages-file] (list 'menu-item "Write List of Pages for TOC" 'html-toc-create-pages-file)) map)) + +;;;*** + +;;;### (autoloads (html-site-query-replace html-site-rgrep html-site-find-file +;;;;;; html-site-dired-current html-site-set-site html-site-buffer-or-dired-file-name +;;;;;; html-site) "html-site" "nxhtml/html-site.el" (19364 56214)) +;;; Generated autoloads from nxhtml/html-site.el +(web-autoload-require 'html-site 'lp '(nxhtml-download-root-url nil) "nxhtml/html-site" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'html-site 'custom-loads))) (if (member '"html-site" loads) nil (put 'html-site 'custom-loads (cons '"html-site" loads)))) + +(nxhtml-autoload 'html-site-buffer-or-dired-file-name `(lp '(nxhtml-download-root-url nil) "nxhtml/html-site" nxhtml-install-dir) "\ +Return buffer file name or file pointed to in dired. + +\(fn)" nil nil) + +(nxhtml-autoload 'html-site-set-site `(lp '(nxhtml-download-root-url nil) "nxhtml/html-site" nxhtml-install-dir) "\ +Not documented + +\(fn NAME)" t nil) + +(nxhtml-autoload 'html-site-dired-current `(lp '(nxhtml-download-root-url nil) "nxhtml/html-site" nxhtml-install-dir) "\ +Open `dired' in current site top directory. + +\(fn)" t nil) + +(nxhtml-autoload 'html-site-find-file `(lp '(nxhtml-download-root-url nil) "nxhtml/html-site" nxhtml-install-dir) "\ +Find file in current site. + +\(fn)" t nil) + +(nxhtml-autoload 'html-site-rgrep `(lp '(nxhtml-download-root-url nil) "nxhtml/html-site" nxhtml-install-dir) "\ +Search current site's files with `rgrep'. +See `rgrep' for the arguments REGEXP and FILES. + +\(fn REGEXP FILES)" t nil) + +(nxhtml-autoload 'html-site-query-replace `(lp '(nxhtml-download-root-url nil) "nxhtml/html-site" nxhtml-install-dir) "\ +Query replace in current site's files. + +\(fn FROM TO FILE-REGEXP DELIMITED)" t nil) + +;;;*** + +;;;### (autoloads (html-pagetoc-rebuild-toc html-pagetoc-insert-toc +;;;;;; html-pagetoc) "html-pagetoc" "nxhtml/html-pagetoc.el" (19364 +;;;;;; 56214)) +;;; Generated autoloads from nxhtml/html-pagetoc.el +(web-autoload-require 'html-pagetoc 'lp '(nxhtml-download-root-url nil) "nxhtml/html-pagetoc" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'html-pagetoc 'custom-loads))) (if (member '"html-pagetoc" loads) nil (put 'html-pagetoc 'custom-loads (cons '"html-pagetoc" loads)))) + +(nxhtml-autoload 'html-pagetoc-insert-toc `(lp '(nxhtml-download-root-url nil) "nxhtml/html-pagetoc" nxhtml-install-dir) "\ +Inserts a table of contents for the current html file. +The html header tags h1-h6 found in the file are inserted into +this table. MIN-LEVEL and MAX-LEVEL specifies the minimum and +maximum level of h1-h6 to include. They should be integers. + +\(fn &optional MIN-LEVEL MAX-LEVEL)" t nil) + +(nxhtml-autoload 'html-pagetoc-rebuild-toc `(lp '(nxhtml-download-root-url nil) "nxhtml/html-pagetoc" nxhtml-install-dir) "\ +Update the table of contents inserted by `html-pagetoc-insert-toc'. + +\(fn)" t nil) + +(defconst html-pagetoc-menu-map (let ((map (make-sparse-keymap))) (define-key map [html-pagetoc-rebuild-toc] (list 'menu-item "Update Page TOC" 'html-pagetoc-rebuild-toc)) (define-key map [html-pagetoc-insert-style-guide] (list 'menu-item "Insert CSS Style for Page TOC" 'html-pagetoc-insert-style-guide)) (define-key map [html-pagetoc-insert-toc] (list 'menu-item "Insert Page TOC" 'html-pagetoc-insert-toc)) map)) + +;;;*** + +;;;### (autoloads (html-chklnk) "html-chklnk" "nxhtml/html-chklnk.el" +;;;;;; (19364 56214)) +;;; Generated autoloads from nxhtml/html-chklnk.el +(web-autoload-require 'html-chklnk 'lp '(nxhtml-download-root-url nil) "nxhtml/html-chklnk" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'html-chklnk 'custom-loads))) (if (member '"html-chklnk" loads) nil (put 'html-chklnk 'custom-loads (cons '"html-chklnk" loads)))) + +;;;*** + +;;;### (autoloads (web-vcs-investigate-elisp-file web-vcs-byte-compile-file +;;;;;; web-vcs-message-with-face web-vcs-get-files-from-root web-vcs-log-edit +;;;;;; web-vcs-default-download-directory) "web-vcs" "web-vcs.el" +;;;;;; (19412 16397)) +;;; Generated autoloads from web-vcs.el +(web-autoload-require 'web-vcs 'lp '(nxhtml-download-root-url nil) "web-vcs" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'web-vcs-default-download-directory `(lp '(nxhtml-download-root-url nil) "web-vcs" nxhtml-install-dir) "\ +Try to find a suitable place. +Considers site-start.el, site- + +\(fn)" nil nil) + +(nxhtml-autoload 'web-vcs-log-edit `(lp '(nxhtml-download-root-url nil) "web-vcs" nxhtml-install-dir) "\ +Open log file. + +\(fn)" t nil) + +(nxhtml-autoload 'web-vcs-get-files-from-root `(lp '(nxhtml-download-root-url nil) "web-vcs" nxhtml-install-dir) "\ +Download a file tree from VCS system using the web interface. +Use WEB-VCS entry in variable `web-vcs-links-regexp' to download +files via http from URL to directory DL-DIR. + +Show URL first and offer to visit the page. That page will give +you information about version control system (VCS) system used +etc. + +\(fn WEB-VCS URL DL-DIR)" nil nil) + +(nxhtml-autoload 'web-vcs-message-with-face `(lp '(nxhtml-download-root-url nil) "web-vcs" nxhtml-install-dir) "\ +Display a colored message at the bottom of the string. +FACE is the face to use for the message. +FORMAT-STRING and ARGS are the same as for `message'. + +Also put FACE on the message in *Messages* buffer. + +\(fn FACE FORMAT-STRING &rest ARGS)" nil nil) + +(nxhtml-autoload 'web-vcs-byte-compile-file `(lp '(nxhtml-download-root-url nil) "web-vcs" nxhtml-install-dir) "\ +Byte compile FILE in a new Emacs sub process. +EXTRA-LOAD-PATH is added to the front of `load-path' during +compilation. + +FILE is set to `buffer-file-name' when called interactively. +If LOAD + +\(fn FILE &optional LOAD EXTRA-LOAD-PATH COMP-DIR)" t nil) + +(nxhtml-autoload 'web-vcs-investigate-elisp-file `(lp '(nxhtml-download-root-url nil) "web-vcs" nxhtml-install-dir) "\ +Not documented + +\(fn FILE-OR-BUFFER)" t nil) + +;;;*** + +;;;### (autoloads (nxhtmlmaint-byte-uncompile-all nxhtmlmaint-byte-recompile +;;;;;; nxhtmlmaint-start-byte-compilation) "nxhtmlmaint" "nxhtmlmaint.el" +;;;;;; (19378 31293)) +;;; Generated autoloads from nxhtmlmaint.el +(web-autoload-require 'nxhtmlmaint 'lp '(nxhtml-download-root-url nil) "nxhtmlmaint" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'nxhtmlmaint-start-byte-compilation `(lp '(nxhtml-download-root-url nil) "nxhtmlmaint" nxhtml-install-dir) "\ +Start byte compilation of nXhtml in new Emacs instance. +Byte compiling in general makes elisp code run 5-10 times faster +which is quite noticeable when you use nXhtml. + +This will also update the file nxhtml-loaddefs.el. + +You must restart Emacs to use the byte compiled files. + +If for some reason the byte compiled files does not work you can +remove then with `nxhtmlmaint-byte-uncompile-all'. + +\(fn)" t nil) + +(nxhtml-autoload 'nxhtmlmaint-byte-recompile `(lp '(nxhtml-download-root-url nil) "nxhtmlmaint" nxhtml-install-dir) "\ +Recompile or compile all nXhtml files in current Emacs. + +\(fn)" t nil) + +(nxhtml-autoload 'nxhtmlmaint-byte-uncompile-all `(lp '(nxhtml-download-root-url nil) "nxhtmlmaint" nxhtml-install-dir) "\ +Delete byte compiled files in nXhtml. +This will also update the file nxhtml-loaddefs.el. + +See `nxhtmlmaint-start-byte-compilation' for byte compiling. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads (zencoding-preview zencoding-expand-yas zencoding-mode +;;;;;; zencoding-expand-line zencoding) "zencoding-mode" "util/zencoding-mode.el" +;;;;;; (19275 63380)) +;;; Generated autoloads from util/zencoding-mode.el +(web-autoload-require 'zencoding-mode 'lp '(nxhtml-download-root-url nil) "util/zencoding-mode" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(let ((loads (get 'zencoding 'custom-loads))) (if (member '"zencoding-mode" loads) nil (put 'zencoding 'custom-loads (cons '"zencoding-mode" loads)))) + +(nxhtml-autoload 'zencoding-expand-line `(lp '(nxhtml-download-root-url nil) "util/zencoding-mode" nxhtml-install-dir) "\ +Replace the current line's zencode expression with the corresponding expansion. +If prefix ARG is given or region is visible call `zencoding-preview' to start an +interactive preview. + +Otherwise expand line directly. + +For more information see `zencoding-mode'. + +\(fn ARG)" t nil) + +(nxhtml-autoload 'zencoding-mode `(lp '(nxhtml-download-root-url nil) "util/zencoding-mode" nxhtml-install-dir) "\ +Minor mode for writing HTML and CSS markup. +With zen coding for HTML and CSS you can write a line like + + ul#name>li.item*2 + +and have it expanded to + + <ul id=\"name\"> + <li class=\"item\"></li> + <li class=\"item\"></li> + </ul> + +This minor mode defines keys for quick access: + +\\{zencoding-mode-keymap} + +Home page URL `http://www.emacswiki.org/emacs/ZenCoding'. + +See also `zencoding-expand-line'. + +\(fn &optional ARG)" t nil) + +(nxhtml-autoload 'zencoding-expand-yas `(lp '(nxhtml-download-root-url nil) "util/zencoding-mode" nxhtml-install-dir) "\ +Not documented + +\(fn)" t nil) + +(nxhtml-autoload 'zencoding-preview `(lp '(nxhtml-download-root-url nil) "util/zencoding-mode" nxhtml-install-dir) "\ +Expand zencode between BEG and END interactively. +This will show a preview of the expanded zen code and you can +accept it or skip it. + +\(fn BEG END)" t nil) + +;;;*** + +;;;### (autoloads nil nil ("autostart.el" "autostart22.el" "etc/schema/schema-path-patch.el" +;;;;;; "nxhtml-base.el" "nxhtml/html-imenu.el" "nxhtml/html-move.el" +;;;;;; "nxhtml/html-quote.el" "nxhtml/nxhtml-autoload.el" "nxhtml/nxhtml-strval.el" +;;;;;; "nxhtml/nxhtmljs.el" "nxhtml/outline-magic.el" "nxhtml/wtest.el" +;;;;;; "related/flymake-helpers.el" "related/flymakemsg.el" "related/flymu.el" +;;;;;; "related/php-imenu.el" "tests/angus77-setup-jde.el" "tests/emacstest-suites.el" +;;;;;; "tests/ert2.el" "tests/hfy-test.el" "tests/inemacs/bug1013.el" +;;;;;; "tests/mumamo-test.el" "tests/nxhtmltest-helpers.el" "tests/temp-test.el" +;;;;;; "util/appmenu-fold.el" "util/css-simple-completion.el" "util/custsets.el" +;;;;;; "util/ecb-batch-compile.el" "util/fupd.el" "util/idn.el" +;;;;;; "util/key-cat.el" "util/mumamo-aspnet.el" "util/mumamo-trace.el" +;;;;;; "util/new-key-seq-widget.el" "util/nxml-mode-os-additions.el" +;;;;;; "util/org-panel.el" "util/rxi.el" "util/useful-commands.el" +;;;;;; "web-autoload.el") (19412 26385 593000)) + +;;;*** + +;;;### (autoloads (nxhtml-byte-recompile-file nxhtml-byte-compile-file +;;;;;; nxhtml-get-missing-files nxhtml-update-existing-files nxhtml-setup-download-all +;;;;;; nxhtml-setup-auto-download nxhtml-setup-install) "nxhtml-web-vcs" +;;;;;; "nxhtml-web-vcs.el" (19412 16464)) +;;; Generated autoloads from nxhtml-web-vcs.el +(web-autoload-require 'nxhtml-web-vcs 'lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir 'nxhtml-byte-compile-file) + + +(nxhtml-autoload 'nxhtml-setup-install `(lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir) "\ +Setup and start nXhtml installation. + +This is for installation and updating directly from the nXhtml +development sources. + +There are two different ways to install: + + (1) Download all at once: `nxhtml-setup-download-all' + (2) Automatically download part by part: `nxhtml-setup-auto-download' + +You can convert between those ways by calling this function again. +You can also do this by setting the option `nxhtml-autoload-web' yourself. + +When you have nXhtml installed you can update it: + + (3) Update new files in nXhtml: `nxhtml-update-existing-files' + +To learn more about nXhtml visit its home page at URL +`http://www.emacswiki.com/NxhtmlMode/'. + +If you want to test auto download (but not use it further) there +is a special function for that, you answer T here: + + (T) Test automatic download part by part: `nxhtml-setup-test-auto-download' + +====== +*Note* +If you want to download a zip file with latest released version instead then +please see URL `http://ourcomments.org/Emacs/nXhtml/doc/nxhtml.html'. + +\(fn WAY)" t nil) + +(nxhtml-autoload 'nxhtml-setup-auto-download `(lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir) "\ +Set up to autoload nXhtml files from the web. + +This function will download some initial files and then setup to +download the rest when you need them. + +Files will be downloaded under the directory root you specify in +DL-DIR. + +Note that files will not be upgraded automatically. The auto +downloading is just for files you are missing. (This may change a +bit in the future.) If you want to upgrade those files that you +have downloaded you can just call `nxhtml-update-existing-files'. + +You can easily switch between this mode of downloading or +downloading the whole of nXhtml by once. To switch just call the +command `nxhtml-setup-install'. + +See also the command `nxhtml-setup-download-all'. + +Note: If your nXhtml is to old you can't use this function + directly. You have to upgrade first, se the function + above. Version 2.07 or above is good for this. + +\(fn DL-DIR)" t nil) + +(nxhtml-autoload 'nxhtml-setup-download-all `(lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir) "\ +Download or update all of nXhtml. + +You can download all if nXhtml with this command. + +To update existing files use `nxhtml-update-existing-files'. + +If you want to download only those files you are actually using +then call `nxhtml-setup-auto-download' instead. + +See the command `nxhtml-setup-install' for a convenient way to +call these commands. + +For more information about auto download of nXhtml files see +`nxhtml-setup-auto-download'. + +\(fn DL-DIR)" t nil) + +(nxhtml-autoload 'nxhtml-update-existing-files `(lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir) "\ +Update existing nXhtml files from the development sources. +Only files you already have will be updated. + +Note that this works both if you have setup nXhtml to auto +download files as you need them or if you have downloaded all of +nXhtml at once. + +For more information about installing and updating nXhtml see the +command `nxhtml-setup-install'. + +\(fn)" t nil) + +(nxhtml-autoload 'nxhtml-get-missing-files `(lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir) "\ +Not documented + +\(fn SUB-DIR FILE-NAME-LIST)" nil nil) + +(nxhtml-autoload 'nxhtml-byte-compile-file `(lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir) "\ +Not documented + +\(fn FILE &optional LOAD)" nil nil) + +(nxhtml-autoload 'nxhtml-byte-recompile-file `(lp '(nxhtml-download-root-url nil) "nxhtml-web-vcs" nxhtml-install-dir) "\ +Byte recompile FILE file if necessary. +For more information see `nxhtml-byte-compile-file'. +Loading is done if recompiled and LOAD is t. + +\(fn FILE &optional LOAD)" t nil) + +;;;*** diff --git a/emacs/nxhtml/nxhtml-web-vcs.el b/emacs/nxhtml/nxhtml-web-vcs.el new file mode 100644 index 0000000..fb0fb09 --- /dev/null +++ b/emacs/nxhtml/nxhtml-web-vcs.el @@ -0,0 +1,689 @@ +;;; nxhtml-web-vcs.el --- nXhtml things for web-vcs.el +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2010-01-13 Wed +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'nxhtml-base nil t)) +;;(eval-when-compile (require 'nxhtmlmaint nil t)) +(eval-when-compile (require 'web-vcs nil t)) + +(defvar nxhtml-web-vcs-file (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name) + "This file.") + +(defun nxhtml-require-base () + (require 'nxhtml-base nil t) + (unless (featurep 'nxhtml-base) + ;; At startup, need to load it by hand. + (let ((load-path load-path)) + (add-to-list 'load-path (file-name-directory nxhtml-web-vcs-file)) + (require 'nxhtml-base)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Repository URL + + +;;(nxhtml-default-download-directory) +(defun nxhtml-default-download-directory () + (let* ((ur (expand-file-name "" "~")) + (ur-len (length ur)) + (full (if (and (boundp 'nxhtml-install-dir) + nxhtml-install-dir) + nxhtml-install-dir + (file-name-as-directory + (expand-file-name "" + (web-vcs-default-download-directory))))) + (full-len (length full))) + (if (and (> full-len ur-len) + (string= ur (substring full 0 ur-len))) + (concat "~" (substring full ur-len)) + full))) + + +(defun nxhtml-web-vcs-read-dl-dir (prompt) + "Return current nXhtml install dir or read dir." + (or (and (boundp 'nxhtml-install-dir) + nxhtml-install-dir) + (let* ((pr (concat + "A directory named 'nxhtml' will be created below the root you give." + "\n" + prompt)) + (root (read-directory-name pr (nxhtml-default-download-directory)))) + (when root + (expand-file-name "nxhtml" root))))) + +;;(call-interactively 'nxhtml-setup-install) +;; (read-key "Prompt: ") +;; (y-or-n-p "Prompt") +;;;###autoload +(defun nxhtml-setup-install (way) + "Setup and start nXhtml installation. + +This is for installation and updating directly from the nXhtml +development sources. + +There are two different ways to install: + + (1) Download all at once: `nxhtml-setup-download-all' + (2) Automatically download part by part: `nxhtml-setup-auto-download' + +You can convert between those ways by calling this function again. +You can also do this by setting the option `nxhtml-autoload-web' yourself. + +When you have nXhtml installed you can update it: + + (3) Update new files in nXhtml: `nxhtml-update-existing-files' + +To learn more about nXhtml visit its home page at URL +`http://www.emacswiki.com/NxhtmlMode/'. + +If you want to test auto download \(but not use it further) there +is a special function for that, you answer T here: + + (T) Test automatic download part by part: `nxhtml-setup-test-auto-download' + +====== +*Note* +If you want to download a zip file with latest released version instead then +please see URL `http://ourcomments.org/Emacs/nXhtml/doc/nxhtml.html'." + (interactive (let ((curr-cfg (current-window-configuration))) + (describe-function 'nxhtml-setup-install) + (select-window (get-buffer-window (help-buffer))) + (delete-other-windows) + (list + (let* ((key nil) + (has-nxhtml (and (boundp 'nxhtml-install-dir) nxhtml-install-dir)) + (current-way (if has-nxhtml + (if (and (boundp 'nxhtml-autoload-web) + nxhtml-autoload-web) + "Your current setup is to download part by part from the web." + "Your current setup it to download all of nXhtml at once.") + "(You have not currently installed nXhtml.)")) + (prompt (concat "Setup nXhtml install." + "\n" current-way + "\n" + "\n(1) Download whole at once, or (2) part by part as needed" + (if has-nxhtml "\n(3) Update your existing nXhtml" "") + "\n(T) For temporary testing downloading part by part" + "\n" + "\n(? for help, q to quit): ")) + (allowed-keys (if has-nxhtml + '(?1 ?2 ?3 ?T ?q 7) + '(?1 ?2 ?T ?q 7))) + (please nil)) + (while (not (member key allowed-keys)) + (if (not (member key '(??))) + (when key + (unless please + (setq prompt (concat "Please answer with one of the alternatives.\n\n" + prompt)) + (setq please t))) + (describe-function 'nxhtml-setup-install) + (select-window (get-buffer-window (help-buffer))) + (delete-other-windows)) + (setq key (web-vcs-read-key prompt)) + ;;(message "key = %S" key) (sit-for 1) + ) + (case key + (7 (set-window-configuration curr-cfg) + nil) + (?1 'whole) + (?2 'part-by-part) + (?3 'update-existing) + (?T 'test-part-by-part) + ))))) + (message "") + (case way + (whole (call-interactively 'nxhtml-setup-download-all)) + (part-by-part (call-interactively 'nxhtml-setup-auto-download)) + (update-existing (call-interactively 'nxhtml-update-existing-files)) + (test-part-by-part (call-interactively 'nxhtml-setup-test-auto-download)) + ((eq nil way) nil) + (t (error "Unknown way = %S" way)))) + +(defvar nxhtml-basic-files '( + "nxhtml-base.el" + "nxhtml-loaddefs.el" + "web-autoload.el" + "etc/schema/schema-path-patch.el" + "nxhtml/nxhtml-autoload.el" + "autostart.el" + )) + +;;;###autoload +(defun nxhtml-setup-auto-download (dl-dir) + "Set up to autoload nXhtml files from the web. + +This function will download some initial files and then setup to +download the rest when you need them. + +Files will be downloaded under the directory root you specify in +DL-DIR. + +Note that files will not be upgraded automatically. The auto +downloading is just for files you are missing. (This may change a +bit in the future.) If you want to upgrade those files that you +have downloaded you can just call `nxhtml-update-existing-files'. + +You can easily switch between this mode of downloading or +downloading the whole of nXhtml by once. To switch just call the +command `nxhtml-setup-install'. + +See also the command `nxhtml-setup-download-all'. + +Note: If your nXhtml is to old you can't use this function + directly. You have to upgrade first, se the function + above. Version 2.07 or above is good for this." + (interactive (progn + (describe-function 'nxhtml-setup-auto-download) + (select-window (get-buffer-window (help-buffer))) + (delete-other-windows) + (nxhtml-check-convert-to-part-by-part) + (list + (progn + (when (and (boundp 'nxhtml-autoload-web) + (not nxhtml-autoload-web)) + (unless (yes-or-no-p "Convert to updating nXhtml part by part? ") + (throw 'command-level nil))) + (nxhtml-web-vcs-read-dl-dir "Download nXhtml part by part to directory: "))))) + (catch 'command-level + (if (not dl-dir) + (unless (with-no-warnings (called-interactively-p)) + (error "dl-dir should be a directory")) + (nxhtml-check-convert-to-part-by-part) + (when (and (boundp 'nxhtml-install-dir) + nxhtml-install-dir) + (unless (string= (file-truename dl-dir) + (file-truename nxhtml-install-dir)) + (error "Download dir must be same as nxhtml-install-dir=%S" nxhtml-install-dir))) + (let* (;; Need some files: + (web-vcs-el-src (concat (file-name-sans-extension web-vcs-el-this) ".el")) + (web-vcs-el (expand-file-name (file-name-nondirectory web-vcs-el-src) + dl-dir)) + (vcs 'lp) + (base-url (nxhtml-download-root-url nil)) + (byte-comp (if (boundp 'web-autoload-autocompile) + web-autoload-autocompile + t)) + (has-nxhtml (and (boundp 'nxhtml-install-dir) + nxhtml-install-dir)) + (web-vcs-folder-cache nil)) + (setq nxhtml-install-dir dl-dir) + (let ((root (file-name-directory dl-dir))) + (unless (file-exists-p root) + (unless (yes-or-no-p (format "Directory %S does not exist, create it? " root)) + (error "Aborted by user")))) + (make-directory dl-dir t) + (setq message-log-max t) + (view-echo-area-messages) + (message "") + (message "") + (web-vcs-message-with-face 'web-vcs-green "==== Starting nXhtml part by part state ====") + (message "has-nxhtml=%s" has-nxhtml) + ;; Fix-me: First copy this file and web-vcs.el to its destination: + (unless (string= (file-truename dl-dir) + (file-truename (file-name-directory nxhtml-web-vcs-file))) + (dolist (f (list web-vcs-el-src nxhtml-web-vcs-file)) + (copy-file f (expand-file-name (file-name-nondirectory f) dl-dir) + 'ok-overwrite))) + (when byte-comp (web-vcs-byte-compile-newer-file web-vcs-el t)) + ;; Get basic file list: + (catch 'web-autoload-comp-restart + ;;(let ((file-mask (regexp-opt nxhtml-basic-files))) + ;; (web-vcs-get-missing-matching-files vcs base-url dl-dir file-mask)) + (dolist (f nxhtml-basic-files) + (web-vcs-get-missing-matching-files vcs base-url dl-dir f)) + ;; Autostart.el has not run yet, add download dir to load-path. + (let ((load-path (cons (file-name-directory web-vcs-el) load-path))) + (when byte-comp + (dolist (file nxhtml-basic-files) + (let ((el-file (expand-file-name file dl-dir))) + (web-vcs-byte-compile-newer-file el-file nil))))) + (let ((autostart-file (expand-file-name "autostart" dl-dir))) + ;;(ad-deactivate 'require) + (web-vcs-set&save-option 'nxhtml-autoload-web t) + (web-vcs-log nil nil "* nXhtml: Download Part by Part as Needed\n") + (load autostart-file) + (unless (ad-is-active 'require) (ad-activate 'require)) + (web-vcs-log-save) + (web-vcs-message-with-face 'web-vcs-green "==== Basic files for nXhtml part by part are now installed ====") + (web-vcs-display-messages t) + (unless has-nxhtml (nxhtml-add-loading-to-custom-file autostart-file t)))))))) + +;;(call-interactively 'nxhtml-download) +;;;###autoload +(defun nxhtml-setup-download-all (dl-dir) + "Download or update all of nXhtml. + +You can download all if nXhtml with this command. + +To update existing files use `nxhtml-update-existing-files'. + +If you want to download only those files you are actually using +then call `nxhtml-setup-auto-download' instead. + +See the command `nxhtml-setup-install' for a convenient way to +call these commands. + +For more information about auto download of nXhtml files see +`nxhtml-setup-auto-download'." + (interactive (progn + (describe-function 'nxhtml-setup-auto-download) + (select-window (get-buffer-window (help-buffer))) + (delete-other-windows) + ;;(nxhtml-check-convert-to-part-by-part) + (list + (nxhtml-web-vcs-read-dl-dir "Download whole nXhtml to directory: ")))) + + (let ((root (file-name-directory dl-dir))) + (unless (file-exists-p root) + (unless (yes-or-no-p (format "Directory %S does not exist, create it? " root)) + (error "Aborted by user")))) + (make-directory dl-dir t) + (let ((msg (concat "Downloading nXhtml through Launchpad web interface will take rather long\n" + "time (5-15 minutes) so you may want to do it in a separate Emacs session.\n\n" + "Do you want to download using this Emacs session? " + ))) + (if (not (y-or-n-p msg)) + (message "Aborted") + (setq message-log-max t) + (let ((do-byte (y-or-n-p "Do you want to byte compile the files after downloading? "))) + (nxhtml-download-1 dl-dir nil do-byte))))) + + +(defun nxhtml-download-1 (dl-dir revision do-byte) + "Download nXhtml to directory DL-DIR. +If REVISION is nil download latest revision, otherwise the +specified one. + +If DO-BYTE is non-nil byte compile nXhtml after download." + (let* ((has-nxhtml (and (boundp 'nxhtml-install-dir) + nxhtml-install-dir)) + (base-url nxhtml-web-vcs-base-url) + (files-url (concat base-url "files/")) + ;;(revs-url (concat base-url "changes/")) + (rev-part (if revision (number-to-string revision) "head%3A/")) + (full-root-url (concat files-url rev-part)) + (web-vcs-folder-cache nil) + (web-autoload-paranoid nil)) + ;;(nxhtml-require-base) + (when (web-vcs-get-files-from-root 'lp full-root-url dl-dir) + (web-vcs-display-messages t) + (web-vcs-log nil nil "* nXhtml: Download All\n") + (web-vcs-set&save-option 'nxhtml-autoload-web nil) + (message "") + (web-vcs-message-with-face 'web-vcs-green "==== Starting downloading whole nXhtml ====") + (let ((autostart-file (expand-file-name "autostart" dl-dir))) + (load autostart-file) + (web-vcs-log-save) + (web-vcs-message-with-face 'web-vcs-green "==== All files for nXhtml are now installed ====") + (nxhtmlmaint-byte-recompile) + (unless has-nxhtml (nxhtml-add-loading-to-custom-file autostart-file nil)))))) + +(defun nxhtml-check-convert-to-part-by-part () + (when (and (boundp 'nxhtml-install-dir) + nxhtml-install-dir) + (unless (and (boundp 'nxhtml-autoload-web) + nxhtml-autoload-web) + (if (not (boundp 'nxhtml-menu:version)) + (error "nxhtml-install-dir set but no version found") + (unless (string-match "[\.0-9]+" nxhtml-menu:version) + (error "Can't find current version nxhtml-menu:version=%S" nxhtml-menu:version)) + (let* ((ver-str (match-string 0 nxhtml-menu:version)) + (ver-num (string-to-number ver-str))) + (when (< ver-num 2.07) + (web-vcs-message-with-face 'web-vcs-red "Too old nXhtml for download part by part.") + (throw 'command-level nil))))))) + + +;;(directory-files default-directory nil "\\el$") +;;(directory-files default-directory nil "[^#~]$") +;;;###autoload +(defun nxhtml-update-existing-files () + "Update existing nXhtml files from the development sources. +Only files you already have will be updated. + +Note that this works both if you have setup nXhtml to auto +download files as you need them or if you have downloaded all of +nXhtml at once. + +For more information about installing and updating nXhtml see the +command `nxhtml-setup-install'." + ;; Fix-me: download new files too if you are not auto downloading. + (interactive) + (when (y-or-n-p "Do you want to update your nXhtml files? ") + (message "") + (web-vcs-display-messages t) + (web-vcs-message-with-face 'web-vcs-yellow "*\nStarting updating your nXhtml files.\n*\n") + (message nil) + (web-vcs-clear-folder-cache) + (let ((vcs 'lp) + (base-url (nxhtml-download-root-url nil)) + (dl-dir nxhtml-install-dir) + web-vcs-folder-cache) + (setq dl-dir (file-name-as-directory dl-dir)) + (web-vcs-update-existing-files vcs base-url dl-dir dl-dir) + (web-vcs-clear-folder-cache)) + (display-buffer (get-buffer-create "*Compile-Log*")) + (nxhtmlmaint-byte-recompile) + (web-vcs-log-save) + (web-vcs-message-with-face 'web-vcs-yellow "*\nFinished updating your nXhtml files.\n*\n") + (message nil))) + + +;;(nxhtml-maybe-download-files (expand-file-name "nxhtml/doc/img/" nxhtml-install-dir) nil) +;;;###autoload +(defun nxhtml-get-missing-files (sub-dir file-name-list) + (let (file-mask + (root-url (nxhtml-download-root-url nil)) + files-regexp + (full-dir (expand-file-name sub-dir nxhtml-install-dir)) + miss-names) + (if file-name-list + (progn + (dolist (f file-name-list) + (let ((full-f (expand-file-name f full-dir))) + (unless (file-exists-p full-f) + (setq miss-names (cons f miss-names))))) + (setq files-regexp (regexp-opt miss-names))) + (setq files-regexp ".*")) + ;;(unless (file-exists-p full-dir) (make-directory full-dir t)) + (setq file-mask + (concat (file-relative-name (file-name-as-directory full-dir) + nxhtml-install-dir) + files-regexp)) + (let ((web-vcs-folder-cache nil)) + (web-vcs-get-missing-matching-files 'lp root-url nxhtml-install-dir + file-mask)))) + +;; Fix-me: Does not work, Emacs Bug +;; Maybe use wget? http://gnuwin32.sourceforge.net/packages/wget.htm +;; http://emacsbugs.donarmstrong.com/cgi-bin/bugreport.cgi?bug=5103 +;; (nxhtml-get-release-revision) +(defun nxhtml-get-release-revision () + "Get revision number for last release." + (let* ((all-rev-url "http://code.launchpad.net/%7Enxhtml/nxhtml/main") + (url-buf (url-retrieve-synchronously all-rev-url)) + (vcs-rec (or (assq 'lp web-vcs-links-regexp) + (error "Does not know web-vcs 'lp"))) + (rel-ver-regexp (nth 6 vcs-rec)) + ) + (message "%S" url-buf) + (with-current-buffer url-buf + (when (re-search-forward rel-ver-regexp nil t) + (match-string 1))))) + +;;;###autoload +(defun nxhtml-byte-compile-file (file &optional load) + (let ((extra-load-path (when nxhtml-install-dir + (mapcar (lambda (p) + (file-name-as-directory + (expand-file-name p nxhtml-install-dir))) + '("tests" "related" "nxhtml" "util" "."))))) + ;; (message "nxhtml-byte-compile-file:extra-load-path=%s" extra-load-path) + (web-vcs-byte-compile-file file load extra-load-path))) + +;; fix-me: change web-vcs-byte-compile-file instead +;;;###autoload +(defun nxhtml-byte-recompile-file (file &optional load) + "Byte recompile FILE file if necessary. +For more information see `nxhtml-byte-compile-file'. +Loading is done if recompiled and LOAD is t." + (interactive (list (buffer-file-name) + t)) + (let ((elc-file (byte-compile-dest-file file))) + (if (file-newer-than-file-p file elc-file) + (nxhtml-byte-compile-file file load) + (message "Byte compilation of this file is up to date.")))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Add to custom file + + +(defvar nxhtml-handheld-wincfg nil) +(defun nxhtml-handheld-restore-wincg () + (when nxhtml-handheld-wincfg + (set-window-configuration nxhtml-handheld-wincfg) + (setq nxhtml-handheld-wincfg nil))) + +;;(nxhtml-handheld-add-loading-to-custom-file "TEST-ME") +(defun nxhtml-handheld-add-loading-to-custom-file (file-to-load) + (setq nxhtml-handheld-wincfg (current-window-configuration)) + (delete-other-windows) + (let ((info-buf (get-buffer-create "Information about how to add nXhtml to (custom-file)")) + (load-str (format "(load %S)" file-to-load))) + (with-current-buffer info-buf + (add-hook 'kill-buffer-hook 'nxhtml-handheld-restore-wincg nil t) + (insert "Insert the following line to (custom-file), ie the file in the other window:\n\n") + (let ((here (point))) + (insert " " + (propertize load-str 'face 'secondary-selection) + "\n") + (copy-region-as-kill here (point)) + (insert "\nThe line above is in the clipboard so you can just paste it where you want it.\n") + (insert "When ready kill this buffer.") + (goto-char here)) + (setq buffer-read-only t) + (set-buffer-modified-p nil)) + (set-window-buffer (selected-window) info-buf) + (find-file-other-window (custom-file)))) + +;; (nxhtml-add-loading-to-custom-file "test-file") +(defun nxhtml-add-loading-to-custom-file (file-to-load part-by-part) + (message "") + (require 'cus-edit) + (if (not (condition-case nil (custom-file) (error nil))) + (progn + (message "\n\n") + (web-vcs-message-with-face + 'web-vcs-red + (concat "Since you have started this Emacs session without running your init files" + "\nthey are unknown and the installation can not add the statement below." + "\nTo finish the setup of nXhtml you must add" + "\n\n (load %S)" + "\n\nto your custom-file if you have not done it yet." + "\nYou must also customize the variable `nxhtml-autoload-web' to tell that" + (if part-by-part + "\nyou want to download nXhml files as you need them." + "\nyou do not want to allow automatic downloading of nXhtml files." + ) + "\n") + file-to-load) + (message "") + (web-vcs-display-messages t)) + (let ((prompt (concat "Basic setup of nXhtml is done, but it must be loaded from (custom-file)." + "\nShould I add loading of nXhtml to (custom-file) for you? "))) + (if (yes-or-no-p prompt) + (nxhtml-add-loading-to-custom-file-auto file-to-load) + (if (yes-or-no-p "Should I guide you through how to do it? ") + (nxhtml-handheld-add-loading-to-custom-file file-to-load) + (web-vcs-message-with-face 'web-vcs-green + "OK. You need to add (load %S) to your init file" file-to-load)))))) + +;; Fix-me: really do this? Is it safe enough? +(defun nxhtml-add-loading-to-custom-file-auto (file-to-load) + (unless (file-name-absolute-p file-to-load) + (error "nxhtml-add-loading-to-custom-file: Not abs file name: %S" file-to-load)) + (let ((old-buf (find-buffer-visiting (custom-file))) + (full-to-load (expand-file-name file-to-load))) + (with-current-buffer (or old-buf (find-file-noselect (custom-file))) + (save-restriction + (widen) + (catch 'done + (while (progn + (while (progn (skip-chars-forward " \t\n\^l") + (looking-at ";")) + (forward-line 1)) + (not (eobp))) + (let ((start (point)) + (form (read (current-buffer)))) + (when (eq (nth 0 form) 'load) + (let* ((form-file (nth 1 form)) + (full-form-file (expand-file-name form-file))) + (when (string= full-form-file full-to-load) + (throw 'done nil)) + (when (and (string= (file-name-nondirectory full-form-file) + (file-name-nondirectory full-to-load)) + (not (string= full-form-file full-to-load))) + (if (yes-or-no-p "Replace current nXhtml loading in (custom-file)? ") + (progn + (goto-char start) ;; at form start now + (forward-char (length "(load ")) + (skip-chars-forward " \t\n\^l") ;; at start of string + (setq start (point)) + (setq form (read (current-buffer))) + (delete-region start (point)) + (insert (format "%S" full-to-load)) + (basic-save-buffer)) + (web-vcs-message-with-face 'web-vcs-red "Can't continue then") + (web-vcs-display-messages t) + (throw 'command-level nil))))))) + ;; At end of file + (insert (format "\n(load %S)\n" file-to-load)) + (basic-save-buffer)) + (unless old-buf (kill-buffer old-buf)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Start Testing function +(defun emacs-Q-no-nxhtml (&rest args) + (let* ((old-env-load-path (getenv "EMACSLOADPATH")) + sub-env-load-path + (elp-list (or (when old-env-load-path + ;;(split-string old-env-load-path ";")) + (split-string old-env-load-path path-separator)) + load-path)) + (sub-elp-list nil) + ret + (this-emacs-exe (locate-file invocation-name + (list invocation-directory) + exec-suffixes))) + (dolist (p elp-list) + (when (file-exists-p p) + (unless (string= nxhtml-install-dir p) + (let* ((dir (file-name-directory p)) + (last (file-name-nondirectory p)) + (last-dir (file-name-nondirectory + (directory-file-name dir)))) + (unless (and (string= "nxhtml" last-dir) + (member last '("util" "test" "nxhtml" "related" "alt"))) + (setq sub-elp-list (cons p sub-elp-list))))))) + ;;(setq sub-env-load-path (mapconcat 'identity (reverse sub-elp-list) ";")) + (setq sub-env-load-path (mapconcat 'identity (reverse sub-elp-list) path-separator)) + (setenv "EMACSLOADPATH" sub-env-load-path) + (setq ret (apply 'call-process this-emacs-exe nil 0 nil "-Q" args)) + (setenv "EMACSLOADPATH" old-env-load-path) + ret)) + +;; (call-interactively-p 'nxhtml-setup-test-auto-download) +;; (nxhtml-setup-test-auto-download "c:/test2/") +(defun nxhtml-setup-test-auto-download (test-dir) + "Test autoload in a new emacs, started with 'emacs -Q'. +You can choose where to download the files and just delete them +when you have tested enough." + (interactive (list (read-directory-name "Directory for test of auto download of nXhtml: "))) + (let ((this-dir (file-name-directory web-vcs-el-this)) + (this-name (file-name-nondirectory web-vcs-el-this)) + that-file) + (when (and (file-exists-p test-dir) + (not (y-or-n-p (format "Directory %S exists, really test there? " test-dir)))) + (error "Aborted")) + (unless (file-exists-p test-dir) (make-directory test-dir)) + (setq that-file (expand-file-name this-name test-dir)) + (when (file-exists-p that-file) (delete-file that-file)) + (copy-file web-vcs-el-this that-file) + (emacs-Q-no-nxhtml "-l" that-file "-f" "nxhtml-setup-test-auto-download-do-it-here"))) + +(defun nxhtml-setup-test-auto-download-do-it-here () + "Helper for `nxhtml-setup-test-auto-down-load'." + (let ((this-dir (file-name-directory web-vcs-el-this))) + (nxhtml-setup-auto-download this-dir))) + +(defun web-vcs-check-if-modified () + (let ( + (t1 (format-time-string "%Y-%m-%dT%T%z" (date-to-time "2010-01-01 18:20"))) + (t2 (format-time-string "%Y-%m-%dT%T%z" (date-to-time "Mon, 28 Dec 2009 08:57:44 GMT"))) + (url-request-extra-headers + (list + (cons "If-Modified-Since" + (format-time-string + ;;"%Y-%m-%dT%T%z" + "%a, %e %b %Y %H:%M:%S GMT" + (nth 5 (file-attributes "c:/test/temp.el" ))) + ))) + xb) + (setq xb (url-retrieve-synchronously "http://www.emacswiki.org/emacs/download/anything.el")) + (switch-to-buffer xb) + )) +;; (emacs-Q-no-nxhtml "web-vcs.el" "-l" "c:/test/d27/web-autostart.el") +;; (emacs-Q-no-nxhtml "web-vcs.el" "-l" "c:/test/d27/autostart.el") +;; (emacs-Q-no-nxhtml "web-vcs.el" "-f" "eval-buffer" "-f" "nxhtml-temp-setup-auto-download") +;; (emacs-Q-no-nxhtml "-l" "c:/test/d27/web-vcs" "-l" "c:/test/d27/nxhtml-web-vcs" "-f" "nxhtml-temp-setup-auto-download") +;; (emacs-Q-no-nxhtml "-l" "c:/test/d27/nxhtml-web-vcs" "-f" "nxhtml-temp-setup-auto-download") +;; (emacs-Q-no-nxhtml "--geometry=200x50+100+100" "-l" "c:/test/d27/web-vcs" "-f" "web-vcs-nxhtml") +(defun nxhtml-temp-setup-auto-download () + ;;(when (fboundp 'w32-send-sys-command) (w32-send-sys-command #xf030) (sit-for 2)) + (set-frame-size (selected-frame) + (/ 1024 (frame-char-width)) + (/ 512 (frame-char-height)) + ) + (tool-bar-mode -1) + (set-frame-position (selected-frame) 100 50) + (when (y-or-n-p "Do nXhtml? ") + (view-echo-area-messages) + (setq truncate-lines t) + (split-window-horizontally) + (let ((load-path (cons default-directory load-path))) + (require 'web-vcs)) + ;(nxhtml-setup-auto-download "c:/test/d27") + (call-interactively 'nxhtml-setup-auto-download) + )) +;;;;;; End Testing function +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +(provide 'nxhtml-web-vcs) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-web-vcs.el ends here diff --git a/emacs/nxhtml/nxhtml/ChangeLog b/emacs/nxhtml/nxhtml/ChangeLog new file mode 100644 index 0000000..c24d360 --- /dev/null +++ b/emacs/nxhtml/nxhtml/ChangeLog @@ -0,0 +1,17 @@ +2006-04-26 <lennart.borgman.073@student.lu.se> + + * nxhtml.el (nxhtml-insert-skeleton-if-empty) + (nxhtml-insert-frame-skeleton): New functions. + +2006-04-25 <lennart.borgman.073@student.lu.se> + + * nxhtml.el (nxhtml-coding-systems-complete) + (nxhtml-script-url-predicate, nxhtml-script-completion-pattern) + (nxhtml-image-url-predicate, nxhtml-image-completion-pattern) + (nxhtml-mailto-predicate, nxhtml-predicate-error) + (nxhtml-in-xml-attribute-value-regex) + (nxhtml-read-mail-url-history, nxhtml-read-web-url-history) + (nxhtml-read-url-history, nxhtml-read-url-type) + (nxhtml-read-url-type-help, nxhtml-read-url) + (rng-complete-attribute-value): New entries for completion. + diff --git a/emacs/nxhtml/nxhtml/doc/demo.html b/emacs/nxhtml/nxhtml/doc/demo.html new file mode 100644 index 0000000..8696032 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/demo.html @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>nXhtml Short Tour</title> + <script type="text/javascript" src="js/smoothgallery/scripts/mootools.js"></script> + <script type="text/javascript" src="js/smoothgallery/scripts/jd.gallery.js"></script> + <link rel="stylesheet" href="js/smoothgallery/css/layout.css" type="text/css" media="screen"/> + <link rel="stylesheet" href="js/smoothgallery/css/jd.gallery.css" type="text/css" media="screen"/> + <style type="text/css" media="screen"> + /* <![CDATA[ */ + #myGallery { + width: 660px; + height: 500px; + } + /* ]] */ + </style> + + </head> + <body> + <script type="text/javascript"> + function startGallery() { + var myGallery = new gallery($('myGallery'), { + timed: true, + delay: 5000, + embedLinks: false, + showArrows: true, + showCarousel: true, + showInfopane: true, + showDescription: true, + }); + } + window.onDomReady(startGallery); + </script> + <div id="myGallery"><!-- SmoothGallery --> + + <div class="imageElement"> + <h3>Popup completion</h3> + <p>nXhtml can use popup style completion too (for XHTML)</p> + <a href="#" title="open image" class="open"></a> + <img src="img/popup-compl.png" class="full" alt="Popup completion" /> + <img src="img/popup-compl.png" class="thumbnail" alt="Popup completion (thumbnail)" /> + <div> + <p> + more about popup + </p> + <p> + more about popup + </p> + </div> + </div> + + <div class="imageElement"> + <h3>Emacs style completion</h3> + <p>Emacs default style for completion uses the minibuffer and an Emacs window</p> + <a href="#" title="open image" class="open"></a> + <img src="img/emacs-style-completion.png" class="full" alt="Emacs style completion" /> + <img src="img/emacs-style-completion.png" class="thumbnail" alt="Emacs style completion (thumbnail)" /> + <div>du</div> + </div> + </div> + + <div id="DescriptionDiv" + style=" + text-align: center; + "> + desc div + </div> + </body> +</html> diff --git a/emacs/nxhtml/nxhtml/doc/html2xhtml.html b/emacs/nxhtml/nxhtml/doc/html2xhtml.html new file mode 100644 index 0000000..2228c80 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/html2xhtml.html @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title> + How to Convert to XHTML + </title> + <link href="nxhtml.css" rel="StyleSheet" type="text/css" /> + </head> + <body> + <h1> + How to Convert to XHTML + </h1> + <p> + With nxhtml-mode you can edit XHTML documents, but not HTML + dito. So what do you do with your old HTML documents? The + answer is simple: You convert them to XHTML! There is today + not many reasons not to convert them to XHTML. You may say + "but what about old browsers?". Most users just do not have + old browsers today. Old browsers are too dangerous to use on the + Internet. + </p> + <p> + You can convert the documents easily from within nxhtml-mode + with <a href= "http://tidy.sourceforge.net/">Tidy</a>. However + Tidy does not come with nxhtml, you have to install it yourself. + </p> + <p> + When Tidy is called from Emacs you can do a whole directory tree + at once. When a buffer is in nxhtml-mode (and tidy.el is found) + there is an entry on the menus called <b>Tidy</b> from which you + can access tidy and set the options for it. Note especially the + <b>Quick Options Settings</b> where you can set options for + converting to XHTML easily. + </p> + + </body> +</html> diff --git a/emacs/nxhtml/nxhtml/doc/htmlfontify-example.html b/emacs/nxhtml/nxhtml/doc/htmlfontify-example.html new file mode 100644 index 0000000..0eafb8d --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/htmlfontify-example.html @@ -0,0 +1,424 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> +<style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } + --></style> +<style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.comment-face-1419 { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.comment-face-1419 a { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.comment-delimiter-face-1418 { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.comment-delimiter-face-1418 a { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } + --></style><style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.help-argument-name-1420 { color: rgb(0, 0, 255); font-style: italic; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-size: 10pt; text-decoration: none; } +span.help-argument-name-1420 a { color: rgb(0, 0, 255); font-style: italic; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-size: 10pt; text-decoration: underline; } +span.button-0004 { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } +span.button-0004 a { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } + --></style><style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.completion-tooltip-face-1437 { color: rgb(0, 0, 0); background: rgb(255, 255, 255); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.completion-tooltip-face-1437 a { color: rgb(0, 0, 0); background: rgb(255, 255, 255); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.completion-dynamic-face-1436 { color: rgb(0, 0, 0); background: rgb(255, 165, 0); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.completion-dynamic-face-1436 a { color: rgb(0, 0, 0); background: rgb(255, 165, 0); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.compilation-warning-1435 { color: rgb(255, 165, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; font-size: 10pt; text-decoration: none; } +span.compilation-warning-1435 a { color: rgb(255, 165, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.compilation-line-number-1434 { color: rgb(184, 134, 11); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.compilation-line-number-1434 a { color: rgb(184, 134, 11); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.compilation-info-1433 { color: rgb(0, 205, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; font-size: 10pt; text-decoration: none; } +span.compilation-info-1433 a { color: rgb(0, 205, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.compilation-error-1430 { color: rgb(255, 0, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; font-size: 10pt; text-decoration: none; } +span.compilation-error-1430 a { color: rgb(255, 0, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.compilation-column-number-1429 { color: rgb(34, 139, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.compilation-column-number-1429 a { color: rgb(34, 139, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.comint-highlight-prompt-1428 { color: rgb(0, 0, 139); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.comint-highlight-prompt-1428 a { color: rgb(0, 0, 139); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.button-0004 { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } +span.button-0004 a { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } + --></style><style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.default-0273 { color: rgb(250, 235, 215); font-size: 105%; text-decoration: none; } +span.default-0273 a { color: rgb(250, 235, 215); font-size: 105%; text-decoration: underline; } +span.default-0272 { background: rgb(250, 235, 215); font-size: 105%; text-decoration: none; } +span.default-0272 a { background: rgb(250, 235, 215); font-size: 105%; text-decoration: underline; } +span.default-0271 { color: rgb(250, 240, 230); font-size: 105%; text-decoration: none; } +span.default-0271 a { color: rgb(250, 240, 230); font-size: 105%; text-decoration: underline; } +span.default-0270 { background: rgb(250, 240, 230); font-size: 105%; text-decoration: none; } +span.default-0270 a { background: rgb(250, 240, 230); font-size: 105%; text-decoration: underline; } +span.default-0269 { color: rgb(253, 245, 230); font-size: 105%; text-decoration: none; } +span.default-0269 a { color: rgb(253, 245, 230); font-size: 105%; text-decoration: underline; } +span.default-0268 { background: rgb(253, 245, 230); font-size: 105%; text-decoration: none; } +span.default-0268 a { background: rgb(253, 245, 230); font-size: 105%; text-decoration: underline; } +span.default-0267 { color: rgb(255, 250, 240); font-size: 105%; text-decoration: none; } +span.default-0267 a { color: rgb(255, 250, 240); font-size: 105%; text-decoration: underline; } +span.default-0266 { background: rgb(255, 250, 240); font-size: 105%; text-decoration: none; } +span.default-0266 a { background: rgb(255, 250, 240); font-size: 105%; text-decoration: underline; } +span.default-0265 { color: rgb(220, 220, 220); font-size: 105%; text-decoration: none; } +span.default-0265 a { color: rgb(220, 220, 220); font-size: 105%; text-decoration: underline; } +span.default-0264 { background: rgb(220, 220, 220); font-size: 105%; text-decoration: none; } +span.default-0264 a { background: rgb(220, 220, 220); font-size: 105%; text-decoration: underline; } +span.default-0263 { color: rgb(245, 245, 245); font-size: 105%; text-decoration: none; } +span.default-0263 a { color: rgb(245, 245, 245); font-size: 105%; text-decoration: underline; } +span.default-0262 { background: rgb(245, 245, 245); font-size: 105%; text-decoration: none; } +span.default-0262 a { background: rgb(245, 245, 245); font-size: 105%; text-decoration: underline; } +span.default-0261 { color: rgb(248, 248, 255); font-size: 105%; text-decoration: none; } +span.default-0261 a { color: rgb(248, 248, 255); font-size: 105%; text-decoration: underline; } +span.default-0260 { background: rgb(248, 248, 255); font-size: 105%; text-decoration: none; } +span.default-0260 a { background: rgb(248, 248, 255); font-size: 105%; text-decoration: underline; } +span.default-0259 { color: rgb(255, 250, 250); font-size: 105%; text-decoration: none; } +span.default-0259 a { color: rgb(255, 250, 250); font-size: 105%; text-decoration: underline; } +span.default-0258 { background: rgb(255, 250, 250); font-size: 105%; text-decoration: none; } +span.default-0258 a { background: rgb(255, 250, 250); font-size: 105%; text-decoration: underline; } + --></style><style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.default-1432 { text-decoration: underline; color: rgb(176, 48, 96); font-weight: 700; font-size: 164%; } +span.default-1432 a { text-decoration: underline; color: rgb(176, 48, 96); font-weight: 700; font-size: 164%; } +span.default-1431 { color: rgb(176, 48, 96); font-weight: 700; font-size: 164%; text-decoration: none; } +span.default-1431 a { color: rgb(176, 48, 96); font-weight: 700; font-size: 164%; text-decoration: underline; } + --></style><style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.custom-button-0022 { border-width: 1px; border-style: outset; color: rgb(0, 0, 0); background: rgb(211, 211, 211); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.custom-button-0022 a { border-width: 1px; border-style: outset; color: rgb(0, 0, 0); background: rgb(211, 211, 211); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.bold-0248 { background: rgb(173, 255, 47); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.bold-0248 a { background: rgb(173, 255, 47); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } + --></style><style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.match-1438 { background: rgb(255, 255, 0); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.match-1438 a { background: rgb(255, 255, 0); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.underline-1413 { color: rgb(184, 134, 11); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; text-decoration: underline; font-size: 10pt; } +span.underline-1413 a { color: rgb(184, 134, 11); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; text-decoration: underline; font-size: 10pt; } +span.underline-0219 { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } +span.underline-0219 a { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } +span.underline-1412 { color: rgb(0, 205, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; text-decoration: underline; font-size: 10pt; } +span.underline-1412 a { color: rgb(0, 205, 0); font-weight: 700; font-family: outline-courier new; font-stretch: normal; font-style: normal; text-decoration: underline; font-size: 10pt; } + --></style><style type="text/css"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.default a { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.comment-face-1419 { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.comment-face-1419 a { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.comment-delimiter-face-1418 { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.comment-delimiter-face-1418 a { color: rgb(178, 34, 34); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.string-face-1441 { color: rgb(188, 143, 143); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.string-face-1441 a { color: rgb(188, 143, 143); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.match-1438 { background: rgb(255, 255, 0); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } +span.match-1438 a { background: rgb(255, 255, 0); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: underline; } +span.keyword-face-1440 { color: rgb(160, 32, 240); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: none; } +span.keyword-face-1440 a { color: rgb(160, 32, 240); font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; font-size: 10pt; text-decoration: underline; } +span.underline-1439 { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } +span.underline-1439 a { text-decoration: underline; font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; } + --></style> + </head> + <body style="background: #000000; color: #ff9900; padding:2em; margin:4em; margin-top:2em;"> + +<h1>Example of htmlfontify.el output</h1> + +<p style="font-size: 1.3em; width: 35em;"> + The following is an example of the output you can get with htmlfontify.el. + The version used here is shipped with <a href="nxhtml.html" style="color: #ffbb33; ">nXhtml</a>. + (A new version from the original author is on its way.) +</p> + +<table border="0" cellpadding="0" cellspacing="0" style="border: solid rgb(0, 84, 227); width:44.800000000000004em; background:white;"> +<tr> +<td style="background-color:rgb(0, 84, 227); color:rgb(255, 255, 255);border: none; padding:4px; vertical-align: middle;"><img alt="Emacs Icon (patched)" src="img/emacsP16.png" width="16" height="16" /> Emacs - Frame Dump</td> +</tr> +<tr> +<td style="vertical-align:top;"><table border="0" cellpadding="0" cellspacing="0"> +<tr> +<td style="vertical-align:top;"><table border="0" cellpadding="0" cellspacing="0"> +<tr><td style="vertical-align:top;"><div style="width:22.514999999999997em; height:15.079999999999998em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + +<pre><span class="comment-delimiter-face-1418">;; </span><span class="comment-face-1419">This buffer is for notes you don't want to save, and for Lisp evaluation. +</span><span class="comment-delimiter-face-1418">;; </span><span class="comment-face-1419">If you want to create a file, visit that file with C-x C-f, +</span><span class="comment-delimiter-face-1418">;; </span><span class="comment-face-1419">then enter the text in that file's own buffer. +</span> +</pre> + + </div> +<div style="width:22.515em; color:rgb(51, 51, 51); background:rgb(229, 229, 229); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)-- <b>*scratch*</b> (Lisp Interaction Abbrev hs) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +<td style="vertical-align:top;"><div style="width:23.084999999999997em; height:15.079999999999998em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre>cadr is a compiled Lisp function in `<span class="button-0004">subr.el</span>'. +(cadr <span class="help-argument-name-1420">x</span>) + +Return the car of the cdr of <span class="help-argument-name-1420">x</span>. + +<span class="button-0004">[back]</span> +</pre> + + </div> +<div style="width:23.085em; color:rgb(51, 51, 51); background:rgb(229, 229, 229); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)%% <b>*Help*</b> (Help View Abbrev) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +</tr> +</table> +</td> +</tr> +<tr> +<td style="vertical-align:top;"><table border="0" cellpadding="0" cellspacing="0"> +<tr><td style="vertical-align:top;"><div style="width:22.514999999999997em; height:12.76em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre><span class="button-0004">comint-highlight-prompt</span> <span class="comint-highlight-prompt-1428">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +<span class="button-0004">compilation-column-number</span> <span class="compilation-column-number-1429">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +<span class="button-0004">compilation-error</span> <span class="compilation-error-1430">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +<span class="button-0004">compilation-info</span> <span class="compilation-info-1433">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +<span class="button-0004">compilation-line-number</span> <span class="compilation-line-number-1434">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +<span class="button-0004">compilation-warning</span> <span class="compilation-warning-1435">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +<span class="button-0004">completion-dynamic-face</span> <span class="completion-dynamic-face-1436">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +<span class="button-0004">completion-tooltip-face</span> <span class="completion-tooltip-face-1437">abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ</span> +</pre> + + +<div style="margin-top:2em; color: red; text-align: center; "> Truncated to line 11 - 19! </div> +</div> +<div style="width:22.515em; color:rgb(0, 0, 0); background:rgb(191, 191, 191); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)%% <b>*Faces*</b> (Help View Abbrev) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +<td style="vertical-align:top;"><div style="width:23.084999999999997em; height:12.76em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre><span class="default-0258">snow </span><span class="default-0259"> snow </span>#fffafa +<span class="default-0260">ghost white </span><span class="default-0261"> GhostWhite </span>#f8f8ff +<span class="default-0262">white smoke </span><span class="default-0263"> WhiteSmoke </span>#f5f5f5 +<span class="default-0264">gainsboro </span><span class="default-0265"> gainsboro </span>#dcdcdc +<span class="default-0266">floral white </span><span class="default-0267"> FloralWhite </span>#fffaf0 +<span class="default-0268">old lace </span><span class="default-0269"> OldLace </span>#fdf5e6 +<span class="default-0270">linen </span><span class="default-0271"> linen </span>#faf0e6 +<span class="default-0272">antique white </span><span class="default-0273"> AntiqueWhite </span>#faebd7 +</pre> + + +<div style="margin-top:2em; color: red; text-align: center; "> Truncated to line 1 - 9! </div> +</div> +<div style="width:23.085em; color:rgb(51, 51, 51); background:rgb(229, 229, 229); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)%% <b>*Colors*</b> (Help View Abbrev) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +</tr> +</table> +</td> +</tr> +<tr> +<td style="vertical-align:top;"><div style="width:47.025em; height:12.76em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre><span class="default-1431">________________________ +</span><span class="default-1432">Program and Value Search</span> + +When you use Emacs on MS Windows you sometimes want to fetch values +and program locations from MS Windows. Many of these values are +stored in the MS Windows Registry. Since Emacs is written to be used +on many platforms (with the emphasis on GPL platforms) the effort to +let Emacs read the Registry directly has not been made. Below you can +</pre> + + +<div style="margin-top:2em; color: red; text-align: center; "> Truncated to line 29 - 37! </div> +</div> +<div style="width:47.025em; color:rgb(51, 51, 51); background:rgb(229, 229, 229); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)** <b>*Customize EmacsW32*</b> (Custom Abbrev) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +</tr> +<tr> +<td style="vertical-align:top;"><div style="width:47.025em; height:12.76em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre> Add quick printing to File menu (htmlize-view-print-visible): <span class="bold-0248">t</span> + Keep default print entries in File menu (w32-print-menu-show-print): <span class="bold-0248">nil</span> + Keep default ps print entries in File menu (w32-print-menu-show-ps-print): <span class="bold-0248">nil</span> + Use keyboard Window keys as Emacs META (w32-meta-style): <span class="bold-0248">w32-lr</span> + Underlined accelerators in menu bar (menuacc-active): <span class="bold-0248">t</span> + Inferior shell + path for unix style programs (w32shell-shell): <span class="bold-0248">cmd</span> + + <span class="custom-button-0022"> Set all to w32 style! </span> <span class="custom-button-0022"> Reset all to default! </span> <span class="custom-button-0022"> Customize EmacsW32 ... </span> +</pre> + + +<div style="margin-top:2em; color: red; text-align: center; "> Truncated to line 13 - 21! </div> +</div> +<div style="width:47.025em; color:rgb(51, 51, 51); background:rgb(229, 229, 229); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)** <b>*Customize EmacsW32*</b> (Custom Abbrev) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +</tr> +<tr> +<td style="vertical-align:top;"><table border="0" cellpadding="0" cellspacing="0"> +<tr><td style="vertical-align:top;"><div style="width:22.514999999999997em; height:12.76em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre>-*- mode: grep; default-directory: "c:/emacs/p/070604/EmacsW32/nxml/util/" -*- +Grep started at Fri Dec 28 22:54:06 + +grep -i -nH -e "hfy-tmpfont-stack" *.el +<span class="underline-1412">htmlfontify.el</span><span class="underline-0219">:</span><span class="underline-1413">596</span><span class="underline-0219">:</span>(defvar <span class="match-1438">hfy-tmpfont-stack</span> nil +<span class="underline-1412">htmlfontify.el</span><span class="underline-0219">:</span><span class="underline-1413">999</span><span class="underline-0219">:</span> (entry (assoc key <span class="match-1438">hfy-tmpfont-stack</span>)) +<span class="underline-1412">htmlfontify.el</span><span class="underline-0219">:</span><span class="underline-1413">1003</span><span class="underline-0219">:</span> (setq tag (format "%04d" (length <span class="match-1438">hfy-tmpfont-stack</span>)) +<span class="underline-1412">htmlfontify.el</span><span class="underline-0219">:</span><span class="underline-1413">1005</span><span class="underline-0219">:</span> <span class="match-1438">hfy-tmpfont-stack</span> (cons entry <span class="match-1438">hfy-tmpfont-stack</span>))) +</pre> + + +<div style="margin-top:2em; color: red; text-align: center; "> Truncated to line 1 - 9! </div> +</div> +<div style="width:22.515em; color:rgb(51, 51, 51); background:rgb(229, 229, 229); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)%% <b>*grep*</b> (Grep Abbrev) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +<td style="vertical-align:top;"><div style="width:23.084999999999997em; height:12.76em; border: 1px solid rgb(212, 208, 200); overflow:auto; padding:4px;"> + + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre><span class="underline-1439">5 matches for "hfy-tmpfont-stack" in buffer: htmlfontify.el +</span> 596:(<span class="keyword-face-1440">defvar</span> <span class="match-1438">hfy-tmpfont-stack</span> nil + 999: (entry (assoc key <span class="match-1438">hfy-tmpfont-stack</span>)) + 1003: (setq tag (format <span class="string-face-1441">"%04d"</span> (length <span class="match-1438">hfy-tmpfont-stack</span>)) + 1005: <span class="match-1438">hfy-tmpfont-stack</span> (cons entry <span class="match-1438">hfy-tmpfont-stack</span>))) + 1228: <span class="comment-delimiter-face-1418">;;</span><span class="comment-face-1419">(</span><span class="match-1438">hfy-tmpfont-stack</span><span class="comment-face-1419"> nil)</span> +</pre> + + </div> +<div style="width:23.085em; color:rgb(51, 51, 51); background:rgb(229, 229, 229); white-space:pre; overflow:hidden; font-family:monospace;">-- (Unix)%% <b>*Occur*</b> (Occur Abbrev) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div></td> +</tr> +</table> +</td> +</tr> +</table> +</td> +</tr> +<tr> +<td style="padding:1px; color:rgb(0,0,0); "> +<span style="background:rgb(255, 215, 0); color:rgb(0,0,0); "> M-x </span> hfyview-frame</td> +</tr> +</table> +</body> +</html> diff --git a/emacs/nxhtml/nxhtml/doc/img/Las_Medulas.jpg b/emacs/nxhtml/nxhtml/doc/img/Las_Medulas.jpg new file mode 100644 index 0000000000000000000000000000000000000000..694a2c5a08326cf4a70f3c2c0b4bad24ef0cfc2c GIT binary patch literal 40927 zcmb@t1ymi&wl>-eTR?CN?hYZidx8gd4VGZR9fF4lvT%X~cb5PQO>ly{OK^e)4FrA7 z-r47z`@cKhxc?n*)~GeVnq{+UR##W|>~%MDw+!GY$|}eL5C{a22Lo`oLjOX>%jP8j zC@8Q3r~m+<16U9QfEq+^!H5lFWRT~B5eLL*ATI?Y9t079fc!p^LXiLBbs#4DgTH{7 z`A-=H5Oafd2|(TrMtp?7>)y+4-XZ-}cMil0VE5Gj-vnr?s^|m2Q_UxjWCghef%_r+ zRsSE(&B@6p%*8Ft#YN2}D9j}w%qs*?0x7|NYbXzPnf3>(ftdFFzcpd{gC)ThfoLdz z1Ts!;ZcfDLzctqb%Om~4uRsim`MV4R91TLu-|Yw9mx)FHOQZK7Mvnbk4psx8v48h< zKbxq3@O@Wke=rV+(f^cB0?WUSg#wf)0FVh{AoGttT%4Sc%zw{3LgwGIM~w~uh<|Vr z6fB<u{YwW#5JLXozpRz}cU@2nAp8eL{11%s9~kvNFxr1$^#8!ffBOA$zj#0bRRO5M zj+y`9|IQ-+o$S8)y^i;E-v$jB@8?ABPx{{S)S%(1!8EuEssA1!m;fN4wc<f84fcuv z;%^|H0x{wroDP~23B+!o{3SU3$RG{`@f?UzKzt2i18}CHf6D8CGl=>JQ-W&!r4<Ay z2HpUfz^Ve*UlHpwSPQtH>wAI%r5wC>sK5*WJacDOyc3Q&*C}$M10nz$zzI<N;y?|u zFI@M(|Njt#Oye2Y8(AG0s2^(`tJ5|Z{GI$Etb^@!pca2q9hOt`Klp#o{Y?J%bphZ# zWYdWgaM}X^zx!q&Ky0nzAAFx&aFqq5fX5&#f;<8?K*<OMEOZ}Gx4=k8tB*GsK=;DD z<u3vN3=)%;SS_qN<V57fLCP?L`$hqt#1By_2YrD%ICUJ5I^YG60gNM~++9GxZtq@) z!2t%4-vVn+FtG4C*vYgL^<V9&9;hgJJ1lFdXgWOv7W*Jlt4#Ny9p@*LT=TLZ7_=b3 zvev!cd#Hb_@E^YrEHZ#>VWIgs4yZ5tpMVX)hB$)Z4+mcDI0Bu3B-k+o`v5E^06-kA z!I;C7gYcMZBDVcsoIR9})OhX*&mRuZk+py;>)AaYG#O0z7YCaH$rSR><pSKVJCIKQ z`u!&bu8cnu`L`GXklk<alJs3a55I(M?I7z&q5@m@GY^Czhe5!d1o8zEgvaXyUb;qP z%#W|`2J!yN{k!_VekH-NNZzOZ?mjIM0FLDW2=fsD1abj@z(WAY(*%IHWdMNT0)QZR zE6@NhJq=O-(A)ykUI5??Rz*Go0H-Hl-@D)%$pGy-4*<qQ01&GK04Ct7H32sPtVjUZ zx&ZT&0pKy1<}3$SPCqCc1oOahI`6?d$O!<{VF5spI5_YmP#yxtUa;L(Fn<Az*<fEF zNAd>S1m!wLAU+52Hdt;70Cqg#%W`sZ%kV#JSq_#6lLLPb^bTNha*2A1dWmv>Qh)OP z8vD%l49!gMOsU@ikfU?Fld-d`W3p8QX8n&zlE4o^GMX%hY#GSGQrpVgnl_2?8~Ptt z2MbD;{1bp2r)H;hCkiL4`?>g^)4dHL_+K3$*(^bT$a74{>{TEj83W#9L8?@w0>*E1 zf#<MJ08mQ37eP8Z90A$QR!Ab3I6!vGaW4aaPImAV0A6Cb;Q9jE{}Kgg@&jGLPJr*& zEqDt8>-ydJT_M9ju0NxNJPq=>nT|nT@Wem_8IS~R11td-s2Ct;2cjUL-BIDd5^4|F zBO>q`l^^7nAP37sJ^|gR!(hHVP>i|>as_}7)e8Y!jR*j^(E}Pnf*|_${qkNLbO7<s zSp?kX|8=G@K>PQZ#uUW=-I>M~l>c+4aRKpvcc$?H<q(9w@5C?=BmBX`;EKPe|IL}@ z?my3JVDtAE+uc0y1VBYWfubOzLZMJJG*om90!)kt4=_mZ@UaOfNU10(NXf~m={cCF zY1!$>$(aRM*g3g)d3mXrgv127MLBqQx$hf+prN5*Jis8v#3bgXA*bQ~zoxrZ02dXA z13D2Qv;YDw1Q8c<*9lO8dLn}-%lpIS9|8|YNXRHqR5bJlV1Zg300DxCh=7EMjEn@@ z3gUNvctXNO#-rhqLcv!zgVH(^a0kU?q0&iLwGnEJ9@6uey9A@56Fnp*A!T4>VrF6G z<>MC+6cT>&R7O@#UO`b)OIt@*Pv5}8^2JLlYa3fvH+K(DFK?faH=%Fez5fsv8yBCD z_%SItB|9fKFTbF$sJQxbO>G^#zM-+bqqD2K=UZ>z*!aZc)bz~k+{)_O`o`wgkL{hK z<CD{~U*{LUFYm_%0hiA|^!LF2k8$CG<3d0}LPUbzj|+m}2}VR*BxD*c6g(+)sF^c9 zEq4$qfpkn(RT~-|kH#UPxyvXz5k2n;!_ocF{u<f;Y+%9vtC9U{VE-Q19DsocUNg9e zxPSz3zA_fZoXJk0E(81@5n|fK$YPzTgHK?d80Ptqc|kqQpM^`Nt51NyJS~h%rX&6( zbC(1`gme-8GL{0bkx{;XS<&1!zlM=fV_>mjxs&0H?(h=F5%Tx<XR=r3NmC50F>>ue z(;3gZYj3G-e-`fQ;*ubizCyq_ggRfBgwcO?Sm5~th@h_|()4au?WwnRqX|8FRuU=B z_>pZB0z<JbON_AE(4F%}qzjUfgIhhHq`jn4;x7>(4vZ>JfhikoU6`xi0T8~9-Ze30 z6r@V{*N-ajqm4ZW@lgy-Ca27z>pS3b@(0^5ap$i*rNRjpuYSMVt_z)XjDZtjh@qD9 z9ZlxuKAxSU_4z3BZd*sQ^Vi9BRm+#3uG#}v_>MddVm?y0)j+_aV3BOgLz2**3ciq= zB9Se-o(pEd;xQ%O<fT2=c~SKMnkD0*iYt!+jM%lqJY|n|)h3#28Ru8U&C$^M!ju5^ z*plC)2chep@AN)X9go~1#M@52l03l{J2LTcXNg{yBg4)Ua{owS-?MDnpw_VAI%23( zr9Rkx!)g2Z;_aXwG9KrFWI4U<C{@dYsC-N@cai5m1uyf^nN?gws4nEo`eLi(<<D9P zD!szS<k*<4-@V*nOL}YPo6*2-d5IgMqk~Zduw2{BiG`#X55cdb`=d?^z3+fmYVcnU zP8{aL`A0^+^D@K(u%a{Ctbl5ko;iXHTcfH2ac>Wii5RK_Vfe^qnu*_Ldvk6s{1u-H zpJ76~U%56#_p0mV#PKf{<uf^V8E0Hu0d=lp2Xg$GPf>kkj9>i&4-(PHD%oy{^UNDy zb=7B0b#F&Ha0X(7p_K@qGmi+TmKontz2>4?GrFzv^K>N`|2R`dh8q$C3&^~&dq?(s zRxZI|Xn=ysj_p(~-d0^nJc~CbpP)e$W}6h+as3TK!Oc3(yK-16HB7#lV3{UwKP$8& z<Lt^?>W3H1rtsz!IX+Cqx+qD6OXS`2gD_SHn`2=MlC%6*w&m`IPLe`Krwf>TXL|3R zKH9_d{j}9}%-y}@6Be1QnP@7WU-$)1T8AORGtT%qf0Ag`tT`|z6Oqv9=55h#Q5_#@ zW<a9Vlbwd!gfgoNqhdDpTQ{qG)w6O1OPw~Rh_y0RM?}7v4@QN*N!|;#zOsnw&YIe| zh)g6)zAD{^zF&TR)*ABt(?oBnp3274Fhi0Gk;$LRWvAIZ^>~sLRVlD(Ei0^De2%th z!QonTU8AWHl~~op%k-=*gM=a1ZRPJ6pV$Dgl0mErKMYwe#tk|#q05&QZAAv`><$jM z=7D?Rfn*~o415%?r1R%Ldx)%H$d!!oH9|TpFVUAD@hwPh|0=R{@?_b|IV!31r*Eli zOuU&Gv_lV#5rNFy*r=2!9G5AxjA+=vvqt?IQO8yl=wcZHS7w&)0J@Z>7XcL4hNVB7 zCr@S9{p8e*U|Fjz0vhm^I=H@6iaPCQ4CijC(o{PVt8sTsjWH>FL;L=>bP*>Jp4<9k zoyw1wtnG9kDDNsPoO;SVild7=uoWvM`x&=qH=z2VcHT4MrZ&~lA|#`5S7*Fim!r$U zOby#OH*9C~xS^~6`;(F0=tD``Z2mn%ww{q`WXj6p<B!}H<K89ew&&`f$_8?FW=oW+ zQa`%ZcTGs_Yy}kZUX)usIpG@OYHaXo*7V51pmXdXEXm#J(P+XYa}n%ibz!v?Y{$}= zeW-F08{ugsS3u;!V=PQ>H_nuJ&GxtxZ@xDC=|?UsPU&w1_7sg*;}t)3<{mCBikl?Q z|1>iB>iK1s={c*V^Ts=q1`4^|%jv<%GIkjmrepDsm~XXoB64pvsu-<PDJFO1v-PWw zu3LRL`4Sl5u^|Iw`V*!Chvx;YL|pMq&JqF?eryU1_9Tlc4yqP1v=EdZ{Q|BbGV1iO zWq%6m!gaqv@~$SY_LY9F(?N|e1=lJvQBT31HFe(7JAezhWv7#8uEWB~f$+K)&}!`# z*=(6U$XV0e^b2#Kheq3ESq3!bPKZ03K-R?2%0wO+EU~k7;=pcPwHe16bs1y?N~n-i zpBB;gDUk0EE6&xXa*GbBll7mFRV|yz{a|BU(|QwXy<p`ezI9kgJ<qV#?=)04+*d#+ z5$V#O;`41c`}gxk1!wY)tx`xR8dyp}?Xc@fg@e^l`u8}*81|=SZC1bLMW*2i6SC06 zhmpzj85@_=^a}?kw-;iP>lr?c8k>!K!aM5I^;ORYLbX4|4~tr^){OKB2gjc6>%~-e z@4e8FMI}DV@2(bs5S#a8n&iW+HzQKMYr5<9z7{l2^Ebg%@+?Q)r&5JSlxoo6y>o2t z$#LGED;&(V_4ol>!;<5IYi|+0?CCi7oQ4#z5<AgJKj0TngSJ?(Xu^4ut6eY5OD%Kl zYm>E;)m{vrdw1E*>@t#h)X8z>W};A}emcEIRw~g;^$L@<fIVg>(h`kJzXR5cR%lcg zB_fTCY`gaoHxz!@E-uIs>`5*dZM^llnp_lKvg>yij3|BdI8ktDEl@=~nJUdRpUE_{ zNxsJx);#UEqC_~pUgP_rxhK{yTkJc#o<`3Rll3(l>&Y**aaSLS=Ct%q1HaJ7x|+ns zh-Z}@Y<!)Olv;tpPC{*^H>QUCO~3q5c87yy(Tjb#1Y3t466S2Hy8H^CyKW?9b#IXL zI^-PlrRB~4xb$a)t?ixLqH!xxdR%SR(}X*}zWfe<Qd~}`I6Btp(a2upOhBoZ_!1z3 zK8WQ>_hTy`anqOSNK~&yeFU!rj?RWyVITbhK0ZRy4I50_hzQj4*uM2HPq#jxm9=KH zb|MH#zq$Q-W4luJzDWJ*V6!Suh4jgjxJktD6Lf^C4~R-^AvG3-Tjf4FGE46{oM_G2 z_YbdBrB&6qwxg!%Dk?ZEWxu2I<luIga?w?s6?^)8?r|_V7&otx(qyT37-m`sI4h=| zyHJ&SglD~R#%I`6w!FpUO!r$`mAVjM=>gkq*<XyPMntz)@1@4ormwGIt2NxbOqo?w zV6e!?i7eMXcI_r!gJBY86Y-oAugz?R3C;Xg@8(;W+Oja^ymr=}Tdwcml8DqaOwZ~? zC@V31mY1Vz<UEAwNBRCDK6NGr%@yVZHB)j%Z-ww+7Gz5J9+yZyA<Q_aCVjS%bP^b# zauzPSh9cI`wyTyqKQg8DTYEOg#@mkab+?Pux8Gj3?ktU=dE6zjdK;hHN@eJ5zHQYi zIU>P5A2<RFKQDbVY)N-|!+q(>DkrVrRbH8~Je&Mm8ZJ)4*i%I}u+>#>2L3IPN|~2E zIek`PG_2)%?>qz_{QPO~@!>m#CzvgraYWy|DTY+9z63YSD_o_1&N|r_4{>xmL5is< z7X3W=7J>k;*%u!RSlISd`yjcHTTb%%Ab|Dcv>{q4c2Cwtc4s79i@&;uS8(Z5#Oa`L z{N`jiLEZy6z5R|sdX^)>)aPdr+sE<Ah+N{`pZ8x&6}E9E(o2rAP;j*o^L9_CAE=GL z(MKcugi(b!mgqaouTMJ0V7!JIEkuxml#qvKdGM12Pj%H;YEp#`0|nB(3N7GE;K*`z zr%TRoih&CNmXqH^C45EOo?AMfM_1AvZl%DsRDydqygA}a?Q7MsjK5}<(QeDkF}i3| zu6@_nl2H=TdS`mofzf#x7uNKmX!v!y^!#xkyf;0dbILySAP&)?p*lr(G5T3xR2I3e za@L?(;Ubxz_>_`I+Tp;%g0&f69lktb+3WoHgE?KX2hwAC;c`K<30Cp9NAG*-uEQ!k zv*ny$FAoKpM(32^2vJSJ%OATfGO3^_z0u2*tcS7##N_V#CfbEwu%8B#1U)=bC@1f= ze)YJ17px#nNmCG_n^jY0PLImj=4var{)l^%m%|#7>7p>CT7(#-__YM>RoSBn<u8vy z{MXVtu~nz4c>Oe0CU1vr*7Hh_m=OVr9so~*BLU9%3GON<TG8Bd3_b}H#>c6u=k-ng zqVaw5>!oilx+<$23B9kc?&I<$k`4ayR6NEtC|!EeHJ5RBMSyG8w(XJZXJpm}hp!nG ziYLhjFH$_xwHR{EJ8!JRcHGS#OL*^TXg}M3G{h6j%AzrwtHr?cosRHDvbTt?czwRW zY&f+=$oG_~8<nn^6f*bYTjM;bWmvo>LOBZBHB^y}agacj>xE!%erXv=UtC6+Qj3oj zZHlyMgzl8XYs${xv*s^Q!M5UI7IQ>OWCXgVkS@BXo^FC?d8RIoE|LN(I(4Udlx%EG zvB_6e2R+YDZjfbi^pxpH2t9hvm14R)<9=k%KhYxqsuNA2>Jjdj)0B+O76<MkPVq*0 zLoS}UY=)9+k;}1}SF4o=h-iIR%gp83J0nsyWULv#s)YmM^vZSEI^!$Y#<C-oRZ5k~ z+Hb;m^cFgT59J~2uWR-2qnwTX>hh~!Xn#QVe|0&<@fmAcKP!s*6Q1CpBYI?$0y%zu zY$LZML$w&ofaNj_T5j8?@Gzz-=Vtqs)<>(?3?mcY^Ycb8nNNo8)USp9#4D1m0b<4{ zu#gm|7fTP#Sbfv&%Em<ntjA@C7?O&&h{;r^8hwqirf}Ltc)cb2irRX{MbS4(BHmzT zy^DtlsE*{OXm_$wzoHl`P@gzvYxrCjrSchJ+$uSEKG;kS`spe_anu;WGTDDpA_13# ztDD>FK<^e2@GNuys>dC&64iNQ`_O^ZXBOm^u$+QTyZ*BG?)pE}+G~d7jHbmW!*yis zqY?vtW*lyQW?wXL(xAomC|a7_NLYNUAXJnU-s>+(+`DUVBFj}Rrs!s{knqxLbBVYJ zN)5}LHqO2%*J5$>LM*||mSu2VK=5OWR`N9OJXwIuWgwNxqES;Bd?X&!56i`Vdc^eM z(a%ziA^Ml@PJ4aa!jzD5u>((@S4hlj>6<0FrT8`$uuN<Ni`TP=ndGiUw}U3#r{+cN zqwHwfFk#B(u=EFhBML5F((_!fmhDS+Tq9d98F5ajZXbLYTaB`y5^5b6Q*16S3?bbM zaaU8rR(yw6yMeL*jjryb4lT(iR4}_SHNJ6tmgaL%ZbXs!d{tsEv|uc3P{HF`@z;q@ zPAhloX~BVr9Qo*;O<#c^-`TtF9|G(u1bBX228oRh-wZa7jAWsGVX}IcREps$pE~tq zCA_|KIFHp4ZO}_$RK1NF01lR|YF%}T7_#{bl=(cYw>6afN2SPd=jTiOwul#aT20o^ zHk*VrjAjju)&_850=?TFMfDJuznqc7?`(S?<5ABF?E{vv4Vt`H8GVCWR}vIqkbM)a z@zh4S0$Jxb?lg^6z9rs-()nXE!_MgvWiF(Vr5}U?`*ca@J<5{ZlMNwB5m5&1O)Yr* z#DUH+XXPnev1U3I+*N68qL_g_(E6gBF9~Ypdm-JJa!yF24knxnny2f!^^zTIpKk0L z`1(D(_kE{ilCyoOSQYli&%<N7^xo-*vsOzJV+Fzzs{8tRv7N&DpcF@Onlici4?Z~N zg^E@>`7+-DyVJZ!TuMta$GkUVKi{73d~jQ_)H4hBBq8|)ovOjt%TQ^GRSNxJ8l-?z zX+IouJzVByK>J&mv~CpLsC=F6npKcOuG}tRn#nLcKdAd6I)PnR5OI6^lWx-1KI1`@ zVkCcNQ|jFF2#bjg>w-GYXWxp$R6H>|1W(tPS}ZTRY3#h(RHhToS6mR5EzU~kMfmOB zm+vohe|uUuu<-ipZE-=VopPZqCQql-cAyJax`c`ZI-RoX64aQ_zVE{(2O&k(#AovH z><EOxhH4cTWu|!ov!}`-*Lp=d?xw_#Rn-le(v%Wnd)S@=OUih3xXl;>CRi+Z+K=iF zS*57Yc;l?;%f;uMWT}2?2jfJnAN|y7MGnEx>d1RGt;K9?-NQM@0~3>~kUp&4UD{@A z`QkP6fp{x@?X*I$!xAfVS~J&<v#Y=_OoQO_{;~!2In(@7RT-7%6XB{YnbaF^iwPz@ zdmZ`n6}>Cx8|LD3IRDgfuG$mCzz|mpAqfMv43+NDJfgU&)zLuJK~33qk;oNpVA;Lw zN)?l?vsW}%AtD;JFmqITV0UW;x9VFj-|0a!$+2xjv_aS7U%}>F!$b1q7?WjBOLePd zV^BCUO*vdo&vTn&_VbUQ9B6!HA=koL5Lv2<1J**)?UI)aQfp$XeAwXb2wEc1_S6`z zTKP?KF=4{a<4m8%e{#^ivw4qGjey29UuLH4Lf0muBwz~6E8^5I{8koP%$1oBwg65` z6Or?ysMn{yd~95q-sp>YO9$t@sQE@ap_KSi%>~DO&>%K+9HpVub-#hawN<>fC~wB7 z`3N<nlK#^cx`?YW;bxq@yC;6BAwoo~uz3yMgpCtT^r6D}T7@K=a8iODL!m4T{vxr` z(9Z4TB}SLjrM4^1<lGQyq8Y&$=0+t?)GN)$2VW)~t0#@;MT`TlLJ+V0Yez41mEcv@ z4qF)W@-%rC@x6c_)Mq($!)VymOS7qAbm#C<eiUXiz5h19+wxJc^BLbd{9`P`L{c32 z_2TDUlh37ng9O8y5ZrexHS1fSGWw|!yv|N!&pFgyC;w2fG2?UCvK?bQE1MIK;W7NW z0B{HOZO97_ujm<ed_!Gd#_r2edZ!e?LLBHVc>B0a(m4Kg0d%TSTf}Gz@4y-b>1dE! zZY~5$!2ZmBawJwFd{><}>G^GoqU^#s5nJpQ(uvN~+>@|u^ev&y0+@22R)n?!I>#mV zjzW)O!i(Q>d{V^4fy#>2xZ4_Q&L?_}RG-rQ6GUACuh))B+c*)+_$t&<JS{y7-44Wk z$*!_RPp_@Zy=)JeJDz1;z6|Tw8RNek5J`1;@U&USw6xQCP`i=nyEOx<QN+F&Yc;Ba zsdUeINEVdBj&gNr)v$`RKLImxcHbnz%y0HY`IqpFO7d&`AuaZTU|-WI*@k>6jL}}x zz=yAJzQpTqn@<YV%qQXYywX@`{?!8{O3ontDpDLf*H_gp(mCj3c@&{fYl&RBRR4o5 zCWgwFakQt!2M2y-1Ra>^3L^QbC$L26E6orpNL67wm+-Xar8~=a)6pk}`qv#c4z9QU zwN=?|sl5(V5WVY$)8Q7^=w1<~*^X7SRt6tkDTlEqj`$*08;BdFJKvvkFS}JLQ$_Ct zxdsdS=(wFjXk}k&hEj)IOfu&&2+)y7z`TkDxaCQuwLJ>gHyh$P_G}kN160yXF?mCK z7wZ{)eB4Sr8^;GBNY@Q*I@@CnbiR+ZqTHTZ#*L6Rydanh_TSg+k19<bQnub^_{k$U z$UHMre?*y^SUrpO8EXW^Cs6DT7*=fc{g$*&?i2RvXqcj_m3cj3u~ycJHKO;I+7}mY z9v28jiLF+4;@g<=)ly@-nc$G=`4*#E7T#x9^6@U2)8cI}7OOtP(-Zj0#%1EI1jTOH z6f~5r`NHBng!S@SNLlv}T=n8?-!r;DINl0TBFdx|G}m{IIO9uwoa!xvo4*$;sonLA zh3%>%kyiaeX-zXyPF=;`KoqliwWKR|fp?_SUnkz7C$oHYx?@f|{sGnOls6gTU|hPN zT%L^nSb;-cd##O!Eaf}lrRHk+jGd!e*M-Zey7D8xh?~|6u|}#gv@G_ACq@R1QV*g% z@Ow1p3L1hj_uABFCFeTb*G|jzhd6BICskfIwy3DgJ=pD8JGc3S;u<wpS2KvPw2bdG zHqdHiEl51*X5bNy7Cx99E4v)ryf#&1zZyI{s}6NiW=%>wg}oEe2*BsoeLB8BL8mXN zY9d2eXTWc6=;3;^CgbWlT>o2rlho~)FlviWT&4Tfv0)j3ZWCWo2WB|V@Z$l|?p7x9 zEA1rX-0=^taZTi-G8VjccwMOkOg3~WBVRng*E4Lej7S0<3Z);e1~m$#x$m={BgPo` zcrBXY^DDG%iJz+LJ`O_ir)?RCTCZI2LW-*3OLp2@8BIz+YrX!F{RzRBG{udppY-Vu zQl2L2^VYmnq7nj+ohthBwsvNcZtLvIfKK??L{DX+b+&o^Z#{&LX<+g(PIgjj4|;CY z@EuSgLzpKK`S1?l7z$9m0}KMFHZ;Fyhv1?^Ui9`*#;Y5<Ty&`}Ggo%oWgcd;88=l2 z_i^X`$_~@M1Kzf0bUWB8;{BQ_>=vZ#pe^Sur_~@nTq967alKHVoS6Omfpk<sO$D3p zoyR`G0M4?yj55Key)OM)OpM>|c4vKM9jve*NvggQIbXL<L|1+>q&Mm^zDIdTHS)i= zbR1On!`YcFg%<ovt+T_jsP1O}a$O-KB7r^<&_jZRj0`%3Fz%gLQ0xZ}&@gbZ@$hi5 zadGj9$RFYpkP_nJ64MZqQczG)QQ<$NrKhE&C#R&M{L6I(R)wNKu~1R5C<$;0DF3hN zFV_|5sgM3It}BXvTvz`%uE39;K-U!t6oQHddVnPVaa<uGLJ^T5NT56DzdEjHor7Ws zxU-=5eyh<#LX8#BZ*@dZ^dvY|GrM{WY=I1PwcI<A{?$GJwu68Spg_S)F3^8;?-&C; zV<@0c1|;xnDO^M(JQ{p1DP&r80&X+stWgv?>7c5^n6?$dyZ_?5xuWF?CD_p_i3la2 z%~MQpODfXHGZtpmD$-R6OJLO=&%PJ__*<x-r`YJGU*T$^QJy9?$a<XMwtc`hpplod zO-RTJ$~9eB1qiBCD!7bY_`6T!$0ONw<>yJl^a?b(o<&yW>c(H|CY3iBq+852gXd+9 z@`iZ}XC;Ci*~WGI$S&_N4;J(MEfBF&DSEJ=@5a;#5N@)pCjQl$c?`jh-hBm+u)|ET zqSILtI_YChZ8ZgRC*Z88feaGUEH6b5h-}tJ?Zba%<;-7rTqzu`54#u2=L@7T9(U4x zWkQM@hjlKGI?gjiJsOwx#pKvEi?5cS=}7{FWW;Z77rXrpkKPE7dgLGW(uaPPpk5Cd z30ZL6KQ7%mqjqsSN`~j1N>#q>lYsw3*r~Fec6#8usI%&;MFPVWAs&gj9rGGu6DzeL zO(<*Z-gc&HCn1PML>!VFZn34c%da`%=a_UNXkeoFhL}YmzFN3YT88G-*CQm<`>jVc z4X`Esol=x7&5U-bs+hn!S+u#sdfbv{tXX_-39TK_6vvGPTE9Sx5YlGnndsL37sLFw z*18vl^L_@+w|!vaUcsWPQuL3th*&fReKlQ+`4fZ_+`r9}{bi!RzzM;gM%Q0R3w)C} zE%M5q6*Nnu$IRT?*Seo%Ml(X=>?v-M&YQfZD?|JB^axI9<ep3|?)_Kq_a8AdBm~pj zD$q~&O4JQXkDhJ7D5?hnz4w~~JGp4|oP<yGO$t6`m-C5c9P!`a%QjT=R5pJ4ZmhR9 z@nWoVpPsX!+i1U6v~qt4vUXtYk>`dHGshddpnyk6mg>P37wC(To?xeS2W%`T@$@ys zge&$?C~OwZ^dcy;Xdc-^NE)wuzEarWERCps*!Izys2vDnA>~8gh<Jx?1{HkePB*=^ ztHV@RUzd7VorM|L$w@*&?&n>&BKq;|3%uW7n_l7Q61Ux2?dxK%GQzzLWV{v7@Cn=0 zpk?aETKw$Frbagp@Vb43Gs>Qx*S&X|#znjXqDyttd~gsUJ=GIt`HP7#?cu2w!J-q_ zgl4qnhd2aFj1d*(D`91fWd+niO%ZG5<4wPHSY^$fbTq`|yPo!`9#;0$$|Fb(EFn!8 zU1U#^;YuHTJ+P>u`e<-0K{%5!jI?{)c3T@~`BI3c_nct-;Z4E*QwTN8=(90X*j`Yl zv;22)R=dY|dJBRI0@6KARPTQ3#o(9&(3E4nr&h>cCi$Xjf<6j(k7-;EF3=iF4){Q* z8B2B9wy$MNrTjdRUeGiq5S&3^tWD4mR6eF}Y1}R4?pW}mC%+wXC4Q6N0m2EdWeOb^ z9G*)&^DAkz+Eks0`Y^(x!-`F0lpRCcy;a33cU*)W{*v09S+2sM;#u$In^aQm4*?Xk zoSF`$uDuk<M&Vtf;;8c9#NRgMkAKNxEKabJ`(VzN7JepJ_`S=ikXl;r^6hF){+NFj zV@kqHx+5b)1+Pk9EEykBO`_#z7LJ)iwm!;qJ6zX;e5|Oil?#wCKLi|HcoEFL*3HRW z)i=6ie_2xXh2gU31Z%7`?|a04G@_#ecz=ttIL*@a=bE5zeItW<2h_R*7&NZ9GS7Xo z+jK+M9yaVIO`MoB`?jO#UceM~<~{R<i^U<xV*9-42Pe@B*&?(oVPw|L&%1N6^7FL< zP>P4p3^>8QKv!dAO+)(gE}6yWzzwGAcoh-7p8?`il^De!n{>9Z3PTHd`;0MjK*DJ4 zXIS&xW^_TC?DRG@FKq-SE*3Wp5ysary{u!q6b-pee_<l3Uv;Y6Cgt!v@_>{5X*vn~ zpz9s}j1MByo6oy^)jHhmg&p5|<v!PTl2JqzLoJNO9JT>BXU6~c=3Mx=oM>vu@ZEJ) zk!`Rfk!8@!H+}x&?hgdrzP2rjnhPMWV?dT)-`)X=7k5B+xX3Q%ZI&y2y2rMe2c0X8 zIfQ8w+u%~Q^R3+tolbLu0)>VBF~2w=I;552YHi_4caU^Kmo%}6Z*st4II;WJ(4^3^ zFM^M5jJ?&w4jGf#jH=_dk4YkCc<&ce)bz)l_{8LHzYv3NNuN~~kr5yx?Nf$aOZ1hO z#~+mlMX`Gg38RPEks!vKcMwBi$&_CW#7}>x(2>F9qYdWgJE&5*V&<u$-HlErw5zVx z7YN@@G9iBPPZRs1y*gj++$`@L4Q$VqKBty<v7C8`(Iy<t^J#>8{o(hd*MgBA8Rk7} zUs1nhrpafCr7S(W18(hlMV(g|G*t4j;VbL+>GuoD);VbGFh8lD^DgXkw=KK+UytIh zOD4;y{jK_vzop%N@Ak(_4$dz_h`R%h>8P(N5h7+5W^8eiOReCI@5vvAPPU3CQ|xZy zJNY8`+1gQ<pR1-0RW;Pt#^qmFG6yKqv>lpuYp$ynm@H!70hWHnB=*ZP17XEt7v;D% zS8_+saEafR(1(GqfWmqXWCIL77hEj&bMQUYY`Oy)1GmK2QYvI_Uo@5+iCB6}4K?MU zcTB3-lEkTo-{!Ozj8v9Ce;CFqcMYFcIFqFs`(R+p@5$D<bjjj8{VFiVxawW<eEi^> z^G0^ZnvIr81wyhNQb74T?j2CWGWb%z-|h7{f80_j!Sy%JmZb`-v8h&UZ}3W|x%u(B zF|;F?kUC0iQrNGzctgx9KfVOUU@J$HBI&8hES^>Mth3GaA{qNL`9zcVkTTad^<h4S zlIFk+JpRZTD^x6BtlCFa=rh*6XKkw`N+JQMYZH_D`3Y|yT#E-cl^ikUonYKD_R4jM zQ2(BYUYPlcyOcwvJoz!9K{VLkU1fz#lo_SGT-95)8*0;pEb&(BYND_s<SP@Xo6!%^ z-u5Q!m?FHLBMFAikUQYpC^n}>6n>^LkG$-(V^Q%6F=DbrnMIt|#CTr6pCq5C&#xjX z9hmBM+?BQ@T@Zb=a&kV?>XzVd4NMY2>eWEGRlBS^Kw}8yx21N_>ibJFjOz@lvHThN zxqNbMIJ1kPr=#LYzeclCkE$X*^usH?+sh%no?=eNeOdPM)BdU?4z2VZS=38i{j^$3 z^F`I8klkI)E^B(}PU=Wmu@jxxIi~CCZvUDi^F{5rpK5y7{j3n=L0ibpJRU2LBlXth zXhz%Mr{MfNJ%sWXxcS1dPOKd?lrL1MUrSOx3z=$WVQL|@sp%TpO?42XC)8O}AETqE zFWlM+IxpXq{~@(QuYqRVF)}eVEif{;Y0%5-INwhnz#79xCa2s>V6~u#S|LH%B!B%> zaIg6LiP3CsIq<rj-=A)}Yy-KxdB9yEP~t=e{ElVlfF9c!v!YkP^0pQht6&_Y9TBn+ zq2;0yb9j{1bES;2Z>`<{MR`Skl((^YRuf7M_*)!NO^3bh=}M_#AN^M38F6bCES~*Y z=REP?t>6lEx@y-{8vTxRLAOvZu<U1B11a+B4CnF2hVd?E8b6^|je1Xmg=}1R<nc~$ zc=h_L6*1pnm?2Meb>mhcB5itNqZf7Zn>Unu1iJQ;LTO)VL{$p;TB!4Xp0P=aZ2&jL z6AyLHQ7O^Z5>%yOs5fk|1w$EUnqvb7y2>@)$x5z_rNPQyh((2SwM&LYu~$a>Ld2!e z@MgKDBlK8VdvhfBl_mt$hHa_+7qN5gejnlQLs5kSLYRVLZrwA>tX!RKgGCzZ`h7NC zYXfL=UK97A8%CKlpI1EIO<6729>2OBAN5g*(Q~g3uombsxZYn8*<}vv;A`(RlD`6k z$h<`@KOydkmAp-p{UN@kH?th~R*1IoCu~{u_G9xG+|su9p|nYsoVu+R!_YP2-Ld+b z#D(RcK%NL4*{FR1G5<7#yxhi=(r~7qkLD|?D(ENZJWYR%BlJW+{J!;MwF>4N`tpNX z;YHN8Mu!6-S}4UwdUvsH_zb2j*H7A&2O=eeNr^^~bdQm%Ubi)tg)#CfR#H*O_I$?g z3ZjQf5eoH$();O2cfd>$v3Hy>UMzvxVFiN}V#Ra{nLVacpI#Ay{dGrreSRYS8A@3a zgoG|={~1^2w+GWpE#G+7V(Siku=Bj+#iWXw%dxbm%6K~^&x)#Or7wQ#hDRJbYZ8bF zRv?*f#e}8eu}Tkg9(^O+b5S5eiJT>yASZoBs6bNjAp49OJ56PUHlpe_r!bW5qQC4* zx}EuZy^9RJS}EfC6LlXn*#MIo1Y>FDG#vjE?`}CMZLF4;^s@{t?I#hTNPca_5rtm$ zPYS+e{}>84Tk~9T*q3XfxqWvv72MIuFA#G6m<;YN1l_ZX(|bN+l4xktQ5_KzjCwWM zB|^+Cq(gx!m~F2KeI+tf?g&S$W1up4dAzk|3hiqc{8CmZ)4s?PG<*AasuUhRw=~mF zTN+4iMpcx>&p;lB5iwwm*5v-|HF<`n_R^Aq&=9oD>e03S%R}#c`=W^0nbzNvso3~4 zOAf~lgze<y8~(F}#Je@C(;hT3a4jKlw=AQN-lEd%Vy+dOC&S;JDiDrmi=KV-)94A} zoYS0~H*}c*qbVvjVnX9-7^?hRKf{!SiqR-0g3wOorCc`e7`s(XuCJiC#ze{D_%>et z6&*GHX%U@uTU$hi$)p{v?1-ra+8tm|hh3FZT7`qYY*EYGg)0W>;S<@7qqg`gjdYAA zs#}B+Q|abXDvaY~ld`e6U)Io28%!91^R;<*9$o|u(h?OZ-hKEB&&YUNE$~g~@yuIO z!R=xCF}ocfS1V84&C^KvEO;ER&Sl!3AeN5Qjx6SLRUGceHxGwj@tMbUr&C1f`Ei_W zRwt90dB>xkdy+sSd_JL1v{#AR@iob@TP2vi)u9qUz1+lLcjcLXrd<a|F>oY!zJ}XL za8(zOht)Xg=wP|%G;q6EJe;`0Qw#h?4-IrphgJ}h#iu__i^yrNxajV=A-o#L91+4q zqcW)4$lCd8_Kd5*!B(0kVQJMHQ3}2m&2qphZ7M3OHi1p#gFTjH|9iFA32{^JC0*z1 zupR99V{qdO!PQFN{B4M`sq?$ec1MmiYCv@;WomD0VlqbYJl=(@CKyxY63?G~-BVp> z|7;dFAvc0wIG7uI9wiks+6v)W=&yn$Jy}#-nx2NuyaeLWPkDjM{r#)GL@012LsM8P zakjnStvl5kbvkuEZL-j>TQ}xec%D~GKmJSZ{^LSoZU0$|<kW){*8tNhX1!He#1o2z z>2Q}Zt6sMR`7O+hT`8ot)p>R=v+E~$3fb1xOH1nu5A>jq7`^F6<y@7T7}JzCc#+JW zY|=P~r=+ni=2tf^R3kQU5@ftz&-fvJrnB@QQoOxyXiUo08NY|*X0vsjw#1=T)Wwi; z@v~f_A7%HVy#zkFVm(>XwH{5?aJl!D8Z_=%U1)A?;?(UvqNwF!y262^1QECD*Rd}F zJHlBd6XaonJkyu{L>+G|1ccs2)v{ehHp<j!kQp*}j*GxInXI?>W{G=$c<<`jJdL83 zpVd(j6kXSqKC%x{uw&@-<m|B%j9jF28rlyTS_^6Ise_uZ5&Gu0+0!wtzJ{wGA-yo0 zt}sbI^ApON^Rb+-d=RpFVu9T9P1H&Cf<>{Ky)REiVNgGjKaB5r=RV2MrV-+=0%@kS zYB&qy=n$DGc(i3mt)`=#%X}fPp`6RZ8_{DC)D0nD9)Dz!cygpc%gWx@r}_hXm^gcL zX_a}P7`M7WaK|>GRCWmpe*WUny<oY18IV*gt|Tg*FKozTUwd-IERn|-G^|ZUr+>0a zoaXt;G^E6yf@Nga=~-?UyWAIa@~E+vx;1f;@oSoHsP%=^WtcS{(Oj6gbWnc@A$_Rk zFu8fLu^n8|Q@U7$(By4_cOo&`Pu}h&4bgVa7H$>fr|ME|Y<IxVuwLbI+iFF9wY}?3 z&Td=c>nEa}oxAopJ=%hf;P-$u10nBHQc8L=>mr)tu<Fsv5+xM-jaANdBl-0p?ZH0i z4}FWehdhE+JqG#5)!x4rIaV!`T3TE=avQnjtasf&T_lY2@WYfPgao_^6h6AKrQ>98 zc2Xsu7*N3CiMUcL&dCaqw+Pf%$$$7FI&cdqnD`{Bs*ONa%tGDJ>w3oQM1DaQi_@Fp zay7n~se0m!$@CeGkMmKJ#cvcolr-yeQp>rJs$=cz8oD9}v|BfxLQ8UD%TbFyzmE4V z2b+3sg^$-GSmkpGb{k-vV)ea)knsw0Uy=81rfXQm9ng_GK(*FZ)R7$RMZx@&_ENG5 z(_>DAjFD-MDL&++BDfCLI|LcQo?6*dx*ei9UEL_k=qo6`Hc4dLkQU|F6J7T5^vOAS zixWsYr4!G5y5DX_KHQJMM4$SS2g^<>b4NIGfX&_MsmI9ERdy$nXHIhEXh<2aG}+7E zJK$;!B;RE47`m=%jk_Zfbaj1MmcV^Lj+ML&ewO&$miv}@9B+P5Sw(2r$kOu4b*Uj9 z#jsYV>8bQrB1H0xbQRX*Me=G~hw4{MEAG3;UHGn*kO=+CLi*xED@E|RAX>lT4!}}n zeGm#@KN(W3BsA~ujIBDRu`AgQ2%?QR_OU#;)In@hHyAE7;@g!Yux@|}n3AN9QzqR` z)*RjeVZ44sFD+pY-hY4ui+3-Fd^*2w!KU(2)l9Cc(n88OAFxn<M;7Qp8mqKA_*^z7 zV3OuTe?@y_sOU0Gj)HkHDqL5s8XI2*G3NJ%3$5%q6G_|YpzBv0+eZ71o;!eXTiS|2 z>453eDG6QC&$)6vuY8dbn(X=69(SnBQWD!?`opXqilZBhx&onYX8(ZgPf5HTEEGK- zMtL3a^i8;*Fns@ML3JGrZO;nedEInfrF|{7W-Ow0gxsCVMRe55R@NNx{Q+WZnA8s+ z$ga`mxq9qs?+3jRkx&{Hy?v@qpY-g^@zTv^{q(s<x6fo1<e@8SKDXHo$4y1_(}Z_G z<%L^c1oCqM@Jaqhi~peIsMU$K0)w8JD-8OpbnC5sPR-%)Wv<TArXc-%)H`}2q4Q<` zcT){p@9qG*$XpwEqe%tkQVx&calRGQfdJt2;}my)2xi*8eV||Sw1#oaP=QwRMn@W3 z=s-w_@^+>a`_?~8tB{Dp5nH3R({*6zxnYkl`1UEw!!>sOOzh%vLYy$8Q`n?_#6}?2 zP<qz$^)-Y5Pp{%hAU4I0{()p5VmI-!PSY>t%(hkCsl=5&I>QH+?m+eDN+FV8(&Du> zb2%X-7BkPTFWJ52f2Z3#uVbsvgJEh6a+pg)KXH~yf)8j%r%38-U*~$>na>=xxeIw* ztZ6;ih$?EkB;BB78r4*q=5XufL+x*4iQu7oZFELF3^!8iU*tcSjty!P?BjRwZ=QmQ zzHi0x9TtcqdO?pn=ZBkfF)ce~uQa22)yh5c73-_2s&kBry^bo^M`rQ>EFr40*JBat z)lw=wbc8<R+AVO?(V<yHL?%JPfl^gW4Z;a*mxY7NFD)gr70Ku_^p-(Kk7+|IV0_{N zQuaM+1W~(2JJ<vZN_h0s+(jmw2IWt@=#6_>;h)K=zAB0nQfrb0^|hv|3t04!zVo%S zICcD~*|AnqOXru+gl#TkMzrjl&{j~^uHN42z*A^*%RTO3h1(Zvi1K4d>Uj|b+Y|f3 zSydcdRgBDI{%_cPojUGfJ2IcPsHa~w(9z&Gs5&DBn$wJzdk<>9M(p;l{gySsk&W12 zpTIS47xUD<S+3-%?Bm>k>sH4tBm7rY-wc~~h(^8hl4ByABZuMTV&ZP<2eAmbPwFdY z-tyE$eWe85hYn7UJMb5btP=-?w7u1a_Ci9U70aQOz1xu;Q@Qo^FrxmU;;M3O!_Stc zSDtI%x1Nii4f@);BSYt!1NP3pL}nQgBT_XqNSu+C_G1QOI(rp<jd{J`QosBCQS0r( zlxk-*!%h72;0AfCPbE2@6b`FHYJx_{U0ml$irmX&yH_{uIlLw%BM-~lLI5Qkp7EgZ z1+_(!0oz|M{kZo%xA&^?VCvZnDv0E;hvVN7>q|q8OF0}Kvvsz6Wdp4tG~RjY)NYV) z>^_1|r>#s;MyB9*IY?~eW@^!Q0MUjRir0;@!E}BaeY6ygwx@ZP*IJdt&<8T^M)0ls z7;vj^I^@C$h`v6S_(<3k_1pS!4VGlFN6-MSyF+xTh=ca^%sBxNSwL^P?!HVO5#^(! zb1wUvaeT{qA+15Dhw=^Xpi#qM=hCYjyG-1q)&~&)PtVBf9XqxpYL3?*b*;FH9kwXH zBn-xft~K+s(|kD?$t7JJY=4~K1UxGtl2pQl`8ca}dHQWAiF(S%(7gzeE@1lMx09W; zmX;~GyIEvEAB8#o!={2*M!tVw1&bbOonKbP&qiD33u6er(Z!n=4P?d^p&5=h&1$|? zERMp&DRd#R1te#y5en?;ruEco<#XVz60?g|v&Yq>4f2JlpBon*$2M<^A+fvh&cR1} z{R_fuzHuZh^NawqwHG)#E_!8O!LfP#h|ZfhSPwA}Y7{r(XI)yNW2(uvh-Fdk&XUW7 ztVO<sP?#*(R`F6!mL?uni*`9m00;)Yq(7nO03W6RC!0@~8eH;n=>7>d`VM5<*{$^a z!YG6<r|hMF?IYRl1-<ovA@j(L=ck)5>6t>hfA(kia3Av86ZpG`>ii(jwW~FF(u;H^ zxCWP+``DkLH4Xj=#+*IL{6H}0P-(6-=qJY+a(mHYD7xHt`iwHe@kg=K%5~!o#K`r{ zlHaft3wO^%)r|2hynT7kEpyd!kmRL+Q^fS!$;?A7yfkS{gDr9G+P1U~?0y`h#NR7k z=X80N>-5IAuAYilyD-)~D*Pp}p%%CDw%CW9J+M^u_r#^1?`uY>lD+L{bcR-28g_4f zbX_0G9uFN~3o!|vmu{R59#jdexJ`IJq#}9<FA{s#!WT$Tyo~zD!r}!@gSfbbThnvl zSqF}XEA;!&$X3ta0T!}3uiG}>wzDonMgo!ukw(+R3E}lGA`Im=IC}ut*CIZdGbJg< z&?G#7cnFiHetnZM$ms*V9o5^GSdwUNXsg)-_O34SO?-r<f<^yPNW{@eX<lc#W$B*O zf~(r;fifq~(=S;;Dd)!=S_&J`XNL-{h3{6VX=%~ph70+KJ_gwHa<yM+$J@{Os9U|4 zFDB)C(F2@jJ!G}zP3j0oLAoY?%to9~&rDayB$%zkYEG8@?FBjcjZndY-V<J5bR^>C z3fm&2hx~i}WF-~3Z@{xCT#a*6%anNviN*ry90B!F4!G@n4keFuz5@^%bweK43}fVd z`QZLAqu6#FDOt-IfszjCGEr#lGx%CntZJI0^x4Y?sM=;^-Lra@p@L$NVIRaYuatA` z2?>Jp(B}a5l@mZrx6UTPkC75(Lr}G6kT)K=Wcm|dia&J~Q%*Grm!YLIx=v2w0qza! z1J5+YY9ZNSXg=F4r2-S)(4Z?F#gI{~;df6>Wv#?bSHc?h&h<Bv3W!CBUlD3?G=P`- z{GII{<ErjSdG+QcZFGW+jRkudofRuZ`=v;nWJ0--4wTYTYI+B8;%#4Vv+E~x%N%CZ zgH=>p9>S-wlMJkmk8^Av(+BM;+MecczbdDjQ#M$&AMj2|^Vsasn7DpYB>iU4&!Znd zVU-z<7%ip>T(|5p#!yKNOgwqVp-nb{#oYDj@Hf5eRU7$<G+%1IyuAL$Az6&fwF1>$ z^+;j=QS?1>M;kLUPQ^}@WiE_jo+u~($#tE&@`Azl4p0&*Y${gl+Y%>i*36ihsi?LT zzwXb-8)v=Nuh?7hl!N-=8&W?PE+NO+mP~jD7RaDC%P)*W$4|IxqPm~eLXf1yKsM^j z(D6-f{qdtw=}_W@y$(dtUkg4SWsgJL=!$y8vge?t`G%=+-@+J31S#vOG<y_DB;K1| zi~O*&oErIEYM;a+ZptJYE%XZax=3J3s8(f_H$5##k31d{`dVZe^u3L2P1;*MXJI(r zUrXUh4Te0bfjMzaQ+|2-xuRGKqgu+>o)@2{ZLY0ny5OuL>+4H@n#25r<t8yU?IV=b z7lrd}M_r=XOd1M;)N7wC___jKJv1PK7tN`zT<z+=RI-PMqD65dsAzrNY^Cwqg|{F+ z*-42=p5;a~!FaB}Jwy1I%6V-QE%<Wm<;`R}d^n6Y@r3xgr_*_Vf#d?o*YAfwa5G&% zg{{jIQH?Gehws<nd1?d^r%20qvd+`{#%y}k;m?|{kz3w;B&sZRmLsk^p=hrlVS?qk z&Yb;Ju@ie`N=K@0T^BW)%K139z15@9@PQsv%!`0d)1J^5+8R8~pWLq8cIC==4N=dS zv%a^izc{vdiJbAtiny(pZhZIYDfsD`L4>2&56=0lc>;S%2)!xt&p@=^?Ve$%8wH*r z*{*M1XhGDGGb_8be(*a}Lk#COzYf4{IL~`gwQPr5@B8!k*^X^N4cHQN*gI=9#U9>F z+wm%!fTNW?N%O6d&x#Z|)f?AAtH)O9Vv5J!bAqcco{$Nw8(lLsp4u10#f|v7kzq2p zIbzA#`|O-^Kjiqm<N8~cYsA!#EeUj?Xu+#Edu*JdoXG_jA9fO6hz4?{wMCr}cbPt5 z{9=_kTG`jh<T!^sU30-_xTqwjjx+Iyr!psUz@Ji5kX?oA@E2vS+H<TVH%xqe?w?7w zgiqkfhjoex46Y+5um+^7sqhYA8@$Dfx4#){zcyG<)T0Fl682;LzV6tVE-VsNMH2X! z_-oXlyTq5F27CZ=YHcc@_k6x%6BLcT@g28s^Oot+;YPS^I!C1x4(vgAUd#q{F#(2> z#Sc`<Yn`~xO}j{gl~*~TiX1=I9D+DIEBB+`n4S_3Qi>D5dkQ1c)svLLc@fSXwfg(G zBkRETME}NQQzX^UFhj!r+lhty9QJGSC?^*#*k-cOWjXpUa>aZ`b0zPjgeU>u>G&-= zfA6i!JAk#;HkNQnlVqr)Tk02|!`zbKnhl|6CA8wnE%}KCsywA@NOSp5c8vX>QL2h| zjCQL$?^KPx2^dK^q7&ZYl`3o%7+p^1eXD)RC`nJF2|C4`mErovv?od=B=4VdV!3|n z87mX=dKtkiGUMDv4Vj*M=Vmv+hbMuic&>I*Sru}ij7`UcG#MZm(rT7IQ$cFA<iUm? z;kIou^T;EElHIU5dM$2SmZS7#_2EX|?JP8d<y*I4+x+$Cv&=esa(JZ-&x&P?_BX0{ z{NA#F_t$0?7jk3vYbTFJ%;{(&@&$=kKThx*XsZWsm2q3l40Jc6g-2<mX?w=7Rsixm zfi~SQ%;MF!y@|Jvi#7X(Rw~2ldk{$qlauuz9BBFRSVyi_A-uvbllgk(s9Etpr8~>* zxmiD_G~+%~?}n;;-`dsde`K=LC!=L5IV6Aq^BKL7=&b4&$Pg`MSbqgY	Z!RpSXz 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/Toco_toucan.jpg b/emacs/nxhtml/nxhtml/doc/img/Toco_toucan.jpg new file mode 100644 index 0000000000000000000000000000000000000000..269886c070dad674a077dacbf25cce9164ca0886 GIT binary patch literal 17430 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≦>fq)ddC< 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/bacchante2.jpg b/emacs/nxhtml/nxhtml/doc/img/bacchante2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a736099335dd062d1b72d104dba59e8054e62d0f GIT binary patch literal 67205 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�#4hLAwA9E^H`JAQQ=%Gz9(GRmh;Fa}69 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 L5%R@56F>jic%>!p literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/butterflies.jpg b/emacs/nxhtml/nxhtml/doc/img/butterflies.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7352a686e597713cdddd91206705cbaa1dc0ba6 GIT binary patch literal 14954 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/butterflies.png b/emacs/nxhtml/nxhtml/doc/img/butterflies.png new file mode 100644 index 0000000000000000000000000000000000000000..8d606370bc91615877294e8d9f023dec76342401 GIT binary patch literal 65893 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/butterflies.xcf b/emacs/nxhtml/nxhtml/doc/img/butterflies.xcf new file mode 100644 index 0000000000000000000000000000000000000000..9260725dde04b827a0ef2e3a613988814417f485 GIT binary patch literal 87456 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/continue-play.jpg b/emacs/nxhtml/nxhtml/doc/img/continue-play.jpg new file mode 100644 index 0000000000000000000000000000000000000000..587113ee38a25a48232ebfe54a72aed12047447b GIT binary patch literal 44390 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 SBQo$n!2Kw1;f?+@p#RxIk>(!& literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/divine2.jpg b/emacs/nxhtml/nxhtml/doc/img/divine2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a8ea5158499b6db338ef0f8c1324b26b8e4f830 GIT binary patch literal 69985 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/edit-part.png b/emacs/nxhtml/nxhtml/doc/img/edit-part.png new file mode 100644 index 0000000000000000000000000000000000000000..7c6ab2a81a4ce8be2c7e441a85052ab84d87a922 GIT binary patch literal 23263 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 F{TC<2(0u>^ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/editing-web-files.png b/emacs/nxhtml/nxhtml/doc/img/editing-web-files.png new file mode 100644 index 0000000000000000000000000000000000000000..ce30bdfc50b34eb57797806baf7490bb7ef2f586 GIT binary patch literal 7237 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 T@6J(r00000NkvXXu0mjfY*bpq literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/editing-web-files.xcf b/emacs/nxhtml/nxhtml/doc/img/editing-web-files.xcf new file mode 100644 index 0000000000000000000000000000000000000000..670388214446d2fc9b70479cc2edbc6f5b85074b GIT binary patch literal 15415 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 bHtSxpvBlXQ>)-Q|AA!o>Kj$SsF17wI4ONR= literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/emacs-style-completion.png b/emacs/nxhtml/nxhtml/doc/img/emacs-style-completion.png new file mode 100644 index 0000000000000000000000000000000000000000..0a404fbf48d1fda7ea4fef6f88f020408bfac5ec GIT binary patch literal 23199 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 Pr7@IWX~>tzntu2{Wt-&N literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/emacsP.png b/emacs/nxhtml/nxhtml/doc/img/emacsP.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a5ecb60f46493ab46b3a3cd824cc6f71e5372f GIT binary patch literal 1882 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 U_ANi>qW}N^07*qoM6N<$f=e=E;s5{u literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/emacsP16.png b/emacs/nxhtml/nxhtml/doc/img/emacsP16.png new file mode 100644 index 0000000000000000000000000000000000000000..54b597b6ece9515c79940ead71a5a047bdbdcff7 GIT binary patch literal 694 zcmV;n0!jUeP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iFW7 z7AhEcd<d-o00K5iL_t(I%Vm>IYZE~j$A2?Bn;1f>(UiU*D%gV1i+Hf$y^w<!^$Vzw z9z5zz@C5|FfOxTj-Yn=vMDgIIf<Zmhig@uL7Io82+NMdHG}+nR@i1$)(S<+k%>QMc znR!M4m>=^70MURbg3dDkeM&+w0h!p2T?aAsUI_F3oWUtWb`1Ky4e19%ULB0%7B<0* zTAh&4c?8=YidGCG0=?tmx?dqW2uIID?${u}#e-%QUDLQ>9h3p54Bgu(+|QWKDO~dl z+zgz!I$XNH1nZ9>8pX|J(7l;7xD}yjl@R$gi0V+9A2$EI54Go@T#yF3lPK9pd8dv- z*CFzu8^h`YD4t0LT@QK&Q~>)LAVGvO<=Y_X^?)^qYtZ@x)j8PyXa&=^VC=O0-w9wR zhG1=g-8M+VI<!IveJ}>5ZbBh3$qXF70*5OQuY>l9y8QvRnjp*z%;u`SxrxiKVgGDW zp9jkoYD-lBvYDhE)Sfd6K+@lH?Pd?Ta-FTWRq~0UAJ_u5P7y~S<1qF7eprT;i+1&s zcR4U^ML7X^1%Vz$6oZHsF}`O7ag=P`fswfzwkMj;;9Z4{Z{Wz3?}U&sAb~-dU{ke* zjaPSQFBI+M*(QfBEg<tLpA+`kh-eYht_=r(CFA5w#w#zA{_qH&%+N~oIs_?Q=mpmJ zuenr$@$xJb|GtY!)XXe8v}RX<6c-TLEbR7D_-!Z@Kpg=bADUID--9<rzC8UvV;izr cC|yJR0qB+q|Cax#9{>OV07*qoM6N<$f+Kq_S^xk5 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/embedded-css.png b/emacs/nxhtml/nxhtml/doc/img/embedded-css.png new file mode 100644 index 0000000000000000000000000000000000000000..25c11d4b675cd1652cbca8dae42833d03023fc8f GIT binary patch literal 14019 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/embedded-xhtml.png b/emacs/nxhtml/nxhtml/doc/img/embedded-xhtml.png new file mode 100644 index 0000000000000000000000000000000000000000..85b98f3cb605eb87a04ef97b6cb1785178614155 GIT binary patch literal 17326 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 PtPKWFS3j3^P6<r_m${h{ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/foldit-closed.png b/emacs/nxhtml/nxhtml/doc/img/foldit-closed.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1b49c167e7d60f794f07ec57209b1389727e0a GIT binary patch literal 7894 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 A8UO$Q literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/foldit-temp-opened.png b/emacs/nxhtml/nxhtml/doc/img/foldit-temp-opened.png new file mode 100644 index 0000000000000000000000000000000000000000..5e027257860c526f6bce9b15ea6fc9924c88a49b GIT binary patch literal 17590 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 R1CJSD@O1TaS?83{1OTLepu7M8 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/fun-brain-2.png b/emacs/nxhtml/nxhtml/doc/img/fun-brain-2.png new file mode 100644 index 0000000000000000000000000000000000000000..a24f0f4730ed6cc12538d84255a28d3a5294402f GIT binary patch literal 40042 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	F& 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 W)L`e(2h>{t0000<MNUMnLSTZ{h75uL literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/getitbuttons-1.png b/emacs/nxhtml/nxhtml/doc/img/getitbuttons-1.png new file mode 100644 index 0000000000000000000000000000000000000000..5f3c757b506235ca25c183830d03c615fb2527da GIT binary patch literal 1931 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 RJ68Yz002ovPDHLkV1f&mmjM6( literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/getitbuttons-1.xcf b/emacs/nxhtml/nxhtml/doc/img/getitbuttons-1.xcf new file mode 100644 index 0000000000000000000000000000000000000000..8ec9aaa86baed854515c6eb18851a153ff05cec5 GIT binary patch literal 5446 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/getitbuttons-2.png b/emacs/nxhtml/nxhtml/doc/img/getitbuttons-2.png new file mode 100644 index 0000000000000000000000000000000000000000..c3615f3cbee8f308553009b14af51ac4b1e6e091 GIT binary patch literal 1276 zcmV<Y1OxktP)<h;3K|Lk000e1NJLTq0077U002e^1^@s6iQ?Nf00001b5ch_0Itp) z=>Px#24YJ`L;!LC(f~w-?Q91C000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOK3 z0WvAEis&i;000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000D6Nkl<Z zc-rlqy>1gh6ov0t<{>Dk=xIm?B@&3528lE@6m&@N5EMa_G&E4Arb-PBG&}<m50DVz z*q%!fE3nS&?!B|K_L}{^Cdp=h=ghh1PGV_;6ynp*_bLDb;o<eCp~QItMgWXcz#td{ z#%Pp)F#w}v8U%B|*i8~J20*=0CJYOJqs1aUfE1}Q2<8B&nq<mwK%b~+@_Xws7aLS0 zgp03T&-Kr5s+Z8_7K`-o4YWm|<UR=@^3Ih$W?g7qiL5Qhrtd-9uc-cUv0S^lP22p^ zaL>kZTl@L(jhCU4AW@><)tLih5u;9Q-(XzbFF9dqDpZhQp1i4j?a$f$xvUeosM%BF zt73cR+OY{HrPueXOMtG$Cy0m~{&=gt0ZfZronuW8tG!jKe6iIvX>Hf?8N9wQXm3TQ z%emIK*4}5wl(D6oS|o54vFA4r!c;`$_wvMCA?k<9*4LGrz*=N*)tU&I&*CmLR~5Zd zXKcm6)=G4FuAGT$DLh?F>MIWIC2J}oa=JV&&^H>zb}!=cgwAjI67gMI>2p#>9hu`v zf%YTwTRzLPm7KiRto4m=dQI5;`&EMcYN@hy{kTW$GLEhvl#taXby}dBQ%xJ2PETR5 z2<<CkmT@fE2^iZW6~p{%K3DtfY+uJrMMTcxiQCcAhtO)R@b)WMCa|^+Wtkq>T)|D# zwp;s|doNZq<`<p3gfSN}XIp%^2J!U3)+(;9$=v^<(jvAFw3U#I|0h6q5(X)=;IaPw z9l>Gn23hF5my<K?Vb|f)yZ{&k0D}M&=kmjfFTUSn$pEn8;MP$fK>(}?LW%%X(}M&7 z@FWN+0;I=LXfy~W0nG6iS}Xuhi$#(E$ze1ICV?@V!(<SQ0%J6W+aMSP#$=3agJ2x^ zAC1tvLB75Fia}s7+<vyV9fM#57?W`V#sG}c!5|m|#%z>;IRKOF`TkLeF#w}nz-O@l zJS`UK0i;NcK`;kE)g-)v4F-=!l`sjSQ7hXlMB{!MV{?l|dTdT?%eK-&=iJv&iSsCv zYZHm{*xNPkyt*4YCCK`KdIq>Jv3E)2b;0{$xrl{~9fzgC*=FWM5E1$E=Ccmn)un{C ziajK=mAn_rxjfgirC;31vAqBK!Nn`sX2-LQxw@3tYEB_7a-LlkdDDfUt+Uu>;aM)1 z?qjARBIl>)J1=(0^H>*z+Y&oR=%MQy7jf(Nm%7)fh{*hOj?g7qiA5aL{q4${EcuGJ z%EXNlCX?(xK-lMFOdDh|UkpO*p;hXxBBzAjOyP-JFBU^t&|BYz+}L6*&K9*NOtl<{ zy?L>_3Jo0$GCQ4ZL})~Yois>XMn(c40iWgtz#sq^1fV#VA6ESM=mRTgfE7;;_jv^y zfH^@(5rArXkRSk_1R+I$^w@8I1sf&-%t4C<;BT==5+FH@2EimSW^<Sff>B_M#&8=1 mqrjMqk!=u+1OKBD>i7dt%&7J~JMygn0000<MNUMnLSTZh_(?nf literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/getitbuttons.png b/emacs/nxhtml/nxhtml/doc/img/getitbuttons.png new file mode 100644 index 0000000000000000000000000000000000000000..b9b0c43f82a8926f4e381164070531015d3d81c4 GIT binary patch literal 1324 zcmV+{1=IS8P)<h;3K|Lk000e1NJLTq0077U002e^1^@s6iQ?Nf00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOK4 z4K*VLvB7x&000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000DsNkl<Z zc-rlqv5q4}5QeL~%X<)9f*?9U1Z404h=2zn0&&rikPr})5ughQh%Y1{04)(A67R5D zYdO2C2-e!Q$K9Upp7z+|`M%_&yYWnS|MPWqkF6V(M*Q*bw=Mu@!Uu1Eqb<&(hyaMw zKoG=$If|l)0f<s52y(#OB~ioxNQ<&ySO5x^SX2+7iX;R<4uD-rt{DzE*>WX85ZnEn zySS>T*UaCRb(AO0tyGWWg&iW{)P-ChbP$oN&7V&jPpi6Sh#ax-;kS)P+G7XW8(if| zU4rkY(APK5?E6R0zSo@!q7_!xQy;br3_5zlxQnS)hwWmbve+B^SnFbK?gpLPudJ|L z_l~lfJk%5SMSAu<I6FtrXY%mesDB*SosYZ4kM)|qZM9cLM1KG0D?fBn%M5wj>V=q? zEV9DR4Z4|pk#O3DTs{%(UCSDT+zC3jpULsbXhZ4<wSnWJ^^<Xbf75OG<ei`NT0~?O z?s^(wS*P5#I&6Y&Vss>I&z<cn!j8>jY7GRa2-@96RWti*O>Q8s6g#I4xw#E%L%bbc zu|n7ga$B(o_fc&wJ$L;8+hhG3-k<Xcx}+`n=O5a);e9G;L$v=}E0fs2UyF#WZCSO( zCg|})&I!6+&iEeS*g3`T4ef2$kZY>CxU1;aL~kbfg7^_1sU<s;*k=r@24e+n32C(a z;Y4A7wNuT_%0Dw$#_rf=?ulwL@P;dm%q7;{ftyMnZ7Y>wXwat!yLU4_@Udo#pxr0% zME*j)G<c{WJA%~Bs$*JB*f6Rf!B>m~Km>lx3xFU12m;WY$45A?{(R0>6kx*_@82jD z1R%G9P(=WCs|OVXprnFOMS$vYqXz{+5<re8SYiQ`EU~C0K;_631W91da%2gDC@@Dc ziUmOwn3EXQf*=lDq6jIP{m+W;{rVZHz!`DV<SfOO{r%!4l>#QqyDwiHXNiRvFh@}o zF#u621wjs&yCjMj0BKS9Efzq@5{v2qRFQ-r$N{h`39n#-v&VfQswVDFI|2_O>$7I- z%xm<#f{p4iUf6qoml5{RpnE@;dBdH>7_NfoTUX+%<F)zu58vsa3epX_WPpzq_LM^I z27WB;&Hbo-G1GA_bf4Xz;hXfozWmzH-Rg@CdW4WmClUA1^nBK^{lmvHKi3a`{&DjP zw%g@+RyP`~+-lJmcK%v+njw!}b@$%%72Y&i0=AiF$}@Zr<nDIzVYdo8_D;ZV$fpkb ztYmGJi>*&2&en22Hm(ov2U#u&y2VmreZuD)k$v4%#y2+6*w#x~f-mGsO@bfyd+n7c z1PQCvd4!$VyiXzMR5j@aJqEF$TcV9_4YSqBaw%G3t?&O!p3uZ)A-WSZVUHj7Bwo9A zfn1A-EY~(l(1Z+=6eJ`zp#XD-U-JSW2mpcrH0SYKx?ev2lpQp{hR=U{%`4advMUHx z1Yoy%P(c7nDhO2ss2;ETU%`eXfE+Bb0LqtGR1%<aWD0^LFlRZk1VI#-qZq}4APUS$ ijA}s;2QE>B6#oOv7WE%*Vo>h@0000<MNUMnLSTX+7G3-R literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/getitbuttons.xcf b/emacs/nxhtml/nxhtml/doc/img/getitbuttons.xcf new file mode 100644 index 0000000000000000000000000000000000000000..ce416ce7496f6884674cb755a5ba4e554e4c44f8 GIT binary patch literal 5988 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 TN+W(L-KD>&YXAJh@1MT{YrtuL literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/giraffe.jpg b/emacs/nxhtml/nxhtml/doc/img/giraffe.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6bf9b57ef94f217595a099571fcfa7c57876bd0d GIT binary patch literal 20966 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 JX)3gT|Jh62BhUZ< literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/healthy_feet2.jpg b/emacs/nxhtml/nxhtml/doc/img/healthy_feet2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed3ab6f8ee9aeea5060d00ee727090b278ba58ab GIT binary patch literal 24042 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/itsalltext-pref.png b/emacs/nxhtml/nxhtml/doc/img/itsalltext-pref.png new file mode 100644 index 0000000000000000000000000000000000000000..3b3d9f1a2248776dc06eedce2321f6d54d0052ed GIT binary patch literal 14720 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/links-appmenu.png b/emacs/nxhtml/nxhtml/doc/img/links-appmenu.png new file mode 100644 index 0000000000000000000000000000000000000000..a03ba4ac666f85d424d8c1deaad0cdf5b4c96aa4 GIT binary patch literal 7124 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 Fe*n-agkS&w literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/nxml-where.png b/emacs/nxhtml/nxhtml/doc/img/nxml-where.png new file mode 100644 index 0000000000000000000000000000000000000000..102d0849ece3a70b9a5da8639a126733862dad18 GIT binary patch literal 17217 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 Vwk1;Sz~e6%JYD@<);T3K0RZ%k^jH7@ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/php-in-nxhtml-2.png b/emacs/nxhtml/nxhtml/doc/img/php-in-nxhtml-2.png new file mode 100644 index 0000000000000000000000000000000000000000..c204f4d9a3cfbc4c7cf7d15a8bfe4c7bea3028a2 GIT binary patch literal 23203 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 Q7MKPo%fFGUdTkN>Kg?F>e*gdg literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/php-in-nxhtml.png b/emacs/nxhtml/nxhtml/doc/img/php-in-nxhtml.png new file mode 100644 index 0000000000000000000000000000000000000000..cda754a79adb1e1535b1fb5c0651b7a73f2907f7 GIT binary patch literal 22179 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 VLL%BLfeU8wbTstUYaYIM`#+Jy28;jz literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/php-in-php.png b/emacs/nxhtml/nxhtml/doc/img/php-in-php.png new file mode 100644 index 0000000000000000000000000000000000000000..c7664da519395f358478bfdc6d99e114a1efa9bb GIT binary patch literal 21113 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¢>J#Ewz01&zy!guLZ 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 P00000NkvXXu0mjf0r{_D literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/php-in-xhtml.png b/emacs/nxhtml/nxhtml/doc/img/php-in-xhtml.png new file mode 100644 index 0000000000000000000000000000000000000000..310d07f0e9634fdcab155e0f54b9edddcc497cc5 GIT binary patch literal 21510 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�<j4Q85j5zG31;_qICnST-_iTll#x3?g%(V#Y| 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 D2m0}j literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/popup-compl.png b/emacs/nxhtml/nxhtml/doc/img/popup-compl.png new file mode 100644 index 0000000000000000000000000000000000000000..a40bd49a70015adad62751767e1773b9e948f190 GIT binary patch literal 8709 zcmZvCcUV)+_H_U$Qbd#@T~LIO&;+DNlOh7rn-KwNp(q`s7ZpK>fMN(pZ=u(K6d`n^ z1tQIW^b&fnQUYJ}-uK?`KF{xu^URq!IXP3-UTg0?6RD@8PDjl~4FCY>G#;rM001PO z#A}|4l-Od?=nzgUF1tN~5F2T(|G7v2Nhvpojg(#*+G><PX*nsc-0r$qrU3wM0yI<~ z82SF%NJaNA)W(M!M^notCOg_w+;Lx~qm%yi;|qHbWg~TL=YURa_r2=2Nt$gyKlJW& z*CkE_S)aq`nT*_RdZ2+nmjv5Efe~Xzx@iP_e|P6N4{P?J#u7aV02KPFFaQ8OqyPaL zKn57_r+D16*Sd7*D_89tfVK#~%$8g2)naf(`SbmJ0pzWBgqo>zvR`$^PNp#sj9Exx z1}@G;SrGz3%UPD;ETlUlzN6#~ii%>QcB={}?5q(gnz1yw0eCMhz0Hd$q!I)^pw-!^ z?`b@+pn5)}JuMWqI=@;I5pjjSu-pD#k+L82NP-#Ig24`36yahroG{)mxx_>#m4yc$ z-D*3p{eW6uDqotq4=QtLjoUr!-b}x?TW-!gqPbsd!K)n49r8^rvpYnPlklpJ1Abh* zro(iAcO2W1@wQ;v$o#faowJpuWn|K@pN$9Z-x@!!9hHNPlNs`rvPz{fd8@~QiXt_J z1vzS}$P*q;?qRy9mLxOehrK8Bg;fnfnu@<-i%;gQvoo_^cvN4cj7)%%Oq=GRHlGI* zT}oJaMT{nz;YEEj%;qUeUxL7#(q4UMw}<lYj5#Qlp)H_Ps0N08Ailu9f^}j!pNGS= zzOBja31cuag^{+?<YcAWL1h5T5;nxKDbo`N*W@>LNw$XKgd$!l9JoKIk^?=opPI2$ zD2qDO8`g<h)f(lIMDyivBl3R4hP|>F;O1^vqXm2*V#|&M04M*a&|?Ptsp%njXaoFr zcWA2e3RYok4<O&FGR1UzxaptOaJW<}xM>D&57il<6>;*OV-dV(#)ljAvWlOUGht_X z2FJR`?o`L%12cyHq5*z8Z^hK8Gt*%${re&%)A{jXi?0a?f5pR)Qa;cd`uE$s;kdiB z1l8(M5En97px`Vo@S(wR@wS;ps%gD$&uXwN)3HcN!r&{5r%f&<l1nc5*vcG5nDK|n zab4SH5bk8J&^H?^_ZfDwVl)bdSJxaKdRh}KZbQHLJt})?fu0OESQ;4-FOfgQ9Hx&D z3?B#j37&Zwxc>~@L(iZy`JgK(7U#ClPT-HF_`3Y`exr@Np~$Lx$zPu_+H(IGu7dO+ zdGCWog#6K;Jss`~B%20g2k~$@DvIzZBE@U1`VBwBEM7aTYFSDaIKDqTdm%U}dZAo* zIWpm!WX<qth2l9Fz_JA2+4}53SzDf);_Uz@pFyQa@AU<!076m!7}6hmszi;lN1jq1 z8>6=?VY@Xw7~13j(^9Z^4?6TZeUNP^-ms=sZC)_$;9A1zfTmdQ&d=Q4i;V;(hDmxe z|F6zlHAxs+1)sgMCupFQN?UEtLwL`NY~7C&TMY+l_^F!FJ+PYV6C|T;^Si8Je!lvU z-k~uR7IuD>EYR(7;FEjVc`Nbf(gk~k!V%y6$A%RiAQe<`+;o0(g93Y{kG{0ejwrAt z5#qmmSXAc%Fdvh79kf*JS^<Odo*hbQ1YOY;|B9~S5L~qb?OYZ-;3=djE8U}YapYfT zi7@@`ATXH-<zh+vJ(D<WUSO$_+7$V{+<Gzd*^0X%iB92kNgg;n_`2Fpi;?S5n%vP^ z{lK)5zE$h=@BU5qkaoLJHOSaQh;J3P3UchQtgbS0KM}L2Gx!K|q_|_ta_|Y#t(Li8 z>iOy^C?MgfXM$;3i}Q~0n5tqz*4fKCzs{1DnvNfooo<U?#Te=)o^q5+1`C^w(3S>L z;oT4BZ`N_oVo86<&e+}ldgeg&JZ@Cx1EazC)@9<#**%$L;)Rj`lpz0@$MYaNzd-Ec z`+pWpG#(Xr+81lpynAwDyrTk;_Nx+W6R)k8Xt>zcF+l{`?w_1^2X^HG08+*X*QR5! zLaKq#juE(9gpmP2G*LXgrG!QzY-iw<ev8TiuvrQYxQL}->tSWK`%MOrGGJ~~daFnN zT=0&EzBKO@p6Bk|t}=%_MkGoQM!#$ENNe~dfB-B<+M?<&6;F_-ZBmBP0DBt|*O>ky zi%8D@2H5}N?7zJIKfh?MN?Dw|@Sl~wtb`%`=gow<<B*GsX}B^&$nW`dflHwuP(O^L ze(&$xrzQy<xcWx`{`@(y5Pd&q?>704&N)4M((uX<ZGyqVv3Y1w2Uxv~>nGZ>EFnP8 zmVD-o7>q-YV^V?E*}%-A3^%{C9i0Cu)?pvsLk}p<0jC+PvoRFDt;dg+=+jIvw$7tC z<ePVUc-t8>8*?sYi9I6?g@Jk*6xIn%ox`-Vmzy#B-_|fjAb^-w-;H*<hhgqLjaaUZ zE}!DbAXFjaoy1>M02%=pZfQ~xudi#Qi89ml(b1+QYaZ^oD?{K~APYSeq;Vn@C2No( zPUc@d`}c7EJ9EvC19x&bU@JM#HSUD^+htw=0NFhMAmU%Z2-Vulp}N^&l`T1X@K98F z!#_!Qpu<@f@40=v+N=7d$l*K^Qd&T6(nny-^Xj8+SX7szO+L`leiDxfdu68viQ0UO zv3_N&D}-ehz7QyGACBukx7W|$DHAWyEgZfrQC|gpBHd~lO%Q)k0mdaPHfUzIW_h(T zd7yeP<@S_FXfg@n9S6&D<EKg=IBJqMc*Q8jBFSSO&ICC;?leRW?s*RZ1*45*PYCEc zjOKAXY+a0;H5JBTAbY=K#(pj4uiw2U@Mr_AAm<fhDbz-}#6<wtQyT>AxZk9vKT6F; za+;b+PPe<hq|W*Rah<hXSw+9^X@?$q2xw3wn<g)tmuKH8$#3-Y@;k@El`6il`je-V z7BiLcy0Lq!pZY^R0*0mvuT+cV5e#U`xs-=WVQ70@ox0$DM9lF6cJbV^<KL1S(0plE ziJ-Z<4>#z9q^u2~(oD{|)%A00mn-h1YKx66l81XAi=?*DW$X7D!2%5|9<j@d)CI1d z7)ax;{!I9YUH!679L0lBDat%oQ=x+!{k)#8`5Kgl_w7w184*cF(A+tGrsLvAd3dPv zimA5-@JOVj?7PQ{;ZC=lp;6z$x8Xszu$5q$vWkiZFs5&)!9ML^W>MSL&W7_*Z3D`| zTE<VqPxf*%pOwV_LS<;^ynMx@29fQzNO5emQKDW?J){be9rRs#(ZOyX9ve*eV-p`^ z_VhQ<u!tmLk#(X`sBECAjbQvUp?%MJ44ft_GO6g@XtfC2Wj!bZ9yn`oN;y5aY1XY4 zJMLj&miYzdMm-ity-`>tPjwK38qN>jB{_U`5hDam&)j!rh%sAD&ze>gOx3@*5~M&5 zD(0O=47*QyNpMLO1U>E7GVE7YfCV})yj&iCyAHCQKl6&Fobo^AA3k<b^#L6?JMQQ@ z%BZ*Pp`0Ai<4yy9#!beGC=Lm4w#~hlTY{$kF(%xxRi;aiEaRNY8d^N5?Z5KjlpQb< z?aB!Y-wwCGZ*P}s!B{wv)wQlxx*nh$OD>ZJHG`xjk|l=#LX+;-qy<CE--tbM!3w}f zl-c{^VRee|f(Ms`jKt2Q-btNr+xjc+&j#sNtU_9vRMK^=7z=is^<_V@kb_$#oDck* zowQO#i_{wLz1e!KPv{v>|NI_r)M{yKTr{0$M>VueZ|%FBMJU;IoEx_e=;)C>_hF;+ zGhK^PNiZoz1*5T85>%GhrA~ilVVO&fLfFe|zuOz5izlwH1_|2%IddGVZ-M|mrp(Bq z&!U6%qu0d%Zi^074~QIl!v~<m`o}{O=tX{6dSEM}wQ-6;Tri<sPew9!P1RO1z$GKl z#Ni4z=h*$zXtT<2GV|UNVb>$pSgBH&Nh+f-bqOl#h_d@tQ~t`spOiVjEL9%mxkSmI z2);cB`WEf|qB!ZGI<3jE8P_}z5x#+7?=gTFo7E}44-EPkq|&;van4rY1&`Ivi-{9T zpIYKO4OgxA&o0w+y7=a$<2suB4%_eP7Q@OH9qVBiLPr>nl+W4>UgF!z4rJHc8(&ZU zh+KJmH{5A|%#Tg;`zp0{;zdD^RrQN`<t5~o+{@_6g^eUHM1B9er30vv<izct%jO~G z1WAe%Biz`;V0(a3mGfBA1lq%uh7tKQcsb8`D1oej?+qKi>d_4elhe!`sGHPIv>@U3 ziyn2A`HQR_dxkRwgX1lK3*<N`&^d~u5;Q0V-+jf6DCx1!>y^_Q{_dDrVW4j^zJ(nb zYcb;HWy_)o=2kmQ^~c2pFBzYVwV!o}a)L5f7TU7prlqbQj<DvIEpnsGw;q%grQziL zuB;Umz3)By(y$tRZ|Y9{HP?sL$;Tq<5-y=YIC9xIp}T_|LXv1L!I*kT!yhaNjRX8q zsK1d)@4?J>!3^+o-TecHDDu)v!qo8$5xcL0bTu!f!+6sZNE*3_>wNqmf**vERSgo} zR}e7`@?q6u?plr+Nrv_w`x7P3oD{L#h5WXczP3i9r#(bl>Z7LpC8x}Q*#zSJSbaWT zB&7E@l`vD~v$o^z1u#myY)Znd085k2Q~L=OrXaSNo*-clG=6fOCU%PWIZvQgp}jEf z=a)Kw!-95RTAf!W5sE_{U{FlxN2XA6YlQbHKZ;aT4Z{n5vQk$wPkK2NHSE>#V=0o0 zrrCk&ABW^0f1UZSBnfANr9S{BOd*0N7nr!$DI~>gm5<Nmgy%?~w^kZrAJ?UKZ|aFZ zqF)3PI{+K!Kf+EiXCC=0sy-un{6%ys#4m#cv;?ajm;jjHEkTIYV{2xgMagHsc%R|s ze&0J#A&U5BPnMY9Zn(^*wQMW>$^xJ!1`_p#Es7mrXZ4;05HI?c=6|)+?YiB{Q8W8F z1;9ri5z$6|n{0<Pkq_!eQ1-4#S$)mYPX7G+z(@A3u%MAi-}UR0H_jt#0pKu#crAoJ zZ~3sGA;T@0R2l+7m63Dydt}Z}R8^3nNZn8<BQIqfu}^!~(HX>^zMA^5Qq=m~UXXYX zv}P_M8K$++>!NOE?BTtyh=dv&w9r`S`Hm6QyF4L&el}z0={*fuB}}V8+m?RP(1%TK zh12XN_dDQK#*;Ar%EhTY)y)S1IV#|Al+pwErxU}b3-`*$V>|G*wz`!qEQdd3RDZFL zcEr86sAjfoKoFxIqX^ZKu~++G;uSsSS`XI>*|My}E2WpjYumNagI2#)Fr;?!{9kpF z1GROcuV~u48Lo7#aBn@y(cy{jKg8P%op@F6vbqqdhh$_Qv3x$_`p77!3=-Hc$e9y1 zpf^PR%+crLFCM4L^8IpBKw7l<z~NN;im42gmE;a5-8*`Bzl*#(q!OpJS8ukH&)C{s zUfO7NDX8#@!+l}l5?6Z$C}pj*?MpFP&+4L9x+RBwQ%nRkaenaXDzn8-tC0oEWew?6 zX#Wokj6~eMLov$h#(VfuH^qf?81e&HOc9@EYA8Zcqp{Nc*WkL`O}#F!llLMN&m)ze zNJ29wn^WA7k*#PRz%py)*&_BLM_T!O_kIuM+}ZZgv;kH7Ki()yOiJYO>?OP7*{vq| z^RHE{tVvs;a#h@|AUBz@<wG&Gl5VbNiS{;Yb)yZ?E%Cb=XO9-ToCS%Gc8tF-NQuF; zm%Qc^L=iFy0k|oLnd{oO8ys}m>%x{CeC03t(l3B49#!oNyY$&Srd?U5H2h}nsyCs> zU+wB~d`F~wVSriF-S~~s=@)DAr4c6G{*Y9`t1#wlz49r<_R<)&kUTHZdQd`b<t4s- z{wvFb<%oeR;QUuws11ImC>jE#Kd={wQDn0A@G45-sIbsVvf>T9A?lT8=a$lxU#xly zc4!szv3O&_9rrX;OaQkh!vl3s9(L!1S+GxzDzI(TE7JP(>uh3xpxwwSmioJG0|d#A z8>#%eg0f%vUS1{$x<o3x+(k8J9tF6vA9r4yV?#E!cCSr5Jnr2(_a5K1GBLh2maY(7 zQ*+hFJy~eO7-61TEtV=|FLR9oxclqAMex0M$nN=_W;K%LaP$^uMQF{k_b59$dg@$g z#dfa_$h@tAS7)Wm1dF=(`d$wLvc*;9eSUhjRlN6W?=1>Y%%jrdrDGZ4iUqjdCjGGK zTfKr=k-2z*X+^gQq$`}mc1eOveQ<Y<as?ZH^FCW!Oe6tn+Jl}Q$iZ_&cZ3pKMs%m| zvXL%JRxuzNfxq%K^1Rk>iLBe*wY4ESPUg#{;Mtqo3R<7EeRGS+C}{+G=e4fBDW%*E zmh^KWv2$d5!sV%md-BaqN#to!HZMr8v(nOxmYelT`Z3H!5iP>HsP3u$T<JB9jloeQ zW_zN~lSV)*=;pllfE#T4*m}-7AV&Xn7jtcm?y70!2x$g5erK<WrOi+_kzF+>t8V!g zt+(ew>kCJ~5Kzn4FQtSG3j~>M0x5#R<BdaOLW2X%TapX<7phSn)?#;~JzgVRpG2O< z7ZB1gM2`^4Pg5y&@zstmWu;tjds+O~m=K!?eeQEX|Jp%UwTr4?8`<PvHENAy8T-zD zNj{H`u^YYhw{b4^10*^JkUZ+@O_J@Gl41@{U#LeP6HH9@ooCTJp)0&|G{38fA=HcB zk9SjBRGv;fx|HY=^Zj<J=h9*%1b`u>8=GD*X%rHmQJU7r$OoC-pd$&D{~NAUSn<eQ zs)eKWw|QkNq+(?D?LMFYH|Y9!g*UZW-_txxY!s#jitvuT>IxE4wy_@0-b+phUrHej zMKRuzrgx?u=V{?A>_S>mxNFEL?!<6sfNz~Rt&SUp)1pu1P^1Ddi28vAAuZ?gEf7H7 zw^B2f^LhhOrj|OvJ-DiOxT{&Qx48$RzyEaLfn4Uh7Ec0K8)t8;Vb^qy5S*$^ysoVe z5M?9%Cs_J#k_oX`=RBSlJFR~e@Vo$gv2%LyA$aGos0OZ+y}sKnG$9Lp{RvY|6saB$ za)`#UAd#r_STk?(g`z@9fGi-RMUw>P%u-5;a6^ij32y~;m+cnxI1=ek`I+Q*|08)m zC`ozj73FRLY7Whkd$xOygv?2K!~Sxs<&Agdr|AN{%ZSdK%Xi|FlS;7FuMK(^hR-wG zsuV6t;Z!SIYvaC@ziP6<*)}$tveTI!>=AN#vG4;{osCEoZDE?59cgVK=5B_KE{%9C zz}yI0cq50vsL2B*S-v~$jT_aDeuLKd2_N%(rN;T0b;3y2<D^sh`FMii-{spW`%z?Q zK54s?62)VzA8gy?^iT!xoc=%ARN?@|8dxt0(A<<IYABJ0#pJMeAE`F53|>tr`gt%z zxtDhk!UJ9DwThmV&!I{vUfa>%s5%#E2j{7Y<zs^0B=9!H&+{^FHhsLH>G9~dql46y z7yAbDA%j6_YX++kpHG{JNSo|by))$W;`q<~QkS;3#Bk{qvN=1b8|7F2zT`4M&u{DC z3l?i;fYxOyf~F?Hq&h6U_vyKa08R4;9;X7no|oq$#LQtc*Pl$`zdR3O5>W|~8^Mw^ zTkVEBeq1u^C!+*urWjrb$HiI2Z*p$7vskjyd6zjJK{RHRJwC57i}hwCy_zoI_pLkB zlR7C5`ZOK2ErC|p5pwPdMLj#F4p-|v5X2n_cc0|t1nOQ=gv+1P$)_tv5~uq4V@Cb_ zZ#jz<PoQb|lu%Y-j%o>toYKnmZ~8)Fy)r_sHfeaMDg4{2Fq(1YXe(%l+K!cxtX`NM zj=_s?B{|~YTN=X=9ns<N)9aOhXBVpm8|hhfcaVW*mm*h$h^7^a&yP?h2KTZtA+BlM zn{*_9-N=6@ynFZE@`%H}Q7HZXN(NX8Kkgd5ejB9KL{FOWdI=Jjw0qumzl}tHpWF`s z$3H|_X8}tyUP>#H^eE>K9tep0!b$hT{ScOZ7qgSZ)Q_xo84=z-xCCN`h#`pNxrD8V zaPmP|uNb3s8o3_xKGImd6-!0^f7+2AVr~03mlPQQZl_O38u^IiGp)q{dQi?{P4S&a zu{d1W6yflh3ZheFbd^R}{H7<&-Ys54Z0lCG`HKnc2<FF5Lx)mcAAbgTty|N`ur(Ba zaIlv6%3ZOhou-t(cc9zQLTGBWVLSmrvmtoZT<v$4{l3|3?dKH64Djc0K^xKtJ(uc4 zQ<%N{lJ~EYu@N<$&QlYGO*wvYfnL2ZQ$zr^eAzgccjCRv);{ysyAjoY9<ZGlFf`EC zvTvAIt>wPVDl_yMY_Z}eXPIF>3YV*t=6ODrXBxwKC-4`(cr6e&f2|<{+)E#`Yr0Zq zSzpY-eL@G5s0l;MgWkMfEj4qW5aTER5Dv8+rG?!OVU4~p458+J8ZJJ&v>k$X$I1h5 z64Q78C7!?DvK?g;6LH2q{>)jRU?o+81j2(stwW$G)8g9I1pe6X%0gNSK-~GY$~A=B z%i@4G2c@#b$h%6Ahh0%bn!kDQRIiCC71V4?beScUnfOdvV15$}NrIOVT2>TrW^MMx z$8I1y*2Nm@8<nHqIjx-D;0=a<DA^3$b|tA@bjV+O*;QWtXnyo|=gnDNiR-1_%-R5) zDMHkjffQkLr^6Ey<H9Y2&T@ZA{qEt%MBZLx6oI6)3|!i1E9>@awm|p+ptcrei?^Ym zwO5i4AgtFQPhBxM(jL@@RfzOG<h`B{mzGP>!6Af?bO5_L&i0$3sH^2EDI~*`v@L2R z|FKsHd*Bmdg-q@~6Y*wocJ3U!cUu08=V?^{<kJzCK0@41t&B?RcX{H`o~7<|RYK2X z@Kb%I5<TWhJ+<zGHwmTaM>=1oXo>`3ei>pnp^@MCUOK)&BHrH;1VL)@evI(NllW22 zn$7AzN4`~k@<EM!`8;eXP9G8T`g@`t-}-7^qL7+%R#<!GY1jQO3Zu*$K*fN(o3~>^ zn0l<48y>H<#X0x*yD~;YjP~ya`&(Y?7dtRks}S9IgL<;si#2!9<YtyS)6oc>3f8z- zbe9&EX5p#P#DR*AQ(s1hGReISfHvJ#{IRg<_W6>C1GQN1FRF*tozfj9H2W^P$`mh` zq~BGTtro4jl{x783?{6Y!SP80J%CE2laBzNiVtJ;yD1?iSOR{cQ7d1c2ep6xH}3<! z->_78<zJ~nH}+Dwx9p{H4}!?9R#tgTl#E*ODFLhz?z10`o<V;j`iKfQphrYWLvh$v z$41gzV|hUShh2GDnIOC1h8mA|^DZk#@t_#9PtF8-NwcSSi81Jx*+`tzJCfm_azI1* z-PQfZ$6NY&@so_VOyG8`S!GKHn+SXFQ==5g+>hfnbZ_9jZVC1MWKg$~LCei=lZjSy zjMfOg&IhH0*!#$9BdPfsaaT9gEj?hlmSRa=vJGlAYh;LG@|1Iee2YUr;i~-CRSz;a z9^?MegAIA2eQ(UW#GO%Z_T^ykvmy+=fE01ihZRruK@=>+q%ia~1upRauqWgjBG<UR z^CJqt+&ZWfdYMJh@cb$u7_A&~zT&wLBkmib6LWpFzHU;_mHhNypK)fbydpuQskq{> zs2L~q{9CikJU{?d-L81;;_L7KUpichR^mN`2vXyW%mzBud{Vu3A*fq6L#LPzyUsG# zI{RhgKX8`jPJ<IE@IO-YA4LjX8^VfSvIFM7HIkGt!OpWZV3RDrq?&`jRx;lhU{Su8 zs>5d!U|}e<Z9USjkGP#Cq_w}Xv}}qD7Vf+jGj)+<2@%77v+k5dY^ZP5j3#gRMFY>u zArGflYMhqj-X<55jRmwA?mSdv@j)B;kdO93K1;lGniVV>GuAU4M@yPzua#0C?+kXo zqV*dw4cgKy`RSA#5+nms;g?B|K48zyb;Tk!&h~WEvo9=s@U9^Qo`aFY*b;~OkMQ)? zYNP^jcXB-2%pk<6x}H*#FR@4WUh21(EKEtcfrWdnaaL9}!=}*(AgNZP?5|Es#h;#V zJJ^ctc#5$y+N!T71xXwa<k{TS0Y-7s?uE?J!W%il(HY#XOYPv#o#2xf9$J{JrbW}7 zAs`gk<E(YA?cu;xDPRb@r_A%52g(X+wvSLW7x52gnf=7F=f-ATauy4WD1G=oZjV8{ zR=L10cVhN-U1mB=bR|E%!mxjsYZ_Wpukr4FUZY^raB*4-Q?5|SZW(ZCFwkib_^T9y z82}qzuc_YPu!H>eP)+L&>ARd8-?1wo(2LQYaJuHRaPvinOP&8Yf0!S_50W2QHpQ-g z-P4zX<v*15?~ND;=NaTXlXtSB)}$+TR|Qf)10Sa8iMtenP$NKAgMGW%vDLV=EdN=J zx}4k@EUIq<%d1!-vQ$|i2kHl5a#G$aTomlXEFOp!C!}Yy!};LxaNgxq50r)@yu(?d z;FZV?#yaZwNv`;}M!I{!Y1-<W&AaL0c!a#3&G#^3xMpC~-?LvtQ;D=Vl=q{kQTWmI zMzObx#3*(kdbSR}$nXD9Ie3w^Z{t`M(s=bv$)PrWaC@merc(}|^;v{w<d&FLnG#tD zvow-R>sEa*b(b7WaIQJsE*YDShrLQk3}(I~snzQVk{Bx0$*JPP@581NrBWd35NMOc zELIs^MwOj8c58}{jrIJ_QLzu)PGj3Xa|-v)-i_qnd%1NLep|!?1c`sn0{oRca)6fv zTTli#Xf3x!5jGQIHJ6UcpYCbU=5@C?VQa7rcnG=s;mDo=BLY7MdW@S7yLQ|YC+lB( zR+(IWtTx@Tg-Z)j5Wvplu0k7#@6%@;=|<kezdJL@Qn+Jvve^$5r<76jpGFkRbsx-) zcvMeR7qXB>{c_$qY;YbwB%U4^2q~-It!X;{c;a;0X;NkWs7JTOQDyU?Ys9wcn9vv@ zHhMN<*d1?+SCqtOJf2?jP6JvN-q6}B6Tz&T_Pi<V)h(<*vf1MfG4=gsMWQf9^u1K? z>17Gc^gdTU@2?3yE*vjXq{-ri_SOsN0xB9Y6rqWBaf!&er%u-@t1QKxZ4gmcn@@k- zsI0R6$_Fiw)~l|#OhO~p>!5RFAK4i73c=m^j$o1-gxBqV;`FOGXOgYj9_of1<e0~1 zr7&Pl^58m~{fjkODOPmi9I1WUoK;@C^`(tZt6!X%gmG~7iAcKFNAIvJL!J-3xNj>c zTmrro6N3u9OF{CZO^!xYNjrlft%dv#OPS0}Us^LtVBf9KARgfWXsGF^mMTAg^Zx)L C8=1ra literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/raindrops2.jpg b/emacs/nxhtml/nxhtml/doc/img/raindrops2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..04d0610fe47f7813ce1b3c63b87ac354b805b5eb GIT binary patch literal 36480 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�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 YqgY@`7&{PYNe&}ifI&DQ)iWRe*`xlB_5c6? literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/region-selected-after.png b/emacs/nxhtml/nxhtml/doc/img/region-selected-after.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ea5533ac493cf42914ad4b0f72ecb4f3feba86 GIT binary patch literal 3122 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%0A`8<Fk17le1AjxnwsbzA2as&PeE2-+)#= zJ@-YCpUbDfxo7=@syF(Y#E6ryW<IQ4P}t~jV|`iN(@lI%>`{{jssv1C&I&4t8&LLl z6=&V9sEVYKqRm@<{SuA9G3LFQ(cKYh0SpxDh_oo)ek9DuqVT(7)a)65OlHQGOVV2N z?QWGPg}1&dDnIm=Bpf_Lw<<i;G@tG-T^XfQP26ggW^0*^pAJh-7VhO%Dt+W&10tc0 zht`JEX7OEiFMcMQ_l<hl50|>sDd?kLyKkBOyJVp(oh;a}zQ$d%7U)Q`qm1O6Z1MH0 z6Xhn#*QCg~`AMUuZU5$RTc`U2>5PBE`TuV8U&Zjh87_11KWP82i~rx~>qgy@O>Ih( V9W7Vy(xiLIxH@_|pw9e$;~#Z6Ea3nE literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/region-selected-completion.png b/emacs/nxhtml/nxhtml/doc/img/region-selected-completion.png new file mode 100644 index 0000000000000000000000000000000000000000..b971b9da85511b4bbaaecec1717f6d2f3f7e27f3 GIT binary patch literal 27193 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	+ccHHo=Smb@- zC<xPP(B0F+O;Ga}{rka)P|Ar0P6UX9SWEAGW^8|UJ>K7QQ~T{a%|5IhKTevKa5X;e zdf>1U$*?kfcIyri&m~!LOTkpso~XYWMao(X7gGv4-ZEBt-`h+xt|`+lQNoK4I=}BI zfr6VocFS{hKCKOP*JpSz@rUR$Vd+9isU~=le*=!|U5YIA*kcLnrcf43*g>7AQdOHv zUB)I*SZD@jV5}A<6;V_M2(tazLF0i9MTPP?CXf)^x!N)h3J*2U;ly?8!cNE4Z}1N4 zUN{SAVob1gvctFsHi3?a((N|*!AAH;6c~aM<ebN$G$NoMbJyHapaKLy&`KE`fV?!= z$Roi;X46AbZOkXCG6T`>uxuK3u?)!_FkEJY3k&T!S@^j4wh0)N*~ddYK&mEOa;Zal zX-+US?Q@eSl*Fa)0_LkpbQv1AZ%wOHa`6YowCGC#%gLO8nDP6|O+59H3JPd@YCI4e z34r!197C=SBlCaquzLuCx5g*H_u^Sn2H56F9PAA5$Ny_>Bg5~@jPQfMq@P8+dZGjB zsLfs(h^~Qqem?fC(~R!|ZsY`s7q^I^nD<~Y=5w8y4I|bWQaSkLM)}jg1vL}1y90Jg z6=92fIXpRW&jx0-Vt0fT%)nLyy>@<@CXsz))0h3zzZ3i($(V351ZtC6RM1c%t5k?_ zH8U!jjhm&4ceCV!6Y2K&ShpeKLY^N@#gK6ig7UI8`h5nApOE4xpu<jyl?AIvu#+RP z5j*}rTk`)Q@yY5>(AY)#U&Q{O&b<fDKS!{XgLF-bvNv$W^3&V9t+vqhJcJNJ0bSQn z^#1ml|I_XN|F1yQPKzW+avA_U1?Z68{sy%HAClf;GEs<q_GP#_y+-4Z7L?rL+*t86 zu)aP6bZ%_FxH=7$zfit+JnIi};jR=~{X6eTZaI?C7noOtoLHfDex7Ey$5ei(<!9#^ z>gM<*51K+u?~Jb4p|e7PM&$5!62M*LvY>+27wbLODQFB^M4gpNW;^Kb;svK|X&Y!v zl&RX{()x43vs}ND3VUAi08(C~0WW!XV>e@n*&PuIkes$Oz}rJL`oYX$o>Z4`ex7HI zFWIOFRJ>0NLIGj!HspS}EWM@mbFYUcjkG?6^@$TssXNsO`3@8B_FAXL=gqzZkFl9@ ze>FHr)M3~oRg3|CKLM-NzX3sH30wQUGlq1?!(re48l%6P&ryN5<KsLUd&$E;_vQZc zgecAVi>QsIfqkxqcK|++3%AfyW(}YFP7klyj&MC_FGSN^)@)}hICFjM_mIE6505+S z%CX-j?)G}G_b`1)zuop}F9@QDcv^>5>uU`STio9$15Oz^wse8_xfVq@3H9Nb`pRBT z(1>bMn546q7>x(n@*-2z%4+!GE8NRfq(M@6w@k!$@xBzBg}{p-5l5dXJ#8(2eIAA8 z1LD`b{MA$2&VEG8JP*h%_qebLl~3)3{L53T!^<B3;vBM%!fvN-cG&v0PpPZ{tPk41 ziq(B;OJ1#1-R3@v`o~1=!OrJ@n~=)*1@7#MQQw<P*F-eWGw#b@=V(1Fq<Z?zH5b1U zEg%1`nn5b=ThlwWo15+MS1?8s*3g#ZZ#FN7R~<-wOp0Fh+qZohT-;o0FFpT78QH#A z`F_nmu6b2ZSB>g{1@smzJ<WJEDw30VZg7Upw$3{23N#s5#brj*zmrZgvityub<NkM zHD}{JXRY~y-T61u)c)~`>R;lwWMoY3#<QFP0&ESxo*2kzKkjgdx?(hmsD;WSwxlqN zr7)zCjMV2v{zfovaB=I}j52C*^q&6txg44*-RbWtu29tl-T}I@2ZInW(00mmvp%Eo zAV0M%3ANjsqkk>ytns=Z3_Ugd%eecNdOaQ!tMc2)H}odFg3<cqir?v5EkBY~8Duo5 zKJTfXJ_A4gHX9mt04OTGUi!z$75fG~9E=z8LT0RLE)Oejvaz;w9vSWwmo0jek_9oG z5{WBsYrmE#n3>D`N)j4e)Kjt=Ej!Cu@=?#U(-M)_uN;T{CqP#fO5pE3Z%b+MMwAe+ zF4WJJ|0J5f8&1ViZ(rQx1v=okazCY|To$V<0{+Miz6vZT`HNyKARJpLDj2jRJ>ETk z2ip^wd?F5i4}W7(v;DR#*cbnB-Up?5ugUv%lRrHOe^>`A(aO9C3%{5@nh#6-k!mTg z&dj1<{5;Gy;PkPg7zs6TIFQ$;fC06`sQ~%f?t(OPe@jINE%IL&P4w{3q64~Odp=}^ zXx~zziAyqN|Lx50EB?Z@w{?)W=wb>Hf+Zo!Y>q$<u1G9COGvrV%ypySAEZ|L=v;-f z|54Rjo$!aOpxpX`!0|_ZXcTF@VsCPMV&<3-(3bL!ZO7SZ^ox02W9oCW34aRCyx~rk zWhO0u*?&1%ryp}%UqY?uPIgY?ZJ5DL;$)BV8$V0bvFotMPgA3Wf>lR30*J)SbFZC> zX>a0EoW;BpDCJCm5;wcbYcI8K4`NK-fgFNbNbN3Lb^lp26schkbm{VNDdDTI8QM%J z4*#Js*zsu?0{}P$dLCAwn0bvFyzGKauW7Fw?PC1;Q@dP(O=B)Bu3T)ljE*Z6H*Er{ zL>|(Oo)p-GS9&&Xy4(%0O|p9Dg}r??#&J6k4y30SSRDV7>FK9FMqQupHTYh6Uk^LL z40N_yy?AQZcRZi8o&^isrYABG2@5naZam4mO|P(9-_V^2Tb!M~#n{pUak|6jY5(2~ zab#jv;Sk|SFmXC9jmda*Dy&L%e1!8lKe1GHK>~+O;4tx6Z3h!*&sjwE9IBlquCbr+ z=KgcmD;D@!MKxD@H<^V1F|U8UB<lIn$*+zZkN*Vm%)R7C94U*}z2eaFaI?$tGrt8* zq+)vv@=R2dWSH<T3pCkQ@X5gOH6RUeG0vd<&S=!&lmCpZ?{{v@3Wpa>PHD8`&b>R1 zaT!EJ_M*uDN7S^YSwm(C1~93MR-u=20H&hMAU-wGv-!zTU-x06@3qU2G4<*)y;Hp& zFXEFF)~pFX;LEc=H*-`^Pt^#F!?>(WnMlrpNL3QbwuxBA?hWrDSPJuOY-5ARpIF$5 zn2Bxtt={>naF7I&8?C<_d;#|5z5%~o<)8o03MvmY$v>inkINzb04;}X$iT6x>;eIB z6K&u$NDHMw2@Wj9PIC0=t-ucP1dv%e2-^yK`#$}OXqIc3{_W8pP^@>Tt|(}O3Aj_i zdQrui&=_;r|FXBIe{L&aE6jiW<xDIbT4p0vdU1;f%;mmkU@j;<x<)HwSY^ZESfk@T zuFaB(U`8$??CqwOdmuEBHE@%AAIcjhV|SB9JB4HD%ZDwn7!!p?mK>2Y{(Ufs6^^{# z;jv%knis{~l@_<9VSFx_HV}MJsuB$JD+x*Py6VTox|R+{O=3(UI&xYK%zFePksdNe zu0WAvH*oCAZo7}}*+|z(f<Np>o)I(Y7Gd$|cdgqr_m$zE?=Qya?K){J;^N<BoR~Bp z^kAd$ODn<()jfRs;u`3<lKSPmaD1V#$T6n%F*~hemrQe43DnOF6Q+o(9N~+<8xiy# z@Q-Rjmn_2&*a+@}w5|Vg)7QV1rM=~|E17Fbdu}X%jhtAd0ZLLJ!I)ga+JWgby+DaC zP<ZjNjT%uB+HFdz-1b_uC~8}6#}icmqr-{3IN?P42dkkNf2Z6igENx71eOy$miV9| z7y$r*FP*cz5kMBWEHHup@5GVnPn2Q(vN|9R?CMov%F59sa~>!N24xbz1CXmTX>LQ+ z5gwb+I5pR1g{KjjNzf-GHpQID11hH&>r~y3|LH3^hnR2#V#<~{hj?~N=;KHw*vE6w zZ%?)D7tL1+@<y~BuC#X|F)}d!DJIYs35oT#?_YH}NqxGhJ(B8D_g<QPtE|yJjztx& zQB+N&q;3%znZD<fCvah&<$WEruA>frUg_lT5+aRO&&jkLL2Rs0Qo_PT?{TQ?U#kv_ zM&o5J9X~HBe`ZE^&nD7q8e}e8;~RG<T(49e99RVfxw;S9iGAOd(k4x=khOA?7>#_b zAXgVl+>XpJe>|rHO_<##r$9;ti>C(i<u@H@cW=m}i~^2T2SXWZ3&sAS3$lvEKBPtN zV14?(UI6m)!x*eg>i1cO<L&u-B1Q_028BBg4e1kso4&fpV22JJl#edyy-Y46;*WjS zpl;6_HF^BV<)9Nfn1Mtc&Yur__aFS*g~}}#+fj$kO#-FISIu2SLX~xpl0w#mOmr41 z(tZGY8z7<keP}kg33r<lCftp~Sl8DlBFhfk4{>?Qe;I{$gsex12a@YFN;h;zEAha* zX2PB2&XN*OUXI^19CoeONsh}y{eG=wX`hDs&^J0L_-L|Y0V`-6S4ZP;n;4={Z_x1x zdAKEgZ1K|yn8rp0=+g{18;$wMX~|qQX7Vm+p<j^>p=EF`ShhfAHp-rakcs3g2-C59 z_$)~B1XhgMUs4Ut;P;VlW;qk*BnBGd%%*zWlMqeBE?ZvNNCEub&6hPV??fTx!-S9} zArr*Lt0c9QXovmseF@z?xRnoUs8Om6XMqrS_1Y5+9}W}O^3ezDj~3BHV(=8R4~Otc zghs8b!xL@MyA4JMY(pzpD<)1|UMkt&ZXhEy?EKpcqon=I35ivfFN2AzT<;Z}S3W+s z$n!(BLwT+RYx!<+H!6phm;QT;Na{Vb<9Xy#_qBIJHAf2hNnzzH{+4m+Y^3Kbp=)d@ z_n^3Y=|$vnRjUvA4#t?;ejAgZna{`K(~)Ds6&MRpYlRQLISFZZQLUu+<ync^_Txb_ z|16CZ?^*lxORy{*2FUluh3r?@(!FvPUTY?;HLpI%D)t&pZ|c};5!Vg!K7;g&|CR5_ zj`PK}u|P4_0OdoWBY!NU!-jV*`VTC)Ma3=DTJtAJ2}R$43%b^x@|O31NL+sMqa?nk zE+V!hn!8BDKBfzFPmbxz#vboVe~>dn)_Hkm!MGAq9gf#{lxHII3OESsimXn-P}~<H zHEc(kz?ef9v%}!Q;l(GYzVn&GX0#dG@B6zq^eY~*c1h$iyJ~nM2#&py^}dn+tZmH^ zu8KX+s|iO6@zU=1Yn`<vIgg~G7umP-5g4#h{lwj4`q=f%_!2eUXp%s!kPfvU4P)|{ z*15c9^7itH&!@(Mrg+cnWL5iJtM!3Uuj;HBwJd{*x&of6T+L+X@h<1bLcuCYYgVw) z%BLDZOD_iM#&EIN6DR3gBNs%XR57@}VD;*E_5RmbF8756o@^5%^NnUUgXy!axpD(h zgw-KD0<cILG~=M{O|jUYtdbC=?=+s;U%ZDmsb>{tn;|L{5pt>c<azf+R}au1{4m z#cx^LGA86Fc+OU@YL1{VyQTb+WyOLF1L(gRnWfYV*%qX};k^`R7pKQ=<YhfNCZcAL z`(XAyDXzJI;Khd`%l*OkeI*wo=+|t-MMh0@?XZjkt@Tp7-k)QaM>L8BYNb}Q#9}i3 zyOC_m5;wgN3a6?;8RLIw7~bK3;Eoj&%wM!aKt6QE1aJBxihIQQ{8pK(o&iDQ)a*+) z=X~&>lzr78^2Q1_FSK8-^tAtHAVN&uq)BBQpDa-e4{4aU1aYvd=#Qb=L(a*7x|w(N zc7vgZ&|C$Uxw3xeSS3w$a5RgGW~80ol<W&V(mOy;_)bPrQjLr(*bAyr!ENEGfBY?U z8z@=@Rjv5Ab^|Q6De|7nXDJ%zR;Nb`?zpb3kpeyb_EE;em6_#1Gk9)b1e7g#qq4q` zilEzt;(9|FBta>c9AgTS^qQ_j9f0SO2V=KJ5G9mH;1Khn8)dYLOX`khx#Il0>Xtg& z+Osr_`d5ljMDp3Ik*v;4vB|_&u`r#46q^^vDqJ%b6&?_9U#8PgPF%5)AYJuY#{v}! zH7sM}fFzQ(06~dOIi0MSB)W3)(i@DBzJapwF*QH?P-ggdYCSgK<nXVu9arW;fUY@# zDk7aAY->-7`Z_{PZ3ZrB8CZ(rBf}NNmMV5n?O=pibyir#uZO5Fi`T|A>RZxd>v$+a zccw&Sb(Z#{`DmEEwan4Hz4e`1Q9H6f%gZm={e{g*sjkoX^fI-lAC9(x%DuRS1`=g0 zt2C>l`No^Yy*O($E&3|IJC?t4XO$Tw$`^-^`H0Lps_;WGj<ke9Orc3~(w99f7h4)L zxvi{MPvE7U@*XUeLX<2SIkV>eJCCeIO@fo4qI*5JCx*@v!eEk{Yd%o#!@ZVr1#64` z-_813Ssou*EI66plpw*{f*|h^->GkewWOTY_ho#?-#$}cSAt>oL6oE|8LQxzBsJB> zby5@7+`6lba-aU{@N)%+m&YGBj<;w=_bs_7%TagEgSqDAt`t+%@XEMwlTgk3DX(li zsR`_-FCJX%f}3lQC|*pD!k-=6oIP}*HE}kkaA#7&fJ)4*w(xO_FtcjXmsB#P<;NQz z_HfKgP*5C^$`}8~11<n|j%Q(48ZC$BYvY||(JYLmI*Mc>)HJ~lAa~4hs|B&k5dsj? zRD#0e*WV}g9rFUYi-pEg<tw_8IRlnq@LdD=&Czq1#*oPOlVlshH{LhGRmW%VHcV-6 zHc=ldc{4F$9fR2CcbQ^`3nY0aBk7f@@E+aaHH5~uV^#h=kKYT+kIp=vtgpf`mmG2u zk;_b4-t-z>qdwc(duwrZNjznSX#QR}9jIfr0f@iURbh^6e==qwr33AaMrbjkXcSvt zd*7tDE5iaxQonB>_!9-_S}S}Q?@$iozql>pX6}g+KKaomRhiD#%n!;wNbjHo@IMR~ zbSWGs#1FTZ6JXo<S2Jag3k_z&0Rq~ibTjFHI}0_1j@cv;K{n8y___8qBMmF#;3c%C zU6eufdC^~;8q`|iJ>I2s(C7tSCytL=H-NrePRjZ5TC7z;DnNn->P_Y%`<lsy&(%mj z%glb58TFskN^1x1KS8mpyGt#5W2GxgCQi*O>8~RYAs+f%^baRFrriSP%#C~F$6rbf z!uBKv_qzqRgNThkCOl>@hC40(3cL(8+%f%lS!EUW|JS!7x337)T}_e|+N;8c(hqfd zhc0M<oVmT@J#o5(B%DmYf`V)!LqahJp+Ms-+I^~1m6;l!nh~py`Ucgz(GgM95)+{e z;Iw*lJCHU59#XA!n^vRg%$$<vv1>Xrn8T*M(hyx;dx7n}LfKmP*6>hqF^A6d@Yb3a z49QCDZu`y*f6EgS;OqWjr4YaCx=U~N<u37EbSHPar^DG&d$UDy@z(4`b=q$^JC2%S zEt?@}v@G`@fI&P|0suhBfQl*8saM19TFS&+u{-VT`J`E+_FbPSf?)@FJ>eMX*XfaK zC|K6khEP`&9s_nW)E-q~0jDDk4o!4=P;r>wj^6@$5%)C0NjR(6FdE9T5U)?jP<9Uh zDDt0Q7+LY2Nna>#a0r5J?E%ka)R(ukO@wTO#mq{qKQ3MSR0NyTp&)ZkB0LgM?}F_O z!7FW_g&nMOIJ0$0S+C39ctX>RyO+~(4uc0yz}K5moL3)r$jaL3VQKU_YVqm{0z+Zn z_?hO$3N5Kn6+%aVi~}c3ME{kB7$ovUC7MdaL1>!lk@hKgk09#g)j8F+Qe8DLV&kqm z$jzmBsY7|w1T=rymha)bVlaof+ts!99IYtdFWh9|=Jd8gx0!q)5398!d)eLqazEDV zlZRF65pQ0SwUr}0McKs{WAB~ojMV5C9}9VkhJ<z<Nxf9CdD90#OpU4Qam93Gd#ds+ z>red<XVaL2KT815HG-}TW@*#<Qao&Zpqi`p=4qdUXY-@h?z=mm>h^*vd>{Eawr$x| z>?T4wIY65*w+tsj1z{jDaTC3B9KMgbDTUvd@Z<Fv;_VI1vc{wK$1w7c@&O(c4^0W< z-e9eaS5td4+>;o43^b^C@;lJQ_QwJ0VsK<lmlLstotpI-YL`<Y6Nn}8(>X<p=Y-D8 z>(BezH(}+6ZAcjGlnIf%1v*q$xvN?`v={T}B}pe~YRY}z)Y(@GCHLTLM%a|R_!p=D z=PzYnO7g7Cxf(^1QJ&BE26sL`i#!~UQ~QJ(*nZKlV%$4mZEw{dISr=_^2_A)X@OGD z2Qe8hvW~YA7FQ<b#uE--7}C}ZplDs{a~Hpt_(W&)i%ZilqyGabNy^|VLv^5@ODwo) zGZ^vtitL>x)FQOGDdBj?xRW~D%>O0d3f4Ji0$h;4(`1dLYI4N)CDYO=-uGy-`Wx;} zH0#m=Od(3g2-9Si3~*2`uVtpO#H?5|>|}rgIpakto~n`m`Z{WhbUNN&Em`q6d*<)) zNI$>viuHVs<O23^Xqmq4KjH!I@D>XQU(ySKuDil?*?7zTwHLoECUc$uY>b`-x`8mX zu!uwNH9Y1_x~vq4yAXX{mEX@?seBntSZ;j$jkF?nux5A`dwMKA*V9jrFW`k>>po#P z9vwTEJ%oJFRM}OGRdb84-7j(y5`D6IQ=!Cr2(;^<7se|Ay}Rc8Nm+E%jMB@mm#+3I z&%o5ooe!mhQpgGf&i-9oc9?4+PNx!uZiPAImM;{r4D(C0Cs`aiq!sqz9-OLrWeJ<t zUOeMthi4VmkV7Z*p8VT%aimGx{$lwdD@NRr)AdbVDv8kJI!ve<4S?Lr4c&7ot%F`S z;=N2e!+wS7y1XbJygMmSgVa5ADU0jaByh~n;WEKs-23vXz=@vot}WKV<SW1b2Ewmr zv*`&s*xfc^^3T{laC?g<Nwyy88!`5lI`HWFa)}Q<`f*8I*IrR=GQ~UtlBebP&su*r zAY(tRRC&l+M^N^aLgs}r%z$=JBrA@w5E;^nl=805Y10f`agS_yg}}B|lJ#0IOd!+A z3VNr>h+N!^muu=Saw_8ht_~;&h?cBO64gi9gFcPdq$<a7@u<~wPVk(9@0))gXzJj# zqIXldF_#E$p)3t@44iiHFBxb0+``|TuP%V<zsB+Wq;G8LsGqy}ECPxx9<~Yplk<6` zqi?dKermqaw#S~XTePsokY+Lw-adzH6B2}KSoY2`JJ}g8JhJ<nJ*ctr#@X(%NteW5 z_WUmEd1*nQWS>up5v+RtLr#W0nI%Ob!d`6Ip%^BtRBAO>ac21??pE*d8zWhHP$grc zJUoJt0tSblsQ~XZP{GIc@nNw~pjsZ-5!=zAGXfF#JxA$z(L%iq|K`AufCC??j{6jA zSY&eYwbYOY2nHCw_^pzb|1smGU2P1q-mP*LBEKYH7$IO|bU+QUR*ljNdI*5YdfJw? zmznY!K623>twkYg@#>G4Q10X?&?dZR+jk({a{0dVTg_Q|4*3_U#m6GFo(Z+Z%{pDf z2U?i2-0;~(h1Tt0nz_&gl3<&yDdX?IzwSsuMH<9#>W98DXk**j`E8bRA9Xsj2qDK; zJANE%(9}g4yD1#utNqG%`Kl#AXP$Yv8@R+VnEIR6;bw(O)3AQ*gr6xdY%sj8Q1E^j z<R=y<+eg`V0O?#k>^s%7mf~CV4dB1IweY)ZIjgk7lVo0h2vYVjt71Vtr5%2HikBCN zqvx0b>pab^&!~f(cZ4FKa`~v)tAzSZB>UByO69>=gD5YPt7l_xHO8-MM0!%+7DO|E zj}yo`T`4~UDm2IsFv1p(VhmDc*ibTq$r3mWQgXijV@}tq`gbpOb2YcoZH}lN?WTa( zg9(}-rTIwy6+5RRowi5=a*EaFe*jcDTbw)W`ixUWv7Ty@Y_-RSAl9>lL7<Z;oriev z6#<t-x5;MR3YNDk=--bqRoa8bZajwluaJPrW@sIP5=Gm~k`z`mj>i3mQ2ZEZ*w^$k z&U?vv{*pA-DG7d*m_i2zs)rF6umu@s;XvB%V}8|Fbjj~@w~!oM7=O24SwU3$;bb;X zxZAcoL^616H>}TuT^ZXs%;Z0tr)x0A2%cRjVD3S`xM8(NJU&`~ceK*0OX4mQnhEi0 zXYz1C=ZKcS(^H*urWR_jyRsAWGTuAfZAjBi!_o;d91{Gvk5tmZ`aTUFT92A(95enP zbR-3k+UtqrPRSVK)ck~!Q@9&Zgq7mD3OPm?BX$ZQP+tD;1J<AZ*pGyQwph9?eAdgC ze;RUtU-ti15*dJ*ZKhpMUeMExE*dDL!h4Ex#+b|cDGqG9=Q@;BaOsx@uIP-NSI7}n z#<#w6C&9K|ZS5JNMKsPyL7T4pkLc_>q}5Z`KgpZF5UL}FR<MglmDHIjp(_Ua{XO<Q ztgEKr)$K%EVSv`XUVg5NY9q_I1`c*eiKRXH+A0j7!uT}67C(5ZeKPcx8UincSaN6C z?`%k*a((=sx3j5$-ZFkA=_RIRu*YX^lIk<4-^3~AQe515%NN?XL)n&~v5(NgcuA5D zR)Kl=3VV=OSO9B!dTl5f-?)5P3`cI4$%PC4Xj=v4WkY(ar@ZdPy+rAb09aEvlxt-P z=7O!*Xy1$fljnPZc9?>>NF?Op<H|oK5gKv0^?v=lj(TeiKe4RWaAG}t^*u!9{UD;k z_Z25I7fFzdztJ$Xf7a@_Sf3T#cq_@LN`dovajR|=hZBV9g8~e+9aC8_;TIj7tvxl0 zwAcInkN}zEp;P;-93(kYQR5F8l8!bzb|ek8*13`xs3CyHM~45o;iwnKA9I4a_W;X8 zGpN_sX3ftJ%x>NZx6Shf9918zIn!o)3Yh)|mj$wXe;u!1jMglQ0FbmiDoE@j`~8V$ zAei{`4I^btS$#ICm_R&T|AC60Uge?{OkSFPrsS*nubx{ws}96FrhLR%8g1(gnfA~x zjSec*e1d!#q=}jhr4`0-iNbaieTF9Vaw=cYIA9N?>^?$$8=vUJP{3(jP8kflSf8@2 zuyIVTK7aAEM)VO;8AGxglDV+^Gy(`vvQt&c=_lA(scFVl&zs5bIZTN)wtm$XEMs8= zh==~|*GMY<oQ#kzB5VzMQ<Y`bYS*~l_ppp}^3JqNgj%#n;TuPO<sV5HKKZ8W%u~Ql zNWeftP%5#M{naw?eZD*iPXzsYXpj4a9APEe*}Oc)Hv4}UB0zzt_b4j}f^&0@L&W2l z2pe$CvSD&ble-`+B~51k7=u|({0hDeNJ`_r-AwM;5W#N_{u%MOFnv}@4S{!VwiY&W zie;J+e<BOH2uk}?0dFGFf`s3n_dOQy3Buk9oBSnp1iISu&Fkhd(sVc?z#@|wsOP1J z^<HfVCw$^`$+ttLJi;fzqiDu6s2884uWv$|dvGpk_ioxUud&XAGuTY8UM8!we+dJq z-mI?Aoh%;rlkI)xN41x$gbX?aBF!a@pU(Dw2&hz1Bw}*egGKXoz%sRtxQzvQEUHUg z&k?Nl>P^h3{qI~|q-2e;ME=p?<K<4Z7n6W1Nl_LwR*L(YIvlG!-*k2+u2t4vtlKT5 z%@Js~p1&VJymFiw)q0A^T-0mx)8p$meXs`Gya<?XKoBcIKj=-j=Ybk)o-F-bY8;sc zIuAa(^RHB0(4dDzmZ0NQYL75G(ON<+DL|7IzeNqwvr9ae?Y_eUM+E_s!GZc|2IUFD ze(jz+_3De{@OY0iW5qU}!v8Ed|DX(hAUO@?nySsY)&Ad`mD1*Nk66CcV!A4428&-J zfmf)HeXqZp{FbXIe61g*>kr@V=L`d?I<6~10kCNS*2)mO_QjjUCs#3=)qDZTUtnCj zBjrDSCy+S6ggv!YI+GMKR_Pg?{8Gl_&tc$AoWibxM>zfF1p+c6*0#Q`_N}f$??2?! zqIjKiEpGkIc2uQ0{ozpjm$z!o3(wlecYvETcUS0!A4gXAL!5Q-H#sPWgeZVha1VJQ z=Z@jwgTPCj^%I5TiRrrmXdN(o?Yxoe{U0f$Wz22q0!NUZDJ6YfPM?KDs-ERs*r;>J zOnj^MS2t1AeX}Gw#rrbtlH-?IJ&WXHeKEb3OUx~`;+6y`rh!gynH2JTiP08B#nhF; zX|?Of^Ja4CVZnRI#=6ir#gMa{U5(>j;I)nZXZpxx!EEx~9=pNe*mb$6WIaciRXip? zP*ag8aTcR$vX%a4!2|FIxQ&E4nK~{R%m$Dyql7g-+q3u8pl<yut@BUZ!1%jc?d2(= zlButjxf7v_Yy-;df-dSx@Vf6AY?+me%@JqQ?Sx^leQbF|OHsp!3<K005qMUc&3D8$ zB&WLWK2Tu_bvDO-{dG|n<HfC2@D-IHe2fy+uq4iNb@=CCi?HAgetg(M^48gl)bBr& zB?e#E%Gr*#7xFTShoZckYNu7PcZsc5aZ4PuB-j~?$`sPBENw~bQneMzVnNEc2SEs6 zi=N)F8dXBw7Ov<ofYKv2MmoZSVb%N+ka0h4d3Yu~x&%f1&Jv7he(n@Y(Xy$qPQq;Y z!|a57bS_d<usTPNaTzwPAfc|*pE+xfEFQA*hzGDmz5{(d#a4e(!<b3j+ZF;{Bunx) zL?UCh2)$00JLdB!?3J}x$svzyG%&<WGJ&0m;MGM>BMOL?`lDMke_jjsR1j)IMwU~p z|D1^p8}=*Tx)jM7I1hq9BGQ-|HFar7DYMIyi6@P!FcD5>2U~bb5=m1H^Sw`(`UsT| zl+idFf2bb@rExeTb@fq7nb0q0lHQKjfy@HB2r(y|VQ-r(*4On43^TRP5wJs&MJEk1 z2E3OAlsEo~A}EBjsMMr+DP4UD%&AQL=a=&Zf}91e97OsO5n5@osk0u@QdnOuV#Sh$ z`+-q4C+Pjy-Y5)y*=~9L6cw#M_uCWc^w=d2l7yPpNNve5=oaqcIL?o}U6$l5fIAFG zIUY32*2JRzPfi>{@Fqj}NKp^hi^}eAbx|e)c2U*l(dco>W`iqwn*bKNwl#UL%S8a2 zQWAG^5&|}-#02YFA4Fn)eWEOjo<e~#0~k|Ywk54^y9Q3OFQ!by)}YcHrs*_sI<j0e zn(M+_NquJj@_)~f|6>A+bWr^+=Zp|4t;QjkR6~%CDoLDaG*80SFF(y$zAoie;s-{C zK`&IV;y!8R>c2A;r5J#(3&S~8rw|pF4jmFMRh*`)@w$`-s-i-viR_D{niEt?;_n~F zeeB%DqQdw13-f+LL4BQuRX>iA(>Ij){+e;D4vs)y@XVFnR$Pb;Hw)AV55B1g@O)lE zh{muzI>4?Er_7o82B)a(^>X!AtWpJFWD`Zc%a*+q<bNPw+Q-)j&cNB=k|$9aX{??V z&xC;kV%S<ItcpVmj8s&Bs@d1%xJqFeY!b8)-r&SfAxg5M`M)f6ib`n+eVc#&pPBDU z*I;}f#<C7ap8}!jv?k1n=QDHvDOGXC78&3|hq|Mp&Ct%5$US}#{!OsX7*pk23;05P zl`A|H=klIGOfg)OC=XaNS7I_Nu04Rr#VKn~YIMU-ok6-M-EWzs5Y=iz*~mmKCI|S( z^*4#n@N*F!QQNf_3#4SRP=_r(sE~kN28vu$KB+^q3RD11EzBSkqNc1&uz?vswrPu> z*7p!C)2ZxrAs+aCx*P1ZG7X&Trl!qZrY=@bs~$H1yXNze#WJ1Vbrk{mR6veUX4Dw0 zJmqsZ)%uAPu{p*Ti8dq4K#fFUIhP#^Wx3J>5`MZTqin+cK~t1ZNm{>%xbaej8Zd~B z3<wxZ<0W#CBeIEeH!RNXP9JVF_u^F=q9tFJV=kt7*A+Y6BXMd7xAgkW@YZm1#-jMj zJLyA9Dbv{uHU`s6&DFr;hoIZS^Z78fWV&a!OFvE>5pTBr#s7(N5^Fkt8VPURN~@5g zP?KJjEjY(~D>gHBf)Tm{VZN3H)7NuMz84!wl+G_9TI1u;X%VzH*(g9ovlj^?k^OkW z-hxM1nDpG|BU10+b}<!+oy9(E^&QWE=#9Ky`lT&r<jD}8ckSH~8oqkNlO72ryEELM zm0g7@{mqNtc0xS6ZTq=yhfw5yu1Yy>dPsfV!_#!0Cnus^jh!8!0DS$=$@Bj8KPQja zv}ZFPMi->F0|n5fQM*^p0DUgdU0PnI9+jNgBjf+*-pF)o@ceQ4@-NZKMw7&ujxR!m zNP$$M(<ef-l$8rBV@v>mc_(-GWz*Zh*N*%R1=zIqi#F}K?{^ho^Rs?2z0T0LJrkNm z19}r`%L(zJ*1$MSKMFr!iejhN6>)ma=Ejl{mrX}E4%GJoeACcM3?QSL;C<0Jb-@A_ z-Anmyn~&})%3o}P?1$&5nTj&Psv^jt+s>7BY7Bth!*hjtMx+4pybYVqI`_O!oc@YX zJIt^~Vdn<Sb*3Nw^GXUcsgtI@2T3bCueL_!&&{q6@ArnW02>8`{#oCqPx>eUG07EB zf951RRKIlS(Y|)FI;Sezc`B&kw-{k8&XsNQcr%YkcNce^=#N(Re-{uvyoDJE(@XYw zE^F<`uj=#Kx>78rwUR8^P+YB&ggO}BHju|JU0@Gfz*}Tk3A7lrIl`X?G>AgMI!xR1 zMFr%Zr0o`aL3IiV3R$pnOwy@X;0UgXzA9lQL22qi*slMT`?@CZcqz;Fh^LL$W)L)! z{q&ZgkQTQ5IL%f38R2{hdoXG_*#*wNKliM>n`gOT3q$7g7h&<6ahi?7E0b#%CDnI7 zKDpIgZT1bs|A8UDb<TV6@Hra)EKl=8fE}Sv5^BW8{QW^kyCqX6h}mk~L0asn{1+xQ zH(^_bV*GEkkthTSW4qNIqr_PcnK>a86A2yC*lBP$CZ!rtgMI-`ndVl*{~TDUzbY9W zDOYsx-rSzpvRaMtYOZpAGm~Z?lr2c^_~e^aUcsZie<Om&QNnv$c-Z)YlNfv}CFXzp z>DF3sl8_Y!!`_Gdw(gmam>0jMUxmr`WAOaHUVyq~pEVYaQprkD-wke<w*f)~^&)0Y z-<Q-*8|UNfO6D^Y3Nes>kV6}JBet(X)6g|igcxP8%A$CZb>2IuK%iuH0F+^Px5DI% zM7;8!MYLko&OyL8y_@0TG8Xd?Kb3SEtJ)$Z0W6u1oYjXJc1jmm>#u9MaxGLNNZwz7 zFXb|5e3`u=<7ivu&UMz1*a|gq16@wuEHX^D7sOyZ@CpX@2vyw5$$Ig`U(oJ@y3BP{ zTwD_AGyq(%?6P>R5QQaE&_5K_k2meF@s+A!-}Qq8v?%`J>xogjM(|7(`fXiWTwHz< zPF%R}u1cK#a*9Fw%1Ns~0=0}kI{lo`Kj&1C@@QQ1IYfoLS!345Z)_eGV;AI{P(}MP zn%3DuoKCde&ogdx`h;TD(DLsrgV}hM{M9w#fDHAkXccRptwGz2h_{}y53Z>!5X6Aw zm;0yCV<`Gy`&@wA@#-@Q1^{(h3iIsG5XZjIHj*nJaZb7jiigd@Ip;eCz0dfF6Xx0$ z(Zpu+okK0Nj#`~0c6#Fa>!(A}`tljNw35MqrcUNVll@z@tc_|znBS5HKgfLKm{-mk zH-b7J%=1SUIh~<)t?Z#}|J$*R?ceff>dxF8lr?8m%G4H}oZo4-(CC@qXFGmhws}dc z%klHsIj=AEFrBsd?r&6JTa57dSClS9eYW^uv{-O|z;<zdQ<0QucZLs!ZrHEFJA=~T z>Ha#J?Gt|f-)H=?H(-sse@ixYuC1)iw;RppWH9QDge}y#6h9Dd7av#i`kVJ&|NEma zsiu%CU_U8hU8bme;u`;TN(`px|7+_jqv8nKF0mjXIKd@?1Shx?2<{#v1oy$+6C8qT z@Zj$5gy1%~4Hn!9&M*vYllT43?w;L0bB3C#?&_+d>XCbIi!38zp+@xWDvrHaAtGEm z*~Hsc$OVVKk`8il9d~%gL3y3!c6n0=fR;KM@*bu2pfMe14CD>Sv-3fz(tX9W$nP&$ znKK)I9G-Z0(m%B3(Fj6LF1aX8T^n;ifF<n%23UAv{TaZ;CTa@$Pu5m@O7?qTZDSqo zeg49W1Eluuqkm5dDwnSm%(`ZfnN;vO4Pr-WN6hKTCzuWZbPEt{BP%>|71HQ<lcuD1 z>6)+&4yeRQ5z2NM{y4sU2~I!8eCEVD-#j~*`PMg)KrHsv{#a<iEKX$5S+)txd^7dF z1zy#1n96eTa4}lev8RSjCe=hLgpZGigdiI=XW}dw@_|v_@BQnT<;f3Tl6V5Pk%xta zp}p;P9F%mW!f1m7f)+ce2Bt{~h2T(U5PB`N=!!<bVqdrmO?be~<#GXVZ~T9>F07&G z`2(RHP3^U{Qxv-W)`Z|ZiK}1q5KFAB;<KYwil0;vymiw*OG6qQYD7n7m_Y7ZNZ`~- zWnK~&C6(F1{joPJ2J7sdJ~3d>)pmEh!7~;2u=l!HE2`7(Icq|G!ih%*DYx?8jNYYG zw1*PO&dSq{q3CZKp#gAmQ<|ea>PMp@lk3uX=mn5xv?M^d_1nFto_MkvQAou|95Z(T zPmIUTwUoWX6KWyIF3gJsF{r=tAJb0@Ic96@vqw7|UOVXqFAxVD&)*m5AXKycDMVbD zd<$OEflEA|tkvS2)B9EuA|TX`J6@EZ3QONJz$zZ1y_Xq}u@SnZvqy#hCW`K~8g!41 zIBep0Q^UPa;yZ}TlUkZytW6&oI<`Bd?iT&|CH%#{0W2!KFM5{m#3s06o&9*B_w=B5 zGuJGX?fZ}SL=Zus%lwxa8kLWr&4gpcy6;^=nQ$b-yJkNdy^Nh~{hcd42(`im_`y{G zRxv<&39c&Iaa$c6#XP(B2l+eTtk3Vzt|nJr2pWL0d4-p^o9kB7S4X?_;ildM>-Y5c zY={~7ZV$`Qb+9?&t;MdAR+o@pLRRhRf#5(F+Aa6v5r_Z7T)GO>eWTLmVR_H?3J0Re zIo8z~*CkxCe39}8$4HQ`y}~aCtRF(|zp($|wwLlOxziKAa^e5*txKrE_D+UZI3W6X zFs}-OQ$8&}HN6%G&o-6dL_1sBp(SqilirS2-HPMmvsLebA|tQu)ys&hn{l>3SVu>G zSHcMGlkTh9)c5rKs$r|vYY3~*BUF^>`#|q@HlbVtnUt{)4!coyg^QE+KID2ru=3Nj z6ND}&oOJ@<i>z_<kBDxoraBA+nri~se~(YDx80%pDo~Ru*y<&%Jq8=~T62N>YC3lE zA7S*RoHcK>%u{!}`dXZm?Mp4#{mnuY<-@~;g8+|NPP}hMPqO77pIgZW%m9v~^CuyL z+V|%TaI0BfBqzv^$ch8;kIpF@;|`nn2neSZ{#gKO;LBqwITdY}%Ce6420a9UKFQme zsk-i9bW11C0kYfW{)S3w_?x`s4VUA5$5p>zZu3Q-+m-j%n`_mO?(iMBNAPA;!jeCB z|3X!S>3*!IOUviX9GR6@^4lYXClSeX5p&dJg;}Y9K#Y&9O%jqOCnj6@exqT$w^h@Z z>tFALTVBt&t7I0*thD8~x?qeD^xfFI7ec41LZ`F3*7zTvl`n6CZ#;8=5mQk1y`=h= zU8VM(^PV2=qC{ID5Vf*DqS);iVLRR%9u7@%sy=x1vbM9hVLA{gpPbKh6aVrsbr=l< z_+A(ZqWpMRWJ?VeE%_WWt1KYsxvC#yT_}pAl8x!*&p`#>1@>g%@XT6SzA`o`kviD< zkgWB3{iMnx$7u1*+fu)kSM)o;4%+|B#$VD^>-*xbgiIWSndI^}u7}5(Mc_;}J^`aX zY0kN*$kEW3(<H456pJ+8qGtb%@|wt@k&tmUmCx<Wj7)Tc9R6Qiop8q;#}PQhK;t9q zETPy*?Krhw_{CtBhkSM?sA^o<SO2!@ZlGe5>83X6=B{NT>lR4r&+lffq_;s&^n@Ed z*1Cdy{-x4yoSYx^s{Bp`W}@bSHJIh24XiEyrQwT3GwlK;oxU&g=fU*y&;<5$UpFB6 zF8m-=0F2IU)wvI_u9tVZI<PW5)LK%4*)A2C&@PgCWc}|a1bGge#ZHy6%O4ePpp=g} zgB9i#?Z&3eCKdDKpE5U9$^c^Si8C2O_<{B(r{xz-rVq3wFp|BC{Z#(vD;?vEcqsH^ zS2+v6PX-Wo$}|!77@~A$Gi%eTN)4XNDHC!wW_^yK-wyck4UUehevrQWpr8%dB%HF| zU;BJ-^G@Bz{Wrdgl+*5yFJ0z;pMmcSZze}#dMZP;9@q6csy13a#u4(I+M@XxcFQf= zU#+EMN5eeJto%=UKhMh%F)I|mAQYUiAr_h(gX+Np?NjIY%F!tXyp#grLt<Ci41jb5 zC*eMK<)_f{a=IDPH=6G0*0@Adl>5S70!HD-*`3095M;m`PosjUz`&QVgflk~Gi5Eb z^!~FU_>-zjVB)h!nrV<|)x~C^g%k$#JNT3E)%iO`9Pzd7$Qpk}n#lrkNl#pBk_e`q zfy^y%-yjV9TByr}swS><M<yLp#cehKz;5A=2iowRdHwS*9Z@vqFKp(-E^d!+i31!& zcARF({xIqR`byC=^#!CxifFHlJ8Y8@?6-z{<p?yX1cn3r&jxGFT{kE!zOb^BGR=L* zTGcm4oR>r>b`Y=7tnDv3MK`B&Q&lgqPlWH|{a{hD|CE#at)G=1Tx}6>{Z*JO06^*U zn_bhR&G^$DD{rLI2=mOm{&;7PQw)UB%~WD+m&GVKOhu1>`SjqS@Czt>HTg)%fdWAe zcm)rv<p#Wjr(+8+8=jaC0!xTbMzG8sYmPMJqvd6vyw{snDO2NLD{#DCWgu5ll$nFw zgI_L6<akW*Pfh`iu;z-;NK7@^x2;(~kKY+Nlml*hxU$!>EBwEM70Yn`*eP#TgLCQ7 zNqPV#D!315N(D?^6iEZQFEn&pV(4TJi?^Rq7`c&xKt;UY`0_`Y(iOGKEGJinB3)Sb z!CiIjEMt48F(0`wQ>(XJ5(3+tS$s-cNDk{kP9or6Y>$rRxh_7EFYOV?YNi;;PJZ~5 zOeU%Sl5_Qv!~$TLVG}N~p67W_8~C!4``T~CL<)N9aM`~B6CnKWTq4XZ_N-H>uS-|b z0&-ZNvm>R?qJNXMVPl_@*rAl3#&Ipd&YNV1xeO%9?nK<oJ_23$Mf(7tTApA35M-~p zY+W$QAQeybY%QvG{ffVbQ{y`GwJ-%W?#_DVi0MxpQ<p|MZ$k0in?REjWIfA}lN6|c z8A(X%ptmT_58E#%*Dd6rM+O+*WK#)O06+)Vl6HdZ&4m|Kup4l5VGNhjs!Git8izP4 zy^yve520(p4$MJLRPYb0$dj6tM{evSt2>>hQ9DgjebrSw>?!NZTzhUYPrUd^;)~8S zqRi~xu%~z6{7hZ&6G$a@pr(R^DUl;#><NW~@O9PN5}v&$f@y8HU)r`}D?dQ|28B}Z z?(cV|7TUfgqdP6VheW>L3}x4asdK3E$khNDhv`C~E?-Q3e)&*WFzC5EGaJW;?3Xk0 z>9!ucLv&Y_$3<oDKc-yFZoD1AuGX~rj4MkGeQOmz6fjGJA3c9X_>Gs?cw*z+ura@M z#J1=CrxJjt;-t9FXB34~K%+Uf<aupPFO8p3tjUL1&sgJBY}t9aw-SqCa-RYtsOc;P zA%2synj=cBziOR{e5sFBiLIf9b*D6&e-P$ntJ(al&%>vioIia2o8DX`M55&xQ?tbm zF6EDg<u(0Fd+HMG!i!|Qj-E&w9zB0A1KEss_l>jf0^(yXRLvs!YOG1JD0=qsP~JAy z2l6x*-1cyPm4R~#9H(4c?})gx1Avd*OG~SRf-xYHP&S-KS=qO(TvElkmpB&_46qIR zV|o4kH}5(7lk754Xtab6slxxkA3}_Za~5fa1jh8?3R|rxJM2I4MEc~|cCAvY&x&r) zd+t8z%g?nNR%cwF@o_O|lXyMgUAb0L8I**ZKfz1_C~Tu=)Yq@f67mN^y0s)d7&cBL z?*7OysJ=!QdG<w^XW7$~quLMp!Fp-x#lt1J7%mOcGLsWWx0MeNsucMZ_7n*HFJTgp zIx^)z-;0$TiO15cA6-4Q?W!w9CgfQ0%Bd%RGJmn_=C|$=zfLgbvmA!xj2!EQjx+r{ zU~rnDNM9ugqG~kSiroNxC<mtQ+O|UpvK;*CZE3Me#4Cc61+HyPJK8`T4yOr_CZCdu z3&MmgMzFRpn8s9MHoU)QINL|onTNv+Jv$^=$|PT9jO?n1{$My@)3`wnQ~?*jf1#+M zAuJi4ZvydNQaw4yaj<Rh)r}-rU$9wya;v}J;E)39bgzDrl@205x$n!TsB-VUvSfYr zc;<5>zQ>o^?fbN*pubBD0Y@Z@yILn=7(^3S$v3cZBLHGS747)?hjtw-%r@(jhwq=z zbYtp+jAFCuTZ8<K^Md5=kbf+c+b{=3&tZU@UGV8omctWK`^`Jiw6!N+?~G00pNHHY zF0)iG$JySw@h)Tgi3@^|%@)rm3^vWpOCHH#@DIUw>VmO+&YiVH$MQezE(8GDIK_{z zZ}Sh+*7+lHX5Dk3C_JLHXfVzR1i|?aD+Ne9QBqd^zcg<(M||-AMf0XnJg>Dzqm`AV z6IeQ|zYxL+lnX%x8_VUO+DNoeFeKWHu~c|UGhQ-0tg52`>S{NXEx88_9Fx(ur&iJ} zkhwK*#FO9Jvo>uppKq`LhGICvT_FEqhC5Mrb(JmKZgxnh1sP~);v&T*1DnJ)Quyq} z5%GVLiXzjY&6Yp@>cpuP+eMM2yv-iAeN%t<D;z<&qN1++ZB}u#G1}8ihM5R@(lLE` z8n~JL_x(p?e_{ssM*b!7Zv8^@U$j*0B%23;T`iNCX(y!nPHd4Ty|QW+S{#=dtH@_P z5yA+F%?Q~&v@!@wHQz=|6z@ko?-OF!fqvj$(S=z2Ln5GXYz&ttg_u9x4?8k&amD{B z)_=H3{rR%r_Fw*yhYvkZXj|?TxrGD_9O2PFr|Q#DclI}QMg24+lnW2V{YH6IE4Z!C z{jBKOEujM4>IxjkoM5ZvdrJ$jDsUiRP*eU5ke!^jn(C4em|V|FEEiRBmjr;MJNo*e zz>P-r1%fMx#ne8)YU%WO0jf>t*Feb1<IH7&jZ%IAL)BCIjk7OXE6M;RI+J;Q;cY<v z^A=m&dH{vN(q~cXm3*$ipxiR0_qEHRVDrS1=83Ny*=3UVHtYRF`V%87yjwB$|How> z3<?xC{>N>mTTS3sV-2)Th|6U=Qhy-tV0-#k#zocbTO?jkan8hWBq}zG_-P`KSxTk% z3ge*iHQHu&bG{(2z*a5k1#-!1qhIEt>GPnafQ(8JdU=g$0~-6tZLD@5@t>XL0l7a{ z?NgX8DT)sYfxAUT8$4w}Vjaal5uuQ%NGB2wa|61IRa;n+uegdA_9u7qBdo90^Bo#H z%f)klX4#8wlkx{)#sJwW%b<U08B(T!!loZ-rZob&07rx*#IbUS|Ad7ZmrUy@a&jw@ zG5#61o<TtDJ4;c1l;<(861rvFsTRGLJgebu)~rll@(0mxUFT8O+=~j?^wU?L_KJtE z&$$N?djQ}^?nTN?T{ggbCuIDr4s#JItOTj5a3fEs2hp}C06|O!ypn;CR-3_QJ~j~p z8*HBJ8THRe*3y)M2%0sVA5=6Fv}gpQXg7z3=Y}E}pC5Fnh(3Ed?lpE;)r!XIrwm^1 z#_ZU{AUo4-0r@4;a1(;V#!FfQIl9<P2EuH}2-~exjgr1KiQ3T%b9|!N7cUu}!r1}J zTM5Y(37Tae@SeGL!atvu8KQH%rih#<-mVnl$Qf1_6Gd#8*Wwjda-V&1I;npl7ym{^ zXkUi;n$QSiZor!1o`eX4e_8ogki%c`JOo5x9)ubFCvmDNLuON(r;ey|<ld2d4+6$G zKCsmWSTi!Z>&d!L7T!O>3v>=Yhk<63f#{rnnpW7z0}uNPqHxj2pnr@(e!?%u3pMT! z&`gs@mlsbwe7cy5;RV|!|K^t~DphuGC?J9Z3ROIa(TaLIKFl`zJIX5qJd%meq-jlk z-ba1Sr9oSE^-A;H>iC~y!*<z@+86xiI0e-Kbh7)Nt*qq}KzRNqqVQ*NM_Q-&Xl*1_ zmuls%+6@Pvn%v26dC6tM?mk!G>oc_)(Tyhqk5*xt4zxCRSg$z5tAQrj|I>gh+i!iL zX2=nQSJhOYrMP~V{9)P2j12Z-9O%isDlQS>up{d)%Bw*kEv}0zA2D1@XwXGd^ulE6 z%f2N^<0Q_Sl`o8m=PJj^3lGUMg{h+)lFj$mt{r&!I*WUHQVq(Cj_oBJWQlu6{{iOB z$$TO@D)o#$WkMPcD<z0(iOYccRcPMEqc(2a_NfLlm|Axvp;>eFriHLl+M(LfiK$LM zR7&FMT$R<K4zEu;9=8dtw({wPNX^<Q7+rBD`Z4r91kJ8_VKr-=`K7P7!Y_CKi%Vs) z>)jC>m$wcO($I8P0<xAvYu*wp$XjN+pLq-D_y^v`UP#Q1{hUxY)TjGkD(u1H_0Xy? z+}T=cHr%r6B$XU$++>%DP$7ipCU5Sqc&@v^pJE2K%WR%M&zApYp8Z6KT3B*PU2vCU zfgKjhs%Wiv7s;;s436l7g#jfA_cmBdF+mL}V5s2BlwNg-imeB-5>%gl*NObAQ%+W( ztzM>4j|5R1UGvizVs&d$LTx4b&3t))Mh(3^_lPDrYamzWd8}9319Nv6$d!p2U6Pk> zEz9ZCt&6~hs^o_ryB=X(nN=~P8*yJOlC-HhXAUgFoM@Z4OgiwMGDx}5*2y25`udvy zaRRcp*{8^K29P*%jWm2WeYan}M@Hy=6xwYcpSS>rJ;hLcN_12Z04{T`D{Dgr@@p&W zYN4Uye$!4}pM1+}h}LF+3~CcSZ7&AI;%}~bEq^h_XG!E&O=T#S_?d+$FTe!5f!rCE zvcJ21!~)!kq&>OK84@|9C~fQ}aA#^A2iOC}3%}L%aLaWRdVT)pJ%;MhtFfP3C|j8{ zXlX<_zW_WiO&jH=RCBh`jeN-!{fwVUnNA%hGO6PVCp_-9wf;UTI}(FBLLpM?54q$D zd1f#8M02I-Qy5NEp0AWnKyqhx+};tWZF<@zc6KqOcGe1P9;!Odb<|Ha*M(iEmHH%n zs-8t|46%p}Ujf7(q;mEn$pxh*w!bMFj_;5GuFv@@cyx7f#_1yX*{oj`mC%SmUJj7; zK*F(V<hbI9{CGSSILB5nm3=vDe@khbd&qJAh=CnyQnwb?#OSNwzFkYo#Ms(Ocxnu| z!6dDVs^+~L7n)#4UZ;qYcThlN1yvmMdJ&r7%n!dXhlzj77~!_#cG{KE;FmUSl7J#S zCDQ(5{w~%5%7LicvMj5;FJLct0`>muaX{UqEo5B!M-jPflrrASbg2yM6MM#-ThxYe zI%xfr>UceqXz_W8MKcFIs|uBX+qLo~t`7HmoNKH4h4Ux=bl&2{XR~U^`%aa+g3CJs z-LCgQyn138w3W3h0Ci=6k{c?FQl#r*2hEn+lXd%Dgk_HYZRf@<QRpTU{!}m_AIW(` zAVT7ofQ7XjiuUtY2D<~J_<=reLhZp!51Fy~_USm6M}NuNVN(8;mold$(o>NiJW1T- zLH=NdhhEjIhDxS++P^Ob>gfA@u1S5O$EF!azqj60GV3_=9PL;3^5iW1>gej+EdQ=X zpW$Qi%qG!KF*T)dUUjP7Kg21lu5_BY!pZCI`Pzk9@;7d3B7G`lO!q2$)i%dWle}xr zOFxE!2b$6~2ZBJ2<aQfOeEpQPM}K(sqZ2+w#>6`(l>g|WIuhE<;CwJX+mrbkU0e9B zTtG)zZ0%q4Te*h!wyNpzYFxDIH{~XRJC&GJ;1$6$wdrK@zbWhJPNt5@S70H=LRd6x zT3Hl+nZOMW0kjQIOVI<AfAwBm4>S!t3@x$Z^NL9UrwBH(DEvnG@mBPa?;86lA^_;4 z-Zp0YaXgIhHG;=NfhxGBKI|`k$D4iB1B{bbp@Al+_ZNbv_c87iq~yS_D5;<U)W(d) zmisQ8`UndfH&aoM*&V5BbSl^RXo_Mr9y!6E4Fkh9h}|_N19w!hG@8R9lqS8sdqGz~ z!1IJ|ZWfvYF=Aig-ZB(m&c58sw-TocU=>MXqyd8OCauv?g8hyId|?w97eeMWRrkq4 zhq|=)+G$<m7a)g|l|ts9BW58X;(en=Bg|iaUM@hT4}xeXVWgFQKawH=(dqcSkY@^l zy$eypelGJzJ?zIZk?8JK<;H>1I`fkO0+j?&1n;%UZ6{rO+F=Bx_`QeQgPsUgZgK7~ zHs>~WPBcZ18(fn;r^R@gMu`OV{IGi+FO#85zmQVuoyA2q5O3is`IsHUex+wn;V75m zH7}h}N;`b-(etzX{NmvFGN%e_U|UDdRa6@!2V~#5E9V(Zsc9U{(}n*-pF-ypmOENU z!>w&_7ww~z9xltT@m<yWwXEmG=fm8&%9tmx(t5D5wZ&rB;Y$BRS3$nAZlsoB45g2t zwm^ECmwOm(?TNDg1Te3ER&ExYK)`fQKl;M_1Jk0E(BO|v?hn<rZ*@rg6SvC06Jo@^ zLCeRDVw(H<efqWHS6hW&dL%L?-I9&M(pX6dJhLd3fn07#G{&2zBP%Q~iZOonpzhOs zAlr12M4*lhF4_3n_NM#U0>#Fd?#9b|UK$G-xm*g_2fw7>VZT$Q$J#wP^KK-itXIP* zsDCcT@tQ3YKer;&)wW7-1?8Sg_PCFpTNQ3)iShdd6Fd`jb^vXhqrKx9t8qNA>Q70| z^bWqxHX9&HS$kn|Yo<Z4sg~+E1`gBSR*4>CVNsM+zn$o9!{3tPZ_QgoksmOAZ^y)8 zlORQ%IM+HjE%~N$sESYQfvXx)k_Y9-hEK^KE<6YACEL6!9^Ay*L}T$c%*?4d2vwv= zk3+QGJwNFSH|6hOXkii=N*Ru{^6RH%6`m@P#yPCK-XMU^=n%<kO%e)oK`Vo<rCg-z zFq5Ny8{cc0&e25)z4JcIP-e{B$zmKhjJ=IeXEe|<ICd?a61RbCqFynv-%^p|$<m0t zY-!gm*?++Ag0^QFwXBuTBkfMER+Y2TvsmC%Iwz}$NK;#qWac;?gl=1eqHr7*u$*$O zX`+d;>>o*tudc?(Bs)8l)3`3W?5p~J0Y`A}z7<Z(>7ZDd1O*hB)M;l4WFyy)PuW~W z6tRi=P<rt8YgCA>Mn}=?n$3?{Xj+Zr=Y=GE?>LabOWVqpD2^|roSRm<XIfGl5shAl zqSpN>@Q9(XR=Jteb#g$Bq$-gx|5$o*hvQ@|x%DahQzwCy=7EyxbJAbD;BweDlc~_y zWv~Xd=0Sr>bAMTpATn){s*{ba@&zM<#G{Chhv|p{vw>w(;&AA(VMjUZ%&5MkHHGRe zJl@MN_RV{)Q9>A)^|OxBT*IxAT&c#+dFf8LX0%JhuTO!axvu=h;)OCHiN>vYq|f9B zOl$tQi0Dwx6c@>YGPlv@$ggNkEOb;tn;YKJ3}vTb1;2n4&+r87gO=@Hh5mlak5^6> z6Y7{Ey4*<gBmDPU3LT|Sz437k^|mz{bTB~hkpKP<-p-72K!o{Gj(G6s-VotKYH;x< zrn5WXRRXzB?+7@tH2*c_sG~3waU@VYy2emp(m0VTDOpO~<Te^Y0abT%j>cQZ5{VIR zoWzOQI$Q{FmM96up|AB3EMLy_dcYlBC>eaO7;j9TYA8fB0z*gj`ZdGP!`s%i(sb-+ z7b-o2tVd~)$bWJkF5_tpQN{xYs=jZ^Kj8H5j4>GaZEP4R6Tfv&2XO_JUju^tocRom z+B)3WhJz!!v(MFPG?)o7D@_h>?m9%h_yNu>0z$W>S_Tu5yrgtkh0DWsyMMF;7Es6~ z$OA6JQ!TlXW;@L`M+WK<KZmIwA+?hsAbchL3;Je~zHXg{#pBtP?dQkDz>O%%9d~;d z%MD2ja~iGKS8BrX<wIaKrWsSec|Wl^>Ui(?Os_RO$wEEA<!Y-wEa7M&k@DtdGDMe7 zch%891<t;YQk{_Yu2O)mRm5~GD@2{T<<xxLRD9V9wKY>wI14J+TeaKldUQS&noicy zfp=!^q`rQ;$!I+BGCjX3q3p!u=K%lm?Qcopbz-xQa;+gai%G(P7>SBjQ_8_)rIB)| z$=i4{ff@?`6Yi2)ZERQXedFzRXq-VV_VR}~TC76y-Nfy~viIs#mA(>J3dLRB<AM9X zX(9BA)U522>uy<mXs^sN1k<q!Hn&Lkg;Ggy5Z$?h|GH93ZWir%1yETm-4c*)ETA)| z^`wxJWKMqQv|spg_wg#uJPSpV0Vh3^-fN+1QGH_}Y;Of4&MHoA(VifcXvl6{HW&$B zeKi*h<?-A4q!m@Ipm0zxLnx-pR#xH4#xNP5%CK0!vFmiT{qET{-mJQ|e@^BsGK7b_ zuCcnhYX_aKo*-mj0(LaFe3yOVN(J*Z^ql>R-&ual*6eHLAgD~CU|baa=Gt~8A(}HZ z{auT^rM=SY*Pi9b+%*Q@t6&&;wt<NUcEh)C_qxV+zTX5*UunT(^~{O_r3n=Dy4>p9 zMjOtJx2yZ^`uwUyX`?IJwO{Avxmm!I6cos#m)ZywAjH;ml)7~_LbPjZl^&_lWniw& zSHgV}JG+!@WmVS#$9eZh30l#$?gws3+nG7Okp_<{g%>A7CTt9K>k!eo=HVF1v5*<| zj|4-dtF9)*zBWOo*JiVS^J?r&$8C7FTKDxHyjPx65l7W6raGw%IedOuaX-Ow^@ium zx8$ZNTz`~Pf!m0%yM|jY3o!AVs+)KTpXX*w^<&zxyP_yk!YTO)Pr~V2Gb<zisJv8% znOGX&8;j83yYmQ!VG`j#c<FBvW<5Iepmpu7N)@}u(QLe&b$3RA2mKf>`{%Xb`5I2a zkE6C0Tx}zZtIMviT~%*)XH6p-b5Na{za2gv<y=Ku9%+8NHh(=c2YGFSt+(@PnjOE1 zG>vBsj1R)outG1eTUptuTGkxyk|GYzREJLL4#O0rSDn8Q&DwP8Me$-Opyv7sJNWNL zi+;Q|uvOnw`c+{d_=`eUAxGs$R)Nfc%c@n`2u)S_WSzclV&<*kJ2?B~eL<Yp0*8ra z-9dIZ>1W>P$%4ZJ@`m99r&3`3M(Ts-#{(A!APUC^<lLO@f<-QKZA&LM31Or2lsDCC z5{dC7f8@S^XlAgts|5OK-g(;mP!$^=)L*<3m$qlv<*Y=BY_BCM9xwxuH5*F6bv=Z| zViI^C&|y`zt-TZouj}xZYSgzv1skg-2(wbpuoqM3j0P*@p6#@YrsH`c5%7?w|Dwrl z=_%!}cEW$C1#KB0xQfR4OW|eYJCU?tjgd5F{GI%n=#-IWlm76kzcIijyVvWy%A(ep z4lzg@`k<l2NqQX9G5wbrY-{*84CF?|QU$egmgEF|#O$F1H+HfQ<3cyzy3-QAoHq(D zu0&^AZzt>LI2*=UnfgFTcgC4dnx~Di1&}v!i^KcTez|JNTdGfoSr(+SKhRtnxP@UF zXrvM4(GpS~n0(}FbGL*v+TOr?A5Uf7LBt;x43N;>nuXONmov9N5bs=+b9^Y$*#`Rd zoXp%oXKm$$JAP5hAFYG`-A>zVBb$Fk-EtaN3;#nSUDpr#^Vx&UoBJ-z6k*2GgNl!~ zFp+4lZ+{O4hIMyS>9f8(?MUNsSy2hYGJ<}gcKq>|+Kn0NnZwbuNAK`&mZhh@fVL{n zbIbm)veeHRJo7%cN}_HqSO$9>>n<1wVr}h*+K?gaZ(eV@j}3lnSoLJnPQJf~SUgf+ zeA+d7&rV){?f+Ttk^Bf@0+UtN#Q$;aw1BB#<8xe?oW~8Yj~7xx0BP=w8yMWU1bqM% z0l`qpNAI+K{`3kHs3%^7@Exf1!*5s0ZH<+1H^O;s^yO{@XxtwtHI!qJjhDbrs!Ti* z30edS6ogOS<kQIZsp0Jaf3aWT>8)>6PotWDpL>X5M?y%!9crvW!T=h!^21z+dac;e zfYU<<DH=Fo5Gcrj4}_-<AavIt0-p{~r_uTX@bNX(2~?TE1AJrOPCV*dIlc1kpu*En z?Lzw3H@kuB?IX;^pnnI|kp!q3c)`!tRK!qeph0&{6ls}Wg&Rxz)8*^_EGWPYl8$R5 z-GL*_aF_xzut@+9eu+6x<!)CZw^VUVoS7X1{`&ybRR}SG{msrcaPjl<*Y|xzA7pb^ zL(@@muo7}96~8Jom0tQV1kJW7!(lv!5y1O~AUGc3Kr^I#aF_4(<9mPC2P7)!b;|gf z=;-6s>P99xA?AE3`Q@<T-0Lfo62C&ywc~dZm$Fq4zd1S~82p0<5AZc|f3?$<-Znr; zKpvBc%PS}Pc=K#X*&bZErgQ&?=SIwYQ_*|&%qY^NZuojUs{3NdEKslf?q|R!%%|ZZ zZYA_QzRtb-`KC+sk6jFg+dQGC$e2!N7j_jes_RUAJfVU&%@C8^-?8TK?AFJaYqb7v zP;yu8P=NTpe)jTu0ja4M6w~KEPjR_f>YC&x`or$l?QrJZhy*o+jrsd6xhwF1tmH>( zru${H8~tO{RLiD4+`2H#$0nO|mfsINPRC1(b5y|ODQNX3Bf_;y1w}kMt=6>88i9uS zQXqokf72;ONgn?Sn1CM)|EBl<nC|~`6+|DGb<di7_d#j30a_RSstLYY_}K<L$tyNG z$r!AEr6K0{|5Hdjz{Bqan$QQX8;eYkKY+Tz4K&N+WcY6(J6FPw6$8=AsiqLGm-fKI d>z0W=e#G<Qap*gQr~_3IWF?g(D#Z;0{uhq41sebW literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/region-selected.png b/emacs/nxhtml/nxhtml/doc/img/region-selected.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2358b1a665eed0af607e5bc89212106084cdc7 GIT binary patch literal 3662 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/rembrandt-self-portrait.jpg b/emacs/nxhtml/nxhtml/doc/img/rembrandt-self-portrait.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26895984e084bcea0692164550ba64623ddffb6f GIT binary patch literal 52583 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/style-in-nxhtml.png b/emacs/nxhtml/nxhtml/doc/img/style-in-nxhtml.png new file mode 100644 index 0000000000000000000000000000000000000000..151681d14ef872ce1bd102459a5b176d189feeda GIT binary patch literal 19275 zcmZ6zWmsHI)GRtk&>+Fx-3jgx+}$k%cXx;2?(XjHPO!n<CAho$oxJC}=bU?g3_NUR zPxtQbwW?Otf-nU+aRfLVH~;{EASofD1OR~bf?gOf;Gio$MAI0cZ?JX}nvMVfJnFv} z7$7|p3v?0MNm5o6dI^FMoCPYrtwt08AOc8=2&uTOo_ATB;YzlDc$>%NebJ2V1%o~C zTjN9y(+vFqC3cX5WD_T7<j{-QfSf_McX=&HXG&c6D>W+Txi+Q?A}q6a;HKBj3!HKp zf@Q$puu?E!mGJE+f=npJ<j*fw^T7xb$bmSExlpioUPqWsg^LyYEl(fBC~d0c<<-^Q zFXiPI+Qlu*98Q^^YrNxM0TO`RPUv0@fFIbnAR-fl2^1F*CHm~ho**)$y;EG{Czb>X z);S|o{7YS>p~*SVR|i3g=LcXeKV<?%?qQE60KgNW9GRpDIrj?+O9PDQr<5ZZOaLeU zp3_H7{ZzszKMFZO;uCj=0Xf1@-RpH;pX}dVehXm1U=U1^3pz|$7-BQBVw72{o?&kk zLdfD1zYf9^rJj{(T7gPn6X=?MB2_ZA#Z+f?0lm?XLT<0`xg@!Vmy>@^0N>48(7j^} z5@+xB)0~6$owOB%mtc2{((reXnNuu&8C+#UjH5VEb?yyB78fej85$EwN~zuS#Q)A> ztsh^bTw<k6`@Imp(Wuq=#RMw8u(U~Kk;TE;iWoF~niSSD39)<ay-!zKDh-AzsZ2=0 zZ$rM)ZiLW3``es3&-`G9w60pxgYz{8?@vX!fKTz#Cz8kmaZ2MBHjK)OO%Ck~g_SmN zf=U7&jHzHmX#r9GZB~3;+1yDgBek=TLYY><4Br!$s$47$w_a{M?R{h|geWS$P~)BS z?IC#nN%Nu||BNYIcZC#`8nYc=Mz;&6m$ogVDR|+C_xDMFC6{Y|&!d<wGevUjnZkMd zvQwRyOl0hbSBUqML904Wg@a;0Hkk~Xls-~BE|AWbeiTyR!FZs}FBOBF8bPuotSyoO zQ+3fnNlZ$*1g{So-p~2tFfrZFU-NgPLBKoL8Di$Ip9Xf}aUoaF(8>TmRtFT9Eey6` z>=CX+d%i!ZAI&1VAw)-Xr9XUt1a5GPaH+%>B=kb@ewk!oBg6&lDTxpcvGo$tu`a|H z;c773m%P!R85RZ<JG+2Y&7rU6>I2o~d76>}nJEtCwNmD1Qs#<i<BPYS?~C^2!I{7D z0ykL4sSDXhlgqI7KEDCHe&WT(GnMonT{KQ{*-1g3{lo**^5lGGOx?vWIe!ZvDkr*- zs%81wJHjE7PV8^s5KE*9NR0!cCs)w>89_n7ltubfb}h;5A<dH9hIL{L^p5v_-H(2$ zglzc21;8E}m*8T<ZGdDUCI8~taYlr_2Uzw)bD|abI{x*i5F#?UhCe>o0jGnSlMX~d z)O7;#Qe1qjbpO{>@8zsqct)YbA5$4<2`fR3@W4t=amj$hgzsF=Scnpug94+t`|L*J zqET%nGOXtD-)E~K8z9|b7$rxfMvTd<%_Y+I6a8ei`6(Mb<V}Ub(%^>E!VEdSz%a3J z;!;^{X%0{FI<PZ+B`c}F-fFZEK^8$M#GCE#!;Xhk1Sg|T2uuu2RD{|{(-BGwzu>Nk zm9)d+7G?SS7HX6kM#g;eo*qA-bHjYtI=>;bN48H+4dMQ}(|+e6nVB)J;thU_<fqD3 zl&;teF1Z(P_K42jjbz{nu7uJ?Mn*(Q!x-vmrb=<sz$Y+y_I$(?mvjDniFIKYUMdKk z@U)V>)P=%v#LLaRcU0sFri77ifot4Grzj5_>u^%>wCK1iV<F`tNfES8b{6iyFwTYO z_dfF@&f|dWb%z^ppd{dc-VoRFDWqs0agjWw0~*rB|2&q#9wpw&a&81x3Wp0D>waN= zWPghn6;rA?DvG024N%B=yS64wn-AVU7dyyI-lL;G!SX4U(43h_%-hwN(%ei6+_jV( z1-hz%3qqB9<TGJ$n2qnqJlI($#0K&@U=AmZ5IwA*yFZ}Do(a$%x}6B{C^`to^Ttjw zqX%Ezm<f<>tDwZzW(?He@gwZayF1B(qb_R>SHHO_DaD~FerixcNL0DyCS2<RHiy%; zW}nX9KAf%~sD3o$zt8$EODKh+3WTQs#Aa&X5EYd|PKr=d_S5{@9zLa%)D8`r(x&lH z1el7_jv7YMjA-tcEFUhjA!<L>$?j8ZUi0Pn_SaaYFQXYfSd|Hh2Ed^JftjI=kYr$g z&&cG;US_wUcZUwp07m$uc0ERrIff(x+Sg(`3{(wOdG_W`xQ4rnf4}VWd8EG4i)mo+ z<bVM@URXZiy?4?sEAjl~d1=9~#8}_Q$q0x#zkaGh`PI_-z*6LQtAD3n?fQ<G3qu;U z*ku5>`=a$FDoQ&LGu(of<u+@<HYKKN@4aH+v_%l^O*6gNF_E*}h|Gv=!|*^1j;!yg z%jJbNIjoHnl|Cv_h(Wpa5LP1UZq-yBu>9$%t2p%`w-Kr{dw`54hc0&_;8)i--fKmz zF^4zcS~oAC{A2}oz5(zf`#6^7voG>_R`Q|@z5F$+rs1PG0rlG3G~9V1I(9t$#=h$t zOOU|yF7fqk^htat^Y;inl&#y6I`M%%3cyO-Q(pcUHRgkD&~mLNI5iQ5=|f<!Gkb8e zg!-ZUet4r0h<f6k{;NhxAX`cumk)Sm`At=v;Y`+-V)Ve*#H773N)`UQ;Y*yEgS;l5 zvcGCkGXS)-@5o(eiG$4Op%D-ohc-+;9cVAN|9*DEiKq#_55y1P{Pm#h9LiO|C0ezW z9tZY)=(|=TY`ICmjZ7j>GAIj5##{VOLQ>XuZ?aPIbty|rToC08LN{Pr8;4>WDRXSp zqW{E3RxeOv8Nefhjnw3Tj!U>KrP<UcZtJ#8^6-lIq(yMn$b=z1%<v(5@p%yWfcC>` zMH!^zKNi5^VzzabzPR}Dt29ErWPR3j<LNgTQDwL8mH{~sPVi|<6bixs2*+gQ3BwcE zWJ2=T6FTacTip`|h;8UEFjA_@bq#Fo-^0ADzy^&_P?7`jB%bHopxwUA#|Lc%w+z+$ z<V%43F~|Onb0meU7Yn;15gVBJ1wvvKO<&tQGoNHQo#lJXi;My-s-rzcdcp)4m*jUA zze2C2udh}j(ng=|r1yt%Sz@NK$_2!SbfXxOuxh4a(f)0X$>Atd?&m39oR|Y`xop@N zTSDDIs^dxSmPI7(b?4L}7n5bIWKbo4-}T0~>Ti7EgZ?H?a#oNt5Waz%F?xx<6bM^W z)cx|{dsP__-LqvrA;Osp9$jE2s*9eDN`i|&<nV#*_`uoyU~Y6k6-;k{Kn`+^)sW+o znIsn3Zi<LwT>kq>lp5dZyYDtDyJN<qu=~u|;J;d~Uw33&TqmQD8Rk+G*BowZVzl4n z+min>ZS#tB3OM`hBK{cs;=EE`i(zX3fW?NFqu!jUOi(TUD+gAAjY3o%oYutTc+6j2 zSe1RK@v5}0q?AZye$1b?u=P33fBs`986EH#llQmU*{Q|i*Sk|-^G3d>ErX9fE1zQD z=B4<zp1#J;fq@-Btm97k)Zb7or@;l9&{F`>&D1YDM9vMDX9i~eFTJDLO}{!y58kAQ z?z~4_cUMPcUt`n@vMOwL<B){#z`!OXequ>jYdrgYg`B>RYUVDy*B9dmV3-h*R%4&h z<Vxtz1Ti}(6WE`7=wyJhZ;XKJ&+L|uC2gk2`@`SMmp_RlxtKKH3x$9r@tPayv`SMX zu)bV_m9otGZ=n_D6;C=Z`_kr^N{Er{zs1Wu7r5B=tKZYU)k=Jkt9j+Wd%YA(8RB~@ z3lH0+wkujyzM(WE+r;q0ex(gK?49bvrMJJNr_DbaS$i#_UEqlsJc`#WA`0fSOlsC# zWH_a$9ldJljmkU}!}>ro`2aio-l-_^0e9*8Q40VQyr6HGkivg}!!!%vlxb9TpipMR z#@c5la?hpr<Oyb;B-6$k!Q6zv&N8Go%9q18a=?yoSfVui6e`IscM0>g*ZlN^@N=f7 zezDRrhC`v-x}#nJ2&qan6wWIVg6UI6<im`6n-jY9dPHGgnD{t^QL9GX8TvNll{HUz zLHFpwA&iIo&Gex;u=OB8g1i*aFod=lI+6zZ&NYw#sND`DZ|IsswtWM54zWAFA(S+( z3{#)2hv2_zh&ZnT+`k<cYZas%c_|kVeNg|%>HF->fqqKKw;LSg_IJJVAs6wv66tr~ zFPjv<ZFR`u3wiSe4(lJ`V_s9Hzw`c3_7OS8GpqJeLJ2n1fc={2DaxYyUGv$KtwbR` z?BI4ULvR8cF#CyV@)0AiD>RD6>XbXzo*Jt+31OiUcXK?S`5juzBw)P#wKlghePzvm zYQ1(e{;)S^efBk#H<pphyo=QS4aJl@lPOR?`1l$eHIOwM=iNGcrA|uyCCR{+6_NH3 zzb=__2>maIm?T8+sIyIgJ9U2*Vp@S;$<g~AQtF3wxI2;?Z~LR)N-Mu7UA{yLZJfxV ze*U<0_mNti0D|*}XsO=xk$_S`#cd=EU^a)7g5vu{qLInJk?Y9_F%RU0<5e<!c__1* z=G>+5Hn<cdHK~pXQk=e*tlN^Ae@k+R#4s!yu$a#YQ{h52B9}lJM;S-<O&vf=c(E$X z9M~fxB7NY2^G|Q&fyR2D@{|C`)b@ymK(IrpEzo47-Q~!{bBm`<`Z@a@gMS1Dz4JRz z4^Zq_0{(I$WW;i`?#=F}5Wyt9(b2u<C;3Mi?B!_Cn&p>!r}g)LE5suL>mcE`+AGL3 zFGNp!(+7-vV*Z|@dn!OLv2qASh7Whb;-U`@#W00D)*W!2Vce7bEE~dp<{%op{-~OX zWu#o$c_x|I{K9@Or`!b;qauh^g8>tqev0D+7K+rC%u0Sc#-ocD{hl)JX>p<o6Y>={ zcJ^VeYHZ-^UMvc6wn>~ENk;G>iGWlYuAiw2f@);R8;WBu<%3cZL@aGtP~odNx3F>L zVPR1N=o#=)84C}$IIG|3DahvH2Y>D;Ddli7@{;C^Ez6U>9lfQ<qpPkeQ#e{s^horH zPc40V$iAiYGC{dkFvW)Z{E#E)TsvRac^aeq_55O$rk+UVr<mNom-8}yOrbwf7{4b7 zo6meuAc%-7;E8izh1w%=+tWmnQ0kyJUIWJUFszOnWrE^HG1;?-R_|wnI8S#B+U5C@ zc&tEAto!T~87fd|H!Ymn#ObCK_c?}6Nu|i{{-Er0q3mhW$m^BO3*FvT?ZZaj2St`( zHdpnCxoL)D!TizYal;R($eT@ui0Wv}HS5DG=XzS|KxvK(M+nq*5X-k>SRc@>46;7? zyETqx0v3Lv_|Y(Q5;I|G8~Uf`ZT46?(+yfHp?TD|x$LtU+nd?2&qhmcAcb&$TtlEi zlIM8OR~xs6TG?7b9uLup4(3-+?fW2{QLGdR<-31+AQ4PHmxLf}0MUP6qW%54^*bL9 zMGXYX8+^G4?H7x!N_ebGcqkXcw+OkRT}0&0@&x{h<+|{5f_eA2oja9OU8V0lZoU+` zBTn|zctzqe%DJ(Z8vC55DRkhTTl&&$u8am?WgTt7451t&g#ja89_cH?nLbUu8<s3` z7PCt)F>BBfot$>=(0W3WJ0E1sR<^Y>>d|RXv#2h&LBD)=x5)22?oMlWX`g$LCH_hB zDO++r74f6!1<PpdM9&o<ij2TBoegXuL^0oY&UrQZ`#c44MleP<>S%D3P!BngOu~!H z+p}I_(*3vdw5sYG{Yrs{3p+cuuTq|H59W?tT~1<`E&18>loT6hlhl;$*{;tn>S7zs z$SZASbuRQM;bo8;(%R3y8Q8~g#$tlS36-(v)xp;(+li2DSio;n7LE3)g%u|d#A4s{ zWGGg{U1ADf^5OwuVa@)ix6z2z!}@M#|AjAtxpk#{S_r$n_b57g(}g57KTI<H&K|a3 zs$fMzu?X;<+>$}>j5KLn;2!r?HX?w3Xb!XNAi6TuY#vB?cUKg2>gVe-{8&AfTg!p2 zLEmJABcISNoki;z9>u~FS_n<D6>@yN*tW5Txdanjc6zq$*jWo$M{GSYh~kMcNf_%$ za8bOL`PeXA7fwHkTHnIVbfr94!hjg-5{}aJN$v>0DhK#|8uYt2x!RuBR5S?1SOb~N zw!%5L!L`nd`#=+aA@(X`M1BkJIziZ~dSzWaETai^l<XQgt$B+{wDi%{JMKchJl^ML z{w`F3dsZOwB23c7iguE-bI;{FSpJ$nzkOa1WqC7g<@}?y(B~AGf91n$w{)+=PGlMs z?Aq*0`joV7*qJRkvHI3|)p?bj#b~QnB=y*KKx6p#OzL5^6d%B<isvb|h$#dZ)7#4& zQv~~~KgGkNu{&8nP}~xOOm!khaIxqGjBTq7DNH|$y86oZBiDDZMAzf~UAa47eYFp_ zV6r3P?R9Xv1DKaB*4`Cwz0XqGILz*2a<2UCcciAfPEjAR*Kx07_g_5qQ~s!X_YdCQ zZp<CN1YyiaM_V?7u94@w<^1p0swce<cMe;(ynre-x-p<b<g;Z-iJRZ+t9SKGmi1X> z^>n9JQhJ5VL>IeNh)IN@r$=2{|En1m9Xt=bkRMSeNGwuY<=JPd<LlC~cis8OmhhD* zWV~jFz~0cdg<M8dAN<gC66J7Oxm{XEom_Jsr%W`}E}CTXJTpKSIx~mS@98Aq&8eMS zK>zR#6RfSuIJ}kdkth_f>-5LAwUVnvpXg{A#T)PT?dR?}bQiMIyBUGd+xC|7^AJft z;>Ely5ukfw)3lYfjg-6FeU7KKYe`E(zNnBy6kZ=B^@74LOGt!l)c8hm@W}6(kIHZ0 zTy(c?Cg{W~EGpb{^xN}Cn$4WXuJCG*dQO9l{%_DMFov-w$Yps^0aJS+6164Qv=2Ch z@e4XFjr|-Oot~94MP1eNh_V=mpac3l+iD~p=tAV>O2I%FSMI6q0kg??LV-HU5bof~ zzJ{CBR1g6n#JZ3sfbF)~NVA}9>K((EE}Hq2_eP*2X?2s{F;}d6bfSZ$o5ktt@neh( zOFLC($NFLt(7S=N6Yg2^sdm^jce`F7!8ezC78TTjHUIsQkvv-;a#P%y9FgynsrSUO zn+>vd@b&xMTOjmh&`oz}hu)el;4gt__R`AsXgDH24zF)J>OPNlgFE4Q+xLZVERT;q zh~8HGboyvMh!0)cD^z0&$co#^HLJm{xz%#hn=1aZT}py2o|<!~yg#)XtVhJMcSB8O zw_{zlzG}tFHEktN%h}>|qT+8p2_dbW!_6mT*52PJaZt}})8s27@nno14A%!ABbF{m zo>)MFj|W{A8h!5rCiF+vfD2j&5C?JIrM<yO`bGFx&ETbQc9Me{MY#tBQdQNXwP}ox zF%5pSux&^Il0K_cMN8XP+|1Q9JP;raC_3f(0;nQ+g^)#96j&(&h+t3@0*FEbi_E?O zSLGrcAcc?@;v&DOtg?MDe-D;a%J>$tWj*2KPkE9XADu<>`#p9*MOahLi{;zf#V`(H zA`#5a?_P~_=VF}~<L+u=(B}>Sh1ORrN6fWENKP)SZTn|9NSYvo(6|(iA>X1~nGTQe z3;=cwKa8HRE_&4xebYozUf+(N)=G`8?Xuw)A#8pSTNv7E3$(wJgvN~d!#M^PH<zUY zfADL+8>}yH8}ZYUnG|8DTpp{O{KXx#XaXe9u~#fW`PE^lh&@rS#=odciF=`@@XEb{ zovX7>FCJ$V=-&}X2SV`uuwwL>lDSHuxLpCuQm8Me0RyCvAu5q&4mD4B4vj*XDLWaR zB_W@I{e*2?DOnIeUvifm51B)k)@e#(sQ9JANA8z3cr*w6>K6i!3jk<u1$V#;vOd^R zReex@a6h@w2S31KB=kpTbRD5Af+TXAhXe362A&$~kHLU=>sLruN5O6fr|3j6_(@av zsqYmp`5!%?Iv#Bb;8tHae<;<{A$@q3_?ETqT*BXVF4cqU03O_RVW`NJGy1@C?_h2y z4a^Dhlje6{`kj;f8{eJB5bQKAqPlbAXU|_)6I5dT67vC;hPJ<#xwna&L?EEX4JWYs z4avH9isyZvwjv|K9Ui<X?frxQE8vau^j#O+FWQML1M%5v(ypCTM}y)?D$=?rkT3i+ z)7`*PZB9h`?{^YSf90|7&sGbpjo!VEwt{Zl#%=CB%MtGD-hne&V46;qIgGW})MFE1 zJWyBj<dtnYkL+jRA99)(8!e<bo?ynLL?7HE0$*Gm{qXfh)YJ9MOtD1uD=~U!tEo~B zo0XraE!r-qt7DKoVVBN*$Uiv@J}B*$vdmmPs!3lGat{)Wsz=JzsR_H@&ze(8Dc9Gn z)h0i!(JHmnPQDK7w$PZ1&_nN@550Z?T!o;1oQqzjP0mOsJYNB_)&{^zO$%^5$RJf* z^wzD&2u;R<H}gB9*rKRP49GI7<J9HbKl7pp<s1QO*3#a`5=jFU<E)i))*glnXIMR_ z-QLzT_s`xuepO|Oj)D=U=BLUF&ECE4_6o}Z_+B{h<_kmM0G%d0s#7%*b8fyCOH~uv zB(d*RtCDTUN`AVF>!+a~jbwfXHIEJF&iFasU#ZDNDP48BG#26cF9Ntpdj1+^Uv<`_ zA}(2*-k-BQR2UM)<0BtH$y%eXTN&+RY(Pt$)p)R<2*>>P8=a)xJG~=8!DayI4t<r# z^TBHi`1xl#7k#WYK!K6p1Uo*hYAdcv&(LX$XM>_wV~Ve;F||++#m$&D72EkEEAAKN z!?pNY!YLUYN<uaw%n*QhDsX2Qv$prj&9CJ|;M$5GC9S&H<?5??!-Mytw)`EnArZJj zthw0;=11SOL~cS*-x)iLoBO7leRM9TKf~njDZim^sRcF3w&czyWIu1<q&Lvt7qw}* zI3Kur{%o2_w=vpl>#U;w$g>eDJLT_SA${XcazH%VqoAN;wD2w5We`uvbf9WpC{LEI zxDUIL&!-0H5~xLDA24>q-ZE~tZ%l2t?CvXFTT2>0n>{o*8D~0c?6zOR)lo`2*!RmD z80Rb7XOF()CpD`Zdd{pZt~}?b3|$WRBrv>Lscbu2;g#wMj}>>N&aj+OH4=M?9kP-q z+{9r4G0clTvyIv#CDhh(=@@{NJ?4d1=)RojW`?rdLBOSS@}G?DPbCas04UwZa0=m- z2!@X@I*)gYQ`VOH+k`aVvgk3@jn;shnK67$#}_16dlwtFv(G*zyS`c|iFtM3!+?6O z!`XDlH?FNVo~az$EsC%b6fHl+X%L7;#q-v=j8f&vU(I`FbDqs5@#9Z1v&e*iB9r2l z;Zkb|VNk13C5qg{a>(KcARI7g(c)t_r_B0b3^B;xeWZIUpXf;9|NY9>Qk>5Nkv#=} zLd1(dun_c8j1xoj<4khhW5ZSCM1HCt)md??;VN=L?=V5)ji#p?V<9_;<GIkocXoHV zFQ#F0c$A8HntW@`3Ar#?7x!|n1-{PZd6NQ0Ubi0+6vd?+H254&s40*_c-O>lo7)61 z&(I+X)$b?4?-prq>+3|%#QzI4V!~;dleOq_Ssz7^2Zjd*I8Z?)Qvgvq@zX}kPV`S} z)6>r-CPFw<apZxp0>%5vM!ipHye$ovwWBWh%6!-87YHF_gx*y8_|)>xEnttlcP66B zazMjrF8u!GV#R7d9vy{-3_|&vOX-r)Ns*fkWSuXLMbpwVT#sH^BG5h?0=<_|3Aj#b zcVA=_5{Dhk6fzV1aCRS`Fh#g5TM23Z3;M=$e7luf;e&w=?+UBB26^Xao6eKjNByrC zx|A8uwpwF7wm=NjgO-K)ilC?$nM9KL^V^i98WpF+b}ut2e<C@UVO7C4@sX>)KE0#( z<1izgG+)zFx&<j>WC&<;XfT|Q&`lT&?r1Cb;((;2Kf_e{;p|R^c-gzD%&2@ZyQr+x zNw~+NzsE!oj?&BrqU%X+eZu1)Df~blxZcG=+76=MC2p9598(|7p?&Tb_tC?5b^Un& z{adXMjF`xXhCLeq{o9u@w4V2CO&@zP*PVs2cNeCk^~t-p7;P2^xu-EunTQKd@Cgi$ zp({&qFvm$t5h@rlou<v*NSE-92%7Tw>0Z86I#DrjHc~ofZKd8qslBs8OCi4w_wj`} zLBbwv=Lna=Puli%)6gA{>qGhUDulc|mIT#A`UDZH$~^1;_51>0*&?Y8cPP8@4&Q7G zpn{eG#GHf=xlpM&-O+NopX7i%Q}g`<iQzlbs36YFl&{S(^+Dv9`NVG}wWS5l7tkXd z6kof3^g>2loYK160Ulxc_xn}+^i}02p20^;96Uae?8?$!FNp@I1GK66gpfmyd$sP! zlyt8J?N6xS=zKBz^}l_>^>G)&OJ^N_Gv%2di{1$t7-bSACJKcrBPB3Hl_xRBDUX5n zi2Ty%bHG?Jc9bF*!2&4+zWO^DL#ISeP=27{O1LHwH&TKRHbBraCx{Z{cPg^-`A~w9 z!vx?_ae){Rj6*Jn`V24lf1l5U6pDo)hh9aAXQVsbdVu4hACXG6)Kseqj`6kB%*n8| zF5ao>I^EJ*>}eYC;bZ8NdG-Suwc+L4$Rj2m2x<owFz%Y!%Br2&jn!MQW!|2mYmYIW z<<vO&X4&846@*l^{^Z{&k&{Pkq=uFfpixiDdR|^Pg9304U%}Cy{_W^}fgh~W@L*rh zY4F&h>4X3@PI1=$=D(*cXIs-q%87k!(1*r<8TZTtF2rVLFqukT^v*W){c<u)Qb(yU zVK3v<G%m<2sbbvatw^j^k(}(zYB;;X)_vK@3aGLzk`u6L)!)A_Gank8Q(w{dLrU!= zj;z`XWV?6!s5if3Yb8Wsd78aPM>^N80E6eKB5P+&a4(YDcPUN5SB-`yq`ocOL~g|< zcCaGQC4JcP$FZQ|nhq!J*oz=PwJUx-m3g%5;lz{}&6s*w?v{C6O1r3GSv<%NVEli3 z0Y04vw~keyXm4DWa+2eR3|$0Xok92ILU?(}rL>i2*BhQ++?uNC;(o4ey*n3oAnovo znhgk8k373R3Z-VGoM#{0<9VlD@T=mlhOGZ#NyZ-$ZS~lpHWsX+eLO|)Jd#~1$QFAw z*2p<IF;DHD{a_!RuJ8&b-0eAWdY{b!9<uQER{)*>AxU2R2~(yw&ryuY^LgBaKT}@5 zxO+lora)co2?G6_u`*1E*Fu)FH}`lrC&77soCJwxAS#CRcDAz2@r|Pg*X3YZUT2c8 z@Xx*9$JTG_a(cT|cEmm_0pFzh*0K?}!Oq4b&S}52c(RWSc?M+>H^1!lt}t`?FP!`? zO{Bda=UiJLe!G%63sU;?)I$D?hNlnib-~QrqKI*0tN$-Ip_LhHwJ6dNEEHH}uy873 zTCua_I&W`P@UFlc)|rCzH<KOxq^~Eqv?-i*h@k3h2RMQS^gsK%em+{tt674Pb6>JG znBcd~*+OI&($X+l!$Npy(1{A<%|B8f@ZnOx=~u_@pR$CK(s0(A8U-Ps!A2UUT2pCG zW|Ox{%f<LG=x}cxH$MHU?Lg{p333Olb=WCMzvVB&)O(M#vs7u19u8*tOms`;6D?7y zvE(%Ho3Isz`8ZfNCR?a2*OcFzH-4xh3iTS*r-DxmtDVD6zFn|AxhE0i+*ZUU(|>N5 zDSiVTu&S{Hh$>t3Y`ju1AZGF&qA5>D<3|;qW}@TQnvsK<8Pu&OHG+P}<_4XYAo9%= z`|O|sM$!q*MfIj_-ywGl1q?|}=-9{*0L)gf5+Clx6ql*Kn=TN#xxpvv2T=GpHZv(1 zX>ExxqoESB7!&Qd!R6j?vZ))+&++alp`sd#eO<S+Q>pReSJ4`_p6@sCAIyo#5e+_T zlSeOj?I9sFY@$W)<qCxFDt<b&#)_qCFSGB~cNUmTz}wV0hiTQGmyBZJ8WOMsNz6-C zJ)NBZujOA#5Urcow><<+I>8{5gHayBkhaFmI2+H*`&tmYBk8&H&kFv1#CA;=xXB&- z%K&jSFL*IEWmONMB_b06D3*i^?6l=yWjMab@zdD#@lK@0Llmh#ks|SA5-*U2{=t5j z@&1>pLQVxG|Di3k6bSJD%UGbK#*V0xe*kJm!8;0b$bH-B;w%1v49PW($^$*hH(Ilv zhFGIyO7t(~34t#EudFBTi$(}$dXj}&Dhz6Wxk9{i6Bq?<-3Lt7+$s3}&wB^1?Q`!s zuKta}7x(D@z)x^H^OQvtD(sLu?1q@=nK;FppAG7s`S+2by9fU>F%K)!Sr)GLhy<e0 zWa7R$Lc~OpS<p-yXZ_>-P$2DhIK!?5gW7}``I;pEO>!tKSWM?p`~9}3Kl9K0Q2MII zC7v@4=m9<6)VD$JQ(i;UZ?~sl=TVqqbP4flekq`9_yhD(lNet-?l16fmUHNX6hgd{ zfIE7~Z>egy1<_c~oC;$BVSY9C7>b-frww4e%@b=w(cR4+Yl$)7Qmw|)f{!IT-1{{u zzZOg^=5CghJOWlkKH+Q1teF~Rvto%x{0Xpsbj!`9C4EeY@bmg<Jt(I-(%r*8SH@1k z#mQq2I=B>)Y8o8GV*zOhza&BPvGl2va8$ej5h+a>!s6`O9dzmZ$ELqa-Z6VL-G`t) zPiz*kWKnF9IE(yyF0`SuENSmJFPFY81139$mYlQNBLYRd{6~9dHb}r-;j4bB@T=;Y zl79QDRWA)oR6x`@p1~E4=o~mcM4T1LOv|tQZ+!puL}z(B$cugEv)__R4BbS4MQ8zJ z758a-^D^)ZdtOCr13)Fhhh5dYtCBnYCur`;aMes4%g^~7IkF;JUDcw<1NIKN;$)dw z0#=+|W}Qz2H(cTI-sSpVe(kJ<&#^WgV<dXavh-*RJ2st_#Lp6x-Z?t2ide6xfCwDr zs6RoKnaqb>e^1vD-yD~Rxl%HvfemP%uvsO>BC`#|7ZyW}Sh!25(-LC_B<dXRwi0Ag zz5y+8>HOJW8&3jdNrP&h{*(#gTF$b$k!2hpBQzq&{b6ZH3w2VUBnwTr5R|R$F+Nip zGE8upJ^n1e`g&aE&040K6BGlrYO*Z*Cv2uzqshHxHqPKg0P=c<L~@9G=*Y>6ajHMV z3*~?05>f)BdDL+at@v*OlOBY$OWA@c&D`?;j@>R^)bY>1|2XcvHB7*A1;m1Ip9l<S zd)jjl6Mwj%fX-CnfAKO10U`^Wg3um&kcm5<|E@Q3!Np(!x8rE|pXbPu1t(&q|BH|v z#6}Y@c^6JiSCPpVAY?-svuY)EG$n{#O!%{-Y@uqivjO5Sz+84)Gey@T0)Vz_qXGT_ zJ8qzu7{@aczUBjyiD7!r`0-EaNGk*N)#y<(n8u*F7g=5U=D}xri2=!SWVh=dGI<2; zd0_)MF%TQWp0WW$dgS{9Rw>+>H7F^L8ENg6R)pSFD@qjX87k7_kQ{@vrP64_pjafm z5X=a_)C2<!?@>a{%IYii-={!1<{}I}vKDLU$N{N&Cal*|NF&*+U1QJ=<exPyXGYNn zugPF`j(8Nhf|F%<a8~6FCTF<%W%NxTDtgN&oK{9-sHBBI?BGrmbX&R;ucy9`PJeve z?Ixw(5~X;8TaDd<w?AuI*lPe*TqRK${YzZ!F`$G<v664m!rcv89TDK)yWJ@0)%vIG zf9dT)@L1C=fJhFHaQpIqCpb{HL;l|z@?W+=Jr;bnUz|TMV<$ivd<4yKk4u4zfC_No z&*WHkY;||dM=NA602}aRhF8i!P%5X;6q_Y#!@5W7uBSZN$JAXyp1Vc@-N^B5h4u(q zoR|TBwNU8MNIf+OYHKNJQ?#nD&&x&pY<sh`Zb^9_MNipje`(_~&;$4Yz5f&BS|5=+ zKA^pe#5cQl%hg(!cPjMFH14nHZMHt1Q!&zzok@uH8vWf|G4yyQ`Picnby99!#;A*y z`}@D!Wbn-v+;UOY@;Ng<{&%d_`iCm7%Lfoe=Rhn3&x*~(jUR=!$9G%5I*8od1MrVO zwyN5VlCLh~dkWONrn2wGFBhkE(%uVOb3jF#K6Lq#!n+fhz+`lH@({nVj0M%yhpg!9 zTf^)uw)Hn)w5Pf8vJKvrGE3g<QRt?R(!Y@qC;bWRc&F7GEN*RzNdL?e!UQOAj=1Fx z-%FDDWU@8YIh?(~^*n=cqpk;W-b>~&$CGG}P=Nzv7-2u`2;NUO{09$3W-_47d;K2> z81V;%35ZMo3nvc%)&Ru*u;!%>e7zifM}Ci*hY>%H=h05iVz_iY`hE`GHRG3S*;L<p zG;dOZAPVWO^_Fxz;5#{pnFl@P4gR~E0EWITV$;X@&#ilr_yOOA=WWv;PVFj;UWZka zrd0rwn&oN6eu-K6%zOLnW!uk<lt81-9<-PwPEEwS&<&8^b_B}M`sw4Q3((9h)|)J& zq*sPDO5AbIPSH$&)|G(Zo88Js=ENvn_Bmr(Kd<K1XS)A{J*Zv>`yvTpSBwIAN|t}h zUuW@I7U@hp-p$JI2fc+jl6RRdoz-P<KqHSPOzWQEnz4`$ipw4uNZg6R@0H_yQRbbS z)Nm=3d3FKFC$sO-=pMVemdRZe-DIW?{xNr;?uPA&k|M{YJ<!iYTKy*gmaj_pBhnE} zhTXR)mL1VTy`KIbh0h#0G=eC)27+yVnv^V;SpV?Ia%$X!WHt}CImh6IBS<2I_jilD zK1v_};KG?k7|e9|RKFZcG0E92^8Nc)qAcGpbJAr)K}WY=E*wL95Qn6L&*jz6I5?JF z++hR~ZF2nZjLYM<twBni_<u^BvV3dXS|yFePgMh{tnJoQHPKF=@U<GAnTtCe@jJ>s zpROG1kS7W}U(!`Z4ba7P7dQb?`X%_CqG@AS-RtF!L|#KRQH?50uk|mXw*8{7s?@$P zbt!fm7cCV#W1o<k!YilmXCNsU*kkSL(2}(rKGgj4vb?ni@V5Qi*K@|R*zs<bOqA>& z91o;+Ig*V|h}~@OXjOl&TQRB?#_zWcuZzRctoxJSF)@Tx!bNl!o0cZa!PYk{jY+xU z;tb>KNYbt|=U;!Z=CGfYy%xkL9WHm#UawqV3Y23qcE*e}NEvRz#&F4$3ez3Mtyl<7 zSB~I`zf!6z0-U@ImfpOzD4CPZ$-_MZe!)!-wEr~h;I(Ngih58l`oBfH-z0D-dxDSO zR#t+%vh>d0jmDl#tMXLsYNJ4%6g*n`Qw6_~mCp;$@G^3|&m0`pwWu8}co)BLtB1ub z`xE4ek_A5HE$sTMvFEv&!SflJh<%?ZhaIk@w?M5fJ2Gm(u0yocY574vkWDw(?B`OV z8(D#xTd!!m@{rzE#B!tFod1SuEd(t7n&Y~2T{?gE;i18dv1T#jU+7jjFnlD4aLeVf zeb(qq_I#(Ux)=cX8_oH!%<T<QxQhfc9$qD+0!8YBYDfDs3mlcl1xm|2XO{ou?FfD3 zo^JkAL8(82PO>KvS2yWfFRfXR2jL<_+Xo4)btQUq*OvDWCJXmev-+>vYA2O7fHN2o zfT6{pyJVw|*~<%*U-G{OU-#`c9+oTi^>5JILTA0;?rWyA{hRyDr{PfSQ|D19t6>r7 zLyH+QH<)AorTCdvzwA4=e>7KC_&<8f3d;u%f@=^K|NrRge~QzHKl|i$1R+gN&Amu0 zvS<CkCz>sZZvg1PBvX$LqX^7<^to>SnSY@;?LN0*=cgV#B@0#KR=B;k365d*p&D?z zlk8;GE4i4FUqg2_=%Lc16v7LI;5)e%#N985B!nZvM_;~i%L*!$2FYx68`Y4!#co-U z_MwP(8i@Z<Q|&_~eX<<-X2l8_EA}!QAS8!q^?{q4#ymJb8)0u5olmK#`c!<14cUd^ zn!iiQp^IXw(Hgowv0h2MuhflG#dE{OshqU^GX_%0K<wpBX&*n$0n*4dH)>cnI%?Dr ztV6D6Dg+xuEZ{)noOck(8YmjN;|w}&@)tC3!&m~1N*^v1IE;Ir+FtU{%AIlncxLds z{{1#h1Y344go<wp^sOcT4279|x2zXJ?^B26=J;b5O4qDB&|@g}3k^f?ZG!(>_FO+D z-hUjPBJV$NrO2a<1Lf}jJB|Mj{vH_+jU&w7#({R^jx>bORMtAWKTxKM7zf9GW9t;6 z_&*|4j;I(-ILe1?!qCKfo3?!B_Y#RZxJ3p^=!6KXhJROHxhERj*EE#1<8Tq4HI#8r zvjUk8nVRZ~*>UyN!N?!xP{)(`YX4(thT<bj=G+alJ!w>k`F)XkCZIg$r8Z*w52Ew# zLW16C;|L9S^d&&d+&AdTqToTfk5F!p!!u>lDcvh#-X0cI64~Q5;0_{v0Yr8w35UA; z1L?aTzzMi#I~;(=Y+tt6c?n{8k0kP*U<~!y)eruRBj0T{6vi;?8IPE}_xT97!-!2U z_HTLj<p0p@j470m25DP-zV~vinNgffU*2&=y*UTXHvzO<K6p6gInjH=D>F;8%O#PL zdLrC^?rcYee$e}~FaD!SBN5V8xr>lyUtX~h8nNX%Q6R6GITgY|np3`iGj?)58tTBe zzeKzK>1A!&{*<Zr3be=rl8(7|R3M&2iJ1N$6E%XC5_apy0?M>#e}jfj;F*3cc>E46 z^)Eska{q~ZkoH6%VIc8|YB_93Z>SDEx=T{g@L%0%j(C@<FX4;t)qw%=v#oXK*$b&5 z8RP*Nqv&4Tmh9RV#1H;y6R<7kw>{uk6ageh1YW>Dc(2<t12y2E;irldcm}B_U)pOp zX|0#kLG?+(-kAAz*3G7i^Z1JMh`7MB1GlqB&#LC;3fwR=fiIri(uR%aaR|uWJ8-Cf zo5}B*dgEzug|;Zoqf`V{fPItS)D=ZKNL9N^l#??aPkAXpu997j@S8JJ_Y!UWLI9cE zTBRCptWl-xgVt$K-UU4J*7)UaxL@jIZllLp6f-Y83x^ltMA3(uHBWOtuD$vreoQ6W zHNB}d+j>~BOZ$G!+40lKX#)qI`Vijh{E+Rzm#6j`IOZ8QOuM?Z8v}vNJOhD9koa!c z5Ldh_q48lxJ)_`|D_i%!`2swWTCmsIktLv)JS-3mwnUiU<*td9g*GaBWLQ3ZMTL~T zYE>pBsUal;o#c;0Gy5ert*_*c9t$rZG|no$f<BQ!h+X{L2Ht~@1G=^W%bPn5?8?qS zxS7iv_kscNFVi-@fGW{7%GQh|LZprK9ep~g%Z0@L^`D0ljbsM=8Pl5;?@bZ{@XZxn zYyJp2*uU1KWpWa_l(oNoog2fY$As3bw5kjn)EwN6`E$H8zA!q#u?d!{XM1_ky-m$? z>$!o+dqG=T&)1gbq;pOE{Z7;Mq=mCRQ}h8&Z5Y8={ywVq!%f!)u1Y8HeKl+-yUKL6 zDjA<yxf{QCw^gAfihgg)rm1(od%JAs4!&6nq(t+z^q-DhgSt@HRy+(!aeI@09?6Iv z=5`2&dQUG+pR^uHR0BmzWlJt<&QDTN9lqRESxir&zvNM-%KrAsD*iSlvoZC0j6QcG z9<d*j?8OgKL*0LLPtGi5r%i|y3SWxh|KCpKUnKaex&l%qGFrQE{?*KSiU)}}b?~JE zD%)IXm<JFc9--(oP5qE1o&__Qyxzxa-Nq5VOmqx-&HNIp<zjty2QK*Pcev>n2XWu} z3RS=ZaltU?Tz^e1jeak}`T$<-iR;ot_d(s70Rf8qZl$VKY_a1SHTa)1@X%fxu8qu$ ztlOwrfg3kv9q4+#7|!cgD(YZ=?m$P+g|@T1vvy{4!+SWe%FYWuy1G33RECoxyTw-{ zj-Qt6dZ&Mv6EHS7du<YQ?%_(k_~4NvYRI_FuqnIyZt>V^OY~s%$HQ=Z1MzyI^NM1> z^{05pu=ns>ECl-2xaBjYz8pMHQ&u<0D9_At1HvhK42kO4&r2#7RWFvFkFOgX>2<T= zEL}fCY!rjKn1fB{fNUX319GenbeWyIj-}_l8eq$G0LLa3+S9X;|C>%3@x_s|E|n32 z)HiF7ae{pl(q}t!+FB5W`sa{tkjBee5=M0?=^BZ@3~P#;q3a;kPRQssdp5B?I=OFr z+qWcLBR8lxnD$I`UmmLg`XaPnESw<gKAu}DmrY%+fmz8GWkM{pe`4ee{m^Qv0|3<N zp-0<o$D(%c)}a8ffSnyV*GGhskHRGAhF={uKfT($&JH?jcgx&t=B4y&6?OSH3e)G@ zhs`-(HS@42J%>%1rxT^tXbp61{=7OjYx@{BaVrSt7&EGAnL_{Unx5d*)6kz|_pp%5 z)5t3?IXG+n&AMa0@Bj{&mF%54`T$QuBH0XD+6vkiFf6fNy;!R*R}XSQ^0eot)`vky z$kGd0us5u14Z%v*UPX#H!U{El{{2sKf>a+4-BjQP`m;x#b%LZI#!*~8)NweW(m#$l zvSGPac$D)f3f9GEdcqUxqr2TLidZ%Rx{X_vd3k65$A>kk0_HZ{uB*lv@Zg!U=4m1W zIx{fFk~u3egV)g$i`+V>!u(wLTeOj!d&(tJFABIb`9~L&kCCc0uk3ZO9d%|*5~|vV zTD~vRI4&9^bYrsIfs`9vv%82_R%nmeUH@RO!Jg6Qvcic!Xgj~bw=uOc6@V*w<DNcT z{j6I^*@$p23)}gB8sb(IgYLIgq)dOTWMOYFfqd;=y|L<g9^twwjLhZ52j`8AAJ<R2 z$4?m37j+kvrzeD%t~v|BCQ-#p=q(?dnRH4C%uAvbpm;9W0B&MidVsB7YjTJf_r&*9 zv6wpT)PrJ!x9fvWizkKRk(T=0>`PDr8-?Iu#A{g7xBJN9{jQ@ME|>o6s+YC4v_9_} z<GjIH`;aE-ECvlIPt(fRXr!?@QP=E+t;tnzu?Bl*?Rq$0hmb4P62<><aXS~Mr7{(s zk!;jL0fIvUmgg$$QiiUD$76JQutJLme1`jAs7lYYk;nDuwZB?lVwov;oy({}MlLUR z$?;B7%>T#IUGCR8{6p+~L@5tLrEg$6IZV**B=DPKWW(~H8e%w!`FN#~`!^k(N3FU} zo$1_ZyL(H0UMcUDN^pMD?C?IxiKYtB3ovKEG@QO3hiMv)K~7^W-Vx$ncCn<X-%>rj zXM$%}Z|s<LBNbgAT8P8F`>up3zvzF#(*NRs7do7qYP`6s;me*iA2nwQlMt^VcUieP z3EWy_5fpos@@(OjJ&q7ym~SwdX~%8eIkhZ0m0K-oC+=KW?9OA2=A~5Dm_Zq&&w==X z)4Lk5h!}jXV=gB!&CVG$`z7*arAO5*9NI!=<gnN3W@PYjJw5#5>)El-R6AGwR6nKu zq;!t6G^6NY)H@6@R*Zn2sm<5Ab0QopMZSzBn<=yEEbS+{H=!X2axgX(`ST$PX8rGN zpnf!vSG-EUKH4QqsUjFwP?EhGrM9s#p|^mjA($~e9dJqpMlK;3MmossoO?$HY6PN` zubIG*lv((^+}kSodYfmu9p>!{32Be!+1j+J&6(_zR&y7J4G^{l{S_gwV0J?CURW5U z`26QBJHa>xZgOq!C3>nrszmFM^qh<b5t?>6R@LZOtPBd!`TQzb5MP~N)V#Z)Conp_ z-OUPFTFCdWf46Sre^vR6m3O66E7=o9)u?*f{L9&l5Zqh<wjY&V^M<~a|Dda^T~cNp zZfoS*#0aHU(G;jwl-!6UuxXAH!|vfFOj`Xqh{SL?=dRVTj!Kq$A6m@BVP-+Am9Rrl z>c8PcX*yWl0K)L29YRp20NebikF%lvrKw2>CQ1W=4SW0)#m$O{k7GQ~^5P)@8A-_E z0&m}0zXm=?Hl~pp=U><&lpEIpUpfTy%YKdH!SYN30T|ySY6HQ!_s0VA1s$X(K#)Jw zVbqJA*%8){vXu)+%*|aPf%NGR*ujbhi<Eol!=Dklem!ml8tC<&;O=~|Y>P6fI$jpi zv%Cp{r!#hn0;Qp<Z6Swmx6GaYrU=*cR|AC3@wLSsZ<Rds3AL-fY%i$6LLjli^k577 zTy--faaeJ|Y~X)ncd2Tt?4OH&`y2<=#VFId5iT~xh%<}m%H*NZ4Hg6dh=M9#T9%{W z<oBZ(K8}Ch9p|?jD?B-eb4VeH7$VVXuA23>ghu;^zIh$~)8Xg#aPN}S(N^ZEE`;r| z%fpntl)aCm@TCSF7GjK~**H|!R*z(pH%%~ZsBaWhPgq_&y5DGDb$xx^`uKK|Hi|Ie zJ(|9EA}1fE2vmwibv7{F@=T50gv@+&x%IN3zMY1}Q&=yXt8p{DeC&coiu&Ek;vy`& zG$~$Pj$pOJTjfJv)}R9*CZxr*zTxWR&uAa~mfk?Uw&rwArPdVHUT(A2d9#!hWA#RG zsvmsrWcpn3Ox&3Vsz<nGP1RmFP+vlxSN>Pi8M!cF+}4>cxALmu*`!dJ(RBr=CCahC z9^!QZv_?bE5xD&|S^=q7zeG1DH_l}FR2x;pO5AM&J6g6aVt`Upo9jQ<4Eu3(9;N2g zc{s%WwbPit7f1V#9FRTYyk~@YvB#xuq$<fF$zLrXbKu5JnYy?ch`F!|jx4p!mvFDB zE6DqW|F5Mh0BhTC2zxWRoE`D1($JgfH5O5+Nj%b4MDl0IIRj_Fd}#mWT_2VvEgbiK zt!e6B{mt;q!4y=#yanbf6*E@+aCG0)P?LJu=98I#eLMU8Ds}4<>lr&@E9a1+0$rXB zj=()3HT<Q2J$KQUBuDHtO_hn4kane)Vsb7yv0`8iR5Vp0KdT^eAo^;gwhcr^6UC$7 zXcG5O(`PBN)rp69D$PFj{7iy(5$CR_cBq-@q26ow@hdqk-Lm^5xKM!1!lq1Ju*rNH z#j}1M6KINw<H_4;NJQeA*c^}vZwa5)1Pg)d=AsgovwT6*&Ur^q1@Zg<b~qTdhe0$v zr*oQ=buiQ+l)`|KStXCqn<veflW^gQyWSNPZw>|uKt|kg@LteFx=X70`5s^O>2At1 zG){2;0<0JryvtdH_#R1fK<#HDf9@8j8C{cd)Hw1D{|={@oYDwH1z4Zqh3z!;LTKz8 zHYA*UOB8Q??cF@B5wC7TbdSvj#db~b$!K1PV~kr@kGxt-9kfu<E_m&qf{Sl8zf1^e z)mKg&ACsnrhfIl`56#hOH$>Y0Gj;Iy4Vh7@(QH#-$F$l&OiFE*HbxoqC5d6vM)|%* zU-(o-UR1E@1S@jIIc4PobCZImWav_vrjT<uqpNIxaK1i5znY8fqWbEVw;spF?vcHf z-wLf*c|-O+Glo*bHInX=&uzE>@B>Lvp2M2e`y9KDK^>o_Id@`lzaeV;?p(lmL7%NE zYz5&`PyK<nPaU3(Tv8yfE=GlyAv?FZjwygSyP(vEpPd7~EUQFS3`#aB1J(pxJk9ru zI}B2;N2e}VSDyZ+^!w@j^vl9rufN)?f=XzK=8}k{{nmt+M4or=vChhJ8WqxuwwR2D z-h8ptt|i0sBLU6u+<X!AtiAg7BXM)FMYWEqCSsP76951=`|tk(FwJC4r)`=3aOCD$ zVV?ecjjYzp-`?_sPdU1|i<<ot#diRITb^=wTACL}a%XoDCu$A-yb|_;k;}2Ow)&<E zVYxW5L<sW?b#2kN1?J*Ld~+<aYdKAheuWoyDh}G1-(G_y3nk7vsZpRUIX4ZoXUC;^ zB-%N@AeJ-ZGkn%s-rCXW_n@8dilb7Occ(5pN~ex_O$6rdVck%96zxAZF#}@Nxuo^O z2vbJ{=9gwcs=x>(<x-QtuJDccsb$<A3hHyn;d#8c?4=}G)c5CMh5Fbwe!hlojG0kc z2K1szCTBLZ8OGr)O_04AH0WV`rICtFr{Bl;l_hE}WeRJaMx8?kzk@|Z1$$Rr@|(r+ zi@{}99`n9}TB-c8dSle9_Gg;(kh{gO<(X<e+2@Y1=9_36A;t$@I9AlVG*X&<l2oKo zkxRvF_Rw$<=jTo}xvz)$Y^#mvp<(_}b$owC+HK=dMYRJeOG-Fg6k4<C(1lTBOsnR3 z;ygPIEXXms$uO7ObfZl3O-e>pDeLjU*7+Pg9VtwB_TqmhR-8J0o)U=OAeilrpv8X6 zf#lcpV|%I-HAKlq+&KxDnUDunuGps&L5u5{P2Bq%IA%X<r_Elp3X&L^vALRCR`DNS z2o3%z8ZM68y}QfoIv3qTYgLpu31r1s6<w3!T+gaL-t;(c7vj(I-mJwjG^wFC!hQ0( z0e$ix9_x=<cFF_-o5$XCJy}Rj<QCP^tm)krIj1TGiE_!G+?z9ptxKPrpw?GD@g5!W z%?oUoyODu4Yn*V9_VND&i3oQ0#79M)4mA9FrT#omgaaiAf~bdyZzfujPmzF%yA^)E zde=fNP7uT~p^}aj-Uj|Q*=VMzl=e`LwManqHw$dUH>mjuf*=eDFNcAG_)<7Kf*^<{ zAps=_f;bQXjeYO+a^Apl#Q+`Q@jy6LNGT^yEeGWH-tllfMO4YZh*UUGM}~)s(hlQc z!(B=(2fW|M>ddOpjCFkFu*yB4Vbpk`cNMn&Gt@vmwZxp)%Y|a~_47k-3hn$VI?D2a zUJiu*S=v6{??WNoIZ|nRdG`r%UN5IBOKz@;U)k^UO;SmDjQdaH{iHDgO)Uok2u2?D zS1D|o9rW1&z<nzc{K7r97ztjr+ph*Ae6at*Smc4PW-0Dlk>J((e(cHa8)T=oPIEMI z--;~UaaZ~@`M!bk(0(--;UmE>j&!*Pb4}teE=2f9gb%Wh2el3miwa|lkq93d6V_|* z-Z_7SSGs6~_q*%q=l={1u5l4Q65%631P-C&>CP|3Y9J`rXW=40_&BE3Uu~aA5KBwC z{W9Ec*nRwqV{XKzU&OSwbzkTYRy=?AJAIS=L_1y!7kN!9EA^j7`$@wBYQGwc+;UgD zJT5Nvd)&2cBj@#w2LffHu3avQE(>yc&Kvrtb~PwmxZHhX!eaP<JF$F0i^;WBEuOye zhCA}M)Dp%*oHy_b@QcpWC_5Vpeed;-hf_*hg;RT|?_rg@uh%5?66?OEyGXb_?DT-w z%Xz2SZucJYuhh?DQDN+^uh8+L2W>)&&aYH>0fl<X7dihqgSIksEtR$x@kLO%6s5uo z802*QTo#>DpKg@C#KaYy+LhAlowAYXGw_n?fIu5~Ro{2R{&NsR`09!;yy@>gSKBrQ z7suRhz%521d}QH{u%Nc7+zCp3lbjxI)(+TNH_-nms9l6%cd&2x13l5t`4{fE0e&5U z2){6f>ELoosr=%YuIh^WR{nZ3EqEgO^nlwh+qy3l6A`)PhTRu@)DJAd6A7}@gO3p4 zgZ*!&pEqrG4y)XQGNaGexPoe&^GEndWO2-`TpL3Bt8l^rKV4FMex(F_;;3{1;MNAq zhpv^jSHU-ch2>Q2#Wd?FD7AKmx^G2Fe0q6$065njd=!y88@E>E_zcsB$2Er-i9AB} zX*%ECG4~gR3yCuDz3VHUEAS4kaYp0X;{MYVW&l#rolLP17bv#({Xrw|T4pVi0?=J& zv0o@75&M6z_*Xrei@<<)8t$>hh_9#}-0X#bkOJ&A>)-5t84DBJ{lE^u!6NoPsT6Pb z1s@6CyMu#pk1Ym^>Um-8+BsS8b?Gb8-+c~<0<6Qn$CK``$~^#5;lRK&`zWG6@uuGZ zK>wpi@Ekri8acmw4<bIzFpfhrVwJX6whP_t-NC?xvB)ii>xn67m_C(UxEly)oot|L z`c#-_g9WiW=MP2$;grv3uP6?j5Q@Q_9QRIREb_pyE^vOkZmxij_?4BF^F<n3)_<B8 z(9-D%KH}e>!@q~G3o-d3oT?=P73<&9{kp&!Uj0-55^%xoeiP$=OZl$aLF|*5EC&W3 zqvUETt3zrzFnHIy1oS_OG-NJP%Yo<r5v=-^;_heM1r7>3i^aFN>Z>&!G1&ijJqEbz z+iq~yJPLN7tKVjnr;mjOcy2Kgw5yH0r~D0YutG8w6EGHJ`S3qE!RWZSZw1%K3(aNN zf9gd1eF^6MxDV9sD2Wf@_ypP{aq2fd)@+AMEeE`J5#%EgK8U*|3uiImjhj6pO7+js z;Nw{TKrr~IKUQ;cT4^G8;et3`_w5IUer&vfS<BXydl=((WpN;A)ca%4m34z4T0J@L z?i<6u)P;zWQR+b`X7TxD_YJbsx&s#rDN~cNkbZSLl@z{^XM`(luW2gX<;euO9a7=I z-K9Fxt0S6JIQTeLBfZ_n2@AS@99tK->N4l{u)>RV;o^C>hvgS}?YM-;y@dtF?*mJ! z{#5Nh4O0|MMEK59<w>O2_ujxSMZ?3AAwYQCD-0A}_6uLp5~sp}f$124FM<)zy7%r9 z0Qa4R;MJtz5ZkdFke3(xA4U8K>C)Sk+#aE|i+43uQmz9oj0G?9fyXfb?mIzlEg+8{ z-FFrO2r5gW7seI_gh4g^7&|@v3ySKmpIEpsws03gxpCCQ?mJ`b<LM>1#})^Lfs*#o zPZXrW<Ac)}TX>*u(A9H4%RQWtyZ$UJahfT8hdEcraV*QKN<Y_T3GhXY1=ana{QN4^ zr?9^zQ&rl*s<gd&BfG~IgFa|~_6K>tTmR`DcKY#>`-^`3vQ#O(b_xUT{x7ifORWFS znDDrs{DFE#5~*-tfaey2K6@<0EwF|CD(d8=`cr5AM*Rd=GFmW^1_ZP&afx;xWXFnq z?_Kvq{2$+h7eO3>^NTRJj4g+!-%V-)+R`VH&iTiR?DxK#kp*Fl)RQ<V9Ps%?)Ip2G z+4&v>4{%n<7kofRkT^jc==nu7Dxg6+JOn`y4GE}r6X@jMjbr5LBRLZUK^$eIU8$yy zNn&GDArs$BXc6hBebRmn;R%8ujs=Xh-djnQewnXp2u~0MadN2hS2?Rd@jwZJAQWt; zJ4rwZf*_hy&xSOVhVTSI5CD+=kZANPB%lOAoJ6WD4UvEn1VL0}Uw#*!APC|lQ0boc zMg^Aylpu(c2;B!t5CqXYd%q8q1e72M0?^&SRR3~3-3Lk#1X0k<hHhpe0VN26K%?H1 zhVTSIoLuNWP=X+cW@y!YpeESgGIlG&T3~0SowOv`YJ4L{u|WxfIKlio2~mKU!fsM= zpwe!J*~wrRkkU22oTc_72;u}I=>sa~1ZhXY4kT(9f*^=G$z=eTfi!kSY7K%Qh(`JU Y0Z=fIbhbF_G5`Po07*qoM6N<$g2t7(Hvj+t literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/use-nXhtml-trans.png b/emacs/nxhtml/nxhtml/doc/img/use-nXhtml-trans.png new file mode 100644 index 0000000000000000000000000000000000000000..4ae2ff82088d83e7388626793bbf071a1c3b3062 GIT binary patch literal 1485 zcmV;;1v2`HP)<h;3K|Lk000e1NJLTq002$^0012b1^@s61h85}00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOK3 z6fiavS?0z7000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000FjNkl<Z zXx{BveN0nV6#u<`P(CaLR9c{7J3vI#Xiz|`2qpt@pmS`_x(%GT`7x5kxoN`8HltQ$ zy08T#Oozki{2(KugyK{TZWJb11Vssf3IYm+QVQ5YY5VqvY4T7|6y(G7BrosYbME`S zdw%Df`|iyn(5%}Bi@dbZEEHIX8&zQpW{AHTk&x^sm5hf;#@~!cp!UbZyciQD!s8`~ zuS^^@6RGVm#epS4O|c)-)N5<j`L^Z?f|}B!=%zkqiHkV*rpwx@k<P>h_I$Z(cg5Vh zlf$n~?y2W;A6Lz)b_)IHs$hE&b({$_L*<l+{DSH6r2rsQ%ecV}sgaZVRL%rQ;(30& z){OJ$_&4wtH#)D_HRg_47x3_pFqzwii#i6UXIXtx^l*rymMhhvdX8UBg>zKdirPIJ z3i)xFW!&hJu=|N(DsjnvQi;2!bn0@2L~JH*X+ug>9Vei?kiSvhN4GUT&ySHMjx_b_ z%DHQDz1#B_daJGmWO@I1s*~lSvoUBUhdf9Y10?afO7)iW>KYI<5FiP2n`!E?HQU1# zl3-y+@j?dK$08}u+4ZTX6uGUxMI~)8KSt!MY9N@sLbZ%Lza`6ys{hX|rt+lk(F`MD z)$6Uw7XpBe!BG|R<1$m{U)Z1Wy4EOyHgMaVLF&T5zlA$bT@vodphoX8)2VGy)9>?` zMlJnCevC-QDI9`sL@4&fHrmfCAE=ZxR=mb)r_ee8DCEcGiW-kbiW-lt8SVl<SgF29 zn%Hx0FIPxnn%HwIsQT;Ew&Vmi9EtR8lfF$*FbDEuz<7<x$ssayB}$8D<1NnzkljA{ zj6HnudnlLBM8M(-WM9d#Y=F&@emW11PHHG>+;L#{?0&X`yM0kEp9yDPD>5?k06-(N zPZ+JK4fS1PL!2{DkAuIQ2aRUJv6N+Ke#8O*R8>ww>d#?dGW9reJPQtvhLLu7;vczI zMnA&)>k81_H3?sB4h8^hiG2q>Ivd1qmqHYxnvh4X;iP&Ze@FH@<*7iPzIlp~pd0Sm z&bl8rBR#Ly##7sGa8g<k<TnJkc6k9lUQOa&r3XYIW!U+B<<q#|KG^F!7^XSfs9DDe z>Xc|?_6cdcO?e-*oeSg`H0)O9RMjrQUa61vo?~oFhRD&N<~+1=Rc`Y7HM@`_Y9I5A z`=sT>qCM{4U78lqcxchQ;#4i&PJg_5{fcMbP6K{BeE~MMI$X)~2iHZ3^fQ-V7Lyay zDKX#8m-)F+P5#U^KAC?C{Ob?P?1QS4YvMnQYR{Ro*5~XQfq(ts686H{pA_4|$3>}b z_DVZ{##!8`rP~>6Z9KJ`ywa}tXzvZYC(`NYFdCoC<8ikglr5}bV^U<RXKHQ<+rOie z!7=O<CKg+hz1CYjk4ULHkDgloxFD{8v$T!cZ(zCiSdo3qX9nu^1UAR4g1(o91%Y?a z-DQW3;z*cGua5bYl(79f%x$F=S3i)BNg9~rf;f^GBJ7u+FGihW8kU60@s~6QeD{Z_ zy6b^&;sah8^Ns(iW}S7z`Ew%J*y?a7<vLi_CM2a@1cPC~>5LHMX7gSuSO5sp^oA4H z{D_5wZL2_%G>Bsh;4XM_kQRlg@X@FFFq!E1`ipnbs<av^WG9`|6{9>ceYD6M8{*=` z;pk91faj{j4+qNn+4d)u!gI!bw5y!3VeRsvLLTLPc5QFnu9fN{hlJ7C3=@{WToY}L nvk+$?&LS4#EW}xed(-59+ihwUEM7l700000NkvXXu0mjfVJ*)@ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/use-nXhtml-trans2.png b/emacs/nxhtml/nxhtml/doc/img/use-nXhtml-trans2.png new file mode 100644 index 0000000000000000000000000000000000000000..c348c923633cef9bb0a50f1ddf2535d11a19a546 GIT binary patch literal 1520 zcmV<M1rPd(P)<h;3K|Lk000e1NJLTq002$^0012b1^@s61h85}00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOK3 z6$uF1ejMNc000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000F`Nkl<Z zXx{Bvc~BE)6#sU!+1&&a0TT~MKp>)RK+bvqLMYH8XtCOMERI%tWISuzakQs8<J2m& zR?Bo+sEAr?wVgJ~AyO3N&>~oih)n`?s7jCof&|RD*=+x4<7^ZZ1Ua0%nM}TYZ}zv} z`+e`&Hw%5(Lu3M{3|L?%1y16IRgk_6-Q@{VZgg?hXxL<Td4iOFJsS3fjFl4}Er<BX z#L**>zBVe;!-$RwF(8e&U1w1jdzk+ICKlK%2sU+PIVO0id8i{1ai9H{_4Xxy)FY*u z)Hm};U7as;^8CxJX&Y-DA{JthsK=s<xZmn}006Ld*6@st`=TkcW&!{d^dLVTYs3+n zk|4}0wG#D8ZM5sm&Dl}7-<nd0$+egiX$gZNj-IY`hY<H!H&BlhxuO1}#kgpF5hi%~ zszJUZnNA!xx;V?)RqJNBwmsQSoUw7QgvpCkU{hDgAqI<lkRL-z97Wk2t}*ZB<(9Uh z0888HK$oCB1u#CzL|Hn=o0RFv08r55N>%2R1velF1^`gd-8E^%?RKLgEu3gC3jmY_ zb=beT-4*j*p`er2mmfpZRbkX(?X2Mut-0O~5A;fH8W)~@5`r;;Xg}u(000o`uERy^ zi#Sn*-#xAx^&e^XukS`sdr1&WyfvTo^tKZY_hJ0o=Ie)NP^6LZFh7PQ;+TBNRl~JU zQV_Ri6uqSq%o4OQ`7tU00Kom$l$)BqjxjZ5Bo4N~_m!#-E#j_W4aRHRQV_Q=C0&nC zd%Mik_?5(>l10!ld-J2$0~?9S;Yd<^?2U@DX}lRv-ICVS<=tyP6gMwkRbAyfRT9^b zns@q~^9A^SdGYX%m25u0yF($Laz6bt5#4tF^IalUb(Js2!?SbA563G30ANcoTRL2O z>+iEhgg6%-pGeBcJPX0Ft!nQVbMzWD3IG7w1||DK`mRU@iV=$r9zBC`$6JTm;W0mQ z`6n-I4_@`=C3ClqUHHzrZ~y=}@%r*;!l1{ZKKQsoI5(neOpaWG3H373_LAV112Z{h zm75JhNHr%|l^1xRLdWuPXzhu6GHP3@e)nw1&lUf&>=jCV<xela=Mv?So8E7_7k5r` zny4>Kd$iG`Zg+wqYfCX(deQsc%D~p|gK+C@mpkZ`uCvqADtLN1H}qy^D2vc?x^ba4 zFCeF+)pfRR#3L@aB|Es(f9HiSW7RqPBQ75!7%r9<>RyY!uQS0gSaRfeDe5xLtjv`K zas|T9MF)>w7%1lM1Vfhn-~O}T=d1nA=cmw<`THcTIoI7|{#j7}#{B7Ong7orvQzsc ztvNScBX2%0-w-(}QZ+vy`;2nZ;x;RTZPT%QOa<c1s);>yf?g*MqY<`|Bn$umCY=s9 zbZF4QV$!8RoK>#ohV)nv4q58I^9s{uL{Et`9dr})%E_aGxE5E(`g8~PG$WMdzOq0P z1axBMvS+O(BhzbMOrxczoBiwZr4q_!dt}UeMa>QAxjRLme4;lUgCda8(Hx-u!4_^@ z8=`GcOco_3$(PCs%3OVXHR>z1!s5;E&3shMC%&sHa%B_ijvNYQvRzDxdopSe46`lF z%sB@mOzR)}zn#@oRLC39><j<^l<mnTPOnj;r#G&R0~7^^NmpOu3WR0=01(cN=n7xG zu9_lAxM1yDaRzM%v%i=o#7!^0b<AV9$Qu#jWGk0N89F*RT!By<vvr4@Zj1YLcRgPm zsM2fH<7F#ejp{FEjrWG?c;%+p&1c3*hvQ`!a(?9+V>Ql6oRc`GIEix-=OpfllYaq+ WypY`lzPfw>0000<MNUMnLSTX@e!cqu literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/use-nXhtml.png b/emacs/nxhtml/nxhtml/doc/img/use-nXhtml.png new file mode 100644 index 0000000000000000000000000000000000000000..408980f1bf2a326c08d193c8eec7834b211e6e46 GIT binary patch literal 1347 zcmV-J1-$x+P)<h;3K|Lk000e1NJLTq002$^0012b1^@s61h85}00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOK3 z6fPZXq##)U000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000D@Nkl<Z zXx{CadrZ}37{@>7aPCJ)4}*b_QA>=QgGkesmvnd`YHC|%W;(pJ=^~nmOI%TIXt;?E z&|1!N&cZcd+T{q51q{uVx<RE0c@PQ2%aL>CoWt+XA57%uIix5cu=D-vJ<t38zQ5n| zeV*ri-)BeizS-4@4}FHzCxK76L4~Zh2~$N90n^Kd#7CMcl0?6U!gtArON56?5bwKG zdq%(K*wJtRbM-4CTZi!s=95b>RWHPKwQ@i*(SBh!rm7clG!<h%pVKvN{MuuksWKU7 zQ%Sc?u+(As{VhxtbMNZMfM%Sd@i40KX~=_TciY<Q@=#CMh(tCD+n-s;gQoRMx%SLH znQk(Q&}6Kq*P)KdLJ_tQTg@hvkG>{aFIWxOYBErSEdaoN{uAUO^H7AQAdxEm*N=V` zuCr5oi&00ui?gX1=jCtEOw2(l55R4|jICx9;2yA2mFb>EB9Q>@?s2E9?RM}CU*c>k z0>LJF&TVZ#5t1wttv5gV=T!C6B3SC^xN$;cmIu#56Q7I3PlI4Q-9@erM;()e|1|x8 z?NME#d5&+v*;t5n;tn+NyTp!bBXG8SPp8{?S3mkC<CNixu%3AvdFXtvrQ{b7gWs40 z0929bw4dLB{f{jVyutTYs&|7tWDeG|X~;w7-jP`wu>YNdqkfNw)0-b&1NJaFha;<& zQ(Jh5anDcZjUUQA=8Kjs=3Ge;aZBIirM>%n7vNi%yEBi`k3YesstRfg4~gb#4}ZnE zk|KhlVwkrx4}gp^&7ghTy}s+A2&eS-XTko1NM$n0H)r55nE<e~G*h}E4Y^j!qJxFV z)#`qCc-XgGV-qJaV@np+D=k!P{Sbif)~%u4Xk`BGJp@Kh7@jTHgQWV=*!@gy$R*J7 z7lKrYA#gUwqIO|d1c}y8Nq>)v$IJQc(|jaSDfOj#5>i(a`|1)8-stASUO8`NThFZ9 zo@67VOhf5YxlA_f#NY8RH?)!Hqw*MItLM3k**s#uM5})sM`ORhsC}|;r+I%L4jE+{ zT1UlF8nuh&fJBrXZOpuoiOO}8;`l<3^_D9wd_E-s+qG*1$HcMX=W1jsRi8OC$~0_G zvUxmb(9J|2U4TUq!c;>JiI)m!33wWPbbhyO?9E>}ocL|8JcCxMN8%39G<qs-sRFwq zh@T?25pliT>srC-L~ywPuwHG&VKzN5XHV#(3useEAo!^`_1HV8I@-`j=ZkFNH%|<W zJ?^?zygxbQV^Fv~qv#d{j;vaa(`+Vo@#|PyuW)p2sz+DS7tTA;rjEFM8J78bwaMM~ zA#yl)xxsrwbxt;o)m0>{Ttmv<eS{`X;-9i(oXX3+Z_W{asy3ZEN#(Y!sC7DKWM(0i z$$0s*{m4`*j(@P3mb0h();o7K&?8$ohsi`q>M}Y7f$5o9sC7C30wX8z!pGUTT`r1O zEX8TD+%u<H8OAtc#h{7zP=wQ`ucxiSKyd6t5>i)-=AK!*j)<AFFxJ<hPhWq}oWG3! zh?LruZ2VC>D3@W0?_aKAw#WH|^9kpJPdJ}&KH)|j{sRvl^n!}&-sk`T002ovPDHLk FV1l9ZhY<h( literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/use-nXhtml.xcf b/emacs/nxhtml/nxhtml/doc/img/use-nXhtml.xcf new file mode 100644 index 0000000000000000000000000000000000000000..d42da0bcc19c189dd779057696f474dc8c2d0f43 GIT binary patch literal 3484 zcmc&%U2GIp6u#4ecG-4Y3Y36RGeAsB%$nWpwzT1;mKY@|Xu^Y}g2{9{yB(RGZFZ(< z7d4x{5n~JwiufXl`li7re6S`OH1Ri0s|gR)-~$FCSfIhS+wRiqcV_P0wz@?VX*k(4 zbMAM~IdkURbMBo@ndw1oB$3pTre!eDVelg)fEvMyg3DHLp!+mq#Gq~94d6}S?LsEK zCg?wldng6B;Y22#Hf$GTMw43(WDVUl`n6%x9nhXWc<4Er+3cyBX+33xQ(3d0FlZ}* z7RSw5hGyEXk#&rOYi4X`Z?GkqN@T1|R%`KY;cTi;*CJ0uJgOi>#nfJy_Ej*I^V-@1 znT|Mvdcw3*T5C)?47TJdfdUH;*`|x&69WcCJ(5W#9m6dL2q^bY$VXP2Qa%JJ-!Zlk zsjqnrt8t34+H3wq-BqD*0QWjDWxL^^Hslx@=&7`xa7d#XOsmGh0U?trts>z>L9mo- zSIFd6;-M9C17z~G5lp^nz*0|E35}^TcH-_Yw`+{JVN1^$SwNoM-4?>M-K(SCjXWhY zHt-|5?Z{EsF;5y==kh|3iU<0s8#G4@i?Tj|;-N*$d266!pj)Qyh_R*HsUeh|w%f47 zL!S3O-7&)bX4Wq^&2qEw^7nefBF1B_@mM>AeUZ+NNE||}Ez%b4q*8fl$Z^eNPP2@p zi(y}8B%IFl8(M$P*3)J}Kwf#sKq(1=)H6bmYl-Bk=aFAZGLgX5i^%gd0eO{K;0xfc zJR4<8oM}wuJA477he%S{Z7e%}`5U-&U%7b%mEz$AerC=-H#dxBnBntj#-igT(t~o@ zX!gY_#x8Zoeua_B6;|Lqky20OI;&!Z$5DNgnHrdvW~Ge+2fg1+Y-Od=(vp18O&HRT zvC$d6#8@#1^HQ&8Q@kBL%;BP-e)&AR)T6SHAKWyw{oj171HuFzq>A^+&%a4i{Htwj z{}ksUwBO4XXXoFB9Gk>j!bhHc&h}V)F6`;5Ww((7yb%J#<H(+>mhA#lix5$Xqh!6( ztU5}_dN$9)!hfaaA&i=bB3i3?W<>KGl^s&4U!waSV8g7nKmY%Rss0*?A(BgmhN=G9 zha^^ggT{HKvCMH+dY^xRQkwgapM&i$`~|Fav6ug}3HQ0S#jEvf=k%RsXcUI|X?B74 zVq05K#!7GSv#5o|9oP9}fP_bH@oU?${T0-UaQTS>wZg0XtqtGuEV=I}{;`EM&n?8r zef?!_;y#<^Q`k>G;1epL${2r-by0-!?4^w~c-R=$dgK<lp4CTBCaP3@vL7%Vh<IAd zQ6kZSXTYzl#skNIS%l?lx>mDt1`DvvP-zC&lP;(g?0s?IzRAYHHQ=T_KkNDO^kqZm zU!|9)GmTo0&at&xuOM1a#(U2Wj6c8*?2N}dA`zTa?H#dbdlW(>y04@4J{(!WgUAn& zTtE~?@VF02EQoUj1)(Npz~{jmU#4B$JEWROs-{Z=T~-cfY3uGCFU)+@gzbG^id^N_ z7&k93{MdPXYT^6G{4-*5e|6KlA46}J3lZCX6`SUt?Fx+E8pGvNUvV$G?r!6s(7ek@ zUW6=EaR!7qU1oh%1r87sX_8p<juH<Nmx71D+B=oRk@_Fi7Gb-jAOJk!Uhd|gcjZZJ z3jeNl>^Jx-tNC%{*$<R_xw(*B+pQ-~q_UYIyPt+Q+&z+w_6|n(`vXxtqGF@T=R>DX ze*egDRbc1AQ^JA3>n;KtCk(sHN$?$T5xdJt@EvdwQ!95D>9664VTsSXL%MT<JfL1Z zlCPh~Xsy?;#~kU?7QGpa@QCE6F2RCA*ayo=2Oe_4{@<rE9y$f=buvKo98qJXm!tj* DwWj`` literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/validation-error.png b/emacs/nxhtml/nxhtml/doc/img/validation-error.png new file mode 100644 index 0000000000000000000000000000000000000000..7682642d9dcdbe6231dbcfd2b39df499bdd41c6f GIT binary patch literal 2293 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 I+AeW_1NZf3XaE2J literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/volga.jpg b/emacs/nxhtml/nxhtml/doc/img/volga.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c11e93cf2467f1ec0eb1ef079b0d42e6cd9299dd GIT binary patch literal 34027 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˗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�(SaIRCe`dy$Ls5nZhdgEuOt9NI+)M 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/img/xml-validation-header.png b/emacs/nxhtml/nxhtml/doc/img/xml-validation-header.png new file mode 100644 index 0000000000000000000000000000000000000000..2093781df3d6cdc57c0a8a4370fab61a8c95fc81 GIT binary patch literal 23172 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/carrow1.gif b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/carrow1.gif new file mode 100644 index 0000000000000000000000000000000000000000..316dea7a64856915da98577cafafd03f8638e125 GIT binary patch literal 243 zcmZ?wbhEHb6k-r#IKsf7t*x!2qr<|&!pzKUWMm{QEv=`g$IZ=cU|?WqXeb~cz{bX= zudmO+!NJMNDIp;tA|fIsCB@6jtEHu-sHn)!&aSMitgEZb#l^+M#H660pr)qA%F4>X zz+h}_3?vnQvH(d21|1LqvXg<eV1as{isQT$>71^U7DZnxZU5MJ+2DNlU$!}S-z7L1 zYB?n`wic+gGO=hXR;p<#HyxT4(xY%E#rX?|I=fuk0UeiWhU~I*9VV8W_a@F=Yx#C3 mb5LEmzqe++lZ30LgOiM%IU~0*ySTXuBcGt&^tp114AuaR_cnk4 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/carrow2.gif b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/carrow2.gif new file mode 100644 index 0000000000000000000000000000000000000000..24a6be117297b04c3ef48eae65fdc48e72399412 GIT binary patch literal 241 zcmZ?wbhEHb6k-r#IKsf7t*x!2qr<|&!pzKUWMm{QEv=`g$IZ=cU|?WqXeb~cz{bX= zudmO+!NJMNDIp;tA|fIsCB@6jtEHu-sHn)!&aSMitgEZb#l^+M#H660pr)qA%F4>X zz+h}_3?vnQvH(d21|1LqvXg-|Z-IKBoa4NVAP%utQtsDNXM0O^>+nyGJ!U1To}kUr zEXu~EXu&4iA$+uQii!u<tH4Ad(=F~NG8pXaT%K(5TkvO<HB*De>SrfhXZ?z8@d$pa k;Z|R*!Xn|<V8$ln=xnDX?!fKRuf!?HH)ZN<B}E2n0Jg?6@Bjb+ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche1.gif b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche1.gif new file mode 100644 index 0000000000000000000000000000000000000000..218233d5415a2e4119376b40c9911245b784400f GIT binary patch literal 1035 zcmV+m1oZnyNk%w1VI}}D0OoxF{r&y=`uYkA3X6-2`T6;Xh=}+1_xt<%<mBY=@bK~R z@#*R5`1ttm@9*{X^|rRQ^78WZ^z`oT?uUnm#Kgqb*47CL2^JO>g@uLQ-rnWq<>%+; ziHV8k=H^>lTjAm1)YR0<%F4aHy~D%9?Ck7;fq|%~s6IYE3kwU~-QD)~_R`YQ-{0Si zjEvaW*xK6K*Vos#x3_tDdCkquw6wHgVPQErIiaDUe}8|juC9WDf+r^@#l^)Q9v<uK z>#(q}e0+Qi3=AnLDUXkjJUl!Y7#L(^WV*V#W@ct-X=zwkSiZi#(b3T@EiKN@&Yqs0 z6B83dLqoZ_xhpFxC@3i6;^G?{8$dunPEJnf=;+JK%hlD@r>Cdt>gsZGaza8vCMG6z zb#;=GlET8m$;ruUYiql^yT`}JoSdAswY6_=Z!Rt_Qc_ac+1VKx85b89mzS5An3#@^ zj**d(+uPfUii)MBrMS4bq@<+${QUm@{r~^~|NsC0|Nj6000000A^8LW004aeEC2ui z044x1000O7fP8|3goTEOf_;jMiinPng^Z1ml#h&+n23v+g#dX60imG>c>sEZlbm{a z1P%%f5)BCu5e5W#r-^->e5(ct3so5@86OA>4GsYSsH%Abd(lBwO;H{|GaCs8xP!Zx ztI*MVC`Cdi9x*To4cxhW-<09w(E=AcUwC9L9SQ`@yynr{V{Z+dB~CJsaB$!qxMu^S zS?Dq3NQf5;A}k9CG2$L5bz+=>u>rzHXW}9XnDBr{1r7cHW)i3p!vhLi5G44=G3CIO zH$muRAoHP5dO#@%O+d7#M}in=j9KwPf{Fm8OzClWh~_{GI&zo^(ME#=2o6*jU_byX z08?H6J4UpCgUb&QS}L$W&>>3~5)u^DB5(jMA+G~Z)G(4nO&A#^IEX=GBFzXUDKauB z-0A33dMMmXxuV2N3lk$=B)j!akDSk+1-zj`giRR?H$+tM0f9j`K|^52z5vDs79=H} zNLjH!fq{mDS_pq?ulVug%bP!M?RmOv+O~1)=Iz@d01nd!h8|t|bn4Z=1+6OZSutbB zkR?;Lj9D}1Li0UEmtA=2#g|`z31&-ST*;RQeI9`&7FlMYr50Om85S3WHAzL4RT*y8 z;D*$(q|{JF&GcZ2L7~WtgB<>3Voou=*vpC@3BW;1FV*;BfF40HfJiQsbP`7~jx*6{ z92U`$(UHz1Nzesr#DNeC3qkiIj^o&aj~)B;!;_6bMpMo?9^A1`JMqO+Ntx4Bb4@ne zw8_yg!3<N(G08yb=0mN#63Z-uwfSczo`51s0HkOL&!IM2l1ikITtca&mR=f(B#Q(B F06QY`?~(uj literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche1.png b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche1.png new file mode 100644 index 0000000000000000000000000000000000000000..61e866057e330e730d5c3fc58841f347bde94b7e GIT binary patch literal 2626 zcmWkwX;f3!7QRC!Ab~&vMhVSD1`!ajpva)PVU_~Mh)8iDAd>?If+M0NKxJqIY7tOS zgQCqtT0>uH)#niAC{QB;BDIW)fg-3NlOcJxKhD|fthM*r-#PpH&ffXlut19bDt!O| zC|iU4c$l@tmJ5l1?Pq=^*<l8k$O+{Dz#XMKzF-_XuRQ7>d31*$;pmANVLZTz6U4?N zTa#lF<9YEhai>zB#CrpPUiVf%PWZ|GSdC7{hQCtiHy=hjz?&Xbhr{f~d`x^3n!4py zF&pg?ppl<Y4U|^|f7C;?xkuKcK%EQMP)oDavhoQYA;x(-#eK$k(?F^-l^xJarlKKk zDfIi<+8cGx7ZG9@IKq$f1)#iq@%<q-NQ|L<A%=ea1g+F}B_X0n89h1jtyZ(x1Ozwf zw9ET(T@sauj{^y$Q8tZ6D>tat!3Q#>ANC>xL@MeSUf@%rhCOg<yVk+SnXb!ApTA$3 zgT=LzOZF#ZK?w;70n~)}_;{d;?C9vI6T2x>*P_RAK`8ILr_V`g^rrdg!Ap-a78_^Z z|K%QmR8Z^)PcPLX?w|$SD4Cp`lrWi0No8dvLKOQ@-vn)udM1j1>$jQ|+X-Zwb0sD8 z3Y%|APc}A-4HqcCX;!dUgU%dI!?o3`SF`DK`lCQUKkpq85n4(?fHYg1<wK@_Mu|}X zj@rW{NbFN)ZLF;~)kfAe(roO+rQ$9|2*ob$aB_0=%%@LU@Dxs6m8teH{r6RVc!Zik z>-duV{M4xb9sikSwt1-8NPjzDtw~EwJ!NlizeJ-erCewv6G@e3a~N@t5Uea*t7=hx zg)w8@k&2DU`mN*Ud>QznCt4twCJKeZ!M?seE%f3gn@Y&{wII&8tw4e8BXXTI3G}ev zw5jh<TcL&V0uz5!c}<~ER7^}vToWC5@62ZFSctZ*vvZlH-V|AwQzihwW}hRAcwzUm zYwVQ}1Zn0cU(vqb=BnIYRaI41UtiDGCy_Mx1c0iAL-y;$m!N&&$U7?$u-c&+9UpHi zVo4N9dRsCUQdSQ{01p35%jI&{^z`&;PN9jJ8DTh6p;~HhX~7HWGVdl5fW^Ivk;>rG zZzNMwQ^RYvT@A5%BU37sqphv2g70#2v>;8xDsB=PYMwPU%@{E*bVz;7c9TIIb*mx# zor!Gds8Cq&C}r4Zqh%oI+8iUjF#z0n&yr6r86544E{4U0kiRqRR;}ovNBz2p(ag__ z9GT^Mc6sUIlZFOMZGZhC{6aT$<K2m%Amv#Y&VGpmika3<PKH9dT{Q!}x!J9{JjJbu zfw9~!_l#C^>Enx^wuKxð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 UWOYJ`4S~Q`|1iH_eE3=a2cqF~I{*Lx literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche2.gif b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche2.gif new file mode 100644 index 0000000000000000000000000000000000000000..dc91f064d0448c25186ca19f0c821dd17fac32af GIT binary patch literal 974 zcmZ?wbhEHbRAVq;c$UTR_U+qm-@g6*`}h9+`<pgx`t|EqY;0_NeEfwA7Y-aaaQ^&x zUS3{4KED0?_y7F)^YG!rA3l8e{{8#=_wVoAx%2z?Z+Ut7j~_pN{rdIUvu9tve0lfo z-NT0uKYjZ2^5shz85tfPo~28dK6&yaC@ARBqetfE=J)R1J96a6*|TR49XfRP?%iwG zuDyBl=J@gBXU?1{C@8pi@#3OIi#j?we0_b5jEpvK-n@JF?)v(AIXStCii(z&mR-Ac z?cKZg)vH%tUS7+VEz{N2-LhrNix)4ZPoF+z%9K5O_B?p-fSa4!&(AM0F>%9&4Q6I$ z&d$y~Jv|K#4F?Y%OixcYHa4!QsmaR9GBh-lm6g49>(-SkSEQw-eSCb{+S-2n_>qy3 z(bUw`-rinYTf2V!`rO>yr%#{WxN##bEiEM_<<zNDfByXW_wOGA1H*qX05T{6ia%Kx z85pt{bU=oH;)H?ye?wMNb5mwpdq-zicUwzq&xDB`Et95BYMwT;r@tqiDNTfR(ISyF zrkQiP($n|^C1nJJq=dx8`O?y-W=&*b6&I3KlvdSLRhAVH+%dgJ+gVRZMU*?^s-BLz zmNEn5=?S}g5-pUx%&%O{NVZbbcfE6OR=XzKrROg^9Q-(#-|zg`mL8%rvyJaABNOMh zufNkh8k*#JxTIWGY?!^jp6OJ@1Pen&`);1g90r0Dm1i}}i5rPLSfb)SMfBlO;SUFv zy3CMI&03VXS;24Wq;njiA67DS&67=z3vs>T!^j?`#IoZ+W5?dvBE@Aw4huusxTV5A za5O2pOj>QXxhVL_0j4%B-T!4ZjfyRve0sh)6`e&#Qnt?TQt+vGpxh=R8L*<}!)b|U zZ3mhiOKvu$wzVJa`75{J;{mP|5rs`QFAbk|O+3>x@ruPq%P%i3Ef1V+vq9<;^T{c? z$<tylFr=UFWDz#&i7<SBPefil>$lmvJG;t1zkB=oIzuBH*N@z{uejDkY)ZShXmj6R zWfgzdg<eauw*LD1=DilD>-#S&et&W>{<w!<{>hnHf1YlcqN=PI%3JyOWk@H3jzkAr z6I0TaLvCu0Gvpif9YP*f3mz+OlVI*lUs(T<$ARC`j&Y(;XJ^A^4z|ZribW+~Zz+DL z(!=n<$3$ZhBb(W+I~~d@d;bWXF*qtSxktN6ch?Fo?R5u~xOKM~+)PoK*I>k@xop8C aFOOXbOv_aJEG(ZXrFK=ODK#=MSOWm%MZM|( literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche2.png b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/fleche2.png new file mode 100644 index 0000000000000000000000000000000000000000..bbf66a19a6d8799b6aa6311112079986a40d7d1e GIT binary patch literal 2889 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 U^+<^h{uc(^op(6hb`T`~4_bQcO8@`> literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/loading-bar-black.gif b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/loading-bar-black.gif new file mode 100644 index 0000000000000000000000000000000000000000..99368d6c6ced24b85d1ffb731d3718dd7b2eb8e3 GIT binary patch literal 10814 zcmb`NXH*mG{<f2lge0IqkN^oFNUtKOprRXa(-hHdLAs%b9(w3$gx;n1BE2e7L@|I= z0a1Dny$Xm8u<*h@?Z4iy=gg;B^JQkun&+D9zJHIFj;8V@^C<u);0xgRI6OR5RaG@G zFtD(&(A3n_)z!Ut@uHZR*yYQYrKF_JoH-*PAb>`r_4M@A)zwib6cUL%fBrlxD=Pwl zke8Q-!C=bD%5rjY?Ck6k5)vvZD);Z-heDxdW@b1XPUtt+EpsbtK?@&2HG6Y{u8X;q zoSn0c3qWWe3_u*+UFeWSPvic*>uPs26y)TYfJc{Pj-TrI`2dhZLBVJ%yDVI3rQ=33 zUgn*L(=4HK+kg9zo`cs0!=Tgxw{FMF*#pHMH!6&(#>%}ev)6(ll(roS3Ufw{@6>d| zZ0DD>U)p2am`1`jZs8-&-!Cx8mrNzl974UrDV{+-?lEx~5*Zpvj82UWPVm6mK+L2~ zt&m(i2t-~b2vdN5273;}SmB+Y*44oqU%Y%(Psg{udi|n_t?hYtPiJ%ci@rBKHNAcB zTE^QZJEpq^t6O<WU`#S#C>+7UdV-w=!d&tV$<6kO{pZimU%&6HZH&f{iik|`o-2g2 zLTVHM$Ch8$Kvo->3!?XiXJB44i1%}V2~W+Ob|^pRp$RpFM7#{#f=w7|BqS0coNnvA z@(GFW^p(ArH}^S<2Xa@!XH+heR^L6*$~>S--7oFSd600e{l#GE`(mRax8b!!`-jQW zFg^o-+KQ|Z{+?mV&Cyn}7v8qJ;>vetvsYYu-`dl?&pvt`bYfJ)M7bK<;mUtnjL)#z zw5RseU~q=vu0=0Vc2=WIU6uknC9@-Q!-3L&vieH-@5yz~&G8`9&gNI7uQJn3*53<H z_$zI_Z1?$5$#1f^yI3957QB_w@Nu=x{n5kebPvQ}u`Jc8kG{J%y9CJ|jm2(Gef`*% z9a9w;=-a$A9Z`QayW#iGUrSz(OjigYAi^npNBE>o^*KNqh}Dac<HDiWWfaV2p`8ov z(@7Bu=`%EVOyef=WQ6_^r<@noWQb$H8ESw8m!S&}2Ji8Dq?kvIOD0;nU-^wQiBVoB zEZkR@(z1*n<G15X7_RBaPvFt*?uig%y~6_D8`zr#nn8<)lFdgRiUneC=oF?|I1d*Z zxR`ORJj5M5?nhwH4<HhmLp2x40oT5XQ%QOqw)V87&{f+I!~`x+TJFVo&Yt$=vHVD> z_2OGk7-4TvIkcnGf+Tw>F4I%F>!sy&>+5CJ9a0<RwIlW$72?#RPyg>F0Q~R2_s-5w z5-b;2ft}{~>S+qdH*2|en&z+4ayy5U&%w#Zm(3p&7)qkJoMfVfgxN=W`vtfsL<I+A zM7U6sLIX&ID8JAkBH7U=8j=z3MX88M&UeVhL;qd~0({3Sp#zP9LfAmIxVLE7hrw=K ze_+$#1RUyaJH|FKIOWm*cK*X~zx&GSB4)IEZgtor@Z<dA#=Fn^(<8+@c4f?X3f=XP z0g)jB+T_7Z2JA3>b07uEt{^9Y$EHwYPM^m1YP+>in7C9A#bB4>MZi#+3i+kr2W!m~ z>8s1-cAU$dj|D|{JnWt>yvvl;nP)wSv$-23t_I>d_+qV_h|HL%m3q*6qvC450>qC4 z2n-XrC?j|&S2o+Cy}+EkI;X<49vQion3S_cW%b@)y&x8~HQU4sX4A}}%QNUc+`{ty z4Nmi2ewZH>D&|XAh`-VwdKnD&xxPd$+rpoFRrasY62jkP48J{s**;{)SAW|AgE8#5 zP}B)EG6EGZ?&6TKhi~pmlztSey0<gWlP8^xB^`WTL0r3$okjQgw6Ktx?0xcT!1u3j zCU3fI{Ax1!_+jG@TNRmK;9u=Rf;0ZFTk0Qq{az{r9Rj)K*?|z0fqohkK^!$O=C|rH zwcs)n?+fO&Uo{FI>3*&T74i}ka(vI@ZV@hR^e_W-mew!_<wtb#gkCg?1xBATQ!<G< z<3?ch!e9+VVt-tCED|Z)(;yrt<wY0rlat~#XXcPd0RfqnVdie9`S)`HtdUwaRswo; z#5C07ar20PanZ~S^)m@#q}nCiRJy-K-Dy+&eB+}`Ct2>I9FMKW={yCm;-t(TUf*eG z^o%6Qr)WQ!m@Gk*v~gplYo&msC6g^m)X6p(UTCj7QW4)vO6UD3kV`p`GBnJHQ0*1V z=P85!{8zZpQ{POp&NI>ucJUu494ZGc{n$LT?YMz;pgohLm4drY{wVp={MxE;ZKuEX zQdHrkOTfr$3OaL-w<nb6ZPD7QPiSy#b$QrVIYV8W^HBedn2#Sq^ImBRxJLq5SY&vi zw<o$pqi0a8OEFB@r8VswjznOwIIG|Zu#-6+P*JR)x|SxBZzy3yZPc;rkxt()3X&RJ zFZ6RO{ISx<|AiG}slbWzsHB!Qdi34;1ATso=&aN-=&Mmt0^+CuKs7lZPkcIe(5f>% z7Flt=Fwb_OY<q&^_vqO=Bp={=6DwBcixxhi^m~atCvIwN{M#>qxw&!Ky(zy7_epaW zgB5!OpB1CI$%uDL5u@6UbNeefA#w-k)q;EPH8_fkDi7An>$eUzsypR=Y}Sqjs>A+? z3($X$ix6fz0_-C03vmI@Gx1SP=+>k96NGw|IMvUbe2xSPl!*-!U`NEeP-p>Rp`@rt zzc_n77w2fUApevoDlIgNnCk2u3<=9}OwY^Awj))g`xRt6Ja*y}IEg*_bvp1tco1D^ z#1S$;wjK~R*w7FH);AE_H#j`phq0afFf$B?;s$WmOG6BgfX$iFm5ETy;%C@OxZVEJ z_9|mTKRUbN{4OGog*z%oiSm7(H}(#&1%LuWl_juPH71y#+7UNY$=wM^fkS^*$z3%a zI2@aHzZ)q+VdlD%_EPoP@~v<M%R-axT^qejl`xvg4&5p^<y^uD76183f0jl%=&Iy! z(MS&R#ZxQ9eVjqLP+8uo(s(r{FjyWXodaB?HhJ&!J);3AL<r%N4TG|Y2Kllmfcw*P zcCOPSn3XiW_I765eMFTnCM&z?c0T3===1F<TK98mFI;d+Nn33y6=yHZ*mT((Do-|~ z@e!(*2P=haiR|7GpbA|6HoXw2=I+iVqs{j6HpR0Uo_90*nz<Ti<DIEPy*$bP`_YXs z{mq$vUpEHonZIQ<r-2f7`yP5n2dI4A{@Fe{W4isxGdsxJkimcGpIFm5ZOWq1z(#H_ z!J7ct?_dQSqfBj6K%l8%HJ@syYF$DXb*v?noC=%0z~dO(68@^Oct$}`Pt`I){BFK( z^!a$(7VPNM*eLW&ymCR**`5Z=u&es0{Ad|<-mD9H`l)GAAuXXIQ8G64r4YS%C5vE5 zb~*{nfm6<eh`kCm@LO(|%*A=kSQq*Byi7Wsfh3BrLRq`&(`<GOLslqHg?yLtXj^u( z)>AsRcVjkWV;}i=Wi>=*$3dlVcpnfVD+VEQXO)7>QzbI7)^<;mYu|HDhhNd$%Y~jZ z1T2TMdhAUp>_On0Ry``60+qr>?B$-LR4)f+7wCrFp}E+(h>d4|SV)uVI-SL`sv6Wo zH?MQy9GuOIWQ{AIC208ZXf(KuuEW9XQqqrK80M=ci8xEjDF9d`#h^VNJ|c+(Ssz^m zv%9=j`S6?jq7moQ^vBI1pPR}aDeCKFg(++PaOt|>T&Ei;q2wp;WRRD^c)N?7QgHm9 zCJ(s4E`kF>nXxa7eP|%rFW1sO?7I&X1t1Kb+|;@xo{t3o%7X^+N@c$PRk&B{W2{&q zP;%#ykwI&0v*Gie5;56=EZurq?Z{uxZh94PR{%P+IB^YtZuZ*-QcOhe?lQ15baT4x zmrXK(+@c^Ls}ZJjbMIW6z}9j(T*Z+v9CMTVl15V(@fyP?eiHqHj3LZC(MfkvdNCcH z-K-qlqram}edkYlgQ7E^{kijo+ePJAM1Jn}DsBJ#JfL;<*O#G(F2BD1M?{$Z2V}98 z-#G<N_c-Ws<>ABc<>XYdP0(IWp1WPZNrdz9`2_m}cm_K81^csM0`18JR~II>IIjpA zG=OC9?VOQC3S`2&<YmUhW*227rKH9Ze0`HEh_#RLeAaBXGN#@x5Jcw@SdPeo3p)bK zAPh0s7ZhvverUQ67Z^7+JqpFV3tCtli=X^3Gy>b4+nW9aU!JgsZZGb6{y6Y#W7dm* zL0TSoGN)B(qV@;d)O}TXB7}60jV@25*DR1h%p#$DK67f6XaSbPP+dWiH921VFLi?* zY{9J*1>0-I15b;<847k2Ch$|Dlr%1raGCX*<$+`|cY#E@yU0+AMDRDOeZ|t=e3eGI zuW4V^x)PCf=Ws+KQR5^8sZEj3b)IIGS!iz)#F9*#2%>!HC>P4?YtPRe`ALkOSvsY{ zP%%=uhS5HJpih$-Pop*SN=er-qtDp}1ztbok76a+42CB@__4{egL5enYA{t3%%%2l zE(#4Ws>l$QP;L<eO#&La&>1)Spx<Bc3;cul9r4O!dyh3#U4mbr%D&rtAE(K?N`Hd; ziJ51&Z!?-P`>S3hO7(@!{?iKwAGx!AhHo*=dU9?Ssvo+n{3$pKCUn>FKry-lK(D&) z5x!v5Z)-K`s;8JLl>1r|k=ny|&peDbFIiVX*esOKO;A7oVI+@0atpNQesXWPz*cdt znd-F;%j<kk38P_C)7lmx-k-YoRk+T0=aMDA=o6u*7$JN&g=X65-d?0I0ZW!xJ6?Cm zo&+18_hGfY8E+ls3;j`DYx4^5sj!sP;*!)NFl6`pa!}Wr;fXZ7g@kR)Q{KX5u<yZ` zcxo7OJummS=-vnuhlivoGi%1!_<0r29Q&|2*&=RNnG*ZC(kJ@KdD>5nRHYNpXL4pr z73^0^qlOD6)bc0!700URW~&YgJpvSmX9a2YF^4rz`$ruv+y|y-mrzcOek|pY;vUcI zI0z9%fblu1#rY!*La_{ZW6A}cWtdP*(V5uopdV7{kx`h~l#P&|TSclZqCMzbE9$4O zR$kwbP}w%GH3@60Kd#w{K&uW|3L^RM^WE;0`G9k>MLz19e<98)&tW>Y7TyAMoERG| zP+C#BWjU+i?cNY4VDuS$HAH!;pH0lE2Ba$-{snm5h|{x=pY`g}J582b7Zl>pohX7_ z-*}=sG@f{?e|Ra8zp~2Zz*bE|n&|ogoF_+jNr(NUmQ)K)rm#LRwNO6Yg%&VS&g&66 zSp#N1CE&Oq)G9?P9^XeRk13rsGh2AChq|N{I7X`6ypS(!<ixlrwZpmme(hs}RjlQ2 zS?Jlj&(zj~;0y?hmZQ+$Wcm52>*0~L{C{K_vkm&UwSfN@Y@ti~A<}DouP-al>;Qc; z#W1WVRRVX$M1B*!yuE$g?BRiMCKpO1EhI1k?+f+!2(qS76WM|s!uisuZp6^Igf#yr zVX0BxF?K}fNZ*sCS@u?VYd*+v-uGf-gR&veUFf%%j#&5+TaM5&*cVV3_<m#>-d`Bn zF+DOCJGM9qt*IIKFf_w(nA#bcoe2A~IGen+2K%117BL#q-{8^5F0_7+*hT`%z+}#N z3AHdCg&cd6I}9Q<Mo`pbsG%l-3Ksw4(8y6$L6`y(x)*LWzAJj;u{fs*&-hUQiY0nk zl-nW2yO_`GDD1(JD?Lf<NuXcP6z#gxRehu`jNcc(TYU3s-WTEAR49nU??JgBwuM@c z7yntJbmIDC1O6|)GMjg@W{vRQ)9vZz&KH^y(1lEgTO`YNJPWf|B-YU4b%dzLLOQ_R z>eZUy%J8N^o7sC##7$LA+3}^<rGw)d0N_UiXyd;Ao&&Ij76kV?G-Xebqa#o<Z=S32 z?Kv;GrVCd_@Lm40{51G%r`he6PWZsA!dbJvFP~m>Hf(>D6S`!!=0R!m%+69#*`CPf z&bHbA0iKj%pfXHXt*e37QKI_TL(pUXZ)0vQysKm8mGC<Z(i6#iK}Tl&4m9Y<P)Kfb zI-v{&bg1?j4`iCHStxHWw|R*Fu;`hP3zgo&<~$>-W6&VaJ3QnO`dCX42QMCI%+kPY z%6$4SN{Tn@fD-yrxAq-tf{R9&uFw5S?RhPUq(&eUyB@o>wT&+{3*un(Oc!Jvt^|CX z_OX3Ab>490NrvPLjXZ*tn5BT~EjP(z@Y@}wTef<w&utVOKft+(l8g~8zuR5|K&FIS z`*B6{K8SU*ke(IElI(ab$<TKd2PoImC_`Y$oR0Tc{xHegwv6+#a%p*?0#CVRTcy#a z&5$;JBkpraCpYw6vu*ide&^i5MoH7|jnjn^I3ob~cE9p8Rca!20?M;$w-DOg9}0{U z+%k~6@mNoKKCU~ibhPr1W{uLu(8eS=6D{ayTJyQ)wUV$39k@s|M}9i+^#EGADj!(Z zwAInM<tNF)q>Uwl0(O6hlbsCVGuctkGp2g+0>skCM&ERBS=hT_0?><RGepx|S|MM2 zm46JoxM{6~lAgGzGk;0mQOU#&q4;F2gURz;wsDzjKX>gfoV=9{VXpwt!0fuJq=ee$ z3CF5NG5NE@d#{{ip>lV%NMmnEk)MI5c32)VIBazq@<_JI-)HqN&g6JUOzzvoZ0M*q zv^|@UT}n=See0PbBxmNA&uZjkK=G_A91uC7?I?5{a-4sBY&cFoFTZd7*#4Kb9I-|G zKOBMl_Z*3~rAuCU6CCCHO6bZAzF+W_-q<A<%Jsu#l})0(6_o1d;*Nobg~KWSzR=LH zgeXERHIB_QGAY=fDJ?xQ#s6fEmwjY(fo)J^DPLAfJkcwf=I0*ns73e(O57=ImB%RQ z?S)~wABRDDU?Zagxe@U0(V6j*gz1@)fw_{Q#ijQV_T7l}fhNzPoyDo#V$9knX!;=A zkPuy5HeJ=-aWhhwS??Z@2??zhWRNB(EJT5SI12Nzqe!Y*YQ+SJ9Eu3~v@GhtSOp?Y zF72vOlI8D}7L2<syiGX+40H7Pyrh*TauanGeqZ!vvaa=3K`LFWKVL_~=$EAD%0R_m z*Tp9GiS$3QJm-qJs<GtBdd|(_Haco+GV$BX;pZ4768#lkvFmwJjy$%(jpLMAA*0&3 z1<p7}8EufAO&r<1_Kc6`nNnK@$4!GI!|T?~uA&kbo!)%{x0F_y7vIU<{4?kbO9a)y zoE&Tm^8RefZkS0$ybR!Ei=L_sUJ8HJ=Qa65_KU*{QIYKGjOyoWE`EQUt!$Ze9U5gZ zzVgSEi`ih4?EUXoW8FL;tsm91Gp08YAgIV4pdCC%EX6lmRt#|X2*szJdX>jf)ztQJ zjeZK%-@3ZRqL0UhK`XExNpbPA!^J4V{#2d=^LyY0K}#)!x$qbg;g*l^W!p1e5l*pc zG>pY}ewwrAoqU_CHjHcpz)W5+kTtd|&zKNqpobd@^AINewJRELr=XBP2knNfj3oD+ zR}_mv<)kjFnjVN{C5_}XkgQ+vrW$!jJQbY{&uZyP1OKJ3w1PW_cp>KE)Pc%Raq3%{ zOpb3i7>$<%NDM<JYQ`)gSWhKmy@moN)QW}7+^34}84;yYo<5+LdIt6dXB13v6^;A& ztm|a>M$Cz;MP!lDhSlS#2X@7&QEAyO9T(FX&xSsVPajrf9dtOF73dKq5dc)qaE!0O zJ|p&gvrT>|VlQ+f+PE%V%~SJY1IdVLs$2zmGZE1eu$r`yPCHacS~T`W&|ESPdbG-4 z1kZJ)#i+(Z9h(MdTJn))7kV)*En?a=^)jr2BmnbXchzGgUu;e&Rcv(C_Qkn7%h{Y* zJh45pL^so4_NM+AvGNvstsM#(?w*u?6_?h-|MQZ2IU>?f%;fT92oUFXgTJ;VSl0gG z+YhE;?w(ePj(uh*?OG5IvRI8Y)DyN|?$v;-uLd!R;Q^43ztVBxT)na-Gmx`lAEsUg zmnKEN_{FcB5`L4eY!VtHCByLPSs~2Fy_2n0nc=u@u-E6jc2&whUMY+Ida)O}2L`cz zzKAqlto*U{H%IP!{PpHI{Ty?o>R;(6n;rDeItBV)10@*L(k6MO|Kx4+HfI+oU#)Of zU^OQ}Wm-^)Rlo=1W9{#68|XzK!(IGN(t;x6$u`iW*syqCzF=Iaw-4Mk$?as2cSK%H za!65lIKHePG&jD6mR#hF(X!?<H<M<{%U~n=K-tho&FfoCH~GV{oQ#ga;P0PzkB?0f zKRAL$W?=(fIcqDc-QiA4A19r|hd)CjiodT69DG}DR!bL&nytrgjD2;-77>B)qxMza zdQ)8h4*x$uIhD#FcSH*S52Hlv+=Oo&0R?Lk_G$5L3J+&_?-)b0*YdJ$+UEYQ@U2YQ zfDYChcU$jdpFSJC2!F7wr@|JRXLUz#rKd=Vg>N7=g!l#sm9a30I4(~(=X)}VE9szm z{EA-JozX4hSFWB}Z7eC3R0jmI{uc|+Z3_q*$vN^?sYL+-6Hy%5P&QudbK4itj5Gw| z8p(=Udj7su{ljBN2`egB9Rjy`$j(!(R$$@5HE)z6KSi$dLXw%xVgZf2^RB5^vW+t? zEjuFO*^1;cJ(d?+SG-<l@u+<I%$cIprf=40w)R>mJ!tmlg#C$$CFlAqLr<^o^M-Y4 zR*fa9M{njnVEoV;bgE<2G)Bz^?df`T&)9|&l+*%c7ppU(pv9^gMBck%XZ(=Pu_PLw z93?N@)pI~Cn9qXIOGePO4Ws&%Klg^ueQXz^ajYwk(w+#R#-Zl~y7NQO*gIGRvsn&< zjFBHGFzGhOWkU_`;>M!-x{5@xrkWkBDXgmECT<Q2399J_?GSOrYhr+8Nc*SMW#6}} zm!=|J1eWKckc-bVvuQJ(HiY&tYF{p9QG+iVMc=p1Ny-yn%YCOC)=JW!PRxib?&(r> z=eQw8f|MXfr<IEI<QD?PKNtaXfqL~OmE%Nl%PI~tVaHPb@`=)#rZefAVHIi2(xpAV zA@oE4HzoF|rkz=~E#=|A#Mj}>UcoJ<Ai&z9<=IlqM68*Z&0^E222Cik{)4tz94~9r zH0|P6dj5;Uy0LY7U8O^I$fb#%ve+lnqw*1(H$toNZ3wZsSKtlImZem*Ln{CY!>d9F zOUA3sspp`kh4~syfWlU5UjU6s%*ed}S?(noXnS{Mk{GvUBHpX)P^Zf5?<;L*{4nj} zGc$QhuPsaW550<EVQV_i`$orj>fX8s_)c3WY8|nJ=K-D$JgfEaQTtd=y9xb|n@22p z9sa6%#(&V;v!NRjJu}S|_>eT`CC-kg27jNHf)XbuJba^1^EEQQl|uKH+#X#OJhw!% zd{H{fWAP^m&{7`t2KCSO)%nVCb@ET3{6|dwQ=KsX_Y@(wF?jKOxbuzGc1=n)UoKrG zh-~e>8IQfVchw6+AoKD0+Xs=n$-Xp8yOW-9awMJ>7#kl+unDmYjQ63&riN4eLIR;_ zK2fFFWnK{xe$_c_E+9CY^)W->Q0&R46bKs{4eRN_v^`FMcfp27V688F*oH=jTOT_e zdC7R9)8c4rg7X5~%<RCkciTG~^N-g?zDJM`K5c@2U*FN4Oegswcw&zm6LTbOE>88Y z*5etDy~z$kwH<uw>`}b=q^1EE6g>=mqm2YHC5TH$J9eKFZGWt&)2s`BYO5E;ittz2 zS6q0TD-@w#%zN+2hn&;fIsQg;oAyN6Wb{o{`q3<c|6HgBF?WIn;rvjViSJA!+hgBX zX2#}LOxlAM`=7ILlgKaK2g&zUQ_2lrIWRj2nj{I%*LsS+w2u5<gN2Wv9-ibI-(GAZ zjf>r>PLVgKyKh9-(ag`SKQBFZzgRGL0|8?8(g}2Mx(;FCB(iiu*?{eI6iP%wZq9q> zc~9y?ZD|$4mnN&CGRQR{U-Ox#jV=%So2p$`=9|t|efveg?rtV$vhlzAVsT<?uuZ(L z>5`jcp(K&yB*iXBS1*uk%RU6;T34$P-)3m?JLV^L&O*C}ttSGIZr=o{mDYPg=6yJ# zkZoBFGdGRj129SX-W}2c<;~GXD{@HT^9U$q9xOSiZ#a+kslve0o(rUdMSxG;1BUI2 z(uolchN>Jc2z$XLs=X<1F4?%>`iYfjd=eeBW+-nH*5^nEBqvK!7A$NLw&EJQiK}9X z?<x$VY@%I@Z14p2HCCo!xE4orP}*K$8YTKtk$>@%5ZipTOc)60X)>PTC`(I2`2brV zkcy{FS56ea`>T`g>nzF0GLmhU%8cb7L$H<AE~gb3p9+@REGw)LF9WyIZfwSM8pW1Z zWwkRSJ=<E>A0A%lYm_jlcpLCAs!;sA<S8iQ{i=}5DALB+Uf8#8?8W4Mv0>wd-Brty z^^u#o!B0M>=tnrl8Os>%=mGGcinvw7me>}Ub+ZG%2`Y$tghk#ozwc%W_&0j<Olua2 zxf0H#El3A)!DN7G4~&Q{!1udJ5A*C^{ai37U!ElOJ?W0LDWKl?wip%td~+9w(W_HP zw%^rFEte6$5$D*hZfb3GFBy%?wl^#JYB;HO;AUx++U=J3@TrZ>b!j5$ZqHMJJDFu4 z$wj7PRd-KVftc^?2z2$PbkxkcON!&WkYA?l@vM&c1_qM-w@amP9k<WhC}!=-q&PNo z24oDzhrKc%UuI2+8&9mXnYo(2u2hf@n#lsZu07&O!^%Ij<d`S_u1@}~CI8_G?0><N zJ3Fj=xZ0LENynKT;m&inuRvp{f!U0qPAG|h@uLO=k;rVc$UsXk?+7?8A&?Y%lz5mz zlL`J*Omr+XH5hK|Ky)bdPjU!*;*$^@T@&u=3t_VQ8z&$n+sQPSBcQ<0eSH{cZY`$! zDCWRg(tL);MkesJ(=#oRF7So1rMa#noV@q_ur|6exVp8yw3`dsUwp3~oW~q9dx;DS z=RM{L&>V4!ry)m+tN~9ztB!TKs*#vboF*@KRE0aESOgA<Z+P6UcPC(YRT{JvTW+Q( zI9Q0-?OOH3%5d&b;Vr@gvDeKD!IH?ezJyD5M!E=3v5s(Lv0J3n1L+<^I86Cej_NXm zm503`O5*RjL{ax?Ap=dT!!Lxt)c>A7`O;;@$T)q+#jFu?ru0b!_YOD?eWvjFH+uEV z37ClS-~dlGqigi?Mq*Aw73e))TqC-e=PS4oxk=W;?pI8)a7k&iH<9Tih&NYRnS6`- zr+L)VS8p{{svs;ZNSWKJQ-qn-!Lrjz(V5P#mOE!P&;H`y`MlN2r9BX6>bv{`alYJ} zbvoeZZghTCG@nniXTw<gC^zWyC8ZWZ{HNoYFcMb{g!WH`sDYwiB>^1XR@bQ!d=pWR ztT1SahkyPYzF-cGjtZSq5DzB^h4uY;>I_!cw=)ui@lv(4IK6ve!JJzm!Q2M(+tviC z(psz!l4u?#MQdBES_c0WSWF~K%BO_HkHF|e9~8EhH)y=!>m%$58<b`0@-1SVqSc4x z3|E&{US2a>TB;2-Bh_xo-T8&Bt!>bH<2cdnjCY2%{6z{ec~W+Qp`f0$&zJMg5NvzZ z#ut?yi^d+2rQ4u@ZngekXEDKLxD%aMy1w_wd$HP^uVVXLGItqkLr4^e>kf>&s(F`d zv-0vcDHEICiWlqPo-|aPMnCdL>7m8YgCAD49<tX>UHb)ArOPKPdYm5RWvK!Lkk|q4 z&|3mYDc<M~%qV3C9-9A3tGP?YRHN0}6ttBD-A+X<H%-{_8g#CMb#64Ny)4)F$tH3Z zr7WiXI9aw}xwTbq)yDRkw(TdTu(s2=CzoCcryolSL^>8%_U>p-?9<EW&h4*q3s)?= ze70Azuyf4>7#7LvwFXvY>5?fJF*T~S`LzF2d`R)x#jnW~b!bmtjE8Rt#F7mr=|)_4 z91Tzk`S=a{{lc-NyjPJ8)_j3DZ3>x}ac*(2_){$qJR9l+31LEIHc6Cu10b3wv$kiV zZqwHn%x=GJpm%&V!mD@1-;+~bsp?U>H1F_NkI6DI?^+Hx;SX7}`NgY@x6?<%<A2p9 z$L-1gi8=om^8BYgf&VYCvLnH!99=8)ap%;<oxSDWN<V?Hmx0k2_YRo|aEuR?FCZw8 zL<y#Zcsi1(QScZ?BKdJlkR>!C5)b!C4o^);40W)}_Khw{De?^oBf5ZmtT9Io?2)5@ zj&_>7_M>7!=$;-J3<IUUr#AHs_r3E?9UAF-oty9iG&K#S%+4*qW<J2X*4p1kLfF>E zK7IVWy)^5yzwmAIr>ikH;`CJq9+6EnoeYqNu<!^TPm0?kkOJrbp71a;BTahiYJ@vu zkbfQ)))Lh6b)s2SEncqfiuNSJkv1}R3WZ(SaO2(0Rd<oTT=7qltVV;2o#C3^%~XaW zn`Z7k%l=wr9F77-6FG1asz9b_3OiOcM^$a$@313ymvo^X#OTkARTG)C=Q*`FjTzlG zYI0=eyg1ccfqmt-QCaaV1^)={oNlMh>QkwGA`~MXEi<=0+Y@oFUL(?X%ldhahIh1| zVe1$d_@oR`zGb`#!6^ggp7Co_hM<;=1S_|c=4Rj-EaFEa<1Yh_!H`*pX^(|P*W}LU zGj*;?3~Kk}gK9(mgPjG=>epqN)tA5RJ$s$)aP{KS!DRc&$g!pXnK)FdNr#pnpNrDn z1FZG4DC|9>D8*B)T9f4cnkRH9uR({9q5!#A=n;!W4yyy3kxj0RsCom|FDig%-i)_k zZ&X1H8k%R^yTfC_%-@x`;Qu&4+klyatcgWH&)_)1^3LV(x!xm><N)-MHXMGxO9r3B zWZN0u0{Mn1sWBT?7WYCep<`kxXc0QyW9WHfBoyylwETFi<Qb7bSPvsAcpXS4Yos~R zR&xk)$<`M_J0u^bqE*7kBo<gwsvZ2ks)#?o{7&A5GyB>FCH-+m_8tO(Av49Frk7BJ z{7QsFRDFkrw8!HBabR3ybB}{Dio>{|vMd-?`t;4y9(_uy#D?@?S+0<@8h*fHGO|#7 zQOp1m>NKJsQ|ZdH(Wp>~!Ze8sgz>+;)^o)v@{E~sZj=M6(cGu#(~pg~<%^+}RUSIk z7EzeJ_3apLg_mN{d?5d=Shk}=i-qaU7rJ~Iq;SklMBFM3dZtao)Z|fr`l#FMI#vVg zLD_IaO2!E-Q}yj0)J!(BHcl=%{Aqcb9obNaFG(v~^L)21lZoii#j;?l4?W$%EkJ#j zjsXOg3Vv$II8h}1VchA8$!peLo<i+Y1<8Z<tsQ;SQy#+J#OWbJZl39NZT9a~fmQWc z@~&n3Qcx1fYh%Wt^ZR%IF1TEM_!l+3Vn`u0$x8jyoq7}Ll?|aCz*($tP5ZyLn&@e8 aYYZK?u>aJQe_#bJ1OQw)-jezE@&5qc1_0Rr literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/open.gif b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/open.gif new file mode 100644 index 0000000000000000000000000000000000000000..d145e6687104015a07a607c5550f1144ec51032e GIT binary patch literal 489 zcmZ?wbhEHblw#0gxN5+VmX`MO=TClq{&nltadLA0`SYixrA1Lu@ywYsU0q$@zI{_s zQK_h?Sg~Tov}w~meE87Y+w1M^9TgQ79v<%J=T}rz^!)jAHa0e0U0n$Y2{}2r<mBY@ z=g+TRy?XE7y+T4l2?+@sH*UOr`?j>SbZl&_v9a;YnKQMtw6<^G-q_gK-rj!Tz=4Mk zA5NY;`Tzg_3=9kq638GDDE?$&WMD90&;h9j`H6w;zr&0IjS|Uzk3~V9IcC#+mS5q} zm1Cak`SPokuT<j`p_`Ef=btls*|->8_)y&Sw(oX4&&R@o{rr6f;c2yn+=;%tE#<s^ zLS1D-e(e2)?0(`?3dH?bW@fPXNz6-^@KabEqvEHyLciXZb@DuA)&_UA#kviRZj6#M zCEN9K-8g4z?GDr9XX<C-KY2>JU;5%H?S8pyd-PbPTBNpyB)f^Wh~7R`Q@j3ffV)nM z(#t!HEnHvj$d@zyydzSs@xyx20fvTV4&DdS;ZHl7t@+rb953+nF|Y{5N^G92pxoY- x!BTL7;~`&5kDh>pPsc@hb8#^x0R@4BOtZC4E!%O})8)Az+dSK)4|tdutO4;=vO)j= literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/open.png b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/img/open.png new file mode 100644 index 0000000000000000000000000000000000000000..aebf4989a8a6873eb2eed6d64f1f1d6944ea8e0c GIT binary patch literal 1258 zcmV<G1Qq*<P)<h;3K|Lk000e1NJLTq000^Q001fo1^@s6tuRYt00004XF*Lt006JZ zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$d`Uz>RCwBA z{Qv(y0|CGb#JWJN2*kobECUsP3B)ge_&yL{1>%qR3;_rrMm!eD0&xJ8CI&nP;!QyO z5St`G0O7L86^h9LTY>l>x*$LRVY4U^h&5rHuV241PntAIWz(ijYR{iP7kv2ep*Tof zQd07*yuAEtFE6j#MMXuoxw*OjBAIash?gK63J^dHAd8T2A`o}Ma9dm3MiCK_cR+Rj z@nK<M;SW=$Oj(Vr7it#VY=8hlw!{TlVQ_Hp2|^a2<LKz<BWRYnz|02-Aebexlv)DA zAiZdofy`zA2p}eC2nN7{va730b?w@<=42)W29REm8Aw84vjGAKlo<GdbTusE6%-T_ z-@JJv$Up%A#_RhB4<5`%N+7KO0R-}q7ED23U!N+amVf}r43Jq!LRtU;1hPm0#@n%D zhYACg0Ge3}009KDNFK(!dGn?ewJbt2OCBJAKo;@CcppA|;Gvd9XlC&P1Q5uge=r^s z6VrccS%hZRKY#!NS@agh6BQMGPc4hk%z6tDKp=~rz<8>vsxPT!k&=?qD<tkSfB*tn z^Z>^5^Ygn+EsK18eUZ(&4-i1049f*%G=O-&e*I#Ul9Eb&`}QqAC6)*X2z+_@^5qOR zHa1v1H39?>$VcB`l@&-LK0f{=rM`)cjXjBE3CQfP009K6k3e}T8&(VfeU<*{(<g3n zEaBth`}*wJvzbW6&kP{G2M|C^NVbBiVg`_cu&}T*<oYHkDCjJbB_K2JffxV*gj~ad zii|XH5_$HFU0GQ<{l||V?4(%2!NKwK?%lgHfg$n}Dl`j-?|>Kp0mOu)?hdq7!vIof zWo31XRNsK~AX)MPW(f!Y1P~LN+CxYYdX-d*A|oTOVKWN^00IcTaRRcq1D4b!BqY+_ zzkkn1j3t7Cf}dWzcrgnpwN(N!yuktxK<GaDhn&=HZEcATK9E|pB#qoEVgLvrCM<g3 zZ8B?X>nFrogr*jwT?Y_A*err;aB*>YNrFXhkhss$<pBZ+n?;{t40Uz&uf$rUt*!kT ziTep%9w30QS@aiLEP*pG7Z=wLV)75LeES3Cg4F*;R|610OgQvDK=KvAc+%9=e2iRD zV^aeVK)4$D_CV|nt&&;t^72f8r3Kbx4$PpRfNk?LNIt^a$Oi}@795WJ1!FWcH0Uf| zyx10>kA#GTeoUA!;R3o|WB?FAxPtB(+-vss&p~m3FMdF3u<1nx00D%{B6wSG+qP}; z_zG8$97qi|y~qF{fCwfAVD<ihkdHuWu<1nx00D%{BDf2;Y}q15$VVVG*z_U;fB?dk z>OlS0To`Bl`t{;KtcafSKq)RTFz`MQBbOkPVU;K{00<y_o#ikfHi2=jU%$=`tOh); zUAqQ$y_S~Nqvgw&?*Qf@<kACFGq1vC7(f6q66pRLgKB3WW+jkkK_$UDAU=yr0YCsT z5;4vI>VAZPsvI2hpcd&GAjaD!1PCBvECMGkAhv|ID-@7Y7pST}4lUpC0)PMm0Cf`+ Ud;!mb^8f$<07*qoM6N<$g4OE=egFUf literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/jd.gallery.css b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/jd.gallery.css new file mode 100644 index 0000000..b0d87ec --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/jd.gallery.css @@ -0,0 +1,238 @@ +#myGallery +{ + width: 460px; + height: 345px; + z-index:5; + display: none; + border: 1px solid #000; +} + +.jdGallery +{ + overflow: hidden; + position: relative; +} + +.jdGallery img +{ + border: 0; + margin: 0; +} + +.jdGallery .slideElement +{ + width: 100%; + height: 100%; + background-color: #000; + background-repeat: no-repeat; +} + +.jdGallery .loadingElement +{ + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + background-color: #000; + background-repeat: no-repeat; + background-position: center center; + background-image: url('img/loading-bar-black.gif'); +} + +.jdGallery .slideInfoZone +{ + position: absolute; + z-index: 10; + width: 100%; + margin: 0px; + left: 0; + bottom: 0; + height: 40px; + background: #333; + color: #fff; + text-indent: 0; + overflow: hidden; +} + +* html .jdGallery .slideInfoZone +{ + bottom: -1px; +} + +.jdGallery .slideInfoZone h2 +{ + padding: 0; + font-size: 80%; + margin: 0; + margin: 2px 5px; + font-weight: bold; + color: inherit; +} + +.jdGallery .slideInfoZone p +{ + padding: 0; + font-size: 80%; + margin: 2px 5px; + color: #eee; +} + +.jdGallery div.carouselContainer +{ + position: absolute; + height: 135px; + width: 100%; + z-index: 10; + margin: 0px; + left: 0; + top: 0; +} + +.jdGallery a.carouselBtn +{ + position: absolute; + bottom: 0; + right: 30px; + height: 20px; + /*width: 100px; background: url('img/carousel_btn.gif') no-repeat;*/ + text-align: center; + padding: 0 10px; + font-size: 13px; + background: #333; + color: #fff; + cursor: pointer; +} + +.jdGallery .carousel +{ + position: absolute; + width: 100%; + margin: 0px; + left: 0; + top: 0; + height: 115px; + background: #333; + color: #fff; + text-indent: 0; + overflow: hidden; +} + +.jdGallery .carousel .carouselWrapper +{ + position: absolute; + width: 100%; + height: 78px; + top: 10px; + left: 0; + overflow: hidden; +} + +.jdGallery .carousel .carouselInner +{ + position: relative; +} + +.jdGallery .carousel .carouselInner .thumbnail +{ + cursor: pointer; + background: #000; + background-position: center center; + float: left; + border: solid 1px #fff; +} + +.jdGallery .carousel .label +{ + font-size: 13px; + position: absolute; + bottom: 5px; + left: 10px; + padding: 0; + margin: 0; +} + +.jdGallery .carousel .label .number +{ + color: #b5b5b5; +} + +.jdGallery a +{ + font-size: 100%; + text-decoration: none; + color: inherit; +} + +.jdGallery a.right, .jdGallery a.left +{ + position: absolute; + height: 99%; + width: 25%; + cursor: pointer; + z-index:10; + filter:alpha(opacity=20); + -moz-opacity:0.2; + -khtml-opacity: 0.2; + opacity: 0.2; +} + +* html .jdGallery a.right, * html .jdGallery a.left +{ + filter:alpha(opacity=50); +} + +.jdGallery a.right:hover, .jdGallery a.left:hover +{ + filter:alpha(opacity=80); + -moz-opacity:0.8; + -khtml-opacity: 0.8; + opacity: 0.8; +} + +.jdGallery a.left +{ + left: 0; + top: 0; + background: url('img/fleche1.png') no-repeat center left; +} + +* html .jdGallery a.left { background: url('img/fleche1.gif') no-repeat center left; } + +.jdGallery a.right +{ + right: 0; + top: 0; + background: url('img/fleche2.png') no-repeat center right; +} + +* html .jdGallery a.right { background: url('img/fleche2.gif') no-repeat center right; } + +.jdGallery a.open +{ + left: 0; + top: 0; + width: 100%; + height: 100%; +} + +.withArrows a.open +{ + position: absolute; + top: 0; + left: 25%; + height: 99%; + width: 50%; + cursor: pointer; + z-index: 10; + background: none; + -moz-opacity:0.8; + -khtml-opacity: 0.8; + opacity: 0.8; +} + +.withArrows a.open:hover { background: url('img/open.png') no-repeat center center; } + +* html .withArrows a.open:hover { background: url('img/open.gif') no-repeat center center; + filter:alpha(opacity=80); } + diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/layout.css b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/layout.css new file mode 100644 index 0000000..9c807b6 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/css/layout.css @@ -0,0 +1,91 @@ +body { + color: #ccc; + font-family: "Trebuchet MS", "Lucida Grande", Arial, Helvetica, sans-serif; + margin: 0 auto; + padding: 0; + font-size: 1.0em; + background: #111 url('../images/bg/gradient1.gif') top left repeat-x; +} + +h1 +{ + color: #fff; + font-size: 47px; + font-weight: bolder; + margin: 0 40px; + padding: 0.08em 0; +} + +h1 sup +{ + color: #ddd; +} + +h1 a +{ + color: #fff; + text-decoration: none; +} + +h1 .company, h1 a .company +{ + color: #d01a71; +} + +h2 +{ + color: #ddd; + font-size: 2.5em; +} + +h3 +{ + color: #fff; + font-size: 1.5em; +} + +h4 +{ + font-size: 1.3em; +} + +.content +{ + margin: 0 20px; +} + +.content a +{ + color: #fff; +} + + +.content p.linkage +{ + margin-top: 2em; + text-align: right; + font-size: 1.7em; + color: #ddd; +} + +.content p.linkage a { color: #fff; } + +/*.content p.linkage a +{ + color: #fff; + background: url('../images/bg/biglink_off.gif') center right no-repeat; + padding: 10px 20px; + text-decoration: none; +} + +.content p.linkage a:hover +{ + background: url('../images/bg/biglink_on.gif') center right no-repeat; + font-style: italic; +}*/ + +#myGallery +{ + text-align: left; + margin: 0 auto; +} diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/jd.gallery.js b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/jd.gallery.js new file mode 100644 index 0000000..af83b13 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/jd.gallery.js @@ -0,0 +1,449 @@ +/* + This file is part of JonDesign's SmoothGallery v1.0.1. + + JonDesign's SmoothGallery 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. + + JonDesign's SmoothGallery 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 JonDesign's SmoothGallery; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/) + Contributed code by: + - Christian Ehret (bugfix) + - Nitrix (bugfix) + - Valerio from Mad4Milk for his great help with the carousel scrolling and many other things. + - Archie Cowan for helping me find a bugfix on carousel inner width problem. + Many thanks to: + - The mootools team for the great mootools lib, and it's help and support throughout the project. +*/ + + +var $removeEvents = function (object, type) +{ + if (!object.events) return object; + if (type){ + if (!object.events[type]) return object; + for (var fn in object.events[type]) object.removeEvent(type, fn); + object.events[type] = null; + } else { + for (var evType in object.events) object.removeEvents(evType); + object.events = null; + } + return object; +}; + + +// declaring the class +var gallery = new Class({ + initialize: function(element, options) { + this.setOptions({ + showArrows: true, + showCarousel: true, + showInfopane: true, + showDescription: false, + thumbHeight: 75, + thumbWidth: 100, + thumbSpacing: 10, + embedLinks: true, + fadeDuration: 500, + timed: false, + delay: 9000, + preloader: true, + manualData: [], + populateData: true, + elementSelector: "div.imageElement", + titleSelector: "h3", + subtitleSelector: "p", + descriptionSelector: "div", + linkSelector: "a.open", + imageSelector: "img.full", + thumbnailSelector: "img.thumbnail", + slideInfoZoneOpacity: 0.7, + carouselMinimizedOpacity: 0.4, + carouselMinimizedHeight: 20, + carouselMaximizedOpacity: 0.7, + destroyAfterPopulate: true, + baseClass: 'jdGallery', + withArrowsClass: 'withArrows', + textShowCarousel: 'Pictures', + useThumbGenerator: false, + thumbGenerator: 'resizer.php' + }, options); + this.fireEvent('onInit'); + this.currentIter = 0; + this.lastIter = 0; + this.maxIter = 0; + this.galleryElement = element; + this.galleryData = this.options.manualData; + this.galleryInit = 1; + this.galleryElements = Array(); + this.thumbnailElements = Array(); + this.galleryElement.addClass(this.options.baseClass); + if (this.options.populateData) + this.populateData(); + element.style.display="block"; + + if (this.options.embedLinks) + { + this.currentLink = new Element('a').addClass('open').setProperties({ + href: '#', + title: '' + }).injectInside(element); + if ((!this.options.showArrows) && (!this.options.showCarousel)) + this.galleryElement = element = this.currentLink; + else + this.currentLink.setStyle('display', 'none'); + } + + this.constructElements(); + if ((data.length>1)&&(this.options.showArrows)) + { + var leftArrow = new Element('a').addClass('left').addEvent( + 'click', + this.prevItem.bind(this) + ).injectInside(element); + var rightArrow = new Element('a').addClass('right').addEvent( + 'click', + this.nextItem.bind(this) + ).injectInside(element); + this.galleryElement.addClass(this.options.withArrowsClass); + } + this.loadingElement = new Element('div').addClass('loadingElement').injectInside(element); + if (this.options.showInfopane) this.initInfoSlideshow(); + if (this.options.showCarousel) this.initCarousel(); + this.doSlideShow(1); + }, + populateData: function() { + currentArrayPlace = this.galleryData.length; + options = this.options; + data = this.galleryData; + this.galleryElement.getElements(options.elementSelector).each(function(el) { + elementDict = { + image: el.getElement(options.imageSelector).getProperty('src'), + number: currentArrayPlace + }; + if ((options.showInfopane) | (options.showCarousel)) + Object.extend(elementDict, { + title: el.getElement(options.titleSelector).innerHTML, + description: el.getElement(options.subtitleSelector).innerHTML + }); + if ((options.showDescription)) + Object.extend(elementDict, { + outsideDescription: el.getElement(options.descriptionSelector).innerHTML + }); + if (options.embedLinks) + Object.extend(elementDict, { + link: el.getElement(options.linkSelector).href||false, + linkTitle: el.getElement(options.linkSelector).title||false + }); + if ((!options.useThumbGenerator) && (options.showCarousel)) + Object.extend(elementDict, { + thumbnail: el.getElement(options.thumbnailSelector).src + }); + else if (options.useThumbGenerator) + Object.extend(elementDict, { + thumbnail: 'resizer.php?imgfile=' + elementDict.image + '&max_width=' + options.thumbWidth + '&max_height=' + options.thumbHeight + }); + + data[currentArrayPlace] = elementDict; + currentArrayPlace++; + if (this.options.destroyAfterPopulate) + el.remove(); + }); + this.galleryData = data; + this.fireEvent('onPopulated'); + }, + constructElements: function() { + el = this.galleryElement; + this.maxIter = this.galleryData.length; + var currentImg; + for(i=0;i<this.galleryData.length;i++) + { + var currentImg = new Fx.Style( + new Element('div').addClass('slideElement').setStyles({ + 'position':'absolute', + 'left':'0px', + 'right':'0px', + 'margin':'0px', + 'padding':'0px', + 'backgroundImage':"url('" + this.galleryData[i].image + "')", + 'backgroundPosition':"center center", + 'opacity':'0' + }).injectInside(el), + 'opacity', + {duration: this.options.fadeDuration} + ); + this.galleryElements[parseInt(i)] = currentImg; + } + }, + destroySlideShow: function(element) { + var myClassName = element.className; + var newElement = new Element('div').addClass('myClassName'); + element.parentNode.replaceChild(newElement, element); + }, + startSlideShow: function() { + this.fireEvent('onStart'); + this.loadingElement.style.display = "none"; + this.lastIter = this.maxIter - 1; + this.currentIter = 0; + this.galleryInit = 0; + this.galleryElements[parseInt(this.currentIter)].set(1); + if (this.options.showInfopane) + this.showInfoSlideShow.delay(1000, this); + this.prepareTimer(); + if (this.options.embedLinks) + this.makeLink(this.currentIter); + }, + nextItem: function() { + this.fireEvent('onNextCalled'); + this.nextIter = this.currentIter+1; + if (this.nextIter >= this.maxIter) + this.nextIter = 0; + this.galleryInit = 0; + this.goTo(this.nextIter); + }, + prevItem: function() { + this.fireEvent('onPreviousCalled'); + this.nextIter = this.currentIter-1; + if (this.nextIter <= -1) + this.nextIter = this.maxIter - 1; + this.galleryInit = 0; + this.goTo(this.nextIter); + }, + goTo: function(num) { + this.clearTimer(); + if (this.options.embedLinks) + this.clearLink(); + if (this.options.showInfopane) + { + this.slideInfoZone.clearChain(); + this.hideInfoSlideShow().chain(this.changeItem.pass(num, this)); + } else + this.changeItem.delay(500, this, num); + if (this.options.embedLinks) + this.makeLink(num); + if (this.options.showDescription) + this.showDescription(num); + this.prepareTimer(); + /*if (this.options.showCarousel) + this.clearThumbnailsHighlights();*/ + }, + changeItem: function(num) { + this.fireEvent('onStartChanging'); + this.galleryInit = 0; + if (this.currentIter != num) + { + for(i=0;i<this.maxIter;i++) + { + if ((i != this.currentIter)) this.galleryElements[i].set(0); + } + if (num > this.currentIter) this.galleryElements[num].custom(1); + else + { + this.galleryElements[num].set(1); + this.galleryElements[this.currentIter].custom(0); + } + this.currentIter = num; + } + this.doSlideShow.bind(this)(); + this.fireEvent('onChanged'); + }, + clearTimer: function() { + if (this.options.timed) + $clear(this.timer); + }, + prepareTimer: function() { + if (this.options.timed) + this.timer = this.nextItem.delay(this.options.delay, this); + }, + doSlideShow: function(position) { + if (this.galleryInit == 1) + { + imgPreloader = new Image(); + imgPreloader.onload=function(){ + this.startSlideShow.delay(10, this); + }.bind(this); + imgPreloader.src = this.galleryData[0].image; + } else { + if (this.options.showInfopane) + { + if (this.options.showInfopane) + { + this.showInfoSlideShow.delay((500 + this.options.fadeDuration), this); + } else + if (this.options.showCarousel) + this.centerCarouselOn(position); + } + } + }, + initCarousel: function () { + var carouselContainerElement = new Element('div').addClass('carouselContainer').injectInside(this.galleryElement); + this.carouselContainer = new Fx.Styles(carouselContainerElement, {transition: Fx.Transitions.expoOut}); + this.carouselContainer.normalHeight = carouselContainerElement.offsetHeight; + this.carouselContainer.set({'opacity': this.options.carouselMinimizedOpacity, 'top': (this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight)}); + + this.carouselBtn = new Element('a').addClass('carouselBtn').setProperties({ + title: this.options.textShowCarousel + }).setHTML(this.options.textShowCarousel).injectInside(carouselContainerElement); + + this.carouselBtn.addEvent( + 'click', + function () { + this.carouselContainer.clearTimer(); + this.toggleCarousel(); + }.bind(this) + ); + this.carouselActive = false; + + var carouselElement = new Element('div').addClass('carousel').injectInside(carouselContainerElement); + this.carousel = new Fx.Styles(carouselElement); + + this.carouselLabel = new Element('p').addClass('label').injectInside(this.carousel.element); + this.carouselWrapper = new Element('div').addClass('carouselWrapper').injectInside(this.carousel.element); + this.carouselInner = new Element('div').addClass('carouselInner').injectInside(this.carouselWrapper); + + this.carouselWrapper.scroller = new Scroller(this.carouselWrapper, { + area: 100, + velocity: 0.2 + }) + + this.carouselWrapper.elementScroller = new Fx.Scroll(this.carouselWrapper, { + duration: 400, + onStart: this.carouselWrapper.scroller.stop.bind(this.carouselWrapper.scroller), + onComplete: this.carouselWrapper.scroller.start.bind(this.carouselWrapper.scroller) + }); + + this.constructThumbnails(); + + this.carouselInner.style.width = ((this.maxIter * (this.options.thumbWidth + this.options.thumbSpacing)) - this.options.thumbSpacing + this.options.thumbWidth) + "px"; + }, + toggleCarousel: function() { + if (this.carouselActive) + this.hideCarousel(); + else + this.showCarousel(); + }, + showCarousel: function () { + this.fireEvent('onShowCarousel'); + this.carouselContainer.custom({ + 'opacity': this.options.carouselMaximizedOpacity, + 'top': 0 + }).addEvent('onComplete', function() { this.carouselActive = true; this.carouselWrapper.scroller.start(); }.bind(this)); + }, + hideCarousel: function () { + this.fireEvent('onHideCarousel'); + this.carouselContainer.custom({ + 'opacity': this.options.carouselMinimizedOpacity, + 'top': (this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight) + }).addEvent('onComplete', function() { this.carouselActive = false; this.carouselWrapper.scroller.stop(); }.bind(this)); + }, + constructThumbnails: function () { + element = this.carouselInner; + for(i=0;i<this.galleryData.length;i++) + { + var currentImg = new Fx.Style(new Element ('div').addClass("thumbnail").setStyles({ + backgroundImage: "url('" + this.galleryData[i].thumbnail + "')", + backgroundPosition: "center center", + backgroundRepeat: 'no-repeat', + marginLeft: this.options.thumbSpacing + "px", + width: this.options.thumbWidth + "px", + height: this.options.thumbHeight + "px" + }).injectInside(element), "opacity", {duration: 200}).set(0.2); + currentImg.element.addEvents({ + 'mouseover': function (myself) { + myself.clearTimer(); + myself.custom(0.99); + $(this.carouselLabel).setHTML('<span class="number">' + (myself.relatedImage.number + 1) + "/" + this.maxIter + ":</span> " + myself.relatedImage.title); + }.pass(currentImg, this), + 'mouseout': function (myself) { + myself.clearTimer(); + myself.custom(0.2); + }.pass(currentImg, this), + 'click': function (myself) { + this.goTo(myself.relatedImage.number); + }.pass(currentImg, this) + }); + + currentImg.relatedImage = this.galleryData[i]; + this.thumbnailElements[parseInt(i)] = currentImg; + } + }, + clearThumbnailsHighlights: function() + { + for(i=0;i<this.galleryData.length;i++) + { + this.thumbnailElements[i].clearTimer(); + this.thumbnailElements[i].custom(0.2); + } + }, + centerCarouselOn: function(num) { + var carouselElement = this.thumbnailElements[num]; + var position = carouselElement.element.offsetLeft + (carouselElement.element.offsetWidth / 2); + var carouselWidth = this.carouselWrapper.offsetWidth; + var carouselInnerWidth = this.carouselInner.offsetWidth; + var diffWidth = carouselWidth / 2; + var scrollPos = position-diffWidth; + this.carouselWrapper.elementScroller.scrollTo(scrollPos,0); + }, + initInfoSlideshow: function() { + /*if (this.slideInfoZone.element) + this.slideInfoZone.element.remove();*/ + this.slideInfoZone = new Fx.Styles(new Element('div').addClass('slideInfoZone').injectInside($(this.galleryElement))).set({'opacity':0}); + var slideInfoZoneTitle = new Element('h2').injectInside(this.slideInfoZone.element); + var slideInfoZoneDescription = new Element('p').injectInside(this.slideInfoZone.element); + this.slideInfoZone.normalHeight = this.slideInfoZone.element.offsetHeight; + this.slideInfoZone.element.setStyle('opacity',0); + }, + changeInfoSlideShow: function() + { + this.hideInfoSlideShow.delay(10, this); + this.showInfoSlideShow.delay(500, this); + }, + showInfoSlideShow: function() { + this.fireEvent('onShowInfopane'); + this.slideInfoZone.clearTimer(); + element = this.slideInfoZone.element; + element.getElement('h2').setHTML(this.galleryData[this.currentIter].title); + element.getElement('p').setHTML(this.galleryData[this.currentIter].description); + this.slideInfoZone.custom({'opacity': [0, this.options.slideInfoZoneOpacity], 'height': [0, this.slideInfoZone.normalHeight]}); + if (this.options.showCarousel) + this.slideInfoZone.chain(this.centerCarouselOn.pass(this.currentIter, this)); + return this.slideInfoZone; + }, + hideInfoSlideShow: function() { + this.fireEvent('onHideInfopane'); + this.slideInfoZone.clearTimer(); + this.slideInfoZone.custom({'opacity': 0, 'height': 0}); + return this.slideInfoZone; + }, + makeLink: function(num) { + this.currentLink.setProperties({ + href: this.galleryData[num].link, + title: this.galleryData[num].linkTitle + }) + if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) + this.currentLink.setStyle('display', 'block'); + }, + showDescription: function(num) { + var descObj = document.getElementById('DescriptionDiv'); + if (descObj) + descObj.setHTML(this.galleryData[num].outsideDescription); + }, + clearLink: function() { + this.currentLink.setProperties({href: '', title: ''}); + if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) + this.currentLink.setStyle('display', 'none'); + } +}); +gallery.implement(new Events); +gallery.implement(new Options); + +/* All code copyright 2006 Jonathan Schemoul */ diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.js b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.js new file mode 100644 index 0000000..eb6402a --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.js @@ -0,0 +1,2 @@ +//MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006 Valerio Proietti, <http://mad4milk.net>, MIT Style License. +eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('k 11=f(1S){k 4s=f(){j(9.1e&&Y[0]!=\'7h\')h 9.1e.2m(9,Y);Q h 9};I(k n W 9)4s[n]=9[n];4s.U=1S;h 4s};11.1G=f(){};11.U={N:f(1S){k 4r=M 9(\'7h\');k 7g=f(2s,2f){j(!2s.2m||!2f.2m)h T;h f(){9.1t=2s;h 2f.2m(9,Y)}};I(k n W 1S){k 2s=4r[n];k 2f=1S[n];j(2s&&2s!=2f)2f=7g(2s,2f)||2f;4r[n]=2f}h M 11(4r)},1T:f(1S){I(k n W 1S)9.U[n]=1S[n]}};1H.N=f(){k R=Y;R=(R[1])?[R[0],R[1]]:[9,R[0]];I(k n W R[1])R[0][n]=R[1][n];h R[0]};1H.5p=f(){I(k i=0;i<Y.14;i++)Y[i].N=11.U.1T};M 1H.5p(59,1r,5e,76,11);j(5r 2I==\'3z\'){k 2I=11.1G;2I.U={}}f $q(u){j(u===1K||u===3z)h T;k q=5r u;j(q==\'5o\'){j(u 4m 2I)h\'r\';j(u 4m 1r)h\'1R\';j(u.9Y){2c(u.6x){1c 1:h\'r\';1c 3:h u.9X.15(\'\\\\S\')?\'9W\':\'4f\'}}}h q};f $2B(u){h!!(u||u===0)};f $9V(u,7f){h($q(u))?u:7f};f $7e(3o,1B){h G.9U(G.7e()*(1B-3o+1)+3o)};f $3Q(1f){9T(1f);9S(1f);h 1K};j(12.9R)12.3w=12[12.9Q?\'9P\':\'53\']=1g;Q j(L.6J&&!L.9O&&!9N.9M)12.3W=1g;Q j(L.9L!=1K)12.5m=1g;1r.U.4q=1r.U.4q||f(O,J){I(k i=0;i<9.14;i++)O.1i(J,9[i],i,9)};1r.U.4X=1r.U.4X||f(O,J){k 5u=[];I(k i=0;i<9.14;i++)5u[i]=O.1i(J,9[i],i,9);h 5u};1r.U.7d=1r.U.7d||f(O,J){I(k i=0;i<9.14;i++){j(!O.1i(J,9[i],i,9))h T}h 1g};1r.U.7c=1r.U.7c||f(O,J){I(k i=0;i<9.14;i++){j(O.1i(J,9[i],i,9))h 1g}h T};1r.U.4g=1r.U.4g||f(3a,F){F=F||0;j(F<0)F=G.1B(0,9.14+F);34(F<9.14){j(9[F]===3a)h F;F++}h-1};1r.N({1o:1r.U.4q,54:f(){k 36=[];I(k i=0;i<9.14;i++)36[i]=9[i];h 36},3Z:f(3a){k i=0;34(i<9.14){j(9[i]==3a)9.47(i,1);Q i++}h 9},15:f(3a,F){h 9.4g(3a,F)!=-1},N:f(36){I(k i=0;i<36.14;i++)9.18(36[i]);h 9},9K:f(1u){k u={},14=G.3o(9.14,1u.14);I(k i=0;i<14;i++)u[1u[i]]=9[i];h u}});f $A(1R){h 1r.U.54.1i(1R)};f $1o(7b,O,J){h 1r.U.4q.1i(7b,O,J)};5e.N({15:f(7a,79){h M 9J(7a,79).15(9)},2C:f(){h 5s(9)},74:f(){h 3t(9)},5n:f(){h 9.35(/-\\D/g,f(28){h 28.5t(1).78()})},6O:f(){h 9.35(/\\w[A-Z]/g,f(28){h(28.5t(0)+\'-\'+28.5t(1).3G())})},9I:f(){h 9.3G().35(/\\b[a-z]/g,f(28){h 28.78()})},77:f(){h 9.35(/^\\s+|\\s+$/g,\'\')},45:f(){h 9.35(/\\s{2,}/g,\' \').77()},3I:f(1R){k 1l=9.28(/\\d{1,3}/g);h(1l)?1l.3I(1R):T},3s:f(1R){k 2J=9.28(\'^#?(\\\\w{1,2})(\\\\w{1,2})(\\\\w{1,2})$\');h(2J)?2J.3s(1R):T}});1r.N({3I:f(1R){j(9.14<3)h T;j(9[3]&&9[3]==0)h\'9H\';k 2J=[];I(k i=0;i<3;i++){k 4p=(9[i]-0).9G(16);2J.18(4p.14==1?\'0\'+4p:4p)}h 1R?2J:\'#\'+2J.3r(\'\')},3s:f(1R){j(9.14!=4)h T;k 1l=[];I(k i=1;i<4;i++){j(9[i].14==1)9[i]+=9[i];1l.18(5s(9[i],16))}h 1R?1l:\'1l(\'+1l.3r(\',\')+\')\'}});76.N({2C:f(){h 5s(9)},74:f(){h 3t(9)}});59.N({2e:f(m){k O=9;m=1H.N({\'J\':O,\'o\':T,\'Y\':1K,\'2d\':T,\'2k\':T,\'4o\':T},m||{});j(m.Y!=1K&&5r m.Y!=\'3z\'&&!(m.Y 4m 1r))m.Y=[m.Y];h f(o){k R=m.Y||Y;j(m.o){o=(m.o===1g)?o||12.o:M m.o(o);R=[o].9F(R)}k 2t=f(){h O.2m(m.J,R)};j(m.2d)h 9E(2t,m.2d);j(m.2k)h 9D(2t,m.2k);j(m.4o){6g{k 5q=2t()}6f(73){5q=73}9C{h 5q}}Q h 2t()}},9B:f(R,J){h 9.2e({\'Y\':R,\'J\':J})},4o:f(R,J){h 9.2e({\'Y\':R,\'J\':J,\'4o\':1g})()},J:f(J,R){h 9.2e({\'J\':J,\'Y\':R})},9A:f(J,R){h 9.2e({\'J\':J,\'o\':1g,\'Y\':R})},2d:f(4n,J,R){h 9.2e({\'2d\':4n,\'J\':J,\'Y\':R})()},2k:f(4n,J,R){h 9.2e({\'2k\':4n,\'J\':J,\'Y\':R})()}});k 1b=M 11({1e:f(l){j($q(l)==\'4j\')l=L.6H(l);h $(l)}});f $(l){j(!l)h T;j(l.72||[12,L].15(l))h l;j($q(l)==\'4j\')l=L.44(l);j($q(l)!=\'r\')h T;j([\'5o\',\'9z\'].15(l.41.3G())||l.N)h l;l.72=1g;31.6z(l);l.N=1H.N;j(!(l 4m 2I))l.N(1b.U);h l};k 1N=M 11({});M 1H.5p(1N);L.2G=L.56;f $$(){j(!Y)h T;j(Y.14==1){j(!Y[0])h T;j(Y[0].71)h Y[0]}k 1w=[];$1o(Y,f(1v){2c($q(1v)){1c\'r\':1w.18($(1v));1P;1c\'4j\':1v=L.2G(1v);6F:j(1v.14){$1o(1v,f(l){j($(l))1w.18(l)})}}});1w.71=1g;h 1H.N(1w,M 1N)};1N.3T=f(n){h f(){k R=Y;k 3J=[];k 1w=1g;$1o(9,f(l){k 2t=l[n].2m(l,R);j($q(2t)!=\'r\')1w=T;3J.18(2t)});j(1w)3J=$$(3J);h 3J}};1b.N=f(1S){I(k n W 1S){2I.U[n]=1S[n];1b.U[n]=1S[n];1N.U[n]=1N.3T(n)}};1b.N({4l:f(l,70){l=$(l)||M 1b(l);2c(70){1c"6Y":$(l.26).6Z(9,l);1P;1c"6X":j(!l.5k())$(l.26).4k(9);Q $(l.26).6Z(9,l.5k());1P;1c"6W":l.4k(9)}h 9},9y:f(l){h 9.4l(l,\'6Y\')},5K:f(l){h 9.4l(l,\'6X\')},9x:f(l){h 9.4l(l,\'6W\')},5J:f(l){9.4k($(l)||M 1b(l));h 9},3Z:f(){9.26.9w(9);h 9},9v:f(6V){k l=9.9u(6V!==T);h $(l)},6G:f(l){l=$(l)||M 1b(l);9.26.9t(l,9);h l},9s:f(33){j(12.3w){2c(9.3C()){1c\'1h\':9.9r.6S=33;h 9;1c\'52\':9.4d(\'33\',33);h 9}}9.4k(L.9q(33));h 9},3A:f(1d){h 9.1d.15(\'(?:^|\\\\s+)\'+1d+\'(?:\\\\s+|$)\')},6T:f(1d){j(!9.3A(1d))9.1d=(9.1d+\' \'+1d).45();h 9},6U:f(1d){j(9.3A(1d))9.1d=9.1d.35(1d,\'\').45();h 9},9p:f(1d){h 9.3A(1d)?9.6U(1d):9.6T(1d)},1F:f(n,K){j(n==\'1Y\')9.6R(3t(K));Q 9.1h[n.5n()]=(K.18)?K.3I():K;h 9},6I:f(1L){2c($q(1L)){1c\'5o\':I(k n W 1L)9.1F(n,1L[n]);1P;1c\'4j\':j(12.3w)9.6S=1L;Q 9.6E(\'1h\',1L)}h 9},6R:f(1Y){j(1Y==0){j(9.1h.4i!="3S")9.1h.4i="3S"}Q{j(9.1h.4i!="6Q")9.1h.4i="6Q"}j(!9.4h||!9.4h.9o)9.1h.9n=1;j(12.3w)9.1h.3D="3x(1Y="+1Y*3g+")";9.1h.1Y=9.1Y=1Y;h 9},1W:f(n){n=n.5n();k 1h=9.1h[n]||T;j(!$2B(1h)){j(n==\'1Y\')h $2B(9.1Y)?9.1Y:1;j([\'2n\',\'9m\'].15(n)){h[9.1W(n+\'-2w\')||0,9.1W(n+\'-5a\')||0,9.1W(n+\'-6B\')||0,9.1W(n+\'-2i\')||0].3r(\' \')}j(L.6P)1h=L.6P.9l(9,1K).9k(n.6O());Q j(9.4h)1h=9.4h[n]}h(1h&&n.15(\'1A\',\'i\')&&1h.15(\'1l\'))?1h.3I():1h},1a:f(q,O){9.V=9.V||{};9.V[q]=9.V[q]||{\'1u\':[],\'1z\':[]};j(!9.V[q].1u.15(O)){9.V[q].1u.18(O);j(9.6N){9.6N((q==\'2M\'&&12.5m)?\'5f\':q,O,T)}Q{O=O.J(9);9.9j(\'58\'+q,O);9.V[q].1z.18(O)}}h 9},9i:f(1L){j(1L){I(k q W 1L)9.1a(q,1L[q])}h 9},1E:f(q,O){j(9.V&&9.V[q]){k 1D=9.V[q].1u.4g(O);j(1D==-1)h 9;k 1O=9.V[q].1u.47(1D,1)[0];j(9.6M){9.6M((q==\'2M\'&&12.5m)?\'5f\':q,1O,T)}Q{9.9h(\'58\'+q,9.V[q].1z.47(1D,1)[0])}}h 9},5h:f(q){j(9.V){j(q){j(9.V[q]){9.V[q].1u.1o(f(O){9.1E(q,O)},9);9.V[q]=1K}}Q{I(k 6L W 9.V)9.5h(6L);9.V=1K}}h 9},1x:f(q,R){j(9.V&&9.V[q]){R=R||[];j($q(R)!=\'1R\')R=[R];9.V[q].1u.1o(f(O){O.2m(9,R)},9)}},5j:f(5l){k l=9[5l+\'6K\'];34($q(l)==\'4f\')l=l[5l+\'6K\'];h $(l)},9g:f(){h 9.5j(\'2s\')},5k:f(){h 9.5j(\'9f\')},9e:f(){k l=9.9d;34($q(l)==\'4f\')l=l.9c;h $(l)},9b:f(){k l=9.9a;34($q(l)==\'4f\')l=l.99;h $(l)},98:f(){h $(9.26)},97:f(){h $$(9.6J)},4d:f(n,K){2c(n){1c\'6C\':9.1d=K;1P;1c\'1h\':9.6I(K);1P;1c\'24\':j(12.53){k l=$(L.6H(\'<\'+9.3C()+\' 24="\'+K+\'" />\'));$1o(9.96,f(4e){j(4e.24!=\'24\')l.4d(4e.24,4e.K)});j(9.26)9.6G(l);h l}6F:9.6E(n,K)}h 9},95:f(1L){I(k n W 1L)9.4d(n,1L[n]);h 9},94:f(6D){9.93=6D;h 9},92:f(n){h(n==\'6C\')?9.1d:9.6k(n)},3C:f(){h 9.41.3G()},2O:f(){k l=9,4c=0,4b=0;91{4c+=l.4c||0;4b+=l.4b||0;l=l.90}34(l);h{\'x\':4c,\'y\':4b}},2a:f(x,y){9.3U=x;9.3V=y},3P:f(){h{\'1V\':{\'x\':9.3U,\'y\':9.3V},\'2A\':{\'x\':9.2x,\'y\':9.2v},\'3O\':{\'x\':9.68,\'y\':9.69}}},4D:f(){h 9.2O().y},4F:f(){h 9.2O().x},8Z:f(){k 5i=9.2O();k u={\'3j\':9.2x,\'3i\':9.2v,\'2i\':5i.x,\'2w\':5i.y};u.5a=u.2i+u.3j;u.6B=u.2w+u.3i;h u},2F:f(){2c(9.3C()){1c\'2U\':j(9.6A!=-1)h 9.m[9.6A].K;1P;1c\'8Y\':j(!(9.8X&&[\'8W\',\'8V\'].15(9.q))&&![\'3S\',\'33\',\'8U\'].15(9.q))1P;1c\'8T\':h 9.K}h T}});k 8S=12;12.1a=L.1a=1b.U.1a;12.1E=L.1E=1b.U.1E;k 31={1w:[],6z:f(r){31.1w.18(r)},5g:f(){12.1E(\'6y\',31.5g);31.1w.1o(f(l){l.5h();I(k p W 1b.U)2I[p]=12[p]=L[p]=l[p]=1K;l.N=1K})}};12.1a(\'6y\',31.5g);k 3F=M 11({1e:f(o){9.o=o||12.o;9.q=9.o.q;9.3H=9.o.3H||9.o.8R;j(9.3H.6x==3)9.3H=9.3H.26;9.8Q=9.o.8P;9.8O=9.o.8N;9.8M=9.o.8L;9.8K=9.o.8J;j([\'5f\',\'2M\'].15(9.q)){9.3f=9.o.6w?(9.o.6w/ (12.51 ? -6v : 6v)) : -(9.o.8I || 0) /3}Q j(9.q.15(\'1O\')){9.5d=9.o.6r||9.o.8H;I(k 24 W 3F.1u){j(3F.1u[24]==9.5d)k 6u=24}9.1O=6u||5e.8G(9.5d).3G()}Q j(9.q.15(\'2l\')||9.q==\'8F\'){9.1y={\'x\':9.o.5c||9.o.6t+L.2r.3U,\'y\':9.o.5b||9.o.6s+L.2r.3V};9.5y={\'x\':9.o.5c?9.o.5c-12.66:9.o.6t,\'y\':9.o.5b?9.o.5b-12.67:9.o.6s};9.8E=(9.o.6r==3)||(9.o.8D==2);2c(9.q){1c\'8C\':9.4a=9.o.4a||9.o.8B;1P;1c\'8A\':9.4a=9.o.4a||9.o.5L}}},1s:f(){9.49();9.48();h 9},49:f(){j(9.o.49)9.o.49();Q 9.o.8z=1g;h 9},48:f(){j(9.o.48)9.o.48();Q 9.o.8y=T;h 9}});3F.1u={\'8x\':13,\'8w\':38,\'8v\':40,\'2i\':37,\'5a\':39,\'8u\':27,\'8t\':32,\'8s\':8,\'8r\':46};59.N({2y:f(J,R){h 9.2e({\'J\':J,\'Y\':R,\'o\':3F})}});k 5S=M 11({8q:f(O){9.2H=9.2H||[];9.2H.18(O);h 9},5Z:f(){j(9.2H&&9.2H.14)9.2H.47(0,1)[0].2d(10,9)},8p:f(){9.2H=[]}});k 3c=M 11({1a:f(q,O){j(O!=11.1G){9.V=9.V||{};9.V[q]=9.V[q]||[];j(!9.V[q].15(O))9.V[q].18(O)}h 9},1x:f(q,R,2d){j(9.V&&9.V[q]){9.V[q].1o(f(O){O.2e({\'J\':9,\'2d\':2d,\'Y\':R})()},9)}h 9},1E:f(q,O){j(9.V&&9.V[q])9.V[q].3Z(O);h 9}});k 3b=M 11({2N:f(6q,m){9.m=1H.N(6q,m);j(9.1a){I(k 3E W 9.m){j(($q(9.m[3E])==\'f\')&&3E.15(\'^58[A-Z]\'))9.1a(3E,9.m[3E])}}h 9}});f $E(1v,3D){h($(3D)||L).42(1v)};f $8o(1v,3D){h($(3D)||L).2G(1v)};1b.N({3B:f(1v){k 1Q=[];1v.45().4Y(\' \').1o(f(43,i){k 1q=43.28(\'^(\\\\w*|\\\\*)(?:#([\\\\6p-]+)|\\\\.([\\\\6p-]+))?(?:\\\\[["\\\']?(\\\\w+)["\\\']?(?:([\\\\*\\\\^\\\\$]?=)["\\\']?(\\\\w*)["\\\']?)?\\\\])?$\');j(!1q)h;1q[1]=1q[1]||\'*\';j(i==0){j(1q[2]){k l=9.44(1q[2]);j(!l||((1q[1]!=\'*\')&&(1b.U.3C.1i(l)!=1q[1])))h;1Q=[l]}Q{1Q=$A(9.56(1q[1]))}}Q{1Q=1N.U.6m.1i(1Q,1q[1]);j(1q[2])1Q=1N.U.6o.1i(1Q,1q[2])}j(1q[3])1Q=1N.U.6n.1i(1Q,1q[3]);j(1q[4])1Q=1N.U.6l.1i(1Q,1q[4],1q[6],1q[5])},9);h $$(1Q)},44:f(2Z){k l=L.44(2Z);j(!l)h T;I(k 1t=l.26;1t!=9;1t=1t.26){j(!1t)h T}h l},42:f(1v){h 9.2G(1v)[0]},2G:f(1v){k 57=[];1v.4Y(\',\').1o(f(43){57.N(9.3B(43))},9);h $$(57)}});L.N=1H.N;L.N({8n:f(1d){h L.3B(\'.\'+1d)},42:1b.U.42,3B:1b.U.3B,2G:1b.U.2G});1N.N({6o:f(2Z,8m){k 1p=[];9.1o(f(l){j(l.2Z==2Z)1p.18(l)});h 1p},6n:f(1d){k 1p=[];9.1o(f(l){j(1b.U.3A.1i(l,1d))1p.18(l)});h 1p},6m:f(41){k 1p=[];9.1o(f(l){1p.N(l.56(41))});h 1p},6l:f(24,K,55){k 1p=[];9.1o(f(l){k 30=l.6k(24);j(!30)h 1p;j(!55)h 1p.18(l);2c(55){1c\'*=\':j(30.15(K))1p.18(l);1P;1c\'=\':j(30==K)1p.18(l);1P;1c\'^=\':j(30.15(\'^\'+K))1p.18(l);1P;1c\'$=\':j(30.15(K+\'$\'))1p.18(l)}h 1p});h 1p}});k 6j=M 11({14:0,1e:f(u){9.u={};I(k n W u){9.u[n]=u[n];9.14++}},8l:f(1O){h 9.u[1O]},1U:f(1O,K){j(K==1K)h T;j(9.u[1O]==3z)9.14++;9.u[1O]=K;h 9},3Z:f(1O){j(9.u[1O]==3z)h T;k u={};9.14--;I(k n W 9.u){j(n!=1O)u[n]=9.u[n]}9.u=u;h 9},1o:f(O,J){I(k n W 9.u)O.1i(J||9,n,9.u[n])},N:f(u){9.1e(1H.N(9.u,u));h 9},1G:f(){h(9.14==0)},1u:f(){k 1u=[];I(k n W 9.u)1u.18(n);h 1u},1z:f(){k 1z=[];I(k n W 9.u)1z.18(9.u[n]);h 1z}});f $H(u){h M 6j(u)};k 2q=M 11({1e:f(1A){j(1A.6i&&1A.6h)h 1A;k 1l=(1A.18)?1A:1A.3s(1g);h 1H.N(1l,2q.U)},6i:f(){k 3y=$A(Y);k 3x=50;j($q(3y[3y.14-1])==\'5N\')3x=3y.8k();k 1l=9.54();3y.1o(f(1A){1A=M 2q(1A);I(k i=0;i<3;i++)1l[i]=G.3e((1l[i]/ 3g * (3g - 3x)) + (1A[i] /3g*3x))});h M 2q(1l)},6h:f(){k 1l=[];I(k i=0;i<3;i++)1l.18(8j-9[i]);h M 2q(1l)}});f $C(1A){h M 2q(1A)};12.N=1H.N;12.N({8i:f(){j(9.53)6g{L.8h("8g",T,1g)}6f(e){}},1a:f(q,O){j(q==\'3u\'){j(9.3Y)O();Q j(!9.V||!9.V.3u){k 3v=f(){j(9.3Y)h;9.3Y=1g;j(9.1f)9.1f=$3Q(9.1f);1b.U.1x.1i(9,\'3u\');9.V.3u=1K}.J(9);j(L.3X&&9.3W){9.1f=f(){j([\'3Y\',\'6d\'].15(L.3X))3v()}.2k(50)}Q j(L.3X&&9.3w){L.8f("<52 2Z=6e 8e 8d=8c:8b(0)><\\/52>");$(\'6e\').8a=f(){j(9.3X==\'6d\')3v()}}Q{9.1a("89",3v);L.1a("88",3v)}}}1b.U.1a.1i(9,q,O);h 9},87:f(6c){h 9.1a(\'3u\',6c)}});12.N({63:f(){j(9.3W||9.51)h 9.86;Q h L.2r.6b||L.4N.6b},62:f(){j(9.3W||9.51)h 9.85;h L.2r.6a||L.4N.6a},60:f(){h L.2r.69},61:f(){h L.2r.68},64:f(){h 9.67||L.2r.3V},65:f(){h 9.66||L.2r.3U},3P:f(){h{\'1V\':{\'x\':9.65(),\'y\':9.64()},\'2A\':{\'x\':9.63(),\'y\':9.62()},\'3O\':{\'x\':9.61(),\'y\':9.60()}}},2O:f(){h{\'x\':0,\'y\':0}}});k X={};X.1C=M 11({2j:f(){h{2K:11.1G,2g:11.1G,5T:11.1G,5Y:X.2Q.4U,4Z:84,1J:\'4I\',2T:1g,5U:50}},1e:f(m){9.r=9.r||1K;9.2N(9.2j(),m);j(9.m.1e)9.m.1e.1i(9)},19:f(){k 2Y=M 5W().5V();j(2Y<9.2Y+9.m.4Z){9.5X=2Y-9.2Y;9.2E();9.2o()}Q{9.1s(1g);9.P=9.B;9.2o();9.1x(\'2g\',9.r,10);9.5Z()}},1U:f(B){9.P=B;9.2o();h 9},2E:f(){9.P=9.2D(9.F,9.B)},2D:f(F,B){h 9.m.5Y(9.5X,F,(B-F),9.m.4Z)},1m:f(F,B){j(!9.m.2T)9.1s();Q j(9.1f)h 9;9.F=F;9.B=B;9.2Y=M 5W().5V();9.1f=9.19.2k(G.3e(83/9.m.5U),9);9.1x(\'2K\',9.r);h 9},1s:f(2h){j(!9.1f)h 9;9.1f=$3Q(9.1f);j(!2h)9.1x(\'5T\',9.r);h 9},82:f(F,B){h 9.1m(F,B)},81:f(2h){h 9.1s(2h)}});X.1C.1T(M 5S);X.1C.1T(M 3c);X.1C.1T(M 3b);X.2Q={5F:f(t,b,c,d){h c*t/d+b},4U:f(t,b,c,d){h-c/2*(G.4T(G.1X*t/d)-1)+b}};X.23={2U:f(n,B){j(n.15(\'1A\',\'i\'))h 9.2q;j(B.15&&B.15(\' \'))h 9.3T;h 9.5R},1M:f(l,n,2X){j(!2X.18)2X=[2X];k F=2X[0],B=2X[1];j(!B&&B!=0){B=F;F=l.1W(n)}k 17=9.2U(n,B);h{F:17.1M(F),B:17.1M(B),17:17}}};X.23.5R={1M:f(K){h 3t(K)},2V:f(F,B,2W){h 2W.2D(F,B)},2F:f(K,1J){h K+1J}};X.23.3T={1M:f(K){h K.18?K:K.4Y(\' \').4X(f(v){h 3t(v)})},2V:f(F,B,2W){k P=[];I(k i=0;i<F.14;i++)P[i]=2W.2D(F[i],B[i]);h P},2F:f(K,1J){h K.3r(1J+\' \')+1J}};X.23.2q={1M:f(K){h K.18?K:K.3s(1g)},2V:f(F,B,2W){k P=[];I(k i=0;i<F.14;i++)P[i]=G.3e(2W.2D(F[i],B[i]));h P},2F:f(K){h\'1l(\'+K.3r(\',\')+\')\'}};X.5Q=X.1C.N({1e:f(l,n,m){9.r=$(l);9.n=n;9.1t(m)},5I:f(){h 9.1U(0)},2E:f(){9.P=9.17.2V(9.F,9.B,9)},1U:f(B){9.17=X.23.2U(9.n,B);h 9.1t(9.17.1M(B))},1m:f(F,B){j(9.1f&&9.m.2T)h 9;k 1n=X.23.1M(9.r,9.n,[F,B]);9.17=1n.17;h 9.1t(1n.F,1n.B)},2o:f(){9.r.1F(9.n,9.17.2F(9.P,9.m.1J))}});1b.N({80:f(n,m){h M X.5Q(9,n,m)}});X.5P=X.1C.N({1e:f(l,m){9.r=$(l);9.1t(m)},2E:f(){I(k p W 9.F)9.P[p]=9.17[p].2V(9.F[p],9.B[p],9)},1U:f(B){k 1n={};9.17={};I(k p W B){9.17[p]=X.23.2U(p,B[p]);1n[p]=9.17[p].1M(B[p])}h 9.1t(1n)},1m:f(u){j(9.1f&&9.m.2T)h 9;9.P={};9.17={};k F={},B={};I(k p W u){k 1n=X.23.1M(9.r,p,u[p]);F[p]=1n.F;B[p]=1n.B;9.17[p]=1n.17}h 9.1t(F,B)},2o:f(){I(k p W 9.P)9.r.1F(p,9.17[p].2F(9.P[p],9.m.1J))}});1b.N({7Z:f(m){h M X.5P(9,m)}});X.1N=X.1C.N({1e:f(1w,m){9.1w=$$(1w);9.1t(m)},2E:f(){I(k i W 9.F){k 3q=9.F[i],2p=9.B[i],2b=9.17[i],3p=9.P[i]={};I(k p W 3q)3p[p]=2b[p].2V(3q[p],2p[p],9)}},1U:f(B){k 1n={};9.17={};I(k i W B){k 2p=B[i],2b=9.17[i]={},5O=1n[i]={};I(k p W 2p){2b[p]=X.23.2U(p,2p[p]);5O[p]=2b[p].1M(2p[p])}}h 9.1t(1n)},1m:f(u){j(9.1f&&9.m.2T)h 9;9.P={};9.17={};k F={},B={};I(k i W u){k 4W=u[i],3q=F[i]={},2p=B[i]={},2b=9.17[i]={};I(k p W 4W){k 1n=X.23.1M(9.1w[i],p,4W[p]);3q[p]=1n.F;2p[p]=1n.B;2b[p]=1n.17}}h 9.1t(F,B)},2o:f(){I(k i W 9.P){k 3p=9.P[i],2b=9.17[i];I(k p W 3p)9.1w[i].1F(p,2b[p].2F(3p[p],9.m.1J))}}});X.7Y=X.1C.N({1e:f(r,m){9.P=[];9.r=$(r);9.1a(\'2K\',f(){9.r.1a(\'2M\',9.1s.J(9,T))}.J(9));9.1E(\'2g\',f(){9.r.1E(\'2M\',9.1s.J(9,T))}.J(9));9.1t(m)},2E:f(){I(k i=0;i<2;i++)9.P[i]=9.2D(9.F[i],9.B[i])},2a:f(x,y){j(9.1f&&9.m.2T)h 9;k l=9.r.3P();k 1z={\'x\':x,\'y\':y};I(k z W l.2A){k 1B=l.3O[z]-l.2A[z];j($2B(1z[z]))1z[z]=($q(1z[z])==\'5N\')?G.1B(G.3o(1z[z],1B),0):1B;Q 1z[z]=l.1V[z]}h 9.1m([l.1V.x,l.1V.y],[1z.x,1z.y])},7X:f(){h 9.2a(T,0)},7W:f(){h 9.2a(T,\'5M\')},7V:f(){h 9.2a(0,T)},7U:f(){h 9.2a(\'5M\',T)},5L:f(l){h 9.2a($(l).4F(),$(l).4D())},2o:f(){9.r.2a(9.P[0],9.P[1])}});X.7T=X.1C.N({1e:f(l,m){9.r=$(l).1F(\'2n\',0);9.2R=M 1b(\'7S\').5K(9.r).1F(\'7R\',\'3S\').5J(9.r);9.2N({\'1k\':\'4E\'},m);9.P=[];9.1t(9.m)},2E:f(){I(k i=0;i<2;i++)9.P[i]=9.2D(9.F[i],9.B[i])},4E:f(){9.2n=\'2w\';9.4V=\'3i\';9.2S=9.r.2v;h[9.r.1W(\'2n-2w\').2C(),9.2R.1W(\'3i\').2C()]},4G:f(){9.2n=\'2i\';9.4V=\'3j\';9.2S=9.r.2x;h[9.r.1W(\'2n-2i\').2C(),9.2R.1W(\'3j\').2C()]},5H:f(1k){h 9.1m(9[1k||9.m.1k](),[0,9.2S])},5G:f(1k){h 9.1m(9[1k||9.m.1k](),[-9.2S,0])},5I:f(1k){9[1k||9.m.1k]();h 9.1U([-9.2S,0])},7Q:f(1k){9[1k||9.m.1k]();h 9.1U([0,9.2S])},7P:f(1k){j(9.2R.2v==0||9.2R.2x==0)h 9.5H(1k);Q h 9.5G(1k)},2o:f(){9.r.1F(\'2n-\'+9.2n,9.P[0]+9.m.1J);9.2R.1F(9.4V,9.P[1]+9.m.1J)}});X.2Q={5F:f(t,b,c,d){h c*t/d+b},7O:f(t,b,c,d){h c*(t/=d)*t+b},7N:f(t,b,c,d){h-c*(t/=d)*(t-2)+b},7M:f(t,b,c,d){j((t/=d/2)<1)h c/2*t*t+b;h-c/2*((--t)*(t-2)-1)+b},7L:f(t,b,c,d){h c*(t/=d)*t*t+b},7K:f(t,b,c,d){h c*((t=t/d-1)*t*t+1)+b},7J:f(t,b,c,d){j((t/=d/2)<1)h c/2*t*t*t+b;h c/2*((t-=2)*t*t+2)+b},7I:f(t,b,c,d){h c*(t/=d)*t*t*t+b},7H:f(t,b,c,d){h-c*((t=t/d-1)*t*t*t-1)+b},7G:f(t,b,c,d){j((t/=d/2)<1)h c/2*t*t*t*t+b;h-c/2*((t-=2)*t*t*t-2)+b},7F:f(t,b,c,d){h c*(t/=d)*t*t*t*t+b},7E:f(t,b,c,d){h c*((t=t/d-1)*t*t*t*t+1)+b},7D:f(t,b,c,d){j((t/=d/2)<1)h c/2*t*t*t*t*t+b;h c/2*((t-=2)*t*t*t*t+2)+b},7C:f(t,b,c,d){h-c*G.4T(t/d*(G.1X/2))+c+b},7B:f(t,b,c,d){h c*G.3n(t/d*(G.1X/2))+b},4U:f(t,b,c,d){h-c/2*(G.4T(G.1X*t/d)-1)+b},7A:f(t,b,c,d){h(t==0)?b:c*G.22(2,10*(t/d-1))+b},7z:f(t,b,c,d){h(t==d)?b+c:c*(-G.22(2,-10*t/d)+1)+b},7y:f(t,b,c,d){j(t==0)h b;j(t==d)h b+c;j((t/=d/2)<1)h c/2*G.22(2,10*(t-1))+b;h c/2*(-G.22(2,-10*--t)+2)+b},7x:f(t,b,c,d){h-c*(G.3m(1-(t/=d)*t)-1)+b},7w:f(t,b,c,d){h c*G.3m(1-(t=t/d-1)*t)+b},7v:f(t,b,c,d){j((t/=d/2)<1)h-c/2*(G.3m(1-t*t)-1)+b;h c/2*(G.3m(1-(t-=2)*t)+1)+b},7u:f(t,b,c,d,a,p){j(t==0)h b;j((t/=d)==1)h b+c;j(!p)p=d*.3;j(!a)a=1;j(a<G.4S(c)){a=c;k s=p/4}Q k s=p/(2*G.1X)*G.4R(c/a);h-(a*G.22(2,10*(t-=1))*G.3n((t*d-s)*(2*G.1X)/p))+b},7t:f(t,b,c,d,a,p){j(t==0)h b;j((t/=d)==1)h b+c;j(!p)p=d*.3;j(!a)a=1;j(a<G.4S(c)){a=c;k s=p/4}Q k s=p/(2*G.1X)*G.4R(c/a);h a*G.22(2,-10*t)*G.3n((t*d-s)*(2*G.1X)/p)+c+b},7s:f(t,b,c,d,a,p){j(t==0)h b;j((t/=d/2)==2)h b+c;j(!p)p=d*(.3*1.5);j(!a)a=1;j(a<G.4S(c)){a=c;k s=p/4}Q k s=p/(2*G.1X)*G.4R(c/a);j(t<1)h-.5*(a*G.22(2,10*(t-=1))*G.3n((t*d-s)*(2*G.1X)/p))+b;h a*G.22(2,-10*(t-=1))*G.3n((t*d-s)*(2*G.1X)/p)*.5+c+b},7r:f(t,b,c,d,s){j(!s)s=1.4Q;h c*(t/=d)*t*((s+1)*t-s)+b},7q:f(t,b,c,d,s){j(!s)s=1.4Q;h c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},7p:f(t,b,c,d,s){j(!s)s=1.4Q;j((t/=d/2)<1)h c/2*(t*t*(((s*=(1.5E))+1)*t-s))+b;h c/2*((t-=2)*t*(((s*=(1.5E))+1)*t+s)+2)+b},5D:f(t,b,c,d){h c-X.2Q.4P(d-t,0,c,d)+b},4P:f(t,b,c,d){j((t/=d)<(1/2.75)){h c*(7.3R*t*t)+b}Q j(t<(2/2.75)){h c*(7.3R*(t-=(1.5/2.75))*t+.75)+b}Q j(t<(2.5/2.75)){h c*(7.3R*(t-=(2.25/2.75))*t+.7o)+b}Q{h c*(7.3R*(t-=(2.7n/2.75))*t+.7m)+b}},7l:f(t,b,c,d){j(t<d/2)h X.2Q.5D(t*2,0,c,d)*.5+b;h X.2Q.4P(t*2-d,0,c,d)*.5+c*.5+b}};k 2L={};2L.1C=M 11({2j:f(){h{3k:T,1J:\'4I\',2K:11.1G,2g:11.1G,5B:11.1G,4A:11.1G,1j:T,2u:{x:\'2i\',y:\'2w\'},3N:6}},1e:f(l,m){9.2N(9.2j(),m);9.r=$(l);9.3k=$(9.m.3k)||9.r;9.2l={\'P\':{},\'1D\':{}};9.K={\'1m\':{},\'P\':{}};9.1I={\'1m\':9.1m.2y(9)};9.3k.1a(\'4H\',9.1I.1m);j(9.m.1e)9.m.1e.1i(9)},1m:f(o){9.2l.1m=o.1y;k 1j=9.m.1j;9.1j={\'x\':[],\'y\':[]};I(k z W 9.m.2u){9.K.P[z]=9.r.1W(9.m.2u[z]).2C();9.2l.1D[z]=o.1y[z]-9.K.P[z];j(1j&&1j[z]){I(k i=0;i<2;i++){j($2B(1j[z][i]))9.1j[z][i]=1j[z][i].2m?1j[z][i].1i(9):1j[z][i]}}}9.1I.29=9.29.2y(9);9.1I.3l=9.3l.2y(9);9.1I.1s=9.1s.J(9);L.1a(\'2P\',9.m.3N?9.1I.3l:9.1I.29);L.1a(\'5A\',9.1I.1s);9.1x(\'2K\',9.r);o.1s()},3l:f(o){k 5C=G.3e(G.3m(G.22(o.1y.x-9.2l.1m.x,2)+G.22(o.1y.y-9.2l.1m.y,2)));j(5C>9.m.3N){L.1E(\'2P\',9.1I.3l);L.1a(\'2P\',9.1I.29);9.29(o);9.1x(\'5B\',9.r)}o.1s()},29:f(o){9.4O=T;9.2l.P=o.1y;I(k z W 9.m.2u){9.K.P[z]=o.1y[z]-9.2l.1D[z];j(9.1j[z]){j($2B(9.1j[z][1])&&(9.K.P[z]>9.1j[z][1])){9.K.P[z]=9.1j[z][1];9.4O=1g}Q j($2B(9.1j[z][0])&&(9.K.P[z]<9.1j[z][0])){9.K.P[z]=9.1j[z][0];9.4O=1g}}9.r.1F(9.m.2u[z],9.K.P[z]+9.m.1J)}9.1x(\'4A\',9.r);o.1s()},7k:f(){9.3k.1E(\'4H\',9.1I.1m)},1s:f(){L.1E(\'2P\',9.1I.29);L.1E(\'5A\',9.1I.1s);9.1x(\'2g\',9.r)}});2L.1C.1T(M 3c);2L.1C.1T(M 3b);1b.N({7j:f(m){h M 2L.1C(9,1H.N(m||{},{2u:{x:\'3j\',y:\'3i\'}}))}});k 4J=M 11({2j:f(){h{3h:20,4K:1,3K:f(x,y){9.r.2a(x,y)}}},1e:f(r,m){9.2N(9.2j(),m);9.r=$(r);9.4M=([12,L].15(r))?$(L.4N):9.r},1m:f(){9.4L=9.5z.2y(9);9.4M.1a(\'2P\',9.4L)},1s:f(){9.4M.1E(\'2P\',9.4L);9.1f=$3Q(9.1f)},5z:f(o){9.1y=(9.r==12)?o.5y:o.1y;j(!9.1f)9.1f=9.1V.2k(50,9)},1V:f(){k l=9.r.3P();k 1D=9.r.2O();k 2z={\'x\':0,\'y\':0};I(k z W 9.1y){j(9.1y[z]<(9.m.3h+1D[z])&&l.1V[z]!=0)2z[z]=(9.1y[z]-9.m.3h-1D[z])*9.m.4K;Q j(9.1y[z]+9.m.3h>(l.2A[z]+1D[z])&&l.1V[z]+l.2A[z]!=l.3O[z])2z[z]=(9.1y[z]-l.2A[z]+9.m.3h-1D[z])*9.m.4K}j(2z.y||2z.x)9.1x(\'3K\',[l.1V.x+2z.x,l.1V.y+2z.y])}});4J.1T(M 3c);4J.1T(M 3b);k 4t=M 11({2j:f(){h{3K:11.1G,2g:11.1G,4x:f(1D){9.21.1F(9.p,1D+\'4I\')},3d:3g,1k:\'4G\',3f:T}},1e:f(l,21,m){9.r=$(l);9.21=$(21);9.2N(9.2j(),m);9.4w=-1;9.4v=-1;9.19=-1;9.r.1a(\'4H\',9.5w.2y(9));j(9.m.3f)9.r.1a(\'2M\',9.5x.2y(9));j(9.m.1k==\'4G\'){9.z=\'x\';9.p=\'2i\';9.1B=9.r.2x-9.21.2x;9.4y=9.21.2x/2;9.4z=9.r.4F.J(9.r)}Q j(9.m.1k==\'4E\'){9.z=\'y\';9.p=\'2w\';9.1B=9.r.2v-9.21.2v;9.4y=9.21.2v/2;9.4z=9.r.4D.J(9.r)}9.21.1F(\'1Z\',\'7i\').1F(9.p,0);k 4B={},4C={};4C[9.z]=[0,9.1B];4B[9.z]=9.p;9.29=M 2L.1C(9.21,{1j:4C,3N:0,2u:4B,2K:f(){9.3M()}.J(9),4A:f(){9.3M()}.J(9),2g:f(){9.3M();9.2h()}.J(9)});j(9.m.1e)9.m.1e.1i(9)},1U:f(19){j(19>9.m.3d)19=9.m.3d;Q j(19<0)19=0;9.19=19;9.3L();9.2h();9.1x(\'4x\',9.5v(9.19)+\'\');h 9},5x:f(o){j(o.3f<0)9.1U(9.19+1);Q j(o.3f>0)9.1U(9.19-1);o.1s()},5w:f(o){k 1Z=o.1y[9.z]-9.4z()-9.4y;j(1Z>9.1B)1Z=9.1B;Q j(1Z<0)1Z=0;9.19=9.4u(1Z);9.3L();9.2h();9.1x(\'4x\',1Z+\'\')},3M:f(){9.19=9.4u(9.29.K.P[9.z]);9.3L()},3L:f(){j(9.4w!=9.19){9.4w=9.19;9.1x(\'3K\',9.19)}},2h:f(){j(9.4v!==9.19){9.4v=9.19;9.1x(\'2g\',9.19+\'\')}},4u:f(1Z){h G.3e(1Z/9.1B*9.m.3d)},5v:f(19){h(9.1B)*19/9.m.3d}});4t.1T(M 3c);4t.1T(M 3b);',62,619,'|||||||||this||||||function||return||if|var|el|options|property|event||type|element|||obj|||||||to||||from|Math||for|bind|value|document|new|extend|fn|now|else|args||false|prototype|events|in|Fx|arguments|||Class|window||length|test||css|push|step|addEvent|Element|case|className|initialize|timer|true|style|call|limit|mode|rgb|start|parsed|each|found|param|Array|stop|parent|keys|selector|elements|fireEvent|page|values|color|max|Base|pos|removeEvent|setStyle|empty|Object|bound|unit|null|source|parse|Elements|key|break|filters|array|properties|implement|set|scroll|getStyle|PI|opacity|position||knob|pow|CSS|name||parentNode||match|drag|scrollTo|iCss|switch|delay|create|current|onComplete|end|left|getOptions|periodical|mouse|apply|margin|increase|iTo|Color|documentElement|previous|returns|modifiers|offsetHeight|top|offsetWidth|bindWithEvent|change|size|chk|toInt|compute|setNow|getValue|getElementsBySelector|chains|HTMLElement|hex|onStart|Drag|mousewheel|setOptions|getOffsets|mousemove|Transitions|wrapper|offset|wait|select|getNow|fx|fromTo|time|id|att|Garbage||text|while|replace|newArray||||item|Options|Events|steps|round|wheel|100|area|height|width|handle|checkAndDrag|sqrt|sin|min|iNow|iFrom|join|hexToRgb|parseFloat|domready|domReady|ie|alpha|colors|undefined|hasClass|getElements|getTag|filter|option|Event|toLowerCase|target|rgbToHex|items|onChange|checkStep|draggedKnob|snap|scrollSize|getSize|clear|5625|hidden|Multi|scrollLeft|scrollTop|khtml|readyState|loaded|remove||tagName|getElement|sel|getElementById|clean||splice|preventDefault|stopPropagation|relatedTarget|offsetTop|offsetLeft|setProperty|attribute|whitespace|indexOf|currentStyle|visibility|string|appendChild|inject|instanceof|ms|attempt|bit|forEach|pr0t0typ3|klass|Slider|toStep|previousEnd|previousChange|onTick|half|getPos|onDrag|modSlide|limSlide|getTop|vertical|getLeft|horizontal|mousedown|px|Scroller|velocity|coord|mousemover|body|out|bounceOut|70158|asin|abs|cos|sineInOut|layout|iProps|map|split|duration||opera|script|ie6|copy|operator|getElementsByTagName|els|on|Function|right|pageY|pageX|code|String|DOMMouseScroll|trash|removeEvents|offs|getBrother|getNext|what|gecko|camelCase|object|Native|result|typeof|parseInt|charAt|results|toPosition|clickedElement|scrolledElement|client|getCoords|mouseup|onSnap|distance|bounceIn|525|linear|slideOut|slideIn|hide|adopt|injectAfter|toElement|full|number|iParsed|Styles|Style|Single|Chain|onCancel|fps|getTime|Date|cTime|transition|callChain|getScrollHeight|getScrollWidth|getHeight|getWidth|getScrollTop|getScrollLeft|pageXOffset|pageYOffset|scrollWidth|scrollHeight|clientHeight|clientWidth|init|complete|ie_ready|catch|try|invert|mix|Hash|getAttribute|filterByAttribute|filterByTagName|filterByClassName|filterById|w_|defaults|which|clientY|clientX|special|120|wheelDelta|nodeType|unload|collect|selectedIndex|bottom|class|html|setAttribute|default|replaceWith|createElement|setStyles|childNodes|Sibling|evType|removeEventListener|addEventListener|hyphenate|defaultView|visible|setOpacity|cssText|addClass|removeClass|contents|inside|after|before|insertBefore|where|_elements_extended_|_element_extended_|err|toFloat||Number|trim|toUpperCase|params|regex|iterable|some|every|random|picked|parentize|noinit|relative|makeResizable|detach|bounceInOut|984375|625|9375|backInOut|backOut|backIn|elasticInOut|elasticOut|elasticIn|circInOut|circOut|circIn|expoInOut|expoOut|expoIn|sineOut|sineIn|quintInOut|quintOut|quintIn|quartInOut|quartOut|quartIn|cubicInOut|cubicOut|cubicIn|quadInOut|quadOut|quadIn|toggle|show|overflow|div|Slide|toRight|toLeft|toBottom|toTop|Scroll|effects|effect|clearTimer|custom|1000|500|innerHeight|innerWidth|onDomReady|DOMContentLoaded|load|onreadystatechange|void|javascript|src|defer|write|BackgroundImageCache|execCommand|disableImageCache|255|pop|get|tag|getElementsByClassName|ES|clearChain|chain|delete|backspace|space|esc|down|up|enter|returnValue|cancelBubble|mouseout|fromElement|mouseover|button|rightClick|click|fromCharCode|keyCode|detail|metaKey|meta|altKey|alt|ctrlKey|control|shiftKey|shift|srcElement|Window|textarea|password|radio|checkbox|checked|input|getPosition|offsetParent|do|getProperty|innerHTML|setHTML|setProperties|attributes|getChildren|getParent|previousSibling|lastChild|getLast|nextSibling|firstChild|getFirst|next|getPrevious|detachEvent|addEvents|attachEvent|getPropertyValue|getComputedStyle|padding|zoom|hasLayout|toggleClass|createTextNode|styleSheet|appendText|replaceChild|cloneNode|clone|removeChild|injectInside|injectBefore|embed|bindAsEventListener|pass|finally|setInterval|setTimeout|concat|toString|transparent|capitalize|RegExp|associate|getBoxObjectFor|taintEnabled|navigator|all|ie7|XMLHttpRequest|ActiveXObject|clearInterval|clearTimeout|floor|pick|textnode|nodeValue|nodeName'.split('|'),0,{})) diff --git a/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.uncompressed.js b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.uncompressed.js new file mode 100644 index 0000000..d0ef7e8 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/js/smoothgallery/scripts/mootools.uncompressed.js @@ -0,0 +1,4078 @@ +/* +Script: Moo.js + My Object Oriented javascript. + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. + +Credits: + - Class is slightly based on Base.js <http://dean.edwards.name/weblog/2006/03/base/> (c) 2006 Dean Edwards, License <http://creativecommons.org/licenses/LGPL/2.1/> + - Some functions are based on those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license + - Documentation by Aaron Newton (aaron.newton [at] cnet [dot] com) and Valerio Proietti. +*/ + +/* +Class: Class + The base class object of the <http://mootools.net> framework. + +Arguments: + properties - the collection of properties that apply to the class. Creates a new class, its initialize method will fire upon class instantiation. + +Example: + (start code) + var Cat = new Class({ + initialize: function(name){ + this.name = name; + } + }); + var myCat = new Cat('Micia'); + alert myCat.name; //alerts 'Micia' + (end) +*/ + +var Class = function(properties){ + var klass = function(){ + if (this.initialize && arguments[0] != 'noinit') return this.initialize.apply(this, arguments); + else return this; + }; + for (var property in this) klass[property] = this[property]; + klass.prototype = properties; + return klass; +}; + +/* +Property: empty + Returns an empty function +*/ + +Class.empty = function(){}; + +Class.prototype = { + + /* + Property: extend + Returns the copy of the Class extended with the passed in properties. + + Arguments: + properties - the properties to add to the base class in this new Class. + + Example: + (start code) + var Animal = new Class({ + initialize: function(age){ + this.age = age; + } + }); + var Cat = Animal.extend({ + initialize: function(name, age){ + this.parent(age); //will call the previous initialize; + this.name = name; + } + }); + var myCat = new Cat('Micia', 20); + alert myCat.name; //alerts 'Micia' + alert myCat.age; //alerts 20 + (end) + */ + + extend: function(properties){ + var pr0t0typ3 = new this('noinit'); + + var parentize = function(previous, current){ + if (!previous.apply || !current.apply) return false; + return function(){ + this.parent = previous; + return current.apply(this, arguments); + }; + }; + + for (var property in properties){ + var previous = pr0t0typ3[property]; + var current = properties[property]; + if (previous && previous != current) current = parentize(previous, current) || current; + pr0t0typ3[property] = current; + } + return new Class(pr0t0typ3); + }, + + /* + Property: implement + Implements the passed in properties to the base Class prototypes, altering the base class, unlike <Class.extend>. + + Arguments: + properties - the properties to add to the base class. + + Example: + (start code) + var Animal = new Class({ + initialize: function(age){ + this.age = age; + } + }); + Animal.implement({ + setName: function(name){ + this.name = name + } + }); + var myAnimal = new Animal(20); + myAnimal.setName('Micia'); + alert(myAnimal.name); //alerts 'Micia' + (end) + */ + + implement: function(properties){ + for (var property in properties) this.prototype[property] = properties[property]; + } + +}; + +/* Section: Object related Functions */ + +/* +Function: Object.extend + Copies all the properties from the second passed object to the first passed Object. + If you do myWhatever.extend = Object.extend the first parameter will become myWhatever, and your extend function will only need one parameter. + +Example: + (start code) + var firstOb = { + 'name': 'John', + 'lastName': 'Doe' + }; + var secondOb = { + 'age': '20', + 'sex': 'male', + 'lastName': 'Dorian' + }; + Object.extend(firstOb, secondOb); + //firstOb will become: + { + 'name': 'John', + 'lastName': 'Dorian', + 'age': '20', + 'sex': 'male' + }; + (end) + +Returns: + The first object, extended. +*/ + +Object.extend = function(){ + var args = arguments; + args = (args[1]) ? [args[0], args[1]] : [this, args[0]]; + for (var property in args[1]) args[0][property] = args[1][property]; + return args[0]; +}; + +/* +Function: Object.Native + Will add a .extend method to the objects passed as a parameter, equivalent to <Class.implement> + +Arguments: + a number of classes/native javascript objects + +*/ + +Object.Native = function(){ + for (var i = 0; i < arguments.length; i++) arguments[i].extend = Class.prototype.implement; +}; + +new Object.Native(Function, Array, String, Number, Class); + +/* +Script: Utility.js + Contains Utility functions + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +//htmlelement mapping + +if (typeof HTMLElement == 'undefined'){ + var HTMLElement = Class.empty; + HTMLElement.prototype = {}; +} + +/* +Function: $type + Returns the type of object that matches the element passed in. + +Arguments: + obj - the object to inspect. + +Example: + >var myString = 'hello'; + >$type(myString); //returns "string" + +Returns: + 'element' - if obj is a DOM element node + 'textnode' - if obj is a DOM text node + 'whitespace' - if obj is a DOM whitespace node + 'array' - if obj is an array + 'object' - if obj is an object + 'string' - if obj is a string + 'number' - if obj is a number + 'boolean' - if obj is a boolean + 'function' - if obj is a function + false - (boolean) if the object is not defined or none of the above. +*/ + +function $type(obj){ + if (obj === null || obj === undefined) return false; + var type = typeof obj; + if (type == 'object'){ + if (obj instanceof HTMLElement) return 'element'; + if (obj instanceof Array) return 'array'; + if (obj.nodeName){ + switch (obj.nodeType){ + case 1: return 'element'; + case 3: return obj.nodeValue.test('\\S') ? 'textnode' : 'whitespace'; + } + } + } + return type; +}; + +/* +Function: $chk + Returns true if the passed in value/object exists or is 0, otherwise returns false. + Useful to accept zeroes. +*/ + +function $chk(obj){ + return !!(obj || obj === 0); +}; + +/* +Function: $pick + Returns the first object if defined, otherwise returns the second. +*/ + +function $pick(obj, picked){ + return ($type(obj)) ? obj : picked; +}; + +/* +Function: $random + Returns a random integer number between the two passed in values. + +Arguments: + min - integer, the minimum value (inclusive). + max - integer, the maximum value (inclusive). + +Returns: + a random integer between min and max. +*/ + +function $random(min, max){ + return Math.floor(Math.random() * (max - min + 1) + min); +}; + +/* +Function: $clear + clears a timeout or an Interval. + +Returns: + null + +Arguments: + timer - the setInterval or setTimeout to clear. + +Example: + >var myTimer = myFunction.delay(5000); //wait 5 seconds and execute my function. + >myTimer = $clear(myTimer); //nevermind + +See also: + <Function.delay>, <Function.periodical> +*/ + +function $clear(timer){ + clearTimeout(timer); + clearInterval(timer); + return null; +}; + +/* Section: Browser Detection */ + +/* +Properties: + window.ie - will be set to true if the current browser is internet explorer (any). + window.ie6 - will be set to true if the current browser is internet explorer 6. + window.ie7 - will be set to true if the current browser is internet explorer 7. + window.khtml - will be set to true if the current browser is Safari/Konqueror. + window.gecko - will be set to true if the current browser is Mozilla/Gecko. +*/ + +if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true; +else if (document.childNodes && !document.all && !navigator.taintEnabled) window.khtml = true; +else if (document.getBoxObjectFor != null) window.gecko = true; + +/* +Script: Array.js + Contains Array prototypes and the function <$A>; + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Array + A collection of The Array Object prototype methods. +*/ + +//emulated methods + +/* +Property: forEach + Iterates through an array; This method is only available for browsers without native *forEach* support. + For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach> +*/ + +Array.prototype.forEach = Array.prototype.forEach || function(fn, bind){ + for (var i = 0; i < this.length; i++) fn.call(bind, this[i], i, this); +}; + +/* +Property: map + This method is provided only for browsers without native *map* support. + For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map> +*/ + +Array.prototype.map = Array.prototype.map || function(fn, bind){ + var results = []; + for (var i = 0; i < this.length; i++) results[i] = fn.call(bind, this[i], i, this); + return results; +}; + +/* +Property: every + This method is provided only for browsers without native *every* support. + For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every> +*/ + +Array.prototype.every = Array.prototype.every || function(fn, bind){ + for (var i = 0; i < this.length; i++){ + if (!fn.call(bind, this[i], i, this)) return false; + } + return true; +}; + +/* +Property: some + This method is provided only for browsers without native *some* support. + For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some> +*/ + +Array.prototype.some = Array.prototype.some || function(fn, bind){ + for (var i = 0; i < this.length; i++){ + if (fn.call(bind, this[i], i, this)) return true; + } + return false; +}; + +/* +Property: indexOf + This method is provided only for browsers without native *indexOf* support. + For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf> +*/ + +Array.prototype.indexOf = Array.prototype.indexOf || function(item, from){ + from = from || 0; + if (from < 0) from = Math.max(0, this.length + from); + while (from < this.length){ + if(this[from] === item) return from; + from++; + } + return -1; +}; + +//custom methods + +Array.extend({ + + /* + Property: each + Same as <Array.forEach>. + + Arguments: + fn - the function to execute with each item in the array + bind - optional, the object that the "this" of the function will refer to. + + Example: + >var Animals = ['Cat', 'Dog', 'Coala']; + >Animals.forEach(function(animal){ + > document.write(animal) + >}); + */ + + each: Array.prototype.forEach, + + /* + Property: copy + Copy the array and returns it. + + Returns: + an Array + + Example: + >var letters = ["a","b","c"]; + >var copy = ["a","b","c"].copy(); + */ + + copy: function(){ + var newArray = []; + for (var i = 0; i < this.length; i++) newArray[i] = this[i]; + return newArray; + }, + + /* + Property: remove + Removes all occurrences of an item from the array. + + Arguments: + item - the item to remove + + Returns: + the Array with all occurrences of the item removed. + + Example: + >["1","2","3","2"].remove("2") // ["1","3"]; + */ + + remove: function(item){ + var i = 0; + while (i < this.length){ + if (this[i] == item) this.splice(i, 1); + else i++; + } + return this; + }, + + /* + Property: test + Tests an array for the presence of an item. + + Arguments: + item - the item to search for in the array. + from - optional, the index at which to begin the search, default is 0. If negative, it is taken as the offset from the end of the array. + + Returns: + true - the item was found + false - it wasn't + + Example: + >["a","b","c"].test("a"); // true + >["a","b","c"].test("d"); // false + */ + + test: function(item, from){ + return this.indexOf(item, from) != -1; + }, + + /* + Property: extend + Extends an array with another + + Arguments: + newArray - the array to extend ours with + + Example: + >var Animals = ['Cat', 'Dog', 'Coala']; + >Animals.extend(['Lizard']); + >//Animals is now: ['Cat', 'Dog', 'Coala', 'Lizard']; + */ + + extend: function(newArray){ + for (var i = 0; i < newArray.length; i++) this.push(newArray[i]); + return this; + }, + + /* + Property: associate + Creates an object with key-value pairs based on the array of keywords passed in + and the current content of the array. + + Arguments: + keys - the array of keywords. + + Example: + (start code) + var Animals = ['Cat', 'Dog', 'Coala', 'Lizard']; + var Speech = ['Miao', 'Bau', 'Fruuu', 'Mute']; + var Speeches = Animals.associate(speech); + //Speeches['Miao'] is now Cat. + //Speeches['Bau'] is now Dog. + //... + (end) + */ + + associate: function(keys){ + var obj = {}, length = Math.min(this.length, keys.length); + for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; + return obj; + } + +}); + +/* Section: Utility Functions */ + +/* +Function: $A() + Same as <Array.copy>, but as function. + Useful to apply Array prototypes to iterable objects, as a collection of DOM elements or the arguments object. + +Example: + (start code) + function myFunction(){ + $A(arguments).each(argument, function(){ + alert(argument); + }); + }; + //the above will alert all the arguments passed to the function myFunction. + (end) +*/ + +function $A(array){ + return Array.prototype.copy.call(array); +}; + +/* +Function: $each + use to iterate through iterables that are not regular arrays, such as builtin getElementsByTagName calls, or arguments of a function. + +Arguments: + iterable - an iterable element. + function - function to apply to the iterable. + bind - optional, the 'this' of the function will refer to this object. +*/ + +function $each(iterable, fn, bind){ + return Array.prototype.forEach.call(iterable, fn, bind); +}; + +/* +Script: String.js + Contains String prototypes and Number prototypes. + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: String + A collection of The String Object prototype methods. +*/ + +String.extend({ + + /* + Property: test + Tests a string with a regular expression. + + Arguments: + regex - the regular expression you want to match the string with + params - optional, any parameters you want to pass to the regex ('g' has no effect) + + Returns: + true if a match for the regular expression is found in the string, false if not. + See <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:RegExp:test> + + Example: + >"I like cookies".test("cookie"); // returns true + >"I like cookies".test("COOKIE", "i") // ignore case, returns true + >"I like cookies".test("cake"); // returns false + */ + + test: function(regex, params){ + return new RegExp(regex, params).test(this); + }, + + /* + Property: toInt + parses a string to an integer. + + Returns: + either an int or "NaN" if the string is not a number. + + Example: + >var value = "10px".toInt(); // value is 10 + */ + + toInt: function(){ + return parseInt(this); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + /* + Property: camelCase + Converts a hiphenated string to a camelcase string. + + Example: + >"I-like-cookies".camelCase(); //"ILikeCookies" + + Returns: + the camel cased string + */ + + camelCase: function(){ + return this.replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + /* + Property: hyphenate + Converts a camelCased string to a hyphen-ated string. + + Example: + >"ILikeCookies".hyphenate(); //"I-like-cookies" + */ + + hyphenate: function(){ + return this.replace(/\w[A-Z]/g, function(match){ + return (match.charAt(0)+'-'+match.charAt(1).toLowerCase()); + }); + }, + + /* + Property: capitalize + Converts the first letter in each word of a string to Uppercase. + + Example: + >"i like cookies".capitalize(); //"I Like Cookies" + + Returns: + the capitalized string + */ + + capitalize: function(){ + return this.toLowerCase().replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + /* + Property: trim + Trims the leading and trailing spaces off a string. + + Example: + >" i like cookies ".trim() //"i like cookies" + + Returns: + the trimmed string + */ + + trim: function(){ + return this.replace(/^\s+|\s+$/g, ''); + }, + + /* + Property: clean + trims (<String.trim>) a string AND removes all the double spaces in a string. + + Returns: + the cleaned string + + Example: + >" i like cookies \n\n".clean() //"i like cookies" + */ + + clean: function(){ + return this.replace(/\s{2,}/g, ' ').trim(); + }, + + /* + Property: rgbToHex + Converts an RGB value to hexidecimal. The string must be in the format of "rgb(255, 255, 255)" or "rgba(255, 255, 255, 1)"; + + Arguments: + array - boolean value, defaults to false. Use true if you want the array ['FF', '33', '00'] as output instead of #FF3300 + + Returns: + hex string or array. returns transparent if the fourth value of rgba in input string is 0, + + Example: + >"rgb(17,34,51)".rgbToHex(); //"#112233" + >"rgba(17,34,51,0)".rgbToHex(); //"transparent" + >"rgb(17,34,51)".rgbToHex(true); //[11,22,33] + */ + + rgbToHex: function(array){ + var rgb = this.match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : false; + }, + + /* + Property: hexToRgb + Converts a hexidecimal color value to RGB. Input string must be the hex color value (with or without the hash). Also accepts triplets ('333'); + + Arguments: + array - boolean value, defaults to false. Use true if you want the array ['255', '255', '255'] as output instead of "rgb(255,255,255)"; + + Returns: + rgb string or array. + + Example: + >"#112233".hexToRgb(); //"rgb(17,34,51)" + >"#112233".hexToRgb(true); //[17,34,51] + */ + + hexToRgb: function(array){ + var hex = this.match('^#?(\\w{1,2})(\\w{1,2})(\\w{1,2})$'); + return (hex) ? hex.hexToRgb(array) : false; + } + +}); + +Array.extend({ + + rgbToHex: function(array){ + if (this.length < 3) return false; + if (this[3] && this[3] == 0) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++){ + var bit = (this[i]-0).toString(16); + hex.push(bit.length == 1 ? '0'+bit : bit); + } + return array ? hex : '#'+hex.join(''); + }, + + hexToRgb: function(array){ + if (this.length != 4) return false; + var rgb = []; + for (var i = 1; i < 4; i++){ + if (this[i].length == 1) this[i] += this[i]; + rgb.push(parseInt(this[i], 16)); + } + return array ? rgb : 'rgb('+rgb.join(',')+')'; + } + +}); + +/* +Class: Number + contains the internal method toInt. +*/ + +Number.extend({ + + /* + Property: toInt + Returns this number; useful because toInt must work on both Strings and Numbers. + */ + + toInt: function(){ + return parseInt(this); + }, + + toFloat: function(){ + return parseFloat(this); + } + +}); + +/* +Script: Function.js + Contains Function prototypes and utility functions . + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. + +Credits: + - Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license +*/ + +/* +Class: Function + A collection of The Function Object prototype methods. +*/ + +Function.extend({ + + create: function(options){ + var fn = this; + options = Object.extend({ + 'bind': fn, + 'event': false, + 'arguments': null, + 'delay': false, + 'periodical': false, + 'attempt': false + }, options || {}); + if (options.arguments != null && typeof options.arguments != 'undefined' && !(options.arguments instanceof Array)) + options.arguments = [options.arguments]; + return function(event){ + var args = options.arguments || arguments; + if (options.event){ + event = (options.event === true) ? event || window.event : new options.event(event); + args = [event].concat(args); + } + var returns = function(){ + return fn.apply(options.bind, args); + }; + if (options.delay) return setTimeout(returns, options.delay); + if (options.periodical) return setInterval(returns, options.periodical); + if (options.attempt){ + try { + var result = returns(); + } catch(err){ + result = err; + } finally { + return result; + } + } else return returns(); + }; + }, + + /* + Property: pass + Shortcut to create closures with arguments and bind. + + Returns: + a function. + + Arguments: + args - the arguments passed. must be an array if arguments > 1 + bind - optional, the object that the "this" of the function will refer to. + + Example: + >myFunction.pass([arg1, arg2], myElement); + */ + + pass: function(args, bind){ + return this.create({'arguments': args, 'bind': bind}); + }, + + /* + Property: attempt + Tries to execute the function, returns either the function results or the error. + + Arguments: + args - the arguments passed. must be an array if arguments > 1 + bind - optional, the object that the "this" of the function will refer to. + + Example: + >myFunction.attempt([arg1, arg2], myElement); + */ + + attempt: function(args, bind){ + return this.create({'arguments': args, 'bind': bind, 'attempt': true})(); + }, + + /* + Property: bind + method to easily create closures with "this" altered. + + Arguments: + bind - optional, the object that the "this" of the function will refer to. + args - optional, the arguments passed. must be an array if arguments > 1 + + Returns: + a function. + + Example: + >function myFunction(){ + > this.setStyle('color', 'red'); + > // note that 'this' here refers to myFunction, not an element + > // we'll need to bind this function to the element we want to alter + >}; + >var myBoundFunction = myFunction.bind(myElement); + >myBoundFunction(); // this will make the element myElement red. + */ + + bind: function(bind, args){ + return this.create({'bind': bind, 'arguments': args}); + }, + + /* + Property: bindAsEventListener + cross browser method to pass event firer + + Arguments: + bind - optional, the object that the "this" of the function will refer to. + args - optional, the arguments passed. must be an array if arguments > 1 + + Returns: + a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser. + + Example: + >function myFunction(event){ + > alert(event.clientx) //returns the coordinates of the mouse.. + >}; + >myElement.onclick = myFunction.bindAsEventListener(myElement); + */ + + bindAsEventListener: function(bind, args){ + return this.create({'bind': bind, 'event': true, 'arguments': args}); + }, + + /* + Property: delay + Delays the execution of a function by a specified duration. + + Arguments: + ms - the duration to wait in milliseconds + bind - optional, the object that the "this" of the function will refer to. + args - optional, the arguments passed. must be an array if arguments > 1 + + Example: + >myFunction.delay(50, myElement) //wait 50 milliseconds, then call myFunction and bind myElement to it + >(function(){alert('one second later...')}).delay(1000); //wait a second and alert + */ + + delay: function(ms, bind, args){ + return this.create({'delay': ms, 'bind': bind, 'arguments': args})(); + }, + + /* + Property: periodical + Executes a function in the specified intervals of time + + Arguments: + ms - the duration of the intervals between executions. + bind - optional, the object that the "this" of the function will refer to. + args - optional, the arguments passed. must be an array if arguments > 1 + */ + + periodical: function(ms, bind, args){ + return this.create({'periodical': ms, 'bind': bind, 'arguments': args})(); + } + +}); + +/* +Script: Element.js + Contains useful Element prototypes, to be used with the dollar function <$>. + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. + +Credits: + - Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license +*/ + +/* +Class: Element + Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>. +*/ + +var Element = new Class({ + + /* + Property: initialize + Creates a new element of the type passed in. + + Arguments: + el - the tag name for the element you wish to create. + + Example: + >var div = new Element('div'); + */ + + initialize: function(el){ + if ($type(el) == 'string') el = document.createElement(el); + return $(el); + } + +}); + +/* +Function: $() + returns the element passed in with all the Element prototypes applied. + +Arguments: + el - a reference to an actual element or a string representing the id of an element + +Example: + >$('myElement') // gets a DOM element by id with all the Element prototypes applied. + >var div = document.getElementById('myElement'); + >$(div) //returns an Element also with all the mootools extentions applied. + + You'll use this when you aren't sure if a variable is an actual element or an id, as + well as just shorthand for document.getElementById(). + +Returns: + a DOM element or false (if no id was found). + +Note: + you need to call $ on an element only once to get all the prototypes. + But its no harm to call it multiple times, as it will detect if it has been already extended. +*/ + +function $(el){ + if (!el) return false; + if (el._element_extended_ || [window, document].test(el)) return el; + if ($type(el) == 'string') el = document.getElementById(el); + if ($type(el) != 'element') return false; + if (['object', 'embed'].test(el.tagName.toLowerCase()) || el.extend) return el; + el._element_extended_ = true; + Garbage.collect(el); + el.extend = Object.extend; + if (!(el instanceof HTMLElement)) el.extend(Element.prototype); + return el; +}; + +//elements class + +var Elements = new Class({}); + +new Object.Native(Elements); + +document.getElementsBySelector = document.getElementsByTagName; + +/* +Function: $$() + Selects, and extends DOM elements. + +Arguments: + HTMLCollection(document.getElementsByTagName, element.childNodes), an array of elements, a string. + +Note: + if you loaded <Dom.js>, $$ will also accept CSS Selectors. + +Example: + >$$('a') //an array of all anchor tags on the page + >$$('a', 'b') //an array of all anchor and bold tags on the page + >$$('#myElement') //array containing only the element with id = myElement. (only with <Dom.js>) + >$$('#myElement a.myClass') //an array of all anchor tags with the class "myClass" within the DOM element with id "myElement" (only with <Dom.js>) + +Returns: + array - array of all the dom elements matched +*/ + +function $$(){ + if (!arguments) return false; + if (arguments.length == 1){ + if (!arguments[0]) return false; + if (arguments[0]._elements_extended_) return arguments[0]; + } + var elements = []; + $each(arguments, function(selector){ + switch ($type(selector)){ + case 'element': elements.push($(selector)); break; + case 'string': selector = document.getElementsBySelector(selector); + default: + if (selector.length){ + $each(selector, function(el){ + if ($(el)) elements.push(el); + }); + } + } + }); + elements._elements_extended_ = true; + return Object.extend(elements, new Elements); +}; + +Elements.Multi = function(property){ + return function(){ + var args = arguments; + var items = []; + var elements = true; + $each(this, function(el){ + var returns = el[property].apply(el, args); + if ($type(returns) != 'element') elements = false; + items.push(returns); + }); + if (elements) items = $$(items); + return items; + }; +}; + +Element.extend = function(properties){ + for (var property in properties){ + HTMLElement.prototype[property] = properties[property]; + Element.prototype[property] = properties[property]; + Elements.prototype[property] = Elements.Multi(property); + } +}; + +Element.extend({ + + inject: function(el, where){ + el = $(el) || new Element(el); + switch (where){ + case "before": $(el.parentNode).insertBefore(this, el); break; + case "after": + if (!el.getNext()) $(el.parentNode).appendChild(this); + else $(el.parentNode).insertBefore(this, el.getNext()); + break; + case "inside": el.appendChild(this); + } + return this; + }, + + /* + Property: injectBefore + Inserts the Element before the passed element. + + Parameteres: + el - a string representing the element to be injected in (myElementId, or div), or an element reference. + If you pass div or another tag, the element will be created. + + Example: + >html: + ><div id="myElement"></div> + ><div id="mySecondElement"></div> + >js: + >$('mySecondElement').injectBefore('myElement'); + >resulting html: + ><div id="mySecondElement"></div> + ><div id="myElement"></div> + + */ + + injectBefore: function(el){ + return this.inject(el, 'before'); + }, + + /* + Property: injectAfter + Same as <Element.injectBefore>, but inserts the element after. + */ + + injectAfter: function(el){ + return this.inject(el, 'after'); + }, + + /* + Property: injectInside + Same as <Element.injectBefore>, but inserts the element inside. + */ + + injectInside: function(el){ + return this.inject(el, 'inside'); + }, + + /* + Property: adopt + Inserts the passed element inside the Element. Works as <Element.injectInside> but in reverse. + + Parameteres: + el - a string representing the element to be injected in (myElementId, or div), or an element reference. + If you pass div or another tag, the element will be created. + */ + + adopt: function(el){ + this.appendChild($(el) || new Element(el)); + return this; + }, + + /* + Property: remove + Removes the Element from the DOM. + + Example: + >$('myElement').remove() //bye bye + */ + + remove: function(){ + this.parentNode.removeChild(this); + return this; + }, + + /* + Property: clone + Clones the Element and returns the cloned one. + + Returns: + the cloned element + + Example: + >var clone = $('myElement').clone().injectAfter('myElement'); + >//clones the Element and append the clone after the Element. + */ + + clone: function(contents){ + var el = this.cloneNode(contents !== false); + return $(el); + }, + + /* + Property: replaceWith + Replaces the Element with an element passed. + + Parameteres: + el - a string representing the element to be injected in (myElementId, or div), or an element reference. + If you pass div or another tag, the element will be created. + + Returns: + the passed in element + + Example: + >$('myOldElement').replaceWith($('myNewElement')); //$('myOldElement') is gone, and $('myNewElement') is in its place. + */ + + replaceWith: function(el){ + el = $(el) || new Element(el); + this.parentNode.replaceChild(el, this); + return el; + }, + + /* + Property: appendText + Appends text node to a DOM element. + + Arguments: + text - the text to append. + + Example: + ><div id="myElement">hey</div> + >$('myElement').appendText(' howdy'); //myElement innerHTML is now "hey howdy" + */ + + appendText: function(text){ + if (window.ie){ + switch(this.getTag()){ + case 'style': this.styleSheet.cssText = text; return this; + case 'script': this.setProperty('text', text); return this; + } + } + this.appendChild(document.createTextNode(text)); + return this; + }, + + /* + Property: hasClass + Tests the Element to see if it has the passed in className. + + Returns: + true - the Element has the class + false - it doesn't + + Arguments: + className - the class name to test. + + Example: + ><div id="myElement" class="testClass"></div> + >$('myElement').hasClass('testClass'); //returns true + */ + + hasClass: function(className){ + return this.className.test('(?:^|\\s+)' + className + '(?:\\s+|$)'); + }, + + /* + Property: addClass + Adds the passed in class to the Element, if the element doesnt already have it. + + Arguments: + className - the class name to add + + Example: + ><div id="myElement" class="testClass"></div> + >$('myElement').addClass('newClass'); //<div id="myElement" class="testClass newClass"></div> + */ + + addClass: function(className){ + if (!this.hasClass(className)) this.className = (this.className+' '+className).clean(); + return this; + }, + + /* + Property: removeClass + works like <Element.addClass>, but removes the class from the element. + */ + + removeClass: function(className){ + if (this.hasClass(className)) this.className = this.className.replace(className, '').clean(); + return this; + }, + + /* + Property: toggleClass + Adds or removes the passed in class name to the element, depending on if it's present or not. + + Arguments: + className - the class to add or remove + + Example: + ><div id="myElement" class="myClass"></div> + >$('myElement').toggleClass('myClass'); + ><div id="myElement" class=""></div> + >$('myElement').toggleClass('myClass'); + ><div id="myElement" class="myClass"></div> + */ + + toggleClass: function(className){ + return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); + }, + + /* + Property: setStyle + Sets a css property to the Element. + + Arguments: + property - the property to set + value - the value to which to set it + + Example: + >$('myElement').setStyle('width', '300px'); //the width is now 300px + */ + + setStyle: function(property, value){ + if (property == 'opacity') this.setOpacity(parseFloat(value)); + else this.style[property.camelCase()] = (value.push) ? value.rgbToHex() : value; + return this; + }, + + /* + Property: setStyles + Applies a collection of styles to the Element. + + Arguments: + source - an object or string containing all the styles to apply + + Examples: + >$('myElement').setStyles({ + > border: '1px solid #000', + > width: '300px', + > height: '400px' + >}); + + OR + + >$('myElement').setStyle('border: 1px solid #000; width: 300px; height: 400px;'); + */ + + setStyles: function(source){ + switch ($type(source)){ + case 'object': + for (var property in source) this.setStyle(property, source[property]); + break; + case 'string': + if (window.ie) this.cssText = source; + else this.setAttribute('style', source); + } + return this; + }, + + /* + Property: setOpacity + Sets the opacity of the Element, and sets also visibility == "hidden" if opacity == 0, and visibility = "visible" if opacity == 1. + + Arguments: + opacity - Accepts numbers from 0 to 1. + + Example: + >$('myElement').setOpacity(0.5) //make it 50% transparent + */ + + setOpacity: function(opacity){ + if (opacity == 0){ + if(this.style.visibility != "hidden") this.style.visibility = "hidden"; + } else { + if(this.style.visibility != "visible") this.style.visibility = "visible"; + } + if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; + if (window.ie) this.style.filter = "alpha(opacity=" + opacity*100 + ")"; + this.style.opacity = this.opacity = opacity; + return this; + }, + + /* + Property: getStyle + Returns the style of the Element given the property passed in. + + Arguments: + property - the css style property you want to retrieve + + Example: + >$('myElement').getStyle('width'); //returns "400px" + >//but you can also use + >$('myElement').getStyle('width').toInt(); //returns "400" + + Returns: + the style as a string + */ + + getStyle: function(property){ + property = property.camelCase(); + var style = this.style[property] || false; + if (!$chk(style)){ + if (property == 'opacity') return $chk(this.opacity) ? this.opacity : 1; + if (['margin', 'padding'].test(property)){ + return [this.getStyle(property+'-top') || 0, this.getStyle(property+'-right') || 0, + this.getStyle(property+'-bottom') || 0, this.getStyle(property+'-left') || 0].join(' '); + } + if (document.defaultView) style = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate()); + else if (this.currentStyle) style = this.currentStyle[property]; + } + return (style && property.test('color', 'i') && style.test('rgb')) ? style.rgbToHex() : style; + }, + + /* + Property: addEvent + Attaches an event listener to a DOM element. + + Arguments: + type - the event to monitor ('click', 'load', etc) without the prefix 'on'. + fn - the function to execute + + Example: + >$('myElement').addEvent('click', function(){alert('clicked!')}); + */ + + addEvent: function(type, fn){ + this.events = this.events || {}; + this.events[type] = this.events[type] || {'keys': [], 'values': []}; + if (!this.events[type].keys.test(fn)){ + this.events[type].keys.push(fn); + if (this.addEventListener){ + this.addEventListener((type == 'mousewheel' && window.gecko) ? 'DOMMouseScroll' : type, fn, false); + } else { + fn = fn.bind(this); + this.attachEvent('on'+type, fn); + this.events[type].values.push(fn); + } + } + return this; + }, + + addEvents: function(source){ + if (source){ + for (var type in source) this.addEvent(type, source[type]); + } + return this; + }, + + /* + Property: removeEvent + Works as Element.addEvent, but instead removes the previously added event listener. + */ + + removeEvent: function(type, fn){ + if (this.events && this.events[type]){ + var pos = this.events[type].keys.indexOf(fn); + if (pos == -1) return this; + var key = this.events[type].keys.splice(pos,1)[0]; + if (this.removeEventListener){ + this.removeEventListener((type == 'mousewheel' && window.gecko) ? 'DOMMouseScroll' : type, key, false); + } else { + this.detachEvent('on'+type, this.events[type].values.splice(pos,1)[0]); + } + } + return this; + }, + + /* + Property: removeEvents + removes all events of a certain type from an element. if no argument is passed in, removes all events. + */ + + removeEvents: function(type){ + if (this.events){ + if (type){ + if (this.events[type]){ + this.events[type].keys.each(function(fn){ + this.removeEvent(type, fn); + }, this); + this.events[type] = null; + } + } else { + for (var evType in this.events) this.removeEvents(evType); + this.events = null; + } + } + return this; + }, + + /* + Property: fireEvent + executes all events of the specified type present in the element. + */ + + fireEvent: function(type, args){ + if (this.events && this.events[type]){ + args = args || []; + if ($type(args) != 'array') args = [args]; + this.events[type].keys.each(function(fn){ + fn.apply(this, args); + }, this); + } + }, + + getBrother: function(what){ + var el = this[what+'Sibling']; + while ($type(el) == 'whitespace') el = el[what+'Sibling']; + return $(el); + }, + + /* + Property: getPrevious + Returns the previousSibling of the Element, excluding text nodes. + + Example: + >$('myElement').getPrevious(); //get the previous DOM element from myElement + + Returns: + the sibling element or undefined if none found. + */ + + getPrevious: function(){ + return this.getBrother('previous'); + }, + + /* + Property: getNext + Works as Element.getPrevious, but tries to find the nextSibling. + */ + + getNext: function(){ + return this.getBrother('next'); + }, + + /* + Property: getFirst + Works as <Element.getPrevious>, but tries to find the firstChild. + */ + + getFirst: function(){ + var el = this.firstChild; + while ($type(el) == 'whitespace') el = el.nextSibling; + return $(el); + }, + + /* + Property: getLast + Works as <Element.getPrevious>, but tries to find the lastChild. + */ + + getLast: function(){ + var el = this.lastChild; + while ($type(el) == 'whitespace') el = el.previousSibling; + return $(el); + }, + + /* + Property: getParent + returns the $(element.parentNode) + */ + + getParent: function(){ + return $(this.parentNode); + }, + + /* + Property: getChildren + returns all the $(element.childNodes), excluding text nodes. Returns as <Elements>. + */ + + getChildren: function(){ + return $$(this.childNodes); + }, + + /* + Property: setProperty + Sets an attribute for the Element. + + Arguments: + property - the property to assign the value passed in + value - the value to assign to the property passed in + + Example: + >$('myImage').setProperty('src', 'whatever.gif'); //myImage now points to whatever.gif for its source + */ + + setProperty: function(property, value){ + switch (property){ + case 'class': this.className = value; break; + case 'style': this.setStyles(value); break; + case 'name': if (window.ie6){ + var el = $(document.createElement('<'+this.getTag()+' name="'+value+'" />')); + $each(this.attributes, function(attribute){ + if (attribute.name != 'name') el.setProperty(attribute.name, attribute.value); + }); + if (this.parentNode) this.replaceWith(el); + return el; + } + default: this.setAttribute(property, value); + } + return this; + }, + + /* + Property: setProperties + Sets numerous attributes for the Element. + + Arguments: + source - an object with key/value pairs. + + Example: + >$('myElement').setProperties({ + > src: 'whatever.gif', + > alt: 'whatever dude' + >}); + ><img src="whatever.gif" alt="whatever dude"> + */ + + setProperties: function(source){ + for (var property in source) this.setProperty(property, source[property]); + return this; + }, + + /* + Property: setHTML + Sets the innerHTML of the Element. + + Arguments: + html - the new innerHTML for the element. + + Example: + >$('myElement').setHTML(newHTML) //the innerHTML of myElement is now = newHTML + */ + + setHTML: function(html){ + this.innerHTML = html; + return this; + }, + + /* + Property: getProperty + Gets the an attribute of the Element. + + Arguments: + property - the attribute to retrieve + + Example: + >$('myImage').getProperty('src') // returns whatever.gif + + Returns: + the value, or an empty string + */ + + getProperty: function(property){ + return (property == 'class') ? this.className : this.getAttribute(property); + }, + + /* + Property: getTag + Returns the tagName of the element in lower case. + + Example: + >$('myImage').getTag() // returns 'img' + + Returns: + The tag name in lower case + */ + + getTag: function(){ + return this.tagName.toLowerCase(); + }, + + getOffsets: function(){ + var el = this, offsetLeft = 0, offsetTop = 0; + do { + offsetLeft += el.offsetLeft || 0; + offsetTop += el.offsetTop || 0; + el = el.offsetParent; + } while (el); + return {'x': offsetLeft, 'y': offsetTop}; + }, + + /* + Property: scrollTo + scrolls the element to the specified coordinated (if the element has an overflow) + + Arguments: + x - the x coordinate + y - the y coordinate + + Example: + >$('myElement').scrollTo(0, 100) + */ + + scrollTo: function(x, y){ + this.scrollLeft = x; + this.scrollTop = y; + }, + + /* + Property: getSize + return an Object representing the size/scroll values of the element. + + Example: + (start code) + $('myElement').getSize(); + (end) + + Returns: + (start code) + { + 'scroll': {'x': 100, 'y': 100}, + 'size': {'x': 200, 'y': 400}, + 'scrollSize': {'x': 300, 'y': 500} + } + (end) + */ + + getSize: function(){ + return { + 'scroll': {'x': this.scrollLeft, 'y': this.scrollTop}, + 'size': {'x': this.offsetWidth, 'y': this.offsetHeight}, + 'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight} + }; + }, + + /* + Property: getTop + Returns the distance from the top of the window to the Element. + */ + + getTop: function(){ + return this.getOffsets().y; + }, + + /* + Property: getLeft + Returns the distance from the left of the window to the Element. + */ + + getLeft: function(){ + return this.getOffsets().x; + }, + + /* + Property: getPosition + Returns an object with width, height, left, right, top, and bottom, representing the values of the Element + + Example: + (start code) + var myValues = $('myElement').getPosition(); + (end) + + Returns: + (start code) + { + width: 200, + height: 300, + left: 100, + top: 50, + right: 300, + bottom: 350 + } + (end) + */ + + getPosition: function(){ + var offs = this.getOffsets(); + var obj = { + 'width': this.offsetWidth, + 'height': this.offsetHeight, + 'left': offs.x, + 'top': offs.y + }; + obj.right = obj.left + obj.width; + obj.bottom = obj.top + obj.height; + return obj; + }, + + /* + Property: getValue + Returns the value of the Element, if its tag is textarea, select or input. no multiple select support. + */ + + getValue: function(){ + switch (this.getTag()){ + case 'select': if (this.selectedIndex != -1) return this.options[this.selectedIndex].value; break; + case 'input': if (!(this.checked && ['checkbox', 'radio'].test(this.type)) && !['hidden', 'text', 'password'].test(this.type)) break; + case 'textarea': return this.value; + } + return false; + } + +}); + +var Window = window; + +window.addEvent = document.addEvent = Element.prototype.addEvent; +window.removeEvent = document.removeEvent = Element.prototype.removeEvent; + +var Garbage = { + + elements: [], + + collect: function(element){ + Garbage.elements.push(element); + }, + + trash: function(){ + window.removeEvent('unload', Garbage.trash); + Garbage.elements.each(function(el){ + el.removeEvents(); + for (var p in Element.prototype) HTMLElement[p] = window[p] = document[p] = el[p] = null; + el.extend = null; + }); + } + +}; + +window.addEvent('unload', Garbage.trash); + +/* +Script: Event.js + Event class + +Author: + Valerio Proietti, <http://mad4milk.net>, Michael Jackson, <http://ajaxon.com/michael> + +License: + MIT-style license. +*/ + +/* +Class: Event + Cross browser methods to manage events. + +Arguments: + event - the event + +Properties: + shift - true if the user pressed the shift + control - true if the user pressed the control + alt - true if the user pressed the alt + meta - true if the user pressed the meta key + code - the keycode of the key pressed + page.x - the x position of the mouse, relative to the full window + page.y - the y position of the mouse, relative to the full window + client.x - the x position of the mouse, relative to the viewport + client.y - the y position of the mouse, relative to the viewport + key - the key pressed as a lowercase string. key also returns 'enter', 'up', 'down', 'left', 'right', 'space', 'backspace', 'delete', 'esc'. Handy for these special keys. + target - the event target + relatedTarget - the event related target + +Example: + (start code) + $('myLink').onkeydown = function(event){ + var event = new Event(event); + //event is now the Event class. + alert(event.key); //returns the lowercase letter pressed + alert(event.shift); //returns true if the key pressed is shift + if (event.key == 's' && event.control) alert('document saved'); + }; + (end) +*/ + +var Event = new Class({ + + initialize: function(event){ + this.event = event || window.event; + this.type = this.event.type; + this.target = this.event.target || this.event.srcElement; + if (this.target.nodeType == 3) this.target = this.target.parentNode; // Safari + this.shift = this.event.shiftKey; + this.control = this.event.ctrlKey; + this.alt = this.event.altKey; + this.meta = this.event.metaKey; + if (['DOMMouseScroll', 'mousewheel'].test(this.type)){ + this.wheel = this.event.wheelDelta ? (this.event.wheelDelta / (window.opera ? -120 : 120)) : -(this.event.detail || 0) / 3; + } else if (this.type.test('key')){ + this.code = this.event.which || this.event.keyCode; + for (var name in Event.keys){ + if (Event.keys[name] == this.code) var special = name; + } + this.key = special || String.fromCharCode(this.code).toLowerCase(); + + } else if (this.type.test('mouse') || this.type == 'click'){ + this.page = { + 'x': this.event.pageX || this.event.clientX + document.documentElement.scrollLeft, + 'y': this.event.pageY || this.event.clientY + document.documentElement.scrollTop + }; + this.client = { + 'x': this.event.pageX ? this.event.pageX - window.pageXOffset : this.event.clientX, + 'y': this.event.pageY ? this.event.pageY - window.pageYOffset : this.event.clientY + }; + this.rightClick = (this.event.which == 3) || (this.event.button == 2); + switch (this.type){ + case 'mouseover': this.relatedTarget = this.event.relatedTarget || this.event.fromElement; break; + case 'mouseout': this.relatedTarget = this.event.relatedTarget || this.event.toElement; + } + } + }, + + /* + Property: stop + cross browser method to stop an event + */ + + stop: function() { + this.stopPropagation(); + this.preventDefault(); + return this; + }, + + /* + Property: stopPropagation + cross browser method to stop the propagation of an event + */ + + stopPropagation: function(){ + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; + return this; + }, + + /* + Property: preventDefault + cross browser method to prevent the default action of the event + */ + + preventDefault: function(){ + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; + return this; + } + +}); + +Event.keys = { + 'enter': 13, + 'up': 38, + 'down': 40, + 'left': 37, + 'right': 39, + 'esc': 27, + 'space': 32, + 'backspace': 8, + 'delete': 46 +}; + +Function.extend({ + + /* + Property: bindWithEvent + automatically passes mootools Event Class. + + Arguments: + bind - optional, the object that the "this" of the function will refer to. + + Returns: + a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser. + + Example: + >function myFunction(event){ + > alert(event.clientx) //returns the coordinates of the mouse.. + >}; + >myElement.onclick = myFunction.bindWithEvent(myElement); + */ + + bindWithEvent: function(bind, args){ + return this.create({'bind': bind, 'arguments': args, 'event': Event}); + } + +}); + + +/* +Script: Common.js + Contains common implementations for custom classes. In Mootools is implemented in <Ajax> and <Fx>. + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Chain + An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>. + Currently implemented in <Fx> and <Ajax>. In <Fx> for example, is used to execute a list of function, one after another, once the effect is completed. + The functions will not be fired all togheter, but one every completion, to create custom complex animations. + +Example: + (start code) + var myFx = new Fx.Style('element', 'opacity'); + + myFx.start(1,0).chain(function(){ + myFx.start(0,1); + }).chain(function(){ + myFx.start(1,0); + }).chain(function(){ + myFx.start(0,1); + }); + //the element will appear and disappear three times + (end) +*/ + +var Chain = new Class({ + + /* + Property: chain + adds a function to the Chain instance stack. + + Arguments: + fn - the function to append. + */ + + chain: function(fn){ + this.chains = this.chains || []; + this.chains.push(fn); + return this; + }, + + /* + Property: callChain + Executes the first function of the Chain instance stack, then removes it. The first function will then become the second. + */ + + callChain: function(){ + if (this.chains && this.chains.length) this.chains.splice(0, 1)[0].delay(10, this); + }, + + /* + Property: clearChain + Clears the stack of a Chain instance. + */ + + clearChain: function(){ + this.chains = []; + } + +}); + +/* +Class: Events + An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>. + In <Fx> Class, for example, is used to give the possibility add any number of functions to the Effects events, like onComplete, onStart, onCancel + +Example: + (start code) + var myFx = new Fx.Style('element', 'opacity').addEvent('onComplete', function(){ + alert('the effect is completed'); + }).addEvent('onComplete', function(){ + alert('I told you the effect is completed'); + }); + + myFx.start(0,1); + //upon completion it will display the 2 alerts, in order. + (end) +*/ + +var Events = new Class({ + + /* + Property: addEvent + adds an event to the stack of events of the Class instance. + */ + + addEvent: function(type, fn){ + if (fn != Class.empty){ + this.events = this.events || {}; + this.events[type] = this.events[type] || []; + if (!this.events[type].test(fn)) this.events[type].push(fn); + } + return this; + }, + + /* + Property: fireEvent + fires all events of the specified type in the Class instance. + */ + + fireEvent: function(type, args, delay){ + if (this.events && this.events[type]){ + this.events[type].each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + } + return this; + }, + + /* + Property: removeEvent + removes an event from the stack of events of the Class instance. + */ + + removeEvent: function(type, fn){ + if (this.events && this.events[type]) this.events[type].remove(fn); + return this; + } + +}); + +/* +Class: Options + An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>. + Used to automate the options settings, also adding Class <Events> when the option begins with on. +*/ + +var Options = new Class({ + + /* + Property: setOptions + sets this.options + + Arguments: + defaults - the default set of options + options - the user entered options. can be empty too. + + Note: + if your Class has <Events> implemented, every option beginning with on, followed by a capital letter (onComplete) becomes an Class instance event. + */ + + setOptions: function(defaults, options){ + this.options = Object.extend(defaults, options); + if (this.addEvent){ + for (var option in this.options){ + if (($type(this.options[option]) == 'function') && option.test('^on[A-Z]')) this.addEvent(option, this.options[option]); + } + } + return this; + } + +}); + +/* +Script: Dom.js + Css Query related function and <Element> extensions + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* Section: Utility Functions */ + +/* +Function: $E + Selects a single (i.e. the first found) Element based on the selector passed in and an optional filter element. + +Arguments: + selector - the css selector to match + filter - optional; a DOM element to limit the scope of the selector match; defaults to document. + +Example: + >$E('a', 'myElement') //find the first anchor tag inside the DOM element with id 'myElement' + +Returns: + a DOM element - the first element that matches the selector +*/ + +function $E(selector, filter){ + return ($(filter) || document).getElement(selector); +}; + +/* +Function: $ES + Returns a collection of Elements that match the selector passed in limited to the scope of the optional filter. + See Also: <Element.getElements> for an alternate syntax. + +Returns: + an array of dom elements that match the selector within the filter + +Arguments: + selector - css selector to match + filter - optional; a DOM element to limit the scope of the selector match; defaults to document. + +Examples: + >$ES("a") //gets all the anchor tags; synonymous with $$("a") + >$ES('a','myElement') //get all the anchor tags within $('myElement') +*/ + +function $ES(selector, filter){ + return ($(filter) || document).getElementsBySelector(selector); +}; + +/* +Class: Element + Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>. +*/ + +Element.extend({ + + /* + Property: getElements + Gets all the elements within an element that match the given (single) selector. + + Arguments: + selector - the css selector to match + + Example: + >$('myElement').getElements('a'); // get all anchors within myElement + + Credits: + Say thanks to Christophe Beyls <http://digitalia.be> for the new regular expression that rules getElements, a big step forward in terms of speed. + */ + + getElements: function(selector){ + var filters = []; + selector.clean().split(' ').each(function(sel, i){ + var param = sel.match('^(\\w*|\\*)(?:#([\\w_-]+)|\\.([\\w_-]+))?(?:\\[["\']?(\\w+)["\']?(?:([\\*\\^\\$]?=)["\']?(\\w*)["\']?)?\\])?$'); + //PARAM ARRAY: 0 = full string: 1 = tag; 2 = id; 3 = class; 4 = attribute; 5 = operator; 6 = value; + if (!param) return; + param[1] = param[1] || '*'; + if (i == 0){ + if (param[2]){ + var el = this.getElementById(param[2]); + if (!el || ((param[1] != '*') && (Element.prototype.getTag.call(el) != param[1]))) return; + filters = [el]; + } else { + filters = $A(this.getElementsByTagName(param[1])); + } + } else { + filters = Elements.prototype.filterByTagName.call(filters, param[1]); + if (param[2]) filters = Elements.prototype.filterById.call(filters, param[2]); + } + if (param[3]) filters = Elements.prototype.filterByClassName.call(filters, param[3]); + if (param[4]) filters = Elements.prototype.filterByAttribute.call(filters, param[4], param[6], param[5]); + }, this); + return $$(filters); + }, + + /* + Property: getElementById + Targets an element with the specified id found inside the Element. Does not overwrite document.getElementById. + + Arguments: + id - the id of the element to find. + */ + + getElementById: function(id){ + var el = document.getElementById(id); + if (!el) return false; + for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ + if (!parent) return false; + } + return el; + }, + + /* + Property: getElement + Same as <Element.getElements>, but returns only the first. Alternate syntax for <$E>, where filter is the Element. + */ + + getElement: function(selector){ + return this.getElementsBySelector(selector)[0]; + }, + + /* + Property: getElementsBySelector + Same as <Element.getElements>, but allows for comma separated selectors, as in css. Alternate syntax for <$$>, where filter is the Element. + + */ + + getElementsBySelector: function(selector){ + var els = []; + selector.split(',').each(function(sel){ + els.extend(this.getElements(sel)); + }, this); + return $$(els); + } + +}); + +document.extend = Object.extend; + +/* Section: document related functions */ + +document.extend({ + /* + Function: document.getElementsByClassName + Returns all the elements that match a specific class name. + Here for compatibility purposes. can also be written: document.getElements('.className'), or $$('.className') + */ + + getElementsByClassName: function(className){ + return document.getElements('.'+className); + }, + getElement: Element.prototype.getElement, + getElements: Element.prototype.getElements, + getElementsBySelector: Element.prototype.getElementsBySelector + +}); + +/* +Class: Elements + Methods for dom queries arrays, as <$$>. +*/ + +Elements.extend({ + + //internal methods + + filterById: function(id, tag){ + var found = []; + this.each(function(el){ + if (el.id == id) found.push(el); + }); + return found; + }, + + filterByClassName: function(className){ + var found = []; + this.each(function(el){ + if (Element.prototype.hasClass.call(el, className)) found.push(el); + }); + return found; + }, + + filterByTagName: function(tagName){ + var found = []; + this.each(function(el){ + found.extend(el.getElementsByTagName(tagName)); + }); + return found; + }, + + filterByAttribute: function(name, value, operator){ + var found = []; + this.each(function(el){ + var att = el.getAttribute(name); + if (!att) return found; + if (!operator) return found.push(el); + + switch (operator){ + case '*=': if (att.test(value)) found.push(el); break; + case '=': if (att == value) found.push(el); break; + case '^=': if (att.test('^'+value)) found.push(el); break; + case '$=': if (att.test(value+'$')) found.push(el); + } + return found; + }); + return found; + } + +}); + +/* +Script: Hash.js + Contains the class Hash. + +Author: + Christophe Beyls <http://digitalia.be> + +License: + MIT-style license. +*/ + +/* +Class: Hash + It wraps an object that it uses internally as a map. The user must use put(), get(), and remove() to add/change, retrieve and remove values, it must not access the internal object directly. With this implementation, null values are not allowed. + +Example: + (start code) + var hash = new Hash({a: 'hi', b: 'world', c: 'howdy'}); + hash.remove('b'); // b is removed. + hash.set('c', 'hello'); + hash.get('c'); // returns 'hello' + hash.length // returns 2 (a and b) + (end) +*/ + +var Hash = new Class({ + + length: 0, + + initialize: function(obj) { + this.obj = {}; + for (var property in obj) { + this.obj[property] = obj[property]; + this.length++; + } + }, + + get: function(key) { + return this.obj[key]; + }, + + set: function(key, value) { + if (value == null) return false; + if (this.obj[key] == undefined) this.length++; + this.obj[key] = value; + return this; + }, + + remove: function(key) { + if (this.obj[key] == undefined) return false; + var obj = {}; + this.length--; + for (var property in this.obj){ + if (property != key) obj[property] = this.obj[property]; + } + this.obj = obj; + return this; + }, + + each: function(fn, bind) { + for (var property in this.obj) fn.call(bind || this, property, this.obj[property]); + }, + + extend: function(obj){ + this.initialize(Object.extend(this.obj, obj)); + return this; + }, + + empty: function() { + return (this.length == 0); + }, + + keys: function() { + var keys = []; + for (var property in this.obj) keys.push(property); + return keys; + }, + + values: function() { + var values = []; + for (var property in this.obj) values.push(this.obj[property]); + return values; + } + +}); + +/* +Function: $H + Shortcut to create an Hash from an Object. +*/ + +function $H(obj) { + return new Hash(obj); +}; + +/* +Script: Color.js + Contains the Color class. + +Author: + Michael Jackson <http://ajaxon.com/michael> + +License: + MIT-style license. +*/ + +/* +Class: Color + Creates a new Color Object, which is an array with some color specific methods. + +Example: + (start code) + var black = new Color('#000'); + var purple = new Color([255,0,255]); + // mix black with white and purple, each time at 10% of the new color + var darkpurple = black.mix('#fff', purple, 10); + $('myDiv').setStyle('background-color', darkpurple); + (end) +*/ + +var Color = new Class({ + + initialize: function(color){ + if (color.mix && color.invert) return color; + var rgb = (color.push) ? color : color.hexToRgb(true); + return Object.extend(rgb, Color.prototype); + }, + + mix: function(){ + var colors = $A(arguments); + var alpha = 50; + if ($type(colors[colors.length-1]) == 'number') alpha = colors.pop(); + var rgb = this.copy(); + colors.each(function(color){ + color = new Color(color); + for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha)); + }); + return new Color(rgb); + }, + + invert: function(){ + var rgb = []; + for (var i = 0; i < 3; i++) rgb.push(255 - this[i]); + return new Color(rgb); + } + +}); + +function $C(color){ + return new Color(color); +}; + +/* +Script: Window.Base.js + Contains Window.onDomReady and Window.disableImageCache + +License: + MIT-style license. +*/ + +/* +Class: Window + Cross browser methods to get the window size, onDomReady method. +*/ + +window.extend = Object.extend; + +window.extend({ + + /* + Function: window.disableImageCache + Disables background image chache for internex explorer, to prevent flickering. + To be called if you have effects with background images, and they flicker. + + Example: + Window.disableImageCache(); + */ + + disableImageCache: function(){ + if (this.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch (e){}; + }, + + addEvent: function(type, fn){ + if (type == 'domready'){ + if (this.loaded) fn(); + else if (!this.events || !this.events.domready){ + var domReady = function(){ + if (this.loaded) return; + this.loaded = true; + if (this.timer) this.timer = $clear(this.timer); + Element.prototype.fireEvent.call(this, 'domready'); + this.events.domready = null; + }.bind(this); + if (document.readyState && this.khtml){ //safari and konqueror + this.timer = function(){ + if (['loaded','complete'].test(document.readyState)) domReady(); + }.periodical(50); + } + else if (document.readyState && this.ie){ //ie + document.write("<script id=ie_ready defer src=javascript:void(0)><\/script>"); + $('ie_ready').onreadystatechange = function(){ + if (this.readyState == 'complete') domReady(); + }; + } else { //others + this.addEvent("load", domReady); + document.addEvent("DOMContentLoaded", domReady); + } + } + } + Element.prototype.addEvent.call(this, type, fn); + return this; + }, + + /* + Function: window.onDomReady + Executes the passed in function when the DOM is ready (when the document tree has loaded, not waiting for images). + Same as window.addEvent('domready', init); + + Credits: + (c) Dean Edwards/Matthias Miller/John Resig, remastered for mootools. Later touched up by Christophe Beyls <http://digitalia.be>. + + Arguments: + init - the function to execute when the DOM is ready + + Example: + > window.addEvent('domready', function(){alert('the dom is ready')}); + */ + + onDomReady: function(init){ + return this.addEvent('domready', init); + } + +}); + +/* +Script: Window.Size.js + Window cross-browser dimensions methods. + +License: + MIT-style license. +*/ + +/* +Class: window + Cross browser methods to get the window size, onDomReady method. +*/ + +window.extend({ + + /* + Property: getWidth + Returns an integer representing the width of the browser. + */ + + getWidth: function(){ + if (this.khtml || this.opera) return this.innerWidth; + else return document.documentElement.clientWidth || document.body.clientWidth; + }, + + /* + Property: getHeight + Returns an integer representing the height of the browser. + */ + + getHeight: function(){ + if (this.khtml || this.opera) return this.innerHeight; + return document.documentElement.clientHeight || document.body.clientHeight; + }, + + /* + Property: getScrollHeight + Returns an integer representing the scrollHeight of the window. + + See Also: + <http://developer.mozilla.org/en/docs/DOM:element.scrollHeight> + */ + + getScrollHeight: function(){ + return document.documentElement.scrollHeight; + }, + + /* + Property: getScrollWidth + Returns an integer representing the scrollWidth of the window. + + See Also: + <http://developer.mozilla.org/en/docs/DOM:element.scrollWidth> + */ + + getScrollWidth: function(){ + return document.documentElement.scrollWidth; + }, + + /* + Property: getScrollTop + Returns an integer representing the scrollTop of the window (the number of pixels the window has scrolled from the top). + + See Also: + <http://developer.mozilla.org/en/docs/DOM:element.scrollTop> + */ + + getScrollTop: function(){ + return this.pageYOffset || document.documentElement.scrollTop; + }, + + /* + Property: getScrollLeft + Returns an integer representing the scrollLeft of the window (the number of pixels the window has scrolled from the left). + + See Also: + <http://developer.mozilla.org/en/docs/DOM:element.scrollLeft> + */ + + getScrollLeft: function(){ + return this.pageXOffset || document.documentElement.scrollLeft; + }, + + /* + Property: getSize + Same as <Element.getSize> + */ + + getSize: function(){ + return { + 'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()}, + 'size': {'x': this.getWidth(), 'y': this.getHeight()}, + 'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()} + }; + }, + + //ignore + getOffsets: function(){return {'x': 0, 'y': 0}} + +}); + +/* +Script: Fx.Base.js + Contains <Fx.Base> and two Transitions. + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +var Fx = {}; + +/* +Class: Fx.Base + Base class for the Mootools Effects (Moo.Fx) library. + +Options: + onStart - the function to execute as the effect begins; nothing (<Class.empty>) by default. + onComplete - the function to execute after the effect has processed; nothing (<Class.empty>) by default. + transition - the equation to use for the effect see <Fx.Transitions>; default is <Fx.Transitions.sineInOut> + duration - the duration of the effect in ms; 500 is the default. + unit - the unit is 'px' by default (other values include things like 'em' for fonts or '%'). + wait - boolean: to wait or not to wait for a current transition to end before running another of the same instance. defaults to true. + fps - the frames per second for the transition; default is 30 +*/ + +Fx.Base = new Class({ + + getOptions: function(){ + return { + onStart: Class.empty, + onComplete: Class.empty, + onCancel: Class.empty, + transition: Fx.Transitions.sineInOut, + duration: 500, + unit: 'px', + wait: true, + fps: 50 + }; + }, + + initialize: function(options){ + this.element = this.element || null; + this.setOptions(this.getOptions(), options); + if (this.options.initialize) this.options.initialize.call(this); + }, + + step: function(){ + var time = new Date().getTime(); + if (time < this.time + this.options.duration){ + this.cTime = time - this.time; + this.setNow(); + this.increase(); + } else { + this.stop(true); + this.now = this.to; + this.increase(); + this.fireEvent('onComplete', this.element, 10); + this.callChain(); + } + }, + + /* + Property: set + Immediately sets the value with no transition. + + Arguments: + to - the point to jump to + + Example: + >var myFx = new Fx.Style('myElement', 'opacity').set(0); //will make it immediately transparent + */ + + set: function(to){ + this.now = to; + this.increase(); + return this; + }, + + setNow: function(){ + this.now = this.compute(this.from, this.to); + }, + + compute: function(from, to){ + return this.options.transition(this.cTime, from, (to - from), this.options.duration); + }, + + /* + Property: start + Executes an effect from one position to the other. + + Arguments: + from - integer: staring value + to - integer: the ending value + + Examples: + >var myFx = new Fx.Style('myElement', 'opacity').start(0,1); //display a transition from transparent to opaque. + */ + + start: function(from, to){ + if (!this.options.wait) this.stop(); + else if (this.timer) return this; + this.from = from; + this.to = to; + this.time = new Date().getTime(); + this.timer = this.step.periodical(Math.round(1000/this.options.fps), this); + this.fireEvent('onStart', this.element); + return this; + }, + + /* + Property: stop + Stops the transition. + */ + + stop: function(end){ + if (!this.timer) return this; + this.timer = $clear(this.timer); + if (!end) this.fireEvent('onCancel', this.element); + return this; + }, + + //compat + custom: function(from, to){return this.start(from, to)}, + clearTimer: function(end){return this.stop(end)} + +}); + +Fx.Base.implement(new Chain); +Fx.Base.implement(new Events); +Fx.Base.implement(new Options); + +/* +Class: Fx.Transitions + A collection of transition equations for use with the <Fx> Class. + +See Also: + <Fxtransitions.js> for a whole bunch of transitions. + +Credits: + Easing Equations, (c) 2003 Robert Penner (http://www.robertpenner.com/easing/), Open Source BSD License. +*/ + +Fx.Transitions = { + + /* Property: linear */ + linear: function(t, b, c, d){ + return c*t/d + b; + }, + + /* Property: sineInOut */ + sineInOut: function(t, b, c, d){ + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + } + +}; + +/* +Script: Fx.CSS.js + Css parsing class for effects. Required by <Fx.Style>, <Fx.Styles>, <Fx.Elements>. No documentation needed, as its used internally. + +Author: + Christophe Beyls, <http://www.digitalia.be>, + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +Fx.CSS = { + + select: function(property, to){ + if (property.test('color', 'i')) return this.Color; + if (to.test && to.test(' ')) return this.Multi; + return this.Single; + }, + + parse: function(el, property, fromTo){ + if (!fromTo.push) fromTo = [fromTo]; + var from = fromTo[0], to = fromTo[1]; + if (!to && to != 0){ + to = from; + from = el.getStyle(property); + } + var css = this.select(property, to); + return {from: css.parse(from), to: css.parse(to), css: css}; + } + +}; + +Fx.CSS.Single = { + + parse: function(value){ + return parseFloat(value); + }, + + getNow: function(from, to, fx){ + return fx.compute(from, to); + }, + + getValue: function(value, unit){ + return value+unit; + } + +}; + +Fx.CSS.Multi = { + + parse: function(value){ + return value.push ? value : value.split(' ').map(function(v){ + return parseFloat(v); + }); + }, + + getNow: function(from, to, fx){ + var now = []; + for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]); + return now; + }, + + getValue: function(value, unit){ + return value.join(unit+' ')+unit; + } + +}; + +Fx.CSS.Color = { + + parse: function(value){ + return value.push ? value : value.hexToRgb(true); + }, + + getNow: function(from, to, fx){ + var now = []; + for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i])); + return now; + }, + + getValue: function(value){ + return 'rgb('+value.join(',')+')'; + } + +}; + +/* +Script: Fx.Style.js + Contains <Fx.Style> + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Fx.Style + The Style effect; Extends <Fx.Base>, inherits all its properties. Used to transition any css property from one value to another. Includes colors. + Colors must be in hex format. + +Arguments: + el - the $(element) to apply the style transition to + property - the property to transition + options - the Fx.Base options (see: <Fx.Base>) + +Example: + >var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500}); + >marginChange.start(10, 100); +*/ + +Fx.Style = Fx.Base.extend({ + + initialize: function(el, property, options){ + this.element = $(el); + this.property = property; + this.parent(options); + }, + + /* + Property: hide + Same as <Fx.Base.set>(0) + */ + + hide: function(){ + return this.set(0); + }, + + setNow: function(){ + this.now = this.css.getNow(this.from, this.to, this); + }, + + set: function(to){ + this.css = Fx.CSS.select(this.property, to); + return this.parent(this.css.parse(to)); + }, + + /* + Property: start + displays the transition to the value/values passed in + + Example: + (start code) + var var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500}); + marginChange.start(10); //tries to read current margin top value and goes from current to 10 + (end) + */ + + start: function(from, to){ + if (this.timer && this.options.wait) return this; + var parsed = Fx.CSS.parse(this.element, this.property, [from, to]); + this.css = parsed.css; + return this.parent(parsed.from, parsed.to); + }, + + increase: function(){ + this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit)); + } + +}); + +/* +Class: Element + Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>. +*/ + +Element.extend({ + + /* + Property: effect + Applies an <Fx.Style> to the Element; This a shortcut for <Fx.Style>. + + Example: + >var myEffect = $('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear}); + >myEffect.start(10, 100); + */ + + effect: function(property, options){ + return new Fx.Style(this, property, options); + } + +}); + +/* +Script: Fx.Styles.js + Contains <Fx.Styles> + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Fx.Styles + Allows you to animate multiple css properties at once; Extends <Fx.Base>, inherits all its properties. Includes colors. + Colors must be in hex format. + +Arguments: + el - the $(element) to apply the styles transition to + options - the fx options (see: <Fx.Base>) + +Example: + (start code) + var myEffects = new Fx.Styles('myElement', {duration: 1000, transition: Fx.Transitions.linear}); + + //height from 10 to 100 and width from 900 to 300 + myEffects.start({ + 'height': [10, 100], + 'width': [900, 300] + }); + + //or height from current height to 100 and width from current width to 300 + myEffects.start({ + 'height': 100, + 'width': 300 + }); + (end) +*/ + +Fx.Styles = Fx.Base.extend({ + + initialize: function(el, options){ + this.element = $(el); + this.parent(options); + }, + + setNow: function(){ + for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this); + }, + + set: function(to){ + var parsed = {}; + this.css = {}; + for (var p in to){ + this.css[p] = Fx.CSS.select(p, to[p]); + parsed[p] = this.css[p].parse(to[p]); + } + return this.parent(parsed); + }, + + /* + Property: start + The function you'll actually use to execute a transition. + + Arguments: + an object + + Example: + see <Fx.Styles> + */ + + start: function(obj){ + if (this.timer && this.options.wait) return this; + this.now = {}; + this.css = {}; + var from = {}, to = {}; + for (var p in obj){ + var parsed = Fx.CSS.parse(this.element, p, obj[p]); + from[p] = parsed.from; + to[p] = parsed.to; + this.css[p] = parsed.css; + } + return this.parent(from, to); + }, + + increase: function(){ + for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit)); + } + +}); + +/* +Class: Element + Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>. +*/ + +Element.extend({ + + /* + Property: effects + Applies an <Fx.Styles> to the Element; This a shortcut for <Fx.Styles>. + + Example: + >var myEffects = $(myElement).effects({duration: 1000, transition: Fx.Transitions.sineInOut}); + >myEffects.start({'height': [10, 100], 'width': [900, 300]}); + */ + + effects: function(options){ + return new Fx.Styles(this, options); + } + +}); + +/* +Script: Fx.Elements.js + Contains <Fx.Elements> + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Fx.Elements + Fx.Elements allows you to apply any number of styles transitions to a selection of elements. Includes colors (must be in hex format). + +Arguments: + elements - a collection of elements the effects will be applied to. + options - same as <Fx.Base> options. +*/ + +Fx.Elements = Fx.Base.extend({ + + initialize: function(elements, options){ + this.elements = $$(elements); + this.parent(options); + }, + + setNow: function(){ + for (var i in this.from){ + var iFrom = this.from[i], iTo = this.to[i], iCss = this.css[i], iNow = this.now[i] = {}; + for (var p in iFrom) iNow[p] = iCss[p].getNow(iFrom[p], iTo[p], this); + } + }, + + set: function(to){ + var parsed = {}; + this.css = {}; + for (var i in to){ + var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {}; + for (var p in iTo){ + iCss[p] = Fx.CSS.select(p, iTo[p]); + iParsed[p] = iCss[p].parse(iTo[p]); + } + } + return this.parent(parsed); + }, + + /* + Property: start + Applies the passed in style transitions to each object named (see example). Each item in the collection is refered to as a numerical string ("1" for instance). The first item is "0", the second "1", etc. + + Example: + (start code) + var myElementsEffects = new Fx.Elements($$('a')); + myElementsEffects.start({ + '0': { //let's change the first element's opacity and width + 'opacity': [0,1], + 'width': [100,200] + }, + '1': { //and the second one's opacity + 'opacity': [0.2, 0.5] + } + }); + (end) + */ + + start: function(obj){ + if (this.timer && this.options.wait) return this; + this.now = {}; + this.css = {}; + var from = {}, to = {}; + for (var i in obj){ + var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}, iCss = this.css[i] = {}; + for (var p in iProps){ + var parsed = Fx.CSS.parse(this.elements[i], p, iProps[p]); + iFrom[p] = parsed.from; + iTo[p] = parsed.to; + iCss[p] = parsed.css; + } + } + return this.parent(from, to); + }, + + increase: function(){ + for (var i in this.now){ + var iNow = this.now[i], iCss = this.css[i]; + for (var p in iNow) this.elements[i].setStyle(p, iCss[p].getValue(iNow[p], this.options.unit)); + } + } + +}); + +/* +Script: Fx.Scroll.js + Contains <Fx.Scroll> + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Fx.Scroll + Scroll any element with an overflow, including the window element. + +Arguments: + element - the element to scroll + options - same as <Fx.Base> options. +*/ + +Fx.Scroll = Fx.Base.extend({ + + initialize: function(element, options){ + this.now = []; + this.element = $(element); + this.addEvent('onStart', function(){ + this.element.addEvent('mousewheel', this.stop.bind(this, false)); + }.bind(this)); + this.removeEvent('onComplete', function(){ + this.element.removeEvent('mousewheel', this.stop.bind(this, false)); + }.bind(this)); + this.parent(options); + }, + + setNow: function(){ + for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]); + }, + + /* + Property: scrollTo + Scrolls the chosen element to the x/y coordinates. + + Arguments: + x - the x coordinate to scroll the element to + y - the y coordinate to scroll the element to + */ + + scrollTo: function(x, y){ + if (this.timer && this.options.wait) return this; + var el = this.element.getSize(); + var values = {'x': x, 'y': y}; + for (var z in el.size){ + var max = el.scrollSize[z] - el.size[z]; + if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? Math.max(Math.min(values[z], max), 0) : max; + else values[z] = el.scroll[z]; + } + return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]); + }, + + /* + Property: toTop + Scrolls the chosen element to its maximum top. + */ + + toTop: function(){ + return this.scrollTo(false, 0); + }, + + /* + Property: toBottom + Scrolls the chosen element to its maximum bottom. + */ + + toBottom: function(){ + return this.scrollTo(false, 'full'); + }, + + /* + Property: toLeft + Scrolls the chosen element to its maximum left. + */ + + toLeft: function(){ + return this.scrollTo(0, false); + }, + + /* + Property: toRight + Scrolls the chosen element to its maximum right. + */ + + toRight: function(){ + return this.scrollTo('full', false); + }, + + /* + Property: toElement + Scrolls the specified element to the position the passed in element is found. Only usable if the chosen element is == window. + + Arguments: + el - the $(element) to scroll the window to + */ + + toElement: function(el){ + return this.scrollTo($(el).getLeft(), $(el).getTop()); + }, + + increase: function(){ + this.element.scrollTo(this.now[0], this.now[1]); + } + +}); + +/* +Script: Fx.Slide.js + Contains <Fx.Slide> + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Fx.Slide + The slide effect; slides an element in horizontally or vertically, the contents will fold inside. Extends <Fx.Base>, inherits all its properties. + +Note: + This effect works on any block element, but the element *cannot be positioned*; no margins or absolute positions. To position the element, put it inside another element (a wrapper div, for instance) and position that instead. + +Options: + mode - set it to vertical or horizontal. Defaults to vertical. + and all the <Fx.Base> options + +Example: + (start code) + var mySlider = new Fx.Slide('myElement', {duration: 500}); + mySlider.toggle() //toggle the slider up and down. + (end) +*/ + +Fx.Slide = Fx.Base.extend({ + + initialize: function(el, options){ + this.element = $(el).setStyle('margin', 0); + this.wrapper = new Element('div').injectAfter(this.element).setStyle('overflow', 'hidden').adopt(this.element); + this.setOptions({'mode': 'vertical'}, options); + this.now = []; + this.parent(this.options); + }, + + setNow: function(){ + for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]); + }, + + vertical: function(){ + this.margin = 'top'; + this.layout = 'height'; + this.offset = this.element.offsetHeight; + return [this.element.getStyle('margin-top').toInt(), this.wrapper.getStyle('height').toInt()]; + }, + + horizontal: function(){ + this.margin = 'left'; + this.layout = 'width'; + this.offset = this.element.offsetWidth; + return [this.element.getStyle('margin-left').toInt(), this.wrapper.getStyle('width').toInt()]; + }, + + /* + Property: slideIn + slides the elements in view horizontally or vertically, depending on the mode parameter or options.mode. + */ + + slideIn: function(mode){ + return this.start(this[mode || this.options.mode](), [0, this.offset]); + }, + + /* + Property: slideOut + slides the elements out of the view horizontally or vertically, depending on the mode parameter or options.mode. + */ + + slideOut: function(mode){ + return this.start(this[mode || this.options.mode](), [-this.offset, 0]); + }, + + /* + Property: hide + Hides the element without a transition. + */ + + hide: function(mode){ + this[mode || this.options.mode](); + return this.set([-this.offset, 0]); + }, + + /* + Property: show + Shows the element without a transition. + */ + + show: function(mode){ + this[mode || this.options.mode](); + return this.set([0, this.offset]); + }, + + /* + Property: toggle + Slides in or Out the element, depending on its state + */ + + toggle: function(mode){ + if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode); + else return this.slideOut(mode); + }, + + increase: function(){ + this.element.setStyle('margin-'+this.margin, this.now[0]+this.options.unit); + this.wrapper.setStyle(this.layout, this.now[1]+this.options.unit); + } + +}); + +/* +Script: Fx.Transitions.js + Cool transitions, to be used with all the effects. + +Author: + Robert Penner, <http://www.robertpenner.com/easing/>, modified to be used with mootools. + +License: + Easing Equations v1.5, (c) 2003 Robert Penner, all rights reserved. Open Source BSD License. +*/ + +/* +Class: Fx.Transitions + A collection of tweaning transitions for use with the <Fx.Base> classes. +*/ + +Fx.Transitions = { + + /* Property: linear */ + linear: function(t, b, c, d){ + return c*t/d + b; + }, + + /* Property: quadIn */ + quadIn: function(t, b, c, d){ + return c*(t/=d)*t + b; + }, + + /* Property: quatOut */ + quadOut: function(t, b, c, d){ + return -c *(t/=d)*(t-2) + b; + }, + + /* Property: quadInOut */ + quadInOut: function(t, b, c, d){ + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + + /* Property: cubicIn */ + cubicIn: function(t, b, c, d){ + return c*(t/=d)*t*t + b; + }, + + /* Property: cubicOut */ + cubicOut: function(t, b, c, d){ + return c*((t=t/d-1)*t*t + 1) + b; + }, + + /* Property: cubicInOut */ + cubicInOut: function(t, b, c, d){ + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + }, + + /* Property: quartIn */ + quartIn: function(t, b, c, d){ + return c*(t/=d)*t*t*t + b; + }, + + /* Property: quartOut */ + quartOut: function(t, b, c, d){ + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + + /* Property: quartInOut */ + quartInOut: function(t, b, c, d){ + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + + /* Property: quintIn */ + quintIn: function(t, b, c, d){ + return c*(t/=d)*t*t*t*t + b; + }, + + /* Property: quintOut */ + quintOut: function(t, b, c, d){ + return c*((t=t/d-1)*t*t*t*t + 1) + b; + }, + + /* Property: quintInOut */ + quintInOut: function(t, b, c, d){ + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + }, + + /* Property: sineIn */ + sineIn: function(t, b, c, d){ + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + }, + + /* Property: sineOut */ + sineOut: function(t, b, c, d){ + return c * Math.sin(t/d * (Math.PI/2)) + b; + }, + + /* Property: sineInOut */ + sineInOut: function(t, b, c, d){ + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + }, + + /* Property: expoIn */ + expoIn: function(t, b, c, d){ + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + + /* Property: expoOut */ + expoOut: function(t, b, c, d){ + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + + /* Property: expoInOut */ + expoInOut: function(t, b, c, d){ + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + + /* Property: circIn */ + circIn: function(t, b, c, d){ + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + }, + + /* Property: circOut */ + circOut: function(t, b, c, d){ + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + }, + + /* Property: circInOut */ + circInOut: function(t, b, c, d){ + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + }, + + /* Property: elasticIn */ + elasticIn: function(t, b, c, d, a, p){ + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a) a = 1; + if (a < Math.abs(c)){ a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin(c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + + /* Property: elasticOut */ + elasticOut: function(t, b, c, d, a, p){ + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a) a = 1; + if (a < Math.abs(c)){ a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin(c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + + /* Property: elasticInOut */ + elasticInOut: function(t, b, c, d, a, p){ + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); if (!a) a = 1; + if (a < Math.abs(c)){ a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin(c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + + /* Property: backIn */ + backIn: function(t, b, c, d, s){ + if (!s) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + + /* Property: backOut */ + backOut: function(t, b, c, d, s){ + if (!s) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + + /* Property: backInOut */ + backInOut: function(t, b, c, d, s){ + if (!s) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + + /* Property: bounceIn */ + bounceIn: function(t, b, c, d){ + return c - Fx.Transitions.bounceOut (d-t, 0, c, d) + b; + }, + + /* Property: bounceOut */ + bounceOut: function(t, b, c, d){ + if ((t/=d) < (1/2.75)){ + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)){ + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)){ + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + + /* Property: bounceInOut */ + bounceInOut: function(t, b, c, d){ + if (t < d/2) return Fx.Transitions.bounceIn(t*2, 0, c, d) * .5 + b; + return Fx.Transitions.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b; + } + +}; + +/* +Script: Drag.Base.js + Contains <Drag.Base>, <Element.makeResizable> + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +var Drag = {}; + +/* +Class: Drag.Base + Modify two css properties of an element based on the position of the mouse. + +Arguments: + el - the $(element) to apply the transformations to. + options - optional. The options object. + +Options: + handle - the $(element) to act as the handle for the draggable element. defaults to the $(element) itself. + modifiers - an object. see Modifiers Below. + onStart - optional, function to execute when the user starts to drag (on mousedown); + onComplete - optional, function to execute when the user completes the drag. + onDrag - optional, function to execute at every step of the drag + limit - an object, see Limit below. + snap - optional, the distance you have to drag before the element starts to respond to the drag. defaults to false + + modifiers: + x - string, the style you want to modify when the mouse moves in an horizontal direction. defaults to 'left' + y - string, the style you want to modify when the mouse moves in a vertical direction. defaults to 'top' + + limit: + x - array with start and end limit relative to modifiers.x + y - array with start and end limit relative to modifiers.y +*/ + +Drag.Base = new Class({ + + getOptions: function(){ + return { + handle: false, + unit: 'px', + onStart: Class.empty, + onComplete: Class.empty, + onSnap: Class.empty, + onDrag: Class.empty, + limit: false, + modifiers: {x: 'left', y: 'top'}, + snap: 6 + }; + }, + + initialize: function(el, options){ + this.setOptions(this.getOptions(), options); + this.element = $(el); + this.handle = $(this.options.handle) || this.element; + this.mouse = {'now': {}, 'pos': {}}; + this.value = {'start': {}, 'now': {}}; + this.bound = {'start': this.start.bindWithEvent(this)}; + this.handle.addEvent('mousedown', this.bound.start); + if (this.options.initialize) this.options.initialize.call(this); + }, + + start: function(event){ + this.mouse.start = event.page; + var limit = this.options.limit; + this.limit = {'x': [], 'y': []}; + for (var z in this.options.modifiers){ + this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt(); + this.mouse.pos[z] = event.page[z] - this.value.now[z]; + if (limit && limit[z]){ + for (var i = 0; i < 2; i++){ + if ($chk(limit[z][i])) this.limit[z][i] = limit[z][i].apply ? limit[z][i].call(this) : limit[z][i]; + } + } + } + this.bound.drag = this.drag.bindWithEvent(this); + this.bound.checkAndDrag = this.checkAndDrag.bindWithEvent(this); + this.bound.stop = this.stop.bind(this); + document.addEvent('mousemove', this.options.snap ? this.bound.checkAndDrag : this.bound.drag); + document.addEvent('mouseup', this.bound.stop); + this.fireEvent('onStart', this.element); + event.stop(); + }, + + checkAndDrag: function(event){ + var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2))); + if (distance > this.options.snap){ + document.removeEvent('mousemove', this.bound.checkAndDrag); + document.addEvent('mousemove', this.bound.drag); + this.drag(event); + this.fireEvent('onSnap', this.element); + } + event.stop(); + }, + + drag: function(event){ + this.out = false; + this.mouse.now = event.page; + for (var z in this.options.modifiers){ + this.value.now[z] = event.page[z] - this.mouse.pos[z]; + if (this.limit[z]){ + if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){ + this.value.now[z] = this.limit[z][1]; + this.out = true; + } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){ + this.value.now[z] = this.limit[z][0]; + this.out = true; + } + } + this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit); + } + this.fireEvent('onDrag', this.element); + event.stop(); + }, + + detach: function(){ + this.handle.removeEvent('mousedown', this.bound.start); + }, + + stop: function(){ + document.removeEvent('mousemove', this.bound.drag); + document.removeEvent('mouseup', this.bound.stop); + this.fireEvent('onComplete', this.element); + } + +}); + +Drag.Base.implement(new Events); +Drag.Base.implement(new Options); + +/* +Class: Element + Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>. +*/ + +Element.extend({ + + /* + Property: makeResizable + Makes an element resizable (by dragging) with the supplied options. + + Arguments: + options - see <Drag.Base> for acceptable options. + */ + + makeResizable: function(options){ + return new Drag.Base(this, Object.extend(options || {}, {modifiers: {x: 'width', y: 'height'}})); + } + +}); + +/* +Script: Scroller.js + Contains the <Scroller>. + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Scroller + The Scroller is a class to scroll any element with an overflow (including the window) when the mouse cursor reaches certain buondaries of that element. + You must call its start method to start listening to mouse movements. + +Arguments: + element - required, the element to scroll. + options - optional, see options below, and <Fx.Base> options. + +Options: + area - integer, the necessary boundaries to make the element scroll. + velocity - integer, velocity ratio, the modifier for the window scrolling speed. + onChange - optionally, when the mouse reaches some boundaries, you can choose to alter some other values, instead of the scrolling offsets. + Automatically passes as parameters x and y values. +*/ + +var Scroller = new Class({ + + getOptions: function(){ + return { + area: 20, + velocity: 1, + onChange: function(x, y){ + this.element.scrollTo(x, y); + } + }; + }, + + initialize: function(element, options){ + this.setOptions(this.getOptions(), options); + this.element = $(element); + this.mousemover = ([window, document].test(element)) ? $(document.body) : this.element; + }, + + /* + Property: start + The scroller starts listening to mouse movements. + */ + + start: function(){ + this.coord = this.getCoords.bindWithEvent(this); + this.mousemover.addEvent('mousemove', this.coord); + }, + + /* + Property: stop + The scroller stops listening to mouse movements. + */ + + stop: function(){ + this.mousemover.removeEvent('mousemove', this.coord); + this.timer = $clear(this.timer); + }, + + getCoords: function(event){ + this.page = (this.element == window) ? event.client : event.page; + if (!this.timer) this.timer = this.scroll.periodical(50, this); + }, + + scroll: function(){ + var el = this.element.getSize(); + var pos = this.element.getOffsets(); + + var change = {'x': 0, 'y': 0}; + for (var z in this.page){ + if (this.page[z] < (this.options.area + pos[z]) && el.scroll[z] != 0) + change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity; + else if (this.page[z] + this.options.area > (el.size[z] + pos[z]) && el.scroll[z] + el.size[z] != el.scrollSize[z]) + change[z] = (this.page[z] - el.size[z] + this.options.area - pos[z]) * this.options.velocity; + } + if (change.y || change.x) this.fireEvent('onChange', [el.scroll.x + change.x, el.scroll.y + change.y]); + } + +}); + +Scroller.implement(new Events); +Scroller.implement(new Options); + +/* +Script: Slider.js + Contains <Slider> + +Author: + Valerio Proietti, <http://mad4milk.net> + +License: + MIT-style license. +*/ + +/* +Class: Slider + Creates a slider with two elements: a knob and a container. Returns the values. + +Arguments: + element - the knob container + knob - the handle + options - see Options below + +Options: + onChange - a function to fire when the value changes. + onComplete - a function to fire when you're done dragging. + onTick - optionally, you can alter the onTick behavior, for example displaying an effect of the knob moving to the desired position. + Passes as parameter the new position. + steps - the number of steps for your slider. + mode - either 'horizontal' or 'vertical'. defaults to horizontal. + wheel - experimental! Also use the mouse wheel to control the slider. defaults to false. +*/ + +var Slider = new Class({ + + getOptions: function(){ + return { + onChange: Class.empty, + onComplete: Class.empty, + onTick: function(pos){ + this.knob.setStyle(this.p, pos+'px'); + }, + steps: 100, + mode: 'horizontal', + wheel: false + }; + }, + + initialize: function(el, knob, options){ + this.element = $(el); + this.knob = $(knob); + this.setOptions(this.getOptions(), options); + + this.previousChange = -1; + this.previousEnd = -1; + this.step = -1; + + this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this)); + + if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement.bindWithEvent(this)); + + if (this.options.mode == 'horizontal'){ + this.z = 'x'; this.p = 'left'; + this.max = this.element.offsetWidth-this.knob.offsetWidth; + this.half = this.knob.offsetWidth/2; + this.getPos = this.element.getLeft.bind(this.element); + } else if (this.options.mode == 'vertical'){ + this.z = 'y'; this.p = 'top'; + this.max = this.element.offsetHeight-this.knob.offsetHeight; + this.half = this.knob.offsetHeight/2; + this.getPos = this.element.getTop.bind(this.element); + } + + this.knob.setStyle('position', 'relative').setStyle(this.p, 0); + + var modSlide = {}, limSlide = {}; + + limSlide[this.z] = [0, this.max]; + modSlide[this.z] = this.p; + + this.drag = new Drag.Base(this.knob, { + limit: limSlide, + snap: 0, + modifiers: modSlide, + onStart: function(){ + this.draggedKnob(); + }.bind(this), + onDrag: function(){ + this.draggedKnob(); + }.bind(this), + onComplete: function(){ + this.draggedKnob(); + this.end(); + }.bind(this) + }); + if (this.options.initialize) this.options.initialize.call(this); + }, + + /* + Property: set + The slider will get the step you pass. + + Arguments: + step - one integer + */ + + set: function(step){ + if (step > this.options.steps) step = this.options.steps; + else if (step < 0) step = 0; + this.step = step; + this.checkStep(); + this.end(); + this.fireEvent('onTick', this.toPosition(this.step)+''); + return this; + }, + + scrolledElement: function(event){ + if (event.wheel < 0) this.set(this.step + 1); + else if (event.wheel > 0) this.set(this.step - 1); + event.stop(); + }, + + clickedElement: function(event){ + var position = event.page[this.z] - this.getPos() - this.half; + if (position > this.max) position = this.max; + else if (position < 0) position = 0; + this.step = this.toStep(position); + this.checkStep(); + this.end(); + this.fireEvent('onTick', position+''); + }, + + draggedKnob: function(){ + this.step = this.toStep(this.drag.value.now[this.z]); + this.checkStep(); + }, + + checkStep: function(){ + if (this.previousChange != this.step){ + this.previousChange = this.step; + this.fireEvent('onChange', this.step); + } + }, + + end: function(){ + if (this.previousEnd !== this.step){ + this.previousEnd = this.step; + this.fireEvent('onComplete', this.step+''); + } + }, + + toStep: function(position){ + return Math.round(position/this.max*this.options.steps); + }, + + toPosition: function(step){ + return (this.max)*step/this.options.steps; + } + +}); + +Slider.implement(new Events); +Slider.implement(new Options); \ No newline at end of file diff --git a/emacs/nxhtml/nxhtml/doc/nxhtml-changes.html b/emacs/nxhtml/nxhtml/doc/nxhtml-changes.html new file mode 100644 index 0000000..81339df --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/nxhtml-changes.html @@ -0,0 +1,3395 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>News and Notes about nXhtml</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> + <style type="text/css"> +#nxhtml-home a { + /* Image */ + display: block; + background: transparent url("img/getitbuttons.png") 0 0 no-repeat; + overflow: hidden; + width: 200px; + xheight: 35px; + /* Text placement and size, etc */ + text-align: center; + padding-top: 11px; + font-size: 12px; + padding-bottom: 9px; + text-decoration: none; + white-space: nowrap; + margin: 0; + border: none; +} +#nxhtml-home a:hover { + background-position: 0 -35px; + color: yellow; +} +.bugfix { + background-color: #ffd700; +} + +</style> + </head> + <body> + <div id="container"> + + <div id="rgtcol"> + <p id="nxhtml-home"><a href='nxhtml.html'>To nXhtml main page</a></p> + + <h1>News and Notes about nXhtml</h1> + + <dl> + + <dt id="state-of-the-art" style="margin-top:1em; + background-color: #66cd5c; + background-color: #96cd5c; + padding: 0.5em; + ">The State of the Art</dt> + <dd style="background-color: #f9e529; padding: 0.5em"> + <p> + I believe now that MuMaMo (the multi major mode support) + is fairly stable. It is now possible to have chunks in + chunks and it is reasonably fast. + </p> + <p> + The major mode than once gave the name to this package + for web devoloping, nxhtml-mode, has long been stable. + There are a lot of other minor things in this package. + Of course everything is not perfect. Bug report and + taking part in the development is very welcome. Go to + the project page on Launchpad if you want to join! + </p> + <p> + If you want to know how it works, install and test. It + will not harm, everything is autoloaded so it will not + slow down your Emacs - eh, a tiny little bit perhaps if + you really use it, but then you will also get the + benefits of it. + </p> + <p> + If you want to know current bug status go to Launchpad! + </p> + </dd> + + <dt id="hadron-bugs" style="margin-top:1em;">Thanks for testing!</dt> + <dd> + <p> + I want to thanks the testers and bug reporters (who have + been many now), especially to my first testers Hadron + Quark and Eric Lilja, for helping me by testing and + pointing out bugs and weaknesses, most of them related + to editing of PHP. + </p> + <p> + Without testers all kind of problems I just can't + imagine myself would still be there in nXhtml. For + example Hadron told me once that he got the error + <i>(wrong-type-argument stringp nil)</i>. Eh, I replied, are + you sure. Yes he was. I tried the same file as him. No + error. + </p> + <p> + The error happened during fontification so the error + message above was all we had. A real black box for + me. Or perhaps black magic? After much confusion and + some hard work we finally found out what it was and I + implemented a better way to catch such errors. If Hadron + would have given up the problem would still have been + there. Some problems are just impossible to solve + without good cooperation. So, again, thanks Hadron. + </p> + <p> + BTW, I will perhaps add some even better way to Emacs to + catch these errors so other can benefit from our + insights too, but that requires some time and effort + which I can't afford right now. + </p> + <p> + If is now a bit more easy to take care of errors since + there is a good bug database for nXhtml at Launchpad. + </p> + </dd> + + <dt id="underline-bug" style="margin-top:1em;">Long Red Underlines</dt> + <dd> + <p> + Because of a bug in Emacs 22.1 you can sometimes (at the + end of a line) get long red lines instead of just a + single underlined character. Many users (me included) + find this quite a bit disturbing. I have therefore added + a command to quickly hide/show the underlines. This is + on <em>C-c C-w</em> (nxhtml-toggle-visible-warnings, key + binding changed to <em>C-c _</em> in later versions of + nXhtml). + </p> + <p> + This is particular useful for example in the case where + you edit a PHP file and are bound to get a lot of XHTML + validation errors. + </p> + </dd> + + <dt id="php-attribute-values" style="margin-top:1em;">Attribute values computed by PHP</dt> + <dd> + <p> + If you want to have attribute values computed by PHP + here is a way how to structure that to avoid breaking + completion and validation in the XHTML part unnessecary: + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="<?php foo("bar");?>"/> + </p> + <p> + Unfortunately that still breaks XHTML validation since + < is not allowed in strings. In the long run I + believe the XML validator has to be broken up so that it + avoids parsing the string here (in PHP files). + </p> + <p> + For now I have implemented a workaround. + If you are using constructs like those above then turn on <em>mumamo-alt-php-tags-mode</em>. + This will temporarily replace the above with + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="(?php foo("bar");?)"/> + </p> + <p> + However on the screen you will still see the original + string and when writing to file the correct characters + will be used. + </p> + </dd> + + <dt id="pi-note" style="margin-top:1em;">A note for PHP and its cousins</dt> + <dd> + <p> + The rules for a process instruction in XML, like <?php + ... ?> says that the text can contain any text except + <em>?></em>. So if you want to output that string + from PHP then break it up so it does not look as ?> in + the source file. + </p> + <p> + It might be good to break up the beginning part of the + process instructions too. And please note that to use + XHTML validation or completion you should avoid using + < in strings, since it is not allowed there. + </p> + </dd> + + <dt id="mmm-compat" style="margin-top:1em;">Why the chunks are not compatible with mmm</dt> + <dd> + <p> + Some people have asked why the way to specify chunks in + mumamo-mode is not compatible with the old mmm-mode. The + answer is that I was not sure that the way used in + mmm-mode for specifying the chunks was flexible enough. + </p> + <p> + Some people have also wondered why MuMaMo does not find + chunks just as simple as multi-mode does. The answer is + it did from the beginning. However that way (looking + around current point) is not stable enough. Multi major + modes are a bit different in this respect than normal + major modes. More things can go wrong when you are + guessing. + </p> + </dd> + + </dl> + + <h1 id="change-history">nXhtml Changes</h1> + + <div> + <a href="#v0.89">v0.89</a> + <a href="#v0.90">v0.90</a> + <a href="#v0.91">v0.91</a> + <a href="#v0.92">v0.92</a> + <a href="#v0.93">v0.93</a> + <a href="#v0.94">v0.94</a> + <a href="#v0.95">v0.95</a> + <a href="#v0.96">v0.96</a> + <a href="#v0.97">v0.97</a> + <a href="#v0.98">v0.98</a> + <a href="#v0.99">v0.99</a> + <a href="#v1.00">v1.00</a> + <a href="#v1.01">v1.01</a> + <a href="#v1.02">v1.02</a> + <a href="#v1.03">v1.03</a> + <a href="#v1.04">v1.04</a> + <a href="#v1.10">v1.10</a> + <a href="#v1.11">v1.11</a> + <a href="#v1.12">v1.12</a> + <a href="#v1.13">v1.13</a> + <a href="#v1.14">v1.14</a> + <a href="#v1.15">v1.15</a> + <a href="#v1.16">v1.16</a> + <a href="#v1.17">v1.17</a> + <a href="#v1.18">v1.18</a> + <a href="#v1.19">v1.19</a> + <a href="#v1.20">v1.20</a> + <a href="#v1.21">v1.21</a> + <a href="#v1.22">v1.22</a> + <a href="#v1.23">v1.23</a> + <a href="#v1.24">v1.24</a> + <a href="#v1.25">v1.25</a> + <a href="#v1.26">v1.26</a> + <a href="#v1.27">v1.27</a> + <a href="#v1.28">v1.28</a> + <a href="#v1.29">v1.29</a> + <a href="#v1.30">v1.30</a> + <a href="#v1.31">v1.31</a> + <a href="#v1.32">v1.32</a> + <a href="#v1.33">v1.33</a> + <a href="#v1.34">v1.34</a> + <a href="#v1.35">v1.35</a> + <a href="#v1.36">v1.36</a> + <a href="#v1.37">v1.37</a> + <a href="#v1.38">v1.38</a> + <a href="#v1.39">v1.39</a> + <a href="#v1.40">v1.40</a> + <a href="#v1.41">v1.41</a> + <a href="#v1.42">v1.42</a> + <a href="#v1.43">v1.43</a> + <a href="#v1.44">v1.44</a> + <a href="#v1.45">v1.45</a> + <a href="#v1.46">v1.46</a> + <a href="#v1.47">v1.47</a> + <a href="#v1.48">v1.48</a> + <a href="#v1.49">v1.49</a> + <a href="#v1.50">v1.50</a> + <a href="#v1.51">v1.51</a> + <a href="#v1.52">v1.52</a> + <a href="#v1.53">v1.53</a> + <a href="#v1.54">v1.54</a> + <a href="#v1.55">v1.56</a> + <a href="#v1.56">v1.56</a> + <a href="#v1.57">v1.57</a> + <a href="#v1.58">v1.58</a> + <a href="#v1.59">v1.59</a> + <a href="#v1.60">v1.60</a> + <a href="#v1.61">v1.61</a> + <a href="#v1.62">v1.62</a> + <a href="#v1.63">v1.63</a> + <a href="#v1.64">v1.64</a> + <a href="#v1.65">v1.65</a> + <a href="#v1.66">v1.66</a> + <a href="#v1.67">v1.67</a> + <a href="#v1.68">v1.68</a> + <a href="#v1.69">v1.69</a> + <a href="#v1.70">v1.70</a> + <a href="#v1.71">v1.71</a> + <a href="#v1.72">v1.72</a> + <a href="#v1.73">v1.73</a> + <a href="#v1.74">v1.74</a> + <a href="#v1.75">v1.75</a> + <a href="#v1.76">v1.76</a> + <a href="#v1.77">v1.77</a> + <a href="#v1.78">v1.78</a> + <a href="#v1.79">v1.79</a> + <a href="#v1.80">v1.80</a> + <a href="#v1.81">v1.81</a> + <a href="#v1.82">v1.82</a> + <a href="#v1.83">v1.83</a> + <a href="#v1.84">v1.84</a> + <a href="#v1.85">v1.85</a> + <a href="#v1.86">v1.86</a> + <a href="#v1.87">v1.87</a> + <a href="#v1.88">v1.88</a> + <a href="#v1.89">v1.89</a> + <a href="#v1.90">v1.90</a> + <a href="#v1.91">v1.91</a> + <a href="#v1.92">v1.92</a> + <a href="#v1.93">v1.93</a> + <a href="#v1.94">v1.94</a> + <a href="#v1.95">v1.95</a> + <a href="#v1.96">v1.96</a> + <a href="#v1.97">v1.97</a> + <a href="#v1.98">v1.98</a> + <a href="#v1.99">v1.99</a> + <a href="#v2.00">v2.00</a> + <a href="#v2.01">v2.01</a> + <a href="#v2.02">v2.02</a> + <a href="#v2.03">v2.03</a> + <a href="#v2.04">v2.04</a> + <a href="#v2.05">v2.05</a> + <a href="#v2.06">v2.06</a> + <a href="#v2.07">v2.07</a> + <a href="#v2.08">v2.08</a> + </div> + + <dl> + <dt id="v0.89">0.89</dt> + <dd> + <ul> + <li> + Corrected autostart for nXhtml when not used together with EmacsW32. + </li> + </ul> + </dd> + <dt id="v0.90">0.90</dt> + <dd> + <ul> + <li> + Improved display of XML path. + </li> + <li> + Discontinued xmple-mode. + </li> + <li> + New major modes nxhtml-part-mode/nxml-part-mode replaces + minor mode xmlpe-mode. (While moving the code to + nxhtml-part.el I also fixed a bug in Xmple minor mode that + made Emacs take 99% of the CPU.) + </li> + </ul> + </dd> + <dt id="v0.91">0.91</dt> + <dd> + <ul> + <li> + Fixed some calls to perl which prevented uploading of + a site of you did not have perl in the same location + as me. + </li> + <li> + Glued together things so that editing PHP files works + as I intended. (This means that Emacs switches between + php-mode and nxhtml-part-mode automatically when + moving point. And that you can use completion.) + </li> + <li> + Starting working on the documentation for nXhtml. + New layout to the documentation files. + Examples with images. + </li> + </ul> + </dd> + <dt id="v0.92">0.92</dt> + <dd> + <ul> + <li> + Fixes to make the switching between php and xhtml + style editing work better. + </li> + </ul> + </dd> + <dt id="v0.93">0.93</dt> + <dd> + <ul> + <li> + Better error handling when switching to editing + embedded JavaScript and CSS. + </li> + <li> + Removed PHP spec from embedded switching since they + interfered with the automatic switching between php + and xhtml. + </li> + <li> + Gives an error message if web host is not defined in + site when trying to use View Uploaded File and + cousins. + </li> + <li> + Gives a ready message when finished uploading a single + file. + </li> + <li> + When using Mode Switching at <? ... ?> mode + switching could occur in wrong buffer. Fixed together + with some other buffer problems. + </li> + </ul> + </dd> + <dt id="v0.94">0.94</dt> + <dd> + <ul> + <li> + Add http://www.w3.org/ to the help sites for CSS. + </li> + <li> + Included a CSS mode. + </li> + <li> + Added a menu entry for bug reporting. + </li> + <li> + Renamed menu bar entry from XHTML to nXhtml for clarity. + (But nXml menu bar entry is still called XML.) + </li> + <li> + Added work around for globalized minor modes in the + cases of MLinks, XML Path and mode switching at <? ... ?>. + </li> + </ul> + </dd> + <dt id="v0.95">0.95</dt> + <dd> + <ul> + <li> + Added workaround for the problem with the first + keyboard key after automatically switching of mode at + <? ... ?>. + </li> + </ul> + </dd> + <dt id="v0.96">0.96</dt> + <dd> + <ul> + <li> + Added support for multiple major modes with mumamo.el. + </li> + <li> + More conventient handling of links. They can now be + opened in the same window, 'other window' or in a new + frame. + </li> + </ul> + </dd> + <dt id="v0.97">0.97</dt> + <dd> + <ul> + <li> + Schema was not setup after starting new page so + completion did not work. Fixed. + </li> + <li> + Added http://xhtml.com/ to help sites for XHTML. + </li> + <li> + Added the concept of <em>fictive XML validation + headers</em>. These are just text parsed by the nXml + validation parser to get a start state before starting + parsing a buffer. This allows the use of the nXml + completion in buffers where there are no XML header. + Such a header is often lacking for example in PHP code + since the XHTML header is often generated dynamically. + </li> + <li> + Because of the change above <em>nxhtml-part-mode</em> + is no longer needed and is therefore declared + obsolete. + </li> + <li> + Corrected a bug in mlinks.el that prevented opening an + HTML link in a other window or a new frame. + </li> + <li> + Added support for JSP, eRuby and some support for perl + in mumamo.el. + </li> + </ul> + </dd> + <dt id="v0.98">0.98</dt> + <dd> + <ul> + <li> + Mumamo was not found when nXhtml was installed with + just the zip file. Corrected. (nXhtml is also + installed when you install EmacsW32.) + </li> + <li> + Enhancement to mumamo error handling when a bad mode + specifier for an embedded mode is found. + </li> + <li> + Introduced a bug for empty XHTML documents in + 0.97. Corrected. + </li> + <li> + Corrected a bug for chunks 1 character long. + </li> + <li> + There is what I consider is a bug in Emacs 22.1 in the + handling of global minor mode that are not distributed + with Emacs. If they are turned on by customization, + but loaded after Emacs have loaded the customizations + (usually in .emacs) then they are not turned on + correctly. Added work-around for this. + </li> + <li> + <em>Fictive XHTML Validation Header</em>: + <ul> + <li> + <em>Fictive XHTML Validation Header</em> state was not saved when moving between chunks. Fixed. + </li> + <li> + Tried to make the concept of <em>Fictive XHTML Validation Header</em> + more clear. Added this visually to the buffer. + </li> + <li> + <em>Fictive XHTML Validation Headers</em> can now be turned on + automatically based on file name. + </li> + </ul> + </li> + <li> + <em>nXhtml menu:</em> + <ul> + <li> + Reorganized the nXhtml menu. + </li> + <li> + Added <em>customization</em> groups for help libraries to nXhtml. + </li> + <li> + Added an entry for customization of nXhtml to the menus. + </li> + <li> + Added <em>Tidy</em> to the menus again. + </li> + </ul> + </li> + <li> + Corrected bug in <em>XML Path</em> (nxml-where) for single tags. + Other small fixes to nxhtml-where. + </li> + <li> + Documentation enhancements. + Added <em>The Quick Guide</em>. + </li> + </ul> + </dd> + <dt id="v0.99">0.99</dt> + <dd> + <ul> + <li> + Fixed a serious bug in the cooperation between nxhtml-mode and mumamo-mode. + </li> + <li> + Turn on mumamo-mode by file name (mumamo-global-mode). + </li> + <li> + Fictive XHTML Validation Header: + <ul> + <li> + The Fictive XHTML Validation Header state were not saved when changing major mode in MuMaMo. Corrected. + </li> + <li> + Added more alternatives to the Fictive XHTML Validation Header list. + This should make it easier to use completion with for example PHP. + </li> + <li> + Added default value for the Fictive XHTML Validation Header. + </li> + <li> + Tried to make the use of Fictive XHTML Validation Header more automatic and therefore useful. + Also tried to make it play better with setting schema file. + (There is no need normally to set schema file by hand.) + </li> + <li> + To turn this on by default customize nxhtml-global-validation-header-mode. + </li> + </ul> + </li> + <li> + Possible to hide validation warnings without turning + on validation (which would make completion in the + XHTML part impossible). + </li> + <li> + Some fixes to php-mode: + <ul> + <li>Using the character # for comments now works for most cases.</li> + <li>Now uses the fontification faces in a more standard way which calms down the look.</li> + <li>Initialization bug fixes.</li> + <li>Renamed php-mode-user-hook to php-mode-hook to follow standard.</li> + </ul> + </li> + <li> + Indentation fixes: + <ul> + <li> + Various corrections to indentation in mumamo. + </li> + <li> + Added the possibility to use TAB to indent regions + (indent-region-mode). + </li> + <li> + Warn about bad indentation in mixed PHP/HTML code + when using php-mode only. + </li> + </ul> + </li> + <li> + Fontification now fontifies all text first in main + major mode and thereafter applies submodes. (This + avoids some problems with around a submode chunk.) + </li> + <li> + Reorganized the nXhtml menu: + <ul> + <li> + There is now a minor mode for the nXhtml + menu. This makes it possible to easier use common + features when in buffers not in nxhtml-mode. + </li> + <li> + The nXhtml menu does not disappear when moving + into a chunk where the major mode is not + nxhtml-mode. The changes also makes it easy to + access uploading functions functions etc from + other modes than nxhtml-mode since the + <em>nXhtml</em> may also be shown in them. + </li> + <li> + The nXhtml menu can be turned on globally by default. + Customize nxhtml-menu-mode for that. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.00">1.00</dt> + <dd> + <ul> + <li> + Reached version number 1.00 - which you maybe believe + means the bugs should be gone? Sorry, it is just that + I ran out of version numbers. However it looks like + much fewer bugs at least. + </li> + <li> + Fixed problems mostly related to global turn on of different features in nXhtml. + </li> + <li> + Small fixes to indentation. + <ul> + <li> + nxhtml-mode could get confused by php tags. + </li> + <li> + nxhtml-mode did not indent <!DOCTYPE in a sensible way. + </li> + <li> + Electric keys now works in embedded php when using mumamo-mode. + </li> + </ul> + </li> + <li> + Tidy was very misbehaving since the output buffer was + not erased between different files. But I have got no + bug reports on this. + </li> + <li> + Fixed a bug in validation that should up when using muamo-mode. + </li> + <li> + Fixed bug in <script ...> and <style ...> chunk dividing. + </li> + <li> + Added support for OpenLaszlo. + </li> + <li> + Corrections to mlinks-mode (visible mostly as links in + XHTML buffers): + <ul> + <li> + Links disappeared when a new file was + opened. Corrected. + </li> + <li> + Links were not correctly updated at changes in the + buffer when mumamo-mode was used. Fixed. + </li> + </ul> + </li> + <li> + The welcome message for nXhtml could be shown too + early sometimes when loading, before nXhtml actually + knew if it should be shown or not. Tried to fix it. + </li> + </ul> + </dd> + <dt id="v1.01">1.01</dt> + <dd> + <ul> + <li> + Reported wrong version number for nXhtml in the menus. Fixed. + </li> + <li> + <em>If you use the zip file to install nXhtml please + notice that it has now a top level nxml.</em> Sorry for not + having zipped it like that before! + </li> + <li> + The url links in <em>Welcome to nXhtml</em> was a bit + incorrect and did not work on all OS:es. Fixed. + </li> + <li> + Added customization of popup completion to the 'nxhtml + customization group so they are easier to find. + </li> + <li> + MuMaMo + <ul> + <li> + Struggled a bit with the load sequences of the elisp + libraries used by nXhtml when using MuMaMo. + </li> + <li> + Tried to get the global turn on of mumam-mode to work + in all cases. + </li> + <li> + The screen was blinking when changing overlays after + changes in the buffer. Tried to fix this. + </li> + <li> + Minor fixes do syntax highlighting, like taking care of single ':s. + </li> + <li> + Fixes to the support for JSP and eRuby. + </li> + <li> + Made the support for perl here documents a bit better. + Large perl documents are however still quite slow when + using mumamo-mode. I do not know the reason yet. + </li> + <li> + Refontification could miss some parts when buffer + changes caused chunk division changes. Complex, + tried to fix it, but I am a bit unsure that it + always works. + </li> + <li> + Cleaned up mumamo.el a bit. + </li> + <li> + Rewrote mumamo-test.el and functions called from it in + mumamo.el a bit to make tracebacks from errors more + useful. Changed keybindings in mumamo-test.el from + global to a minor mode <em>mumamo-test-mode</em>. + Renamed mumamo-notest.el to mumamo-test.el. Added it + to the zipped distribution of nXhtml. + </li> + </ul> + </li> + <li> + Fixed a bug related to links and buffer changes. + </li> + </ul> + </dd> + <dt id="v1.02">1.02</dt> + <dd> + <ul> + <li> + Fixed a refontification bug that occured after changes. + </li> + </ul> + </dd> + <dt id="v1.03">1.03</dt> + <dd> + <ul> + <li> + Added the possibility to call GIMP. + </li> + <li> + Reworked the messages for fontification errors to try + to catch an error that shows up sometimes. Tried to + avoid disturbing normal use in spite of that error. + </li> + <li> + Reverted to using a short delay before switching major + mode when moving between buffers. + </li> + </ul> + </dd> + <dt id="v1.04">1.04</dt> + <dd id="v1.04-dd"> + <ul> + <li> + Enhanced the documentation for nXhtml. Starting from + <i>C-h f nxhtml-mode</i> it should now be easier to + get an overview. + </li> + <li> + Bug fixes etc: + <ul id="v1.04-bugs"> + <li> + Completion on an empty page gave a faulty frameset page. Fixed. + </li> + <li> + Insert end tag did not work with a fictive + validation header. Fixed. + </li> + <li> + Insert end tag when all preceding tags where + closed gave a strange error message. Fixed. + </li> + <li> + Changed some key bindings to comply with + <i>(info "(elisp) Key Binding Conventions")</i> + </li> + <li> + Completion in empty buffers with a completion + header did not work. Fixed. + </li> + <li id="mumamo-bugs"> + Multiple major modes: + <ul> + <li> + Fixed a bug that prevented mumamo-global-mode from + beeing turned on in a file opened in + fundamental-mode. + </li> + <li> + Better error tracing for some functions, + including the call of major mode functions. + </li> + <li> + Position was garbled when a ;-char was inserted in php-mode chunk. Fixed. + </li> + <li> + A bad check for if mlinks-mode where available was fixed. + </li> + <li> + Some bugs concerning turning off mumamo-mode was fixed. + </li> + <li> + Fixed a bug in <i>perl here doc</i> chunks. Suddenly the + problem with slowness when using mumamo-mode in + perl buffers seems gone. (Note quite sure, but I + can't see any problems now.) + </li> + <li> + Fixed a bug in mumamo-mode when current buffer was + switched before the major mode had been set from + the current chunk. + </li> + <li> + Fixed a long standing bug in php fontification of + strings and comments. + </li> + <li> + Fixed a bug where <i>sgml-xml-mode</i> was not defined. + </li> + <li> + Fixed a bug related to get-text-property which + gives an error when buffer is narrowed. + </li> + <li> + Tried to refontify things outside of a narrowed part. Fixed. + </li> + <li> + Too little where refontified after changes. I hope I have fixed this. + </li> + </ul> + </li> + <li> + Fictive XHTML Validation Header: + <ul id="v1.04-fic-bugs"> + <li> + View File did not work correctly when a fictive + XHTML validation header was used. Corrected. + </li> + <li> + Fictive XHTML validation headers are no longer + turned on by default in any buffers. + </li> + </ul> + </li> + <li> + Indentation: + <ul> + <li> + Tried to fix a problem when using + newline-and-indent. When this was in a mode + derived from C the indentation sometimes became 0. + </li> + <li> + Speeded up the indentation of regions a bit when + using <i>mumamo-mode</i>. + </li> + <li> + Indentation: TAB now only indents a region if it + is visibly marked (see transient-mark-mode and + cua-mode). + </li> + <li> + Simplified the indentation code. + </li> + </ul> + </li> + <li> + Fixed a problem where string fontification got out + of phase so that wrong parts of buffer could be + fontified as a string. + </li> + <li> + Added a workaround for <a + href="#php-attribute-values">Attribute values + computed by PHP</a> + </li> + <li> + Added .nosearch to subdirectories with no elisp files. + </li> + <li> + Fixed incorrect checks for mlinks-mode in menu building. + </li> + <li> + File extensions where used in a case sensitive way + in some places. Fixed. + </li> + <li> + appmenu: Worked only in html files. Fixed. + </li> + <li> + html-site: Fixed the error <em>Error + (html-site-current): Can't find site: + your-site-name</em>. + </li> + <li> + Fixed a problem with longlines-mode in the support + for Firefox add-on It's All Text. (Note however + that there are some bugs in longlines-mode + itself.) Rewrote the support to be more + general. It is now in the file as-external.el, see + this file. + </li> + <li> + Fixed an encoding problem in + <i>tidy-buffer</i>. Output from tidy was not read + using the same coding system as tidy was using. + </li> + <li> + Fixed some problems with face definitions, possibly bugs (not sure). + </li> + <li> + Made the fontification faster when using mumamo-mode. + (It is still slower than single mode fontification of course.) + </li> + <li> + nxml-where.el: Made it aware of mumamo.el. + </li> + </ul> + </li> + <li> + Menu changes: + <ul> + <li> + Completion menu: Renamed to <i>Completion and + Validation</i> menu and reorganized a little bit to + make it more clear. + </li> + <li> + Renamed <i>view</i> to <i>browse</i> since this is + the normal emacs name for showing files in a web + browser. Also made corresponding changes to + function names. Put back the possibility to view + only the region in a web browser. + </li> + </ul> + </li> + <li> + Uploading: + <ul> + <li> + Added remote dired to the menus. + </li> + <li> + Fixed problems with file names starting with ~. + </li> + <li> + Fixed more problems with file names with spaces. + </li> + </ul> + </li> + <li> + nxml-where: + <ul> + <li> + nxml-where now uses a timeout for more smooth performance. + </li> + <li> + nxml-where can now recognizes both id and name attribute. + </li> + <li> + Hyphens are now accepted in tag names. + </li> + </ul> + </li> + <li> + Ruby + <ul> + <li> + Multiple major mode turned on by default for .rhtml files when this mode is global. + </li> + <li> + Multiple major mode is no longer turned on when rub-mode is turned on. + </li> + </ul> + </li> + <li> + Added support for switching major mode dependent on if + Emacs was called as an external editor. This makes it + possible for example to switch to relevant major and + minor modes when Firefox add-on It's All Text. + </li> + <li> + Added the possibility to easily view the output of scripts on the server (if they require no parameters). + You can now do that from the nXhtml menu. + Previously only html files on the server could be viewed that way. + Image files can also be viewed this way. + </li> + <li> + Filling: + <ul> + <li> + Added functions for unfilling. + </li> + <li> + Added keybindings and menu entries for longlines-mode, fill-paragraph and unfill-paragraph. + </li> + </ul> + </li> + <li> + Quoting: + Added HTML quoting of & and < in text areas. Bound to C-c C-q. + </li> + <li> + Images: + <ul> + <li> + Added image-mode to those that are encompassed by nxhtml-global-minor-mode so that images can be uploaded more easily. + </li> + <li> + Added <em>edit with GIMP</em> and <em>upload</em> to the popup menu for links. + This avoids the need to load the linked files in Emacs first. + </li> + </ul> + </li> + <li> + Added <em>nxml-untag-element</em>. + </li> + <li> + Added a modified version of wikipedia-mode.el. Seems likely to be useful if you are doing web editing. + </li> + <li> + Added html-imenu.el + </li> + <li> + MuMaMo: + <ul> + <li> + Removed the lighter <i>"MuMaMo"</i> for + mumamo-mode. Instead the active major mode now has + <b>"/m"</b> appended to mode-name (that is what you see + in the mode line). + </li> + <li> + The normal way to turn on <i>mumamo-mode</i> has + changed. There are now functions that you can use + in <i>auto-mode-alist</i> to directly set up the + buffer for mumamo-mode. The available functions + are in the + variable <i>mumamo-defined-turn-on-functions</i>. + <p> + You are not supposed to call mumamo-mode + yourself any more and mumamo-global-mode is + gone. So is also mumamo-chunk-family-by-mode and + mumamo-filenames-list. The functionality those + gave are all replaced by the new functions for + turning on mumamo mode. + </p> + </li> + <li> + Added support for buffer local values in + hooks. This is necessary for example to support + minor modes that are meant to be buffer local but + not major mode specific. Instructions for authors + of this kind of minor modes are in the file + mumamo.el. + </li> + <li> + Added support for Django. + </li> + <li> + Added support for Embperl. + </li> + <li> + Added support for PHP Smarty. The <i>{literal} + ... {/literal}</i> construct is not supported. + This mean that you can not use <style ..> or <script ..>. + </li> + <li> + Added support for imenu for the main major mode. + Turned on this by default in nxhtml-mode. + </li> + <li> + Made the temporary replacement of the + attr="<?php ... ?>" a bit better. They are + now more visible and also still mumamo chunks + during the temporary replacement. + </li> + <li> + Added support for <i>flymake-mode</i>. + Maybe add support for checking chunks? + </li> + <li> + Printing: Added htmlfontify.el and + hfyview.el. These makes if possible to print a + buffer fontified with <i>mumamo-mode</i> on in + colors (through your web browser). There is an + example of the capabilities of htmlfontify <a + href="htmlfontify-example.html">here</a> (made + with a little function in hfyview.el). + </li> + </ul> + </li> + <li> + PHP: + <ul> + <li> + Did a first merge with Aaron Hawleys fixes for php-mode.el. + </li> + </ul> + </li> + <li> + CSS: Upgraded to Stefan's latest css-mode.el. + </li> + <li> + Fictive XHTML Validation Headers: Changed the way they + are turned on. They may now be turned on when + mumamo-mode is turned on. + </li> + <li> + Some users want to use their own patched version of nXml. Next version of Emacs will come with nXml. Therefore, the loading routine for nXhtml now checks if nXml is is already loaded. Thanks to Eric Lilja for testing this. Eric also made me aware of that if nXhtml was placed in the site-lisp directory tree then things did not work as I expected. I think I have corrected that by placing a <i>.nosearch</i> file at the top of the nxml tree in nXhtml. + </li> + <li> + Restructured the directories. Moved some files out of + the <i>nxhtml</i> subdir. Some of them went into the + <i>util</i> subdir (those are written by me) and some + to the new subdir <i>related</i> (those that are + inherited from others, maybe changed by me - most + often to work with mumamo-mode). + </li> + <li> + Changed all licenses to be GNU GPL. + </li> + <li> + Additions to tidy support: It is now possible to use + the tidy support to tidy the XHTML part of php etc. + (Thanks to Hadron for this suggestion.) + </li> + <li> + Added <i>winsize.el</i> which allows interactive resizing of + windows. Also added <i>winsav.el</i> which adds the + capability to rotate window configurations and also to + save window configuration to file. + </li> + <li> + Made nXhtml work with CVS Emacs 23.0.50.1. + </li> + <li> + Added freemind.el to the parcel. After all FreeMind + supports web publishing too so why not have the Emacs + support here ... + </li> + </ul> + </dd> + <dt id="v1.10">1.10</dt> + <dd id="v1.10-dd"> + Just jumped the version number for the new release of + nXhtml. There are really significant changes in this + release, not only minor bug fixes. + </dd> + <dt id="v1.11">1.11</dt> + <dd id="v1.11-dd"> + Minor bug fixes to completion. Added fictive validation + header to completion alternatives when buffer is empty and + mumamo is used. + </dd> + <dt id="v1.12">1.12</dt> + <dd id="v1.12-dd"> + <ul> + <li> + Fixed a bug in image link insertion in nxhtml-mode, thanks Niels Giesen! + </li> + <li> + Restructured, reordered and documented mumamo.el. It is now two + separate files, mumamo.el and mumamo-fun.el. + </li> + <li> + Added move by chunk to the nXhtml menu. + </li> + </ul> + </dd> + <dt id="v1.13">1.13</dt> + <dd id="v1.13-dd"> + <ul> + <li> + Better handling of the case when no validation header + is needed and the user tries to turn it on. + </li> + <li> + Added .phtml as php file. + </li> + </ul> + </dd> + <dt id="v1.14">1.14</dt> + <dd id="v1.14-dd"> + <ul> + <li> + Completion of links in XHTML was broken. Fixed, thanks + to Niels Giesen. + </li> + </ul> + </dd> + <dt id="v1.15">1.15</dt> + <dd id="v1.15-dd"> + <ul> + <li> + Added `mumamo-map' keymap. + </li> + <li> + Added a keymap to all multi major modes. + </li> + <li> + Some more refinement to fictive validation headers. + </li> + </ul> + </dd> + <dt id="v1.16">1.16</dt> + <dd id="v1.16-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Changes to indentation: + <ul> + <li> + Removed indent-region-mode since that + functionality is now in indent-for-tab-command in + Emacs 22. + </li> + <li> + Removed some code that checked if indentation was 0. + </li> + <li> + Added indent-for-tab-command to mumamo-map. + </li> + </ul> + </li> + <li> + Reordering and renaming: + <ul> + <li> + Reordered and move some functions in mumamo.el et al. + Added new file nxhtml-mumamo.el. + </li> + <li> + Renamed <i>define-mumamo-turn-on</i> to + <i>define-mumamo-multi-major-mode</i>. + </li> + <li> + Removed the ending <i>-turn-on</i> from the + functions defined by the macro above. + </li> + <li> + Introduced <i>multi major mode</i> as a name for + the functions defined by the macro above. Those + works in many respects like major mode functions, + but they support multiple major modes in a buffer. + </li> + </ul> + </li> + <li> + Added support for noweb as multiple major mode. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.17">1.17</dt> + <dd id="v1.17-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Added support for flyspell. + </li> + </ul> + </li> + <li> + Bug fixes to the version of find-recursive.el that + ships with nXhtml. Thanks to Cezar Halmagean. + </li> + <li> + Added tabkey2.el which tries to make it easy to use + the Tab key for completion. (You must load it and turn + on tabkey2-mode to use it.) + </li> + <li> + Folding: + <ul> + <li> + Added <i>nxhtml-heading-element-name-regexp</i> as + default for nxml style folding. + </li> + <li> + Some changes to fold-dwim.el. + </li> + </ul> + </li> + <li> + AppMenu: + <ul> + <li> + Simplified: Removed the possibility to + automatically show minor and major mode menus. + There is now only one list, <i>appmenu-alist</i>. + </li> + <li> + Added menu item <i>At Current Point</i> for + bindings found in character and overlay keymaps at + point. Those you always forget. + </li> + </ul> + </li> + <li> + Physical line: + <ul> + <li> + Added physical-line.el to nXhtml. + </li> + <li> + Added new functions to move to beginning and end + of line to ourcomments-util.el that supports + physical-line.el. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.18">1.18</dt> + <dd id="v1.18-dd"> + <ul> + <li> + Better Tab completion in tabkey2.el. + </li> + </ul> + </dd> + <dt id="v1.19">1.19</dt> + <dd id="v1.19-dd"> + <ul> + <li> + Even better Tab completion in tabkey2.el. + </li> + </ul> + </dd> + <dt id="v1.20">1.20</dt> + <dd id="v1.20-dd"> + <ul> + <li> + Once again even better Tab completion in tabkey2.el. + </li> + <li> + Fixed bug in hiding of validation errors (they could + disappear totally). + </li> + <li> + Cleaned up menus in nXhtml. + </li> + </ul> + </dd> + <dt id="v1.21">1.21</dt> + <dd id="v1.21-dd"> + <ul> + <li> + Added a bit support for dired (upload, browse, browse + remote). + </li> + <li> + Fixed some strange menu problems (i hope). + </li> + </ul> + </dd> + <dt id="v1.22">1.22</dt> + <dd id="v1.22-dd"> + <ul> + <li> + Bug fix. + </li> + </ul> + </dd> + <dt id="v1.23">1.23</dt> + <dd id="v1.23-dd"> + <ul> + <li> + Bug fix. + </li> + </ul> + </dd> + <dt id="v1.24">1.24</dt> + <dd id="v1.24-dd"> + <ul> + <li> + Tried again to make hexcolor-mode more readable. + </li> + <li> + Mumamo: + <ul> + <li> + Added support for <i>hi-lock-mode</i>. At present + it might however be very puzzling. The hilight + added by hi-lock-mode may be hidden by the + overlays used by mumamo. Tip: you can always use + the face <span + style="font-size:1.5em;">hi-black-hb</span>. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.25">1.25</dt> + <dd id="v1.25-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Handle hi-lock-mode in a more general way + using <i>font-lock-mode-hook</i>. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.26">1.26</dt> + <dd id="v1.26-dd"> + <ul> + <li> + nxhtml-mode: + <ul> + <li> + Removed the indent line patch for nxml-mode. + </li> + <li> + Better test for empty page during completion. + </li> + </ul> + </li> + <li> + tabkey2-mode: + <ul> + <li> + A lot of improvements. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.27">1.27</dt> + <dd id="v1.27-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Worked with bugs in mumamo.el that was due to bad + handling of syntax-ppss et el. Looks like most of + them are fixed. + </li> + <li> + Fixed documentation and reordered code in mumamo.el and mumamo-fun.el. + </li> + <li> + Changed javascript.el indentation to make it work with + mumamo.el. + </li> + <li> + Introduced the function <i>mumamo-make-variable-buffer-permanent</i> as an aid for minor mode authors. + </li> + <li> + Fixed quite a few indentation bugs. + There was one bug that could make Emacs loop after indentation. + </li> + </ul> + </li> + <li> + nxml-where, mlinks + <ul> + <li> + Fixed bugs with left over idle timers when buffer + had been killed (nxml-where.el, mlinks.el). + </li> + </ul> + </li> + <li> + html-site + <ul> + <li> + Fixed a bug in html-site when comparing file + names. File names where not made unique before + comparision. + </li> + </ul> + </li> + <li> + Tabkey2 + <ul> + <li> + Fixed tabkey2 bugs. + </li> + </ul> + </li> + <li> + freemind.el + <ul> + <li> + Fixed a problem in freemind-to-org-mode that + caused the error "wrong-type-argument string: nil" + in string-match("\\(?:^--org-mode: WHOLE FILE$\\)" + nil). + </li> + </ul> + </li> + <li> + Made nXhtml menu available in sub-chunks. + </li> + <li> + Included a slightly changed version of Steve Yegge's js2.el + js2-fl-mode.el from 2008-04-24 with support for jit-lock-mode. This support has some flaws and maybe js2 is not ready for use, I am not sure. However if you want to use this instead of Karl Landströms javascript-mode then please customize <i>mumamo-major-modes</i>. + </li> + </ul> + </dd> + <dt id="v1.28">1.28</dt> + <dd id="v1.28-dd"> + <ul> + <li> + New version with mostly minor bug fixes from 1.27. + Unfortunately I put out 1.27 a bit too early. + Please upgrade. + </li> + </ul> + </dd> + <dt id="v1.29">1.29</dt> + <dd id="v1.29-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + Fixed a bug causing emacs to loop when <?> + was encountered in an html style buffer. + </li> + <li> + Fixed some problems with <? and ?> in + strings in html style buffers. + </li> + <li> + Tried to avoid chunk dividers in strings and comments. (There are still some bugs there.) + </li> + <li> + Fixed an error that prevented byte compiling nxhtml-mumamo.el. + (Thanks Christoph Conrad.) + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.30">1.30</dt> + <dd id="v1.30-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Added support to handle specific rng + schemacs. With the help of this Genshi and MJT + templating languages are now handled. + </li> + <li> + Let the rng schema file name survive mumamo major + mode changes. + </li> + <li> + Added support for to let nxml-mode skip chunks it + can not parse. (This requires a patch to + rng-valid.el too which is not included, but which + I hope can go into Emacs soon.) + </li> + <li> + Chunk dividers can now be a part on their own. (Ie + there will be no parsing or syntax highlighting of + them by the chunk major mode. This is optional and + specified for each chunk types.) + </li> + <li> + Added support for Genshi and MJT. These multi + major modes support completion and error checking + in the XML/XHTML part according to their DTD + (which has some additions to the XHTML DTD). + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.31">1.31</dt> + <dd id="v1.31-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Fixed a bug that caused multi major modes to loop sometimes. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.32">1.32</dt> + <dd id="v1.32-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Fixed a bug in syntax-ppss advice. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.33">1.33</dt> + <dd id="v1.33-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Fixed another bug in syntax-ppss advice. + </li> + <li> + Added support for <i>fill-forward-paragraph-function</i>. + </li> + <li> + Made <i>longlines-mode</i> survive major mode changes in mumamo buffers. + </li> + <li> + Fixed a bug that made Emacs loop when it found + <??> in for example nxhtml-mumamo. + </li> + <li> + Made it usable with Emacs 22 again. + </li> + <li> + Moved some changes from rng-valid.el to + mumamo.el. This makes it possible to let nxml-mode + (and derivates) jump over parts when parsing the + buffer even if not using the patched version of + Emacs+EmacsW32. + </li> + </ul> + </li> + <li> + nxhtml: + <ul> + <li> + Added command to add CSS rollover images. + </li> + </ul> + </li> + <li> + mlinks: + <ul> + <li> + Tried to fix the error <i>invalid-read-syntax "] + in a list"</i> when loading <i>mlinks.el</i> + reported by some Asian users. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.34">1.34</dt> + <dd id="v1.34-dd"> + <ul> + <li> + <span style="font-size: 1.2em; color: red ()" + >Changed top directory name from nxml to nxhtml</span> + <p> + This will of course case some problems if you do not + notice it when you upgrade nXhtml. If you are using + EmacsW32 and upgrade nXhtml you should change the + file <i>emacsw32.el</i>. + </p> + <p> + The reason for this change is that nXml will soon + normally not be part of nXhtml so keeping the old + top directory name would be confusing. + </p> + </li> + <li> + Added a test suite. See the file <i>nxml/tests/test-Q.el</i>. + </li> + <li> + Mumamo: + <ul> + <li> + Fixed indentation when the whole line is a sub chunk. + </li> + <li> + Tried a bit more to stop nxml from parsing non-xml + mode chunks. Because of this php support was + changed a bit (for the better I hope). + </li> + </ul> + </li> + <li> + GIMP: + <ul> + <li> + Registry value location for GIMP had changed. + </li> + </ul> + </li> + <li> + nXhtml: + <ul> + <li> + Added support for <a href="http://hyperstruct.net/projects/mozlab">MozLab</a>. If you install MozLab in Firefox then you can directly use it from javascript mode without any additional setup. + </li> + <li> + Added <a href="http://www.oak.homeunix.org/~marcel/blog/articles/2008/07/18/nested-imenu-for-php">php-imenu.el</a>. + </li> + <li> + Fixed a bug where I inadvertently + added <i>../../lisp</i> to load-path. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.35">1.35</dt> + <dd id="v1.35-dd"> + <ul> + <li> + Fixed a small bug in sex-mode.el. + </li> + </ul> + </dd> + <dt id="v1.36">1.36</dt> + <dd id="v1.36-dd"> + <ul> + <li> + Added the function <i>emacs-Q-nxhtml</i> for easier + testing. It does the equivalent of <i>emacs -Q --load + PATH-TO/nxhtml/autostart.el</i>. + </li> + <li> + MuMaMo: + <ul> + <li> + Forgot to return php-mode in php short tags. Fixed. + </li> + <li> + Borders where not correctly calculated with php short tags. Fixed. + </li> + <li> + Subchunks not parseable by nxml-mode where marked as parseable. Fixed. + </li> + <li> + Debug messages from mumamo where not silenced. + </li> + <li> + Forgot font-lock-syntactic-keywords. This showed up in + bad fontification for strings sometimes. Fixed. + </li> + <li> + To fontify keywords font-lock-syntactically-fontified + must be set in each chunk. Fixed. + </li> + <li> + Find a way to at least temporarily work around the + problem with the last "e; char in + syntax="e;..."e; that could be seen in + large XHTML files, for example this file. The + drawback with the work around is that it bypasses + the cache for syntax-ppss, but this happens only + in multi major mode buffers and I notice no + performance problems here. + </li> + <li> + Fixed a number of problems with the defadvice for the syntax functions. + (I am afraid there are more left.) + </li> + <li> + Took a new grab on the indentation problems. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.37">1.37</dt> + <dd id="v1.37-dd"> + <ul> + <li> + The command <i>emacs-Q-nxhtml</i> and cousins did not + work on all platform. Tried to fix it. + </li> + <li> + Got a report that editing Django was to slow. Tried to fix this. + </li> + <li> + Added a test to the unit test suite that test + scrolling and jumping. + </li> + </ul> + </dd> + <dt id="v1.38">1.38</dt> + <dd id="v1.38-dd"> + <ul> + <li> + Added a workaround that removes validation error marking in non-xhtml chunks. + </li> + </ul> + </dd> + <dt id="v1.39">1.39</dt> + <dd id="v1.39-dd"> + <ul> + <li> + Multi major modes where not allowed in defcustoms + nxhtml-magic-mode-alist and + nxhtml-auto-mode-alist. Fixed. + </li> + <li> + Added tests for the use of the lists above. + </li> + <li> + Fixed some bugs that could make a buffer became + modified due to mumamo fontification actions. + </li> + <li> + The rnc files for mjt and genshi had include path that + did not work if you where using the nxml-mode that + comes with nXhtml. Fixed. (Thanks for pointing this + out, Bryan.) + </li> + <li> + Now trying to keep the launchpad bazaar repository in + sync. + </li> + </ul> + </dd> + <dt id="v1.40">1.40</dt> + <dd id="v1.40-dd"> + <ul> + <li> + tabkey2-mode + <ul> + <li> + Some small changes: support for eshell + and better information about completion commands + alternative key bindings. + </li> + </ul> + </li> + <li> + php-mode + <ul> + <li> + It turned out that my patched php-mode asked in + every buffer to turn on mumamo. Changed it to + once for every Emacs invocation instead. + </li> + <li> + In addition to this it did not turn on mumamo + multi major support if the user wanted it ;-) + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.41">1.41</dt> + <dd id="v1.41-dd"> + <ul> + <li> + There was an error that prevented loading of nXhtml + with Emacs 22. (This was before opening any file.) + </li> + <li> + Fixed a problem in startup order for ido-mode and nXhtml. + (This could lead to that ido-mode was reset from 'both to 'buffer.) + </li> + </ul> + </dd> + <dt id="v1.42">1.42</dt> + <dd id="v1.42-dd"> + <ul> + <li> + Fixed a bug concerning style="e;..."e; and similar constructs. + </li> + </ul> + </dd> + <dt id="v1.43">1.43</dt> + <dd id="v1.43-dd"> + <ul> + <li> + Added file ffip.el for finding files in projects. + </li> + <li> + Added command <i>html-site-find-file</i>. + </li> + <li> + Added aliases for all multi major modes. + The alias looks like <i>mumamo-alias-MULTI_MAJOR_MODE</i>. + Their purpose is to make it easier to find a multi major mode. + </li> + <li> + Fixed bug <a href="https://bugs.launchpad.net/nxhtml/+bug/258169">https://bugs.launchpad.net/nxhtml/+bug/258169</a>. + </li> + </ul> + </dd> + <dt id="v1.44">1.44</dt> + <dd id="v1.44-dd"> + <ul> + <li> + Fixed an error in chunk dividing. + </li> + <li> + Fixed bug <a href="https://bugs.launchpad.net/nxhtml/+bug/258097">https://bugs.launchpad.net/nxhtml/+bug/258097</a>. + </li> + </ul> + </dd> + <dt id="v1.45">1.45</dt> + <dd id="v1.45-dd"> + <ul> + <li> + Fixed bug reporting instructions to point to Launchpad. + </li> + </ul> + </dd> + <dt id="v1.46">1.46</dt> + <dd id="v1.46-dd"> + <ul> + <li> + Cleaned up and fixed bugs in the help routines. + </li> + </ul> + </dd> + <dt id="v1.47">1.47</dt> + <dd id="v1.47-dd"> + <ul> + <li> + Made tabkey2-mode aware of this-command. + </li> + </ul> + </dd> + <dt id="v1.48">1.48</dt> + <dd id="v1.48-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + Added jde-mode as first choice if major mode file spec is java-mode. + </li> + <li> + Fixed a bug concerning buffer local variables saving. + </li> + <li> + Fixed a bug that occured when autoloading major mode failed. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.49">1.49</dt> + <dd id="v1.49-dd"> + <ul> + <li> + Added a CEDET loader which can fetch CVS version of CEDET. + </li> + </ul> + </dd> + <dt id="v1.50">1.50</dt> + <dd id="v1.50-dd"> + <ul> + <li> + Added a Rinari loader which can fetch SVN version of Rinari and ruby-mode. + </li> + </ul> + </dd> + <dt id="v1.51">1.51</dt> + <dd id="v1.51-dd"> + <ul> + <li> + Fixed a regression bug in MuMaMo. If a major mode was + not defined Emacs could hang badly. + </li> + <li> + Added an ECB loader which can fetch CVS version of ECB. + </li> + <li> + Enhancements to the routines for fetching and setting + up CEDET, ECT and Rinari. + </li> + </ul> + </dd> + <dt id="v1.52">1.52</dt> + <dd id="v1.52-dd"> + <ul> + <li> + Added a tool to give major modes priority when + choosing a major mode for a buffer. + </li> + </ul> + </dd> + <dt id="v1.53">1.53</dt> + <dd id="v1.53-dd"> + <ul> + <li> + Quick fix for left-over which made it impossible to + edit php files in version 1.52. If you are using + version 1.52 you may for the moment just add (require + 'fmode) to your .emacs after loading nXhtml. + </li> + </ul> + </dd> + <dt id="v1.54">1.54</dt> + <dd id="v1.54-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + Added better error handling for problems such as + those that occured in version 1.52 with php-mode. + </li> + <li> + There was a bug when changing from a mumamo multi + major mode. + </li> + <li> + Tried to fix <a href="https://answers.launchpad.net/nxhtml/+question/43320">question 43320</a>. + </li> + </ul> + </li> + <li> + php-mode: + <ul> + <li> + Made the indentation check up to date with current + MuMaMo. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.55">1.55</dt> + <dd id="v1.55-dd"> + <ul> + <li> + Tried to fix https://answers.launchpad.net/nxhtml/+question/43320 again. + </li> + <li> + Better test of when to end tabkey2-mode completion function state. + </li> + </ul> + </dd> + <dt id="v1.56">1.56</dt> + <dd id="v1.56-dd"> + <ul> + <li> + Allowed both single and double quotes in mlinks for html files. + </li> + <li> + Added initial support for Mako template language. + (There is no support for the tags yet, like in + Genshi. Additions are welcome!) + </li> + </ul> + </dd> + <dt id="v1.57">1.57</dt> + <dd id="v1.57-dd"> + <ul> + <li> + Fixed another part of question 43320 (see above) regarding php indentation. + </li> + </ul> + </dd> + <dt id="v1.58">1.58</dt> + <dd id="v1.58-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + The change of major mode when moving between + chunks could occur in the wrong buffer because I + had misunderstood how with-selected-window + works. Fixed. + </li> + <li> + Added ${...} python chunks to Mako (ie mako-html-mumamo). + </li> + <li> + Added mako-nxhtml-mumamo. + </li> + </ul> + </li> + <li> + Appmenu: + <ul> + <li> + Fixed problem with point keymap. + </li> + </ul> + </li> + <li> + Php: + <ul> + <li> + Fixed <a href="https://answers.launchpad.net/nxhtml/+question/44504">https://answers.launchpad.net/nxhtml/+question/44504</a>. + </li> + <li> + Fixed a typo regarding indentation check. + </li> + </ul> + </li> + <li> + Tabkey2: + <ul> + <li> + Better support for YASnippet. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.59">1.59</dt> + <dd id="v1.59-dd"> + <ul> + <li> + Fixed a bug that was revealed by the better support for YASnippet. + </li> + </ul> + </dd> + <dt id="v1.60">1.60</dt> + <dd id="v1.60-dd"> + <ul> + <li> + Bug fixes: + <ul> + <li> + Fix some bugs in Tidy XHTML support. + </li> + <li> + Also Some small improvements to Tidy GUI. + </li> + <li> + Added a test case for bug + https://bugs.launchpad.net/nxhtml/+bug/271497 (which I + can't reproduce). + </li> + <li> + Bug fixes to ffip.el + </li> + <li> + Added fix for <a href="http://emacsbugs.donarmstrong.com/cgi-bin/bugreport.cgi?bug=1013" + >Emacs bug 1013</a>. + </li> + <li> + Fixed some minor bugs in as-external.el. + </li> + <li> + New handling of minor modes (buffer local variables). + I hope this should fix the problem reported in + <a href="https://bugs.launchpad.net/bugs/272526">nXhtml bug 272526: Imenu on menubar doesn't work after switching modes</a>. + </li> + <li> + Fixed a bug that could make buffer marked as modified + during fontification. + </li> + <li> + Changed <i>php-mode</i> binding for TAB to follow Emacs normal standard. + </li> + <li> + Fixed a bug that sometimes caused rng-validate-mode to be + turned on in wrong buffer when setting xhtml fictive + validation header. + </li> + </ul> + </li> + <li> + Finished a replacement for the usual help command on + [f1 ?c]. This will in addition to the command show the + keymap. To use it add + <i>(global-set-key [f1 ?c] 'find-keymap-binding-key)</i> to your .emacs. + </li> + <li> + Let tabkey2-mode first look for [tab] and then [?\t]. + </li> + <li> + Added an <a href="http://ourcomments.org/Emacs/nXhtml/tut/tutorials.html" + >nXhtml tutorial page</a> with video tutorials. + </li> + <li> + After question + <a href="https://answers.launchpad.net/nxhtml/+question/45721" + >nXhtml question 45721</a> + there was a short discussion on Emacs Devel where I + was convinced to change the name convention for multi + major modes. They are now supposed to end + in <i>-mumamo-mode</i> (instead of the old <i>-mumamo</i>). + </li> + <li> + Added <i>ourcomments-ediff-files</i> to start ediff + from a shell with Emacs Client. + </li> + <li> + Took a look at autoloading. nXhtml now uses + autoloading in many more cases and loads much faster. + </li> + <li> + Added new general functions for search and replace: + <i>grep-query-replace</i>, <i>ldir-query-replace</i> and + <i>rdir-query-replace</i>. Also added similar + functions to search and replace in a site (they are in + the nXhtml menu). + </li> + <li> + Added <i>better-fringes-mode</i> for my personal preferences + for fringe symbols ... + </li> + <li> + Enhancement for (X)HTML editing: + <ul> + <li> + Added a minimal one-line display version of fictive + validation headers and made it the default. + </li> + <li> + Some enhancements to <i>nxml-where-mode</i>. + </li> + <li> + Display of images inline. Can be used in different major modes/files. + </li> + <li> + Added the minor mode <i>wrap-to-fill-column-mode</i> and + replaced longlines-mode in the Tools menu with this. + </li> + <li> + Added the minor mode <i>html-write-mode</i> that can hide + some simple tags and just show the inner html with a + user defined face. This is meant to make it easier to + write html files. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.61">1.61</dt> + <dd id="v1.61-dd"> + <ul> + <li> + Bug fixes in html-write-mode and as-external.el. + </li> + <li> + Removed left over autoloads (maybe there was a problem with ruby-mode, not sure). + </li> + <li> + Fixed bug <a href="https://bugs.launchpad.net/nxhtml/+bug/290364">290364</a>, + see below about MuMaMo important changes. + </li> + <li>Fixed bug <a href="https://bugs.launchpad.net/nxhtml/+bug/272526">272526</a>.</li> + <li>Fixed bug <a href="https://bugs.launchpad.net/nxhtml/+bug/292393">292393</a>.</li> + <li>Fixed bug <a href="https://bugs.launchpad.net/nxhtml/+bug/300946">300946</a>.</li> + <li>Fixed bug <a href="https://bugs.launchpad.net/nxhtml/+bug/304569">304569</a>.</li> + <li> + Added some support for editing gmail messages in + as-external.el (to be used with It's All Text for + Firefox). + </li> + <li> + Some changes to face handling in Emacs had made htmlfontify.el fail. + Some changes in CSS handling in Firefox and IE made hfyview.el fail even more. + Tried to fix this. + </li> + <li> + Updated vline.el + </li> + <li> + Aaron Hawley merged in some changes he made to php-mode.el. Thanks Aaron! + Now nXhtml uses a slightly modified version of php-mode 1.5.0 is used + </li> + <li> + <b>MuMaMo important changes</b> + <p> + Unfortunately the chunk dividing routines in + mumamo.el can loop, see bug 290364 above. The + reason is that I tried to find chunks at current + point in a buffer without looking through the buffer + from the beginning. Fontification works this way in + Emacs. It is a heuristic that sometimes fails + however, but the consequences are merely just local + errors in fontification. + </p> + <p> + Chunk dividing must be more stable since it has a + global impact on the files fontification. It + therefore have to be done from the beginning of the + buffer - just like a parser reading the file will + do. + </p> + <p> + I have done first part of this rewrite and I hope + chunk dividing can not loop any more. Chunk dividing + is now always done from the beginning. However the + routines actually finding the chunks still looks + both upwards and downwards. I will try to remove + this unnecessary complexity later. + </p> + </li> + </ul> + </dd> + <dt id="v1.62">1.62</dt> + <dd id="v1.62-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + Fixed bugs in chunk creation that caused args out + of range at buffer end. + </li> + </ul> + </li> + <li> + Autoloading caused wrong libraries to load (for + example javascript from mozdev). Fixed. + </li> + </ul> + </dd> + <dt id="v1.63">1.63</dt> + <dd id="v1.63-dd"> + <ul> + <li> + Removed find-recursive.el since there is no use for it + any more and it interferes with emacs-rails. (It was + initally a bug fixs for emacs-rails.) + </li> + <li> + Fixed bugs in <i>html-write-mode</i>. + </li> + <li> + Used the new routines for finding chunks also during + xml validation and syntax-ppss. + </li> + </ul> + </dd> + <dt id="v1.64">1.64</dt> + <dd id="v1.64-dd"> + <ul> + <li> + MuMaMo: nxml was not turned off properly when + switching from a multi major mode that used nxml-mode + or nxhtml-mode. Fixed. This was especially troublesome + for Emacs 22 users where multi major modes based on + nxhtml-mode does not always work. + </li> + <li> + Majmodpri.el: Added a defcustom to give multi major + modes based on nxhtm-mode or nxml-mode lower + priority. This is on by default in Emacs 22. + </li> + </ul> + </dd> + <dt id="v1.65">1.65</dt> + <dd id="v1.65-dd"> + <ul> + <li>Fixed a bug in nxml-where.el.</li> + <li> + Fixed a minor bug in majmodpri.el. It did not work if + magic-mode-alist contained anonymous functions. + (Thanks from Niels Giesen.) + </li> + <li> + Fixed a bug in pause.el and added some mindfulness to it. + </li> + <li> + Adjusted <i>ourcomments-move-beginning-of-line</i> (and dito + for end) to the new <i>line-move-visual</i> in Emacs 23. + Moved physical-line.el to <i>old</i> subdir since it is now + obsolete. + </li> + <li> + Made it possible to byte compile nXhtml. + <p> + To do that use + <i>M-x nxhtmlmaint-start-byte-compilation</i>. + </p> + <p> + A lot of code changes to make byte compilation + possible without a lot of warnings. Most changes + where just moving code around, but some where bug + fixes. + </p> + </li> + </ul> + </dd> + <dt id="v1.66">1.66</dt> + <dd id="v1.66-dd"> + <ul> + <li> + Further work on byte compiling. + </li> + <li> + Tried to fix some problem with defadvice in + ourcomments-util.el. + </li> + <li> + Tried to finish the command <i>M-x search-form</i>. + </li> + <li> + When no chunk is found (border case) then set the + major mode to the main major mode for the current + multi major mode. + </li> + </ul> + </dd> + <dt id="v1.67">1.67</dt> + <dd id="v1.67-dd"> + <ul> + <li> + Removed css.el since it is in Emacs 22.2 and later. + </li> + </ul> + </dd> + <dt id="v1.68">1.68</dt> + <dd id="v1.68-dd"> + <ul> + <li> + Fixed bugs related to byte compilation. This should + now work for both Emacs 22 and 23. Also added a menu + entry for byte compilation. + </li> + <li> + Removed nXml from the distribution to make it + smaller. nXml comes with Emacs 23 (not yet released of + course). For Emacs 22 users see EmacsWiki about where + to get nXml. + <p> + Adding nXml to Emacs 22 startup should be done by + using the file <i>nxhtml/autostart22.el</i>. + </p> + <p> + NOTE 1: if you want to use <i>nxhtml-mode</i> in + multi major modes in Emacs 22 (not recommended) you + must also customize <i>majmodpri-no-nxml</i>. + </p> + <p> + NOTE 2: The major mode <i>nxhtml-mode</i> as a + major-mode works however very well also in Emacs 22. + </p> + </li> + </ul> + </dd> + <dt id="v1.69">1.69</dt> + <dd id="v1.69-dd"> + <ul> + <li> + Chunks were unnecessary deleted and recreated after a + change even if all changes where within one + chunk. This could make editing very slow. Fixed. + </li> + <li> + Search for rng-auto.el in path. (Emacs 22 only.) + </li> + </ul> + </dd> + <dt id="v1.70">1.70</dt> + <dd id="v1.70-dd"> + <ul> + <li> + Validation could not be turned on in multi major + modes. Fixed. + </li> + </ul> + </dd> + <dt id="v1.71">1.71</dt> + <dd id="v1.71-dd"> + <ul> + <li> + Fixed the problem that showed up in the file + nxhtml/tests/in/kubica-freezing-i.html which could + make Emacs freeze. + </li> + </ul> + </dd> + <dt id="v1.72">1.72</dt> + <dd id="v1.72-dd"> + <ul> + <li> + Somehow I dropped this: Search for rng-auto.el in + path. (Emacs 22 only.) Don't ask me how. Fixed again. + </li> + </ul> + </dd> + <dt id="v1.73">1.73</dt> + <dd id="v1.73-dd"> + <ul> + <li> + Worked a bit more on byte compilation and elisp + libraries loading. If you byte compile nXhtml it will + now load very few modules by default. It loads more + modules if you don't. + </li> + <li> + Added chart.el, a small elisp library to create charts. + This works by calling google charts library. + Chart.el is a bit beta, eh alpha, but still useful I believe. + </li> + </ul> + </dd> + <dt id="v1.74">1.74</dt> + <dd id="v1.74-dd"> + <ul> + <li> + Found and fixed a bug in <em>fictive XML validation + headers</em>. This bug depended on the load order of + libraries. + </li> + <li> + Fixed a small bug in <i>nxml-where-mode</i>. + </li> + </ul> + </dd> + <dt id="v1.75">1.75</dt> + <dd id="v1.75-dd"> + <ul> + <li> + Included css-color.el, css-palette.el and gpl.el from Niels Giesen. + (This replaces hexcolor.el which is no longer in nXhtml.) + </li> + </ul> + </dd> + <dt id="v1.76">1.76 -- Released 2009-02-26</dt> + <dd id="v1.76-dd"> + <ul> + <li> + <span class="bugfix">Fixed a long standing bug in XML validation.</span> (I had + forgot to set the defadvice return value in defadvice + rng-set-initial-state in rngalt.el - I wonder why I + did not get any bug reports about this...) + </li> + <li> + <span class="bugfix">css-color.el: bug fix for mIxEd case color names.</span> + </li> + <li> + <span class="bugfix">freemind.el: bug fixes.</span> + </li> + </ul> + </dd> + <dt id="v1.77">1.77 -- Never released!</dt> + <dd id="v1.77-dd"> + <ul> + <li> + <span class="bugfix">Fixed numerous bugs</span>, please + see <a href="https://bugs.launchpad.net/nxhtml/">nXhtml bug tracker</a> + and dito <a href="https://answers.launchpad.net/nxhtml">question and answers</a>. + </li> + <li> + Added some missing autoloads. + </li> + <li> + <span class="bugfix">Tried to fix some smaller troubles with Viper when + changing chunk.</span> + </li> + <li> + <span class="bugfix">Menus for Tidy were broken. Fixed.</span> + </li> + <li> + Added a test that the <i>nxml-mode libraries included + in Emacs</i> are used and not the old ones. (If I + understand it correctly this might have been a problem + for Debian/Ubuntu Emacs 23 snap-shots users where the + old nxml-mode has been a left over from earlier + snap-shots where it was needed.) + </li> + <li> + MuMaMo: + <ul> + <li> + Chunks are now always created from top to bottom. + This should make chunk creation more stable. + It also opens up for chunks in chunks in the future. + (The code still needs work...) + </li> + </ul> + </li> + <li> + majmodpri.el: + <ul> + <li> + To restore multi major modes in files loaded by + desktop-save-mode the new + function <i>majmodpri-apply</i> can be added + to <i>desktop-after-read-hook</i>. + </li> + <li> + New default for <i>majmodpri-sort-after-load</i>: + Sort after loading certain features/libraries that + are known to change <i>auto-mode-alist</i> and + apply to current buffer. This new default should + hopefully make major mode selection less + confusing. + </li> + </ul> + </li> + <li> + winsav.el: + <ul> + <li> + Added save and restore between Emacs sessions for frame configuration. + I am not sure how this works with special frames yet, but I have tested this with oneonone.el and it seems to work. + Dedicated windows should also work. + </li> + <li> + Added saving and restoring of named frame configurations. + </li> + </ul> + </li> + <li> + javascript.el: + <ul> + <li> + Updated to Karl's newest version (and added my additions). + </li> + </ul> + </li> + <li> + Added library usb-setup.el that might help a bit with + using Emacs from an USB stick. + </li> + <li> + Updated smarty-mode.el to the latest version. + </li> + <li> + <img alt="Happy brain" src="img/fun-brain-2.png" width="131" height="119" /> + Added an n-back game for your brain (and mine). + Just do <b>M-x n-back-game</b> to start it. + </li> + </ul> + </dd> + <dt id="v1.78">1.78 -- Released 2009-05-28</dt> + <dd id="v1.78-dd"> + <ul> + <li> + <span class="bugfix">nXhtml version 1.78 is the + release of the previous beta</span> (which had number + 1.77 and existed in many versions). + </li> + </ul> + </dd> + <dt id="v1.79">1.79</dt> + <dd id="v1.79-dd"> + <ul> + <li> + Added a function to simplify adding for example font + lock keywords for major modes used in multi major + mode: <i>mumamo-refresh-multi-font-lock</i>. + </li> + </ul> + </dd> + <dt id="v1.80">1.80 -- Released 2009-06-02</dt> + <dd id="v1.80-dd"> + <ul> + <li> + <span class="bugfix">Fixed a (rather serious) bug and cleaned up.</span> + </li> + <li> + Added mumamo regions. Mumamo regions are temporary + mumamo chunks that you set up by selecting a region + and telling you want that in a new major mode. To use + this feature look in the nXhtml menu under <i>Chunks - + Region Chunks</i>. + </li> + </ul> + </dd> + <dt id="v1.81">1.81 -- Released 2009-06-19</dt> + <dd id="v1.81-dd"> + <ul> + <li> + Added the minor mode <i>mumamo-alt-php-tags-mode</i> + that lets you work more easily with <?php tags in + strings while you are still able to use XHTML + completion. (I added something looking rather similare + earlier, but removed it again because of difficulties + with undo. They are now fixed in Emacs and this should + be safe.) + </li> + <li> + Added support for hi-lock, but please be aware that + chunk overlays hides background marking that hi-lock + does... - so you must use marking that changes + foreground part of face. + </li> + </ul> + </dd> + <dt id="v1.82">1.82 -- Released 2009-06-23</dt> + <dd id="v1.82-dd"> + <ul> + <li> + <span class="bugfix">Find and fixed some bugs when + I tried to fix bug 388729.</span> Not sure I fixed that + bug though. + </li> + </ul> + </dd> + <dt id="v1.83">1.83 -- Released 2009-06-24</dt> + <dd id="v1.83-dd"> + <ul> + <li> + <span class="bugfix">Fontification disappeared for example in *grep* buffer. Fixed.</span> + </li> + </ul> + </dd> + <dt id="v1.84">1.84 -- Released 2009-06-30</dt> + <dd id="v1.84-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + <span class="bugfix">Worked around bug in Emacs + 22.3 where c-after-change was left in + after-change-functions.</span> (This makes no + difference in Emacs 23.) + </li> + <li> + <span class="bugfix">Fixed a bug that occured + after deletion of whole chunks.</span> + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.85">1.85 -- Released 2009-07-04</dt> + <dd id="v1.85-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + <span class="bugfix">Corrected various mostly + minor bugs</span>, like indent-line-function which + where globally set to + mumamo-indent-line. Corrected. + </li> + <li> + <span class="bugfix">Forgot to finish the implementation of support for + font-lock-add-keywords. Done.</span> + </li> + <li> + Added some faces hi-mumamo-* to use with hi-lock, + but unfortunately they are not very + visible. Suggestions are welcome. + </li> + </ul> + </li> + <li> + CEDET and ECB: + <ul> + <li> + <span class="bugfix">Made the routines for fetching and installing CEDET and ECB + from the development sources work again.</span> + </li> + <li> + Added support for ECB in <i>winsav-save-mode</i>. Though I suspect it need some rework... + </li> + </ul> + </li> + <li> + Added pointback.el, found on EmacsWiki. This is just + so missing in Emacs... + </li> + </ul> + </dd> + <dt id="v1.86">1.86 -- Released 2009-07-05</dt> + <dd id="v1.86-dd"> + <ul> + <li> + Made the fetching and installing of CEDET and ECB a + bit better. + </li> + </ul> + </dd> + <dt id="v1.87">1.87 -- Released 2009-07-08</dt> + <dd id="v1.87-dd"> + <ul> + <li> + Some enhancements to winsav.el and menuacc.el. + </li> + <li> + MuMaMo: + <ul> + <li> + Added heredoc for some modes. They are currently + kind of hidden since they are only available in + multiple major modes that offer just heredocs. + The implemented heredoc multi major modes are + + sh-mumamo-heredoc-mode, + php-mumamo-heredoc-mode, + perl-mumamo-heredoc-mode, + cperl-mumamo-heredoc-mode, + python-mumamo-heredoc-mode and + ruby-mumamo-heredoc-mode. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.88">1.88 -- Never released, only betas</dt> + <dd id="v1.88-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + <span class="bugfix"> + Background colors could not be removed by + setting <i>mumamo-background-coloring</i>. + Fixed, but please notice that this variable now + is a number. + </span> + </li> + <li> + <span class="bugfix">Support for chunks in chunks.</span> + </li> + <li> + <span class="bugfix">Removed string-match-p which does not exist in Emacs 22.</span> + </li> + <li> + <span class="bugfix"> + mumamo-alt-php-tags-mode hardly survived major mode + changes. Rescued. + </span> + </li> + <li> + <span class="bugfix"> + Added possibility to display chunk info in + window margins as an alternative/addon to + colored chunks. + </span> + </li> + <li> + <span class="bugfix"> + Fixed a bug in n-back.el that prevented the game to be used on Emacs 22. + </span> + </li> + </ul> + </li> + <li> + Bug fixes and changes to udev for CEDET and ECB. (Udev + is a little utility to fetch and install dev sources.) + <ul> + <li> + <span class="bugfix"> + Changed default directory for installing CEDET and + ECB to be under <i>~/.emacs.d/udev/</i>. + </span> + </li> + <li> + <span class="bugfix"> + Several bug fixes for udev. + It should now work again (it did not if you compiled nXhtml). + </span> + </li> + </ul> + </li> + <li> + Added support for <a href="http://www.emacswiki.org/emacs/CompanyMode">Company Mode</a> style completion. Temporary included a copy of Company Mode with bug fixes and changes needed for nXhtml and Viper. It also include a lot of other small features (which I hope can be included in Company Mode). On of these is integration with <a href="http://www.emacswiki.org/emacs/PredictiveMode">Predictive Mode</a>. (You have to get Predictive Mode yourself. If you want to install it on MS Windows I recommend using the latest version of Cygwin. A smaller change to the Makefile is required, there is one absolute path you probably want to remove.) + <p class="bugfix"> + Note: I thought that I should make Company Mode the default completion style. However there are still some problem so I kept the old default completion style. + </p> + </li> + <li> + TabKey2: + <ul> + <li> + Added support for Company Mode. + </li> + <li> + Made completion only occur at word ends. + </li> + </ul> + </li> + <li> + Added support for <a href="http://www.emacswiki.org/emacs/Anything">anything style completion</a> in XHTML completion. + </li> + <li> + Added support in inlimg-mode to show images in org-mode. (Also made inlimg-mode use font lock which makes it more reliable.) + </li> + <li> + Included espresso-mode (with some possible bug fixes). Not yet the default for Javascript. + </li> + <li> + <p class="bugfix"> + Added simple functions for mirroring html files in + Firefox as typing. This works - at least for small + files. There is also support for automatic update + of Firefox when saving CSS files. + </p> + <p> + This is a simple framework for communicating with + MozRepl which enqueues requests, waiting for + response prompt before sending next requests. + <span class="bugfix">Maybe this can be used to make + some more efficient routines than those I have + written here. Any takers?</span> + </p> + <p> + For larger files (like this one) this version is + rather slow since it always changes the whole DOM. + </p> + </li> + <li> + <span class="bugfix"> + Rewrote <i>nxml-where-mode</i> to be more efficient and + fixed some minor bugs. It can now also be used with + MozRepl to track position in file. + </span> + </li> + <li> + <span class="bugfix"> + Made <i>winsav-save-mode</i> remember maximized state and forget about empty non-file buffers. + </span> + </li> + <li> + <span class="bugfix"> + Added workaround for <a href="http://emacsbugs.donarmstrong.com/cgi-bin/bugreport.cgi?bug=4015">Emacs bug 4015 on w32</a>. + </span> + </li> + <li> + Added <i>ourcomments-M-x-menu-mode</i> which <a + href="http://lists.gnu.org/archive/html/emacs-devel/2009-07/msg01025.html">adds menu commands to M-x history</a>. + </li> + </ul> + </dd> + <dt id="v1.89">1.89 -- Released 2009-08-04</dt> + <dd id="v1.89-dd"> + <ul> + <li> + The release version of all the fixes in beta 1.88. + </li> + </ul> + </dd> + <dt id="v1.90">1.90 -- Released 2009-08-04</dt> + <dd id="v1.90-dd"> + <ul> + <li> + <span class="bugfix"> + Made wrap-to-fill-column-mode cooperate a bit with + mumamo-margin-info-mode. + </span> + </li> + <li> + Made an inventory of utilities in nXhtml and made some + of them more visible in the menus. + </li> + </ul> + </dd> + <dt id="v1.91">1.91 -- Released 2009-08-04</dt> + <dd id="v1.91-dd"> + <ul> + <li> + <span class="bugfix"> + Mumamo bug fix for bug reported on Emacs wiki today. Inline scripts end tag could not be in column one if previous line had a // style js comment. + </span> + </li> + </ul> + </dd> + <dt id="v1.92">1.92 -- Released 2009-08-04</dt> + <dd id="v1.92-dd"> + <ul> + <li> + <span class="bugfix"> + An Emacs bug that sometimes prevent changing local keymap in a timer hit us. Made a workaround. + </span> + </li> + </ul> + </dd> + <dt id="v1.93">1.93 -- Released 2009-08-04</dt> + <dd id="v1.93-dd"> + <ul> + <li> + <span class="bugfix"> + Minor bug in menus gave major problem. Fixed - I hope. + </span> + </li> + </ul> + </dd> + <dt id="v1.94">1.94 -- Never released, only betas</dt> + <dd id="v1.94-dd"> + <ul> + <li> + MuMaMo + <ul> + <li> + <span class="bugfix"> + Hopefully MuMaMo is now fully transfered to the new way of finding the major mode chunks. Chunks in chunks should now work (except for lurking bugs of course...). Tried to fix indentation. + </span> + </li> + </ul> + </li> + <li> + <span class="bugfix"> + <i>wrap-to-fill-column-mode</i> calculated window width wrongly so that the displayed wrapping was not consistent with what fill-paragraph would give. Corrected together with some other bugs in it. + </span> + </li> + <li> + <span class="bugfix"> + Fixed an indentation bug in php-mode I introduced when I fixed another indentation bug for heredoc endings. + </span> + </li> + <li> + <span class="bugfix"> + A bug in <i>ourcomments-M-x-menu-mode</i> made Emacs client fail. Fixed. + </span> + </li> + <li> + <span class="bugfix"> + The version of company-mode include in nXhtml has some changes. It turns out that these probably gives some problems with company-mode support for etags. The version of company-mode in nXhtml is therefore not autoloaded any more. + </span> + </li> + <li> + Improved external editing of web mail. + </li> + <li> + Removed <i>js2-mode</i> (and my attempts to make it work with mumamo) since it is now part of Emacs devel sources. Since js2-mode does not use font-lock its integration with mumamo have to wait until it does that. + </li> + <li> + Reworked <b>folding</b> a bit so it is more useful. + There is a new minor mode, <i>foldit-mode</i>, that shows better markers for folding. There is a new entry in the <i>nXhtml / Tools</i> menu for folding. <i>fold-dwim-toggle</i> now alwo toggles images and <i>html-write-mode</i> things. In html it first checks for headers then does tag block style visibility toggling. + </li> + <li> + Updated <i>vline.el</i>. + </li> + <li> + Removed fmode.el since it is not needed any more when majmodpri.el does the job. + </li> + <li> + Removed routines to fetch/load CEDET since CEDET is now part of devel sources of Emacs. + </li> + </ul> + </dd> + <dt id="v1.95">1.95</dt> + <dd id="v1.95-dd"> + <ul> + <li> + First release after all 1.94 betas. + </li> + </ul> + </dd> + <dt id="v1.96">1.96</dt> + <dd id="v1.96-dd"> + <ul> + <li> + <span class="bugfix"> + Problem creating autoload file in latest dev version of Emacs. Fixed. + </span> + </li> + <li> + <span class="bugfix"> + Fixed typo in wrap-to-fill.el. + </span> + </li> + <li> + <span class="bugfix"> + Autoloaded <i>buffer-narrowed-p</i>. + </span> + </li> + </ul> + </dd> + <dt id="v1.97">1.97</dt> + <dd id="v1.97-dd"> + <ul> + <li> + <span class="bugfix"> + Problem with customize-option because widgets where not loaded. Rearranged code to bit to fix this. + </span> + </li> + <li> + Added support for Groovy from + <a href="http://tiagocury.blogspot.com/2009/10/gsp-groovy-server-pages-support-for.html">Tiago Cury</a>. + </li> + </ul> + </dd> + <dt id="v1.98">1.98</dt> + <dd id="v1.98-dd"> + <ul> + <li> + <span class="bugfix"> + Added support for PHP nowdocs. + </span> + </li> + <li> + Freemind.el: Added support for <i>org-odd-levels-only</i>. + </li> + </ul> + </dd> + <dt id="v1.99">1.99</dt> + <dd id="v1.99-dd"> + <ul> + <li> + Converted line endings from CRLF to LF. + </li> + </ul> + </dd> + <dt id="v2.00">2.00</dt> + <dd id="v2.00-dd"> + <p> + 2.00 does not stand for something very exciting, it is just a consecutive number. But - I do believe this is a rather mature version of nXhtml. + </p> + <ul> + <li> + MuMaMo + <ul> + <li> + <span class="bugfix"> + Fixed some indentation bugs. + </span> + </li> + <li> + <span class="bugfix"> + Added multi major mode local sub chunk dividing inheriting. + </span> + </li> + <li> + <span class="bugfix"> + Made MuMaMo avoid closing org-mode nodes + </span> + when moving between sub chunks in org files. + </li> + <li> + <span class="bugfix"> + Introduced per main major local variables. + </span> + First use is for buffer-invisibility-spec. This can only be set in the main major mode now. (Or rather, it will be reset to what was last set in main major mode when you move between chunks.) This is the most reasonable way I believe, since it may otherwise change when moving between chunks and the new chunk's major mode is called. + </li> + <li> + Added support for Mason. + </li> + </ul> + </li> + <li> + <span class="bugfix">Renamed gimp.el to gimpedit.el</span> and made it open GIMP on other platforms than w32 too. (Symbols in the files are renamed too.) Skipped compatibility with old GIMP versions. + </li> + <li> + <span class="bugfix">Renamed freemind.el to org-freemind.el</span> so that it can be included among the org files. + Also added support for #+BEGIN_HTML when exporting to freemind. + </li> + </ul> + </dd> + <dt id="v2.01">2.01</dt> + <dd id="v2.01-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + <span class="bugfix"> + Major mode was not always switched when moving fast between chunks. Fixed. + </span> + </li> + <li> + Made desktop recognize multi major modes. + </li> + </ul> + </li> + <li> + <span class="bugfix"> + org-freemind.el was broken. Sorry. + </span> + </li> + <li> + Fixed a bug in wrap-to-fill-column-mode. + </li> + <li> + Enhanced support for smarty template language. + </li> + <li> + Mlinks mode used one timer per buffer. Converted to one global timer => much faster. (This actually slowed down Emacs screen update before.) + </li> + </ul> + </dd> + <dt id="v2.02">2.02</dt> + <dd id="v2.02-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + <span class="bugfix"> + Support for #+BEGIN_SRC ... #+END_SRC etc in org-mode. + </span> + </li> + <li> + <span class="bugfix"> + Bug fix for the case <script ...>//<!-- --> + </span> + </li> + <li> + <span class="bugfix"> + Fixed support for ASP again. + </span> + </li> + <li> + Added support for XSL with embedded CSS and Javascript, see <i>xsl-nxml-mumamo-mode</i>. + </li> + <li> + Added support for SSJS (Server Side Javascript) + </li> + <li> + Changed to using nxhtml-mode for indentation when chunk major is htm-mode. Added <i>mumamo-indent-major-to-use</i> to control this. + </li> + <li> + Turned off nxml-mode validation during indentation of regions. + </li> + <li> + Updated htmlfontify.el. + </li> + <li> + Included <a href="http://www.emacswiki.org/emacs/ZenCoding">zencoding-mode.el</a>. + </li> + <li> + Finally got around to implement a <b>C-a</b> that just selects a widget field in a Custom buffer, not the whole buffer. See <i>rebind-keys-mode</i>. + </li> + </ul> + </li> + <li> + Added wrap-to-fill-column-global-mode. + </li> + <li> + Removed org-freemind.el (formerly freemind.el) since it is now part of Emacs CVS repository and you can get it there. + </li> + <li> + <span class="bugfix"> + Added flymake support for CSS and javascript with detailed instructions of how to install needed support. + </span> + </li> + </ul> + </dd> + <dt id="v2.03">2.03</dt> + <dd id="v2.03-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + <span class="bugfix"> + Made the new JavaScript mode that is included in Emacs work within chunks. + </span> + </li> + </ul> + </li> + <li> + Removed the JavaScript modes that were distributed with nXhtml. If you are not using CVS Emacs please get js.el from there. + </li> + <li> + <span class="bugfix"> + Made <i>majmodpri-no-nxml</i> work a bit better. + </span> + </li> + <li> + Put <i>rebind-keys-mode</i> on the menu so it can be found. + </li> + </ul> + </dd> + <dt id="v2.04">2.04</dt> + <dd id="v2.04-dd"> + <ul> + <li> + <span class="bugfix"> + Added web install and update of nXhtml. + </span> + You can find this in the nXhtml menu. + If you do not have this in your nXhtml yet, or have not installed nXhtml please see the instructions on EmacsWiki. + </li> + <li> + MuMaMo: + <ul> + <li> + <span class="bugfix"> + Fixed some problems with temporary chunks. + </span> + </li> + <li> + Added support for html chunks in markdown files with new multi major mode <i>markdown-html-mumamo-mode</i>. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v2.05">2.05</dt> + <dd id="v2.05-dd"> + <ul> + <li> + <span class="bugfix"> + Fixed a problem in flymake-css.el with loading newst-backend.el (which provides the wrong feature). + </span> + </li> + </ul> + </dd> + <dt id="v2.06">2.06 - never released</dt> + <dd id="v2.06-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + Skipped fontification during indentation. (This was troublesome since major mode may have to be changed during indentation.) + </li> + <li> + Included iss-mode and iss-mumamo-mode for editing of Inno Setup scripts. + </li> + <li> + <span class="bugfix"> + Comments in eRuby <%# .. %> did not work. Fixed. + </span> + </li> + </ul> + </li> + <li> + Included better support for Java in flymake. It will can now recognize makefiles, ant and single java files and try to DTRT. + </li> + </ul> + </dd> + <dt id="v2.07">2.07 - never released</dt> + <dd id="v2.07-dd"> + <p> + This version was never released, but was available as beta for testing (and use). During this beta I tried to finish the rewriting of the rewriting of the chunk dividing routines. (Those needed simplification. Initially I believed that chunks with different major could be created starting from anywhere in the file. This was complex and indeed a bad idea since the chunk dividing markers depends on the content of the file from the top.) + </p> + <p> + A lot of bugs where fixed during this and new things were added. Some things were removed. But there is no good logg of this anywhere because I did not have time to update that. Sorry. But if you are interested you can have a look at the bug database at Launchpad. + </p> + </dd> + <dt id="v2.08">2.08 - released 2010-04-25</dt> + <dd id="v2.08-dd"> + <p> + This is the first released version since version 2.05 (which was released in Dec 2009). + </p> + <p> + One noticeable thing is that the menus were restructered to make it easier to find things. You can find some of the new things there. Most of the rest are internal changes and bug fixes. + </p> + </dd> + </dl> + </div> + + <hr class="footer"/> + <p class="footer"> + <span id="latest">Copyright © <!-- this year -->2009<!-- end this year --> OurComments.org</span> + </p> + </div> + </body> +</html> diff --git a/emacs/nxhtml/nxhtml/doc/nxhtml.css b/emacs/nxhtml/nxhtml/doc/nxhtml.css new file mode 100644 index 0000000..eea8750 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/nxhtml.css @@ -0,0 +1,171 @@ +@import url(td_oc.css); + +hr { + margin-top: 4em; +} +body { + margin-top: 0.5em; + background-color: #ffe4b5; + background-color: #ffffdf; + margin-left: 5%; + margin-right: 5%; +} +body, td { + font-size: 0.9em; + font-family: Arial, sans-serif; +} +h1, h2, h3 { + color: #556b2f; +} +em { + color: maroon; + font-style: normal; +} + +a { + color: maroon; +} +a.nonexistent { + font-weight: bold; + background-color: #F8F8F8; + color: #FF2222; +} + +a.nonexistent:visited { + background-color: #F8F8F8; + color: #FF2222; +} + +a.dl { + font-weight: 400; + background-color: #e0ff6e +} + +strong { font-weight: bold; } + +ul { list-style-type: disc } + +dl.contents { margin-top: 0; } +dt.contents { margin-bottom: 0; } + + +p.verse { + white-space: pre; + margin-left: 5%; +} + +pre { + white-space: pre; + /* monospace does not work in Firefox 0.9.2 font-family: monospace; */ + margin-left: 0em; + margin-bottom: 0em; +} + +dl.bolddt dt { font-weight: bold; } + +dt { + font-weight: bold; +} +dd { + margin-bottom: 0.7em; +} +hr { + width: 100%; +} +hr.divider { + height: 0.7em; + background-color: maroon; + width: 67%; +} +#FEAT li { + margin-bottom: 0.7em; +} + +#PAGETOC { + float: left; + background-color: #df7; + background-color: #edef87; + margin-right: 2em; + margin-bottom: 2em; + margin-top: 0em; + -moz-border-radius: 1em; +} +#PAGETOC td { + padding: 0.8em; + padding-right: 1.1em; + //font-size: 0.8em; /* For IE only */ +} +#PAGETOC strong { + color: #6b8e23; + display: block; + margin-bottom: 0.5em; +} +#PAGETOC ul li a { + color: maroon; +} +#PAGETOC a:hover { background-color: yellow; } +#PAGETOC ul { + list-style-type: none; + margin:0; + padding-left: 1.5em; +} +#PAGETOC ul li { + font-weight: bold; +} +#PAGETOC ul li ul { } +#PAGETOC ul li ul li { font-weight: normal;} +#PAGETOC .liul { + //display:inline; /* For IE only */ +} +#emacswikibar { + background-color:#ef4; + background-color: #edef87; + text-align:center; + margin-top:0em; + padding:0.4em; +} +#imgwikiguide { + background-color:#cef; + padding:2em; + -moz-border-radius: 2em; +} + +#download a { + border: groove; + font-size: 1.5em; + padding: 0.6em; + background-color: #556b2f; + color: #ce6; + -moz-border-radius: 1em; +} +#download a:hover { + color: #BF0; + background-color: black; + text-decoration: underline; +} +#emacsw32dl { + width:20em; + border-style:solid; + border-color:#556b2f; + padding:0.7em; + -moz-border-radius: 1em; +} + +#my-elisp { + background-color: #fff; + padding: 2em; + border-style: solid; + -moz-border-radius: 1em; +} +#my-elisp dl { + margin-left: 2em; +} + +#keybnotationdiv { + border-width:1px; + border-style:solid; + border-color:#556b2f; + padding:0.7em; + padding-left:1.5em; + -moz-border-radius: 1em; +} diff --git a/emacs/nxhtml/nxhtml/doc/nxhtml.html b/emacs/nxhtml/nxhtml/doc/nxhtml.html new file mode 100644 index 0000000..01d761d --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/nxhtml.html @@ -0,0 +1,987 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>nXhtml - an Emacs mode for Web Development</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> + <style type="text/css"> + #special { + background-color: red; + } + </style> +<style type="text/css"> + + +#getit { + max-width: 800px; +} + +#getit span { display: none; } +/* This seems to be impossible with CSS2 since the containing block + can not be floated. Why did they design it that way? +#getit, #getit dl { display: block; } +#getit a:hover span { + display: block; + position: absolute; + left: 200; + top: 0; +} +*/ + +#getit a { + /* Image */ + display: block; + background: transparent url("img/getitbuttons.png") 0 0 no-repeat; + overflow: hidden; + width: 200px; + /* Text placement and size, etc */ + text-align: center; + padding-top: 11px; + font-size: 12px; + font-weight: 600; + padding-bottom: 9px; + text-decoration: none; + white-space: nowrap; + border: none; +} +#getit dt { + display: block; + padding: 0; + margin: 0; + float: left; + letter-spacing: 0; +} +#getit a:hover { + background-position: 0 -35px; + color: yellow; +} + +#useit { + position: absolute; + top: 150px; + left: 100px; + width: 85px; + z-index: 100; + border: none; + font-size: 9px; +} +/* I can't get rid of the underline. Firefox bug or my bug? */ +#useit a { text-decoration: none; } +#useit img { + text-decoration: none; + overflow: hidden; + border: solid 2px #990033; +} +div#useit { text-decoration: none; } +#useit img:hover { + background: url("img/use-nXhtml-trans2.png") 0 0 no-repeat; +} + +#quicklnk a { + color: #cd3700; + font-weight: bold; + font-size: 1.2em; +} +#quicklnk a:hover { + background-color: yellow; +} + +</style> + </head> + <body> + <div id="useit"> + <!-- title is for Firefox --> + <a href="http://ourcomments.org/Emacs/nXhtml/doc/nxhtml.html" + title="Get nXhtml for Emacs" + ><img alt="Get nXhtml for Emacs" src="img/use-nXhtml-trans2.png" width="78" height="29" /></a> + Above is a little banner you can put on your site if you want to. + </div> + + <div id="container"> + <div id="hdr"> + <br /> + <span style="color:#FF0;font-size:14px; font-weight: 600;"> <i> Enjoying editing web files!</i> </span> + <br /> + </div> + + <div id="lftcol"> + <!-- Table of contents BEGIN --> + <!-- Table of contents min=2 max=3 --> + <table id="PAGETOC"><tr><td> + <span class="tochead">On THIS Page:</span> + <ul> + <li><a href="#summary">Introduction to nXhtml</a></li> + <li class="liul"><ul> + <li><a href="#featsum">Features</a></li> + <li><a href="#qg">The Quick Guide</a></li> + <li><a href="#toolset">What you may use more</a></li> + </ul></li> + <li><a href="#completion">Completion</a></li> + <li class="liul"><ul> + <li><a href="#complex-compl">More Helpful Completion</a></li> + <li><a href="#ask-compl">But How Do I Ask nXhtml for Alternatives?</a></li> + <li><a href="#region-compl">The Region and Completion</a></li> + <li><a href="#errors">And if I Do Not Follow the Advices?</a></li> + </ul></li> + <li><a href="#xmlpath">Where am I? - XML Path</a></li> + <li><a href="#sites">Why it is Useful that nXhtml has Sites</a></li> + <li><a href="#mlinks">Why the Links Look Like Links</a></li> + <li><a href="#tocs">Did You Notice the Table of Contents at the Top?</a></li> + <li><a href="#tidy">But I Can't Use this Cause my Files are HTML</a></li> + <li><a href="#php">And what about Multiple Modes like PHP?</a></li> + <li class="liul"><ul> + <li><a href="#dtd-needed">But I Have no DTD Links in my PHP Files?</a></li> + <li><a href="#multi-colors">Why Are Colors Different in Multiple Modes?</a></li> + <li><a href="#part2">More Multiple Modes</a></li> + <li><a href="#tips-multi">Tips When Using Multiple Modes</a></li> + </ul></li> + <li><a href="#file-assoc">File Associations within Emacs</a></li> + <li><a href="#bloggin">Not for Me, I Am Only Blogging</a></li> + <li><a href="#bloggin">And Other Goodies...</a></li> + </ul> + </td></tr></table> + <!-- END of Table of contents --> + </div> + + <div id="getit"> + <dl> + <dt> + <a href="http://ourcomments.org/Emacs/nXhtml/tut/tutorials.html" title="Tutorials">Tutorials</a> + </dt> + <dt> + <a href="https://answers.launchpad.net/nxhtml/+faqs" title="nXhtml FAQ">nXhtml FAQ</a> + </dt> + <dt> + <a href="nxhtml-changes.html">News about nXhtml + <span>Details</span></a> + </dt> + <dt> + <a href="http://www.emacswiki.org/cgi-bin/wiki/NxhtmlMode" + >nXhtml page at EmacsWiki</a> + </dt> + <dt> + <a id="download" href="http://ourcomments.org/cgi-bin/emacsw32-dl-latest.pl">Download nXhtml</a> + </dt> + <dt> + <a href="https://launchpad.net/nxhtml" title="Bazaar repository">nXhtml at Launchpad</a> + </dt> + </dl> + </div> + + <div id="rgtcol"> + <h1 id="mainheader">nXhtml - Emacs Utilities for Web Development</h1> + + <h2 id="summary">Introduction to nXhtml</h2> + <p> + nXhtml is an addon to Emacs for editing XHTML, PHP and similar things. It is not + very well-known, but it looks like at least <a + href="http://drewyates.net/nxml-nxhmtl-emacs-mode-for-ruby-on-rails-rhtml">Drew + Yates</a> has found it useful: + </p> + <blockquote> + <p style="font-style:italic"> + nXML mode and the subsequent nXHTML mode for emacs are godsends ... + </p> + </blockquote> + <p> + And that was before I fixed all the bugs ... + </p> + + <h3 id="featsum">Features</h3> + <p> + One of the main parts of nXhtml is nxhtml-mode, a GNU <a + href="http://en.wikipedia.org/wiki/Emacs">Emacs</a> major + mode that builds on <a + href="http://www.thaiopensource.com/nxml-mode/">nxml-mode</a>. + It knows about XHTML syntax and can check this as + you type. It can also tell you what tags and attributes you + can use at a certain point and help you insert them. + </p> + <p> + That feature, which we call <a + href="#completion">completion</a>, is one of the main + features of this mode. Another important feature is the + ability to mix several languages in one buffer and get the + correct syntax highlighting and indentation for each of + them. + </p> + <p> + In nXhtml this is combined with other features to make it + more easy to edit web sites (mostly XHTML based but there is + support for things like PHP too). Here is a list of important features: + </p> + <ul id="sum-ul"> + <li> + Completion and syntax checking for XHTML. + <ul> + <li> Some helpful extensions when completing certain tags (like the <a ...> tag for example).</li> + <li> When region is visible tag completion will surround the region with the start tag and end tag.</li> + </ul> + </li> + <li> + Multiple major modes, which means it can handle for example PHP, JSP, eRuby and Django while allowing XHTML completion. + (Notice however that not all major modes you may need for this comes with nXhtml.) + </li> + <li> + Link handling: + <ul> + <li> Easier insertion of tags with links.</li> + <li> Following links to edit or view.</li> + <li> Moving between links.</li> + <li> Moving files and automatically update affected links.</li> + <li> Copy link to id location and paste it back as a relative link.</li> + <li> Link checking in current site (local links only)</li> + </ul> + </li> + <li> + The concept of a site. This is used in many places. A + site is here a directory tree with additional properties, like + remote ftp and http addresses. A directory could belong to + many sites. + </li> + <li> + Make a remote copy of site: + <ul> + <li> Uploading of single files</li> + <li> Uploading of whole or part of site</li> + <li> Editing of remote files.</li> + <li> Ediff of local vs remote file.</li> + <li> Easy viewing of local and remote files in web browser.</li> + </ul> + </li> + <li> + Table of contents + <ul> + <li>Creating table of contents for a page.</li> + <li>Creating table of contents for a site.</li> + <li> + Merging of pages and table of contents for a site (see + example, notice that the table of content easily can be + navigated using the keyboard). + </li> + </ul> + </li> + <li> Support for folding.</li> + <li> Using <a href="http://www.w3.org/People/Raggett/tidy/">Tidy</a> to convert HTML to XHTML.</li> + <li> Help for XHTML tags and CSS attributes.</li> + <li> Edit a fragment of an XHTML file (for blogging for example).</li> + <li> ... and more of course ...</li> + <!-- <li> Adding a popup menu to [apps] to access these features.</li> --> + </ul> + + <h3 id="qg">The Quick Guide</h3> + <p> + Below are some short notes to get you started using nXhtml. + (Maybe you should start by taking a look at the + <a href="http://ourcomments.org/Emacs/nXhtml/tut/tutorials.html" title="Tutorials">Tutorials</a>?) + </p> + <dl> + <dt>GNU Emacs 22 or later</dt> + <dd> + <p> + You need GNU Emacs 22 (which was released 2007-06-02) or later. + </p> + </dd> + <dt>Installation</dt> + <dd> + <ul> + <li> + Download nXhtml as a zip file <a href="http://ourcomments.org/cgi-bin/emacsw32-dl-latest.pl">here</a> + or download + <a href="http://ourcomments.org/Emacs/EmacsW32.html">EmacsW32</a>. + </li> + <li> + If you got nXhtml with <a + href="http://ourcomments.org/Emacs/EmacsW32.html">EmacsW32</a> + you should use the menus <em>Options - Customize + EmacsW32</em> and there just set <em>nxhtml-load</em>. + </li> + <li> + If you downloaded the zip file with nXhtml then unzip it anywhere and + then follow the instructions in + <em>nxhtml/README.txt</em>. + </li> + </ul> + <p> + After this files with extensions for example .html will open in nxhtml-mode. + </p> + <p> + To make nXhtml run faster you can also byte compile the files. + You do that with <i>M-x nxhtmlmaint-start-byte-compilation</i>. + </p> + </dd> + + <dt id="nxhtml-menu">The nXhtml Menu</dt> + <dd> + <p> + To reach many of the features in nXhtml you can use the + <b>nXhtml menu</b>. If you do not see that when in a buffer + then you can always do <em>M-x nxhtml-minor-mode</em> which + will turn it on (or off) for that buffer. + </p> + <p> + But please notice also the <b>XML menu</b> which + contains the nXml menu! (Remember that nXhtml is based + on nXml.) When you are using nxhtml-mode this menu is + visible when you are in the XHTML parts of a buffer. + </p> + </dd> + + <!-- <dt id="turn-on-some">Turn on Some Things</dt> --> + <!-- <dd> --> + <!-- <p> --> + <!-- There is a good chance that you want to turn on some --> + <!-- things that makes nXhtml work more automatic. They are --> + <!-- in the <a href="#nxhtml-menu">nXhtml menu</a> for --> + <!-- turning them on temporarily. Later, when you have --> + <!-- tested, you may want to turn them on permanently, which --> + <!-- you can do from the menus by choosing <em>nXhtml - --> + <!-- nXhtml Help and Setup - Quick Customize nXhtml</em>. --> + <!-- </p> --> + <!-- </dd> --> + + <dt>XHTML Completion and Validation</dt> + <dd> + <p> + nXhtml knows a good deal about XHTML tags and attributes when you are using <em>nxhtml-mode</em>. + It can assist you in different ways: + </p> + <ul> + <li> + Completion + </li> + <li> + Validation + </li> + </ul> + <p> + <b>Completion</b> means that you ask Emacs to give you choices to complete what you are currently writing. + For example you may have written <b and want to know what tags beginning this way can actually be used at that place in the document. + You ask Emacs in nxhtml-mode this by calling the function nxml-complete. + This is normally bound to M-Tab. + </p> + <p> + On some systems, for example MS Windows with an + unpatched Emacs this is inconvenient and clashes with + Alt-Tab that the window manager uses. There is however a + little utility that comes with nXhtml that let you use + just Tab for completion, <i>tabkey2-mode</i>. Turn this on with + </p> + <p style="padding-left:2em;"> + M-x tabkey2-mode + </p> + <p> + After this the first Tab press will still do + indentation, but the second can do completion. + </p> + <p> + <b>Validation</b> means checking that what you have + written in nxhtml-mode follows the XHTML specifications. + If it does not there will be a red underline at the + places where something is wrong. To see what is wrong + move to this (for example with C-c C-n). A message in + the minibuffer will tell you the error. + </p> + <p> + Notice that the modeline also tells if the document is + valid. Most of the times it will however say + <em>Invalid</em> maybe just because you are editing and have + not yet finished. + </p> + <p> + For files mixing XHTML with codes, like PHP, you can use + something I call <a href="#dtd-needed">Fictive XHTML + Validation Headers</a>. That allows you to use XHTML + completion even if those files does not have the XHTML + headers needed. + </p> + </dd> + <dt>Multiple Major Modes</dt> + <dd> + <p> + nXhtml can automatically divide the buffer into chunks + with relevant different major modes (i e languages, like + PHP, XHTML etc). This is useful for editing PHP, + JSP, eRuby, Django and similar. See <a href="#php">And + what about Multiple Modes like PHP?</a> for more information. + </p> + </dd> + <dt>Links</dt> + <dd> + <p> + The links you put in your XHTML documents actually works + like links with nxhtml-mode too. To follow a link you + can use <em>C-c RET RET</em>. (There are other + possibilities too, they all begin with <em>C-c RET</em>.) + </p> + </dd> + <dt>Sites and Uploading</dt> + <dd> + <p> + If you want to upload your XHTML files, image files etc + you can do that from within Emacs. There are entries + for this in the <a href="#nxhtml-menu">nXhtml menu</a>. + </p> + </dd> + <dt>Keyboard shortcuts (aka keybindings in Emacs)</dt> + <dd> + <p> + When you start to use a new program you often wonder + about which keybindings there are to use. If you have + not used Emacs before you may feel quite lost because + you have looked in all documentation and you have not + seen any list of keybindings. + </p> + <p> + Well, that is how it often is in Emacs. Get use to it ... + </p> + <p> + But do not panic. Because there is help, probably even + better than you are used to - in Emacs dynamic help + system. A help system that change if you for example add + a keybinding yourself. Try the command <i>C-h b</i> (or <i>F1 + b</i>). This list all the keybindings (in their priority + order) that are active where you are in Emacs. + </p> + <p> + You can also try <i>C-h m</i> which gives information about + minor modes and the current major mode. There is + sometimes information about the keybindings there too. + </p> + </dd> + <dt>Some More You Can Do ...</dt> + <dd> + <p> + See <a href="#summary">Introduction</a> above. + Look into the <a href="#nxhtml-menu">nXhtml menu</a>. + And then of course learn some of all the things you can do using the power of Emacs. + </p> + </dd> + </dl> + <p> + </p> + <h3 id="toolset">What you may use more</h3> + <p> + If find it very conventient to combine nXhtml with Firefox + add-on Firebug. I think Firebug is very handy for finding CSS + problem. + </p> + <p> + <a href="http://www.spreadfirefox.com/node&id=0&t=306"><img border="0" + alt="Firefox 3" title="Firefox 3" + src="http://sfx-images.mozilla.org/affiliates/Buttons/firefox3/110x32_get_ffx.png"/></a> + + <a href="http://www.getfirebug.com/?link=2" title="Firebug + is a free web development tool for + Firefox"><img src="http://www.getfirebug.com/images/firebug2.png" + border="0" alt="Firebug - Web Development Evolved"/></a> + </p> + <p> + And of course, another good resource is Russ Weakley's <a + href="http://css.maxdesign.com.au/">CSS-based tutorials</a>. + Russ co-chairs the <a + href="http://webstandardsgroup.org/">Web Standards Group</a> + and seems to know this well. + </p> + <p> + I am sure you know about it, but just in case, here is WDG's + <a href="http://htmlhelp.com/design/accessibility/">Guide to Accessibility</a> + and their + <a href="http://htmlhelp.com/design/accessibility/tips.html">Accessibility Tips</a>. + </p> + + <h2 id="completion">Completion</h2> + <div align="right"> + <img align="right" + src="img/popup-compl.png" + alt="Popup menu style completion" + title="Popup menu style completion" + style="border: thin dotted #00ff00; + margin-left: 2em; + margin-top: 0em; + margin-bottom: 1em;" + width="371" height="483" /> + </div> + <p> + Completion in nXhtml Mode lets you ask Emacs <i>"What can I + type here?"</i>. The most important part, the content, can + Emacs not help you with yet. However when it comes to XHTML and + such things that you really want to get past as easy as + possible, then nXhtml mode can assist you. + </p> + <p> + Perhaps you wonder with <i>"With what?"</i> Well, completion + works like this: You position point in your XHML file where you + want to write. Now you ask nXhtml what XHTML code you can + write there. nXhtml may answer that it can't help you, that + happens in some cases. + </p> + <p> + But most often nXhtml can help you. It knows about tags and + where they fit, and it knows about tag attributes. When nXhtml + can helpt you it will give you choices you can select from. It + may display the choices in a popup menu like in the pictures to + the left, or it may use something like the picture below shows. + It is actually exactly the same question that is asked in these + two cases. You decide by <i>customizing</i> nXhtml mode in Emacs which + way it should display the choices. The way below is the + standard Emacs way to do display choices. It is fast once you know it, but + the popup menus are of course more familiar to computer users + today. + </p> + <img alt="Emacs style completion" src="img/emacs-style-completion.png" width="456" height="406" + /> + <p> + That far nXhtml can take you because it knows the DTD for XHTML. + (You may wonder about different versions of XHTML, more about that later.) + </p> + + <h3 id="complex-compl">More Helpful Completion</h3> + <p> + For certain attributes nXhtml knows their values because the DTD just allows certain values. + For some other attribute values for which nXhtml can know little + from the DTD alone, like links (src and href attributes) nXhtml + can also be helpful. If you want a link to a file, for example, + nXhtml lets you browse for the file and then inserts a relative + link to it. It can also look for anchors (ie <b>id</b> attributes). + </p> + <p> + In some cases nXhtml knows more about a tag. + From the DTD it knows that an <b><img></b> tag should have a <b>src</b> attribute with a value that points to an image. + Therefor it prompts you for the value of the src attribute. + It is the same with the <b>alt</b> attribute that is required. + It even gets the height and width of an image on file if it can and inserts the attributes in the <img> tag. + </p> + <p> + Well, it is better that you test (and perhaps give some feedback?). + </p> + <p> + Normally nXhtml does not care that much. It just tells you that + you when you have broken the DTD rules. If however you want + nXhtml to do less or more of this kind then you can change the + variable <b>nxhtml-complete-tag-do-also</b> - but that requires + that you knows Emacs lisp. If you do write something useful for + this, please tell me. + </p> + + <h3 id="ask-compl">But How Do I Ask nXhtml for Alternatives?</h3> + <p> + Oh, I nearly forgot. Do you wonder how to ask nXhtml in Emacs for completion alternatives? + That is a nice question to answer. + You give a certain command to Emacs to ask for this. + That can be done by either: + </p> + <ul> + <li>Type <i>M-Tab</i></li> + <li>Do it from the <a href="#nxhtml-menu">nXhtml menu</a>: <i>nXhtml - Completion - Complete tag, attributes etc</i></li> + <li>Or more explicit with a command: <i>M-x nxml-complete</i></li> + </ul> + <p> + You can change <i>M-Tab</i> to whatever you want. What it + means? Ah, yes, it means <i>"hold down the Meta key and press + Tab"</i>. That is Emacs jargon and you have to know which key + is the Meta key of course. I actually use the left Windows key + on my keyboard for Meta. See <a + href="http://ourcomments.org/Emacs/EmacsW32.html">EmacsW32 home + page</a> for some information about this if you are on MS + Windows. + </p> + + <h3 id="region-compl">The Region and Completion</h3> + <p> + This is a small but useful thing (and I added it because some people liked it, it + was not my own idea): If some text is selected (in Emacs jargon + "if region is active and hilighted") and you use completion to + insert a tag then the <em>region will be surrounded by that tag</em>. + If region is active like here: + </p> + <img alt="Region is selected" src="img/region-selected.png" width="584" height="50" + style="border: thin dotted #00ff00; + vertical-align: top; + margin-bottom: 1em;" /> + <p> + And you then ask for completion: + </p> + <img alt="Ask for tag" src="img/region-selected-completion.png" width="584" height="393" + style="border: thin dotted #00ff00; + vertical-align: top; + margin-bottom: 1em;" /> + <p> + The result will be that your choice (<em>em</em> here) will surround the region you had selected: + </p> + <img alt="After completion" src="img/region-selected-after.png" width="584" height="61" + style="border: thin dotted #00ff00; + vertical-align: top; + margin-bottom: 1em;" /> + <p> + Eh? Ah, yes, you are right. I happened to choose the wrong picture for the result. Sorry. + </p> + + <h3 id="errors">And if I Do Not Follow the Advices?</h3> + <p> + nXhtml gives you advices about how to handle the XHTML tags, but + it does not force you to follow them. You can write whatever + you want, but nXhtml anyway observes what you are doing and + checks the XHTML code. If you do not follow the DTD rules + nXhtml will silently warn you with a red underline, like here + (where I have written <i>image</i> instead of <i>img</i>): + </p> + <img alt="Validation error marking" src="img/validation-error.png" width="375" height="50" + style="border: thin dotted #00ff00;" + /> + <p> + (Oh, geeh. Firefox took that before, but not now ...) + </p> + + <h2 id="xmlpath" style="clear:both">Where am I? - XML Path</h2> + + <p> + If you have for example <div> tags to separate things or long + list you may wonder in which of those you are. Nxml Mode can + show this. Look in the menus <i>XHTML - XML Path</i> to turn it + on. Here is what it looks like. There is header with the label <i>Path:</i> which here shows that we are in a list with id="sum-ul". + Note also the yellow color of the tag we are in. The whole path up to the top is colored this way. + </p> + <img alt="Showing XML Path" src="img/nxml-where.png" width="456" height="262" /> + <p> + A little tip: I found this very useful when I looked at different CSS designs. + </p> + + <h2 id="sites">Why it is Useful that nXhtml has Sites</h2> + <p> + I am writing this in nXhtml mode in Emacs. Just after I had + written a piece or added an image on my pc I update the web + pages on http://OurComments.org/. I do that very easily because + of the concept of a site. + </p> + <p> + A <b>site in nXhtml</b> is in its simplest form just a local directory tree. + And that is given a name. + In my case I have given it the name <i>nxhtml-doc</i> just to remember what it is about. + </p> + <p> + To that site I have also added information about uploading and + and the http address of the uploaded files. Now if I add an + image to the site on my pc all I have to do to upload it to the + web site is to open the image in Emacs (yes that is possible, + Emacs knows about the most common image formats) and then just from the menus choose + <i>Web Site - File Transfer - Upload Single File</i>. + That is all. + </p> + <p> + And then I can (from the XHTML file I am editing) use the + command <i>XHTML - File Transfer - View Uploaded File</i> to + check that the web page is ok. + </p> + + <h2 id="mlinks">Why the Links Look Like Links</h2> + <p> + As soon as you open an XHTML file in nXhtml mode you will notice that the links you enter looks like links. + They are underlined and blue like in a web browser. + You may think that that is kind of nice, but why do they look like that? + </p> + <p> + It is just because they are links. You access them a little bit + different in a web browser, just so that it does not interfere + with editing. And because you may want to do different things + with them. Take a look at the picture below. I have positioned + point to a link and then pressed tha App key on my keyboard. + That pops up a menu where I can see what I can do with the link: + </p> + <img alt="Link with popup menu" src="img/links-appmenu.png" width="529" height="189" + style="border: thin dotted #00ff00;" + /> + <p> + As you can see I can copy the link (maybe not that useful + often). I can open it - and that means edit the linked file in + Emacs. That is useful. And then I can view the linked file in a + web browser. Can be useful too. + </p> + <p> + And then I can move between the links. + </p> + <p> + All this is useful, at least for me. But there are some more + things, in the menus <i>XHTML - Links</i>. Check them out, you + may like them. They may save you time. + </p> + + <h2 id="tocs">Did You Notice the Table of Contents at the Top?</h2> + <p> + Well, you should notice not because it exactly is the worlds + most pretty table of content. But because it is there. And I + did not write it. nXhtml mode wrote it for me. + </p> + <p> + How it works? Just put <b>id</b> attributes on your header tags + (h1-h6). Then position point where you want the table of + contents. Tell nXhtml mode to write it by using the menus + <i>XHTML - Table of Contents</i>. + </p> + <p> + When you want to change it just ask nXhtml mode to rewrite it. + </p> + <p> + And you can make it more pretty if you are good at CSS. + </p> + + <h2 id="tidy">But I Can't Use this Cause my Files are HTML</h2> + <p> + That is a problem of course. You need to convert them to XHTML + because that is what the browsers and all other tools are best + at today. + </p> + <p> + But don't worry. Didn't I tell you that nXhtml knows about <a + href="http://tidy.sourceforge.net/">Tidy For XHTML</a>? (It + even comes together with nXhtml if you get it with EmacsW32.) + </p> + <p> + Tidy can convert your HTML files to XHTML. + Just open a file in nXhtml mode then use the <i>Tidy</i> + menu and choose what you want to do there. + </p> + <p> + If you do it file-by-file you can compare the "tidied" XHTML + version of the file and your old version side by side (using + Emacs Ediff command actually - an interactive way to compare). + You can also tidy a whole directory tree at once. + </p> + + <h2 id="php">And what about Multiple Modes like PHP?</h2> + <p> + nXhtml mode can handle multiple modes in a buffer. The + benefits of nXml style completion can still be used. This + can even be done when there is no header in the file that + tells what DTD to use for the completion. + </p> + <p> + Mumamo, which is part of nXhtml, implements what it + calls <i>multi major modes</i> for handling multiple major + modes in a buffer. Instead of turning on a major mode for a + buffer you turn on a multi major mode and Mumamo will handle + the rest. Multi major modes has names like nxhtml-mumamo, + html-mumamo, django-nxhtml-mumamo etc. + </p> + <p> + When point is in a PHP part then the major mode is switched + to php-mode, with all that means. Here you can see how that + looks: + </p> + <img alt="In PHP part" src="img/php-in-nxhtml.png" width="448" height="294" /> + <p> + If you move the point outside of those <?php ... ?> areas + then the mode is automatically switched to nxhtml-mode + instead. Now you can use the power of nxhtml-mode and + do for example completion, like here: + </p> + <img alt="In XHTML part" src="img/php-in-nxhtml-2.png" width="450" height="294" /> + <p> + The switching is done with a short delay so that it does not + interfere with your normal editing. That's it. (But maybe + there should be a better php-mode? Does someone has any + better than the one that comes with nXhtml now?) + </p> + + <h3 id="dtd-needed">But I Have no DTD Links in my PHP Files?</h3> + <p> + Ah, yes. Good question. You are right. nXhtml mode needs a + DTD to be able to help you with XHTML and completion. I + thought it was impossible for a normal human to get that + working. + </p> + <p> + But it turned out to be surpricingly simple and it works + quite nicely now. The first time you do completion of XHTML + code in a buffer where you do not have the needed XHTML + headers nXhtml mode will ask you for what it calls a + <em>fictive XHTML validation header</em>. After that completion + should work as usual. A fictive XHTML validation header in nXhtml + mode is something that is used in the background for + validation. It is not inserted in the buffer, but may be shown on the screen like this: + </p> + <img alt="fictive XHTML validation header" src="img/xml-validation-header.png" width="448" height="374" /> + <p> + nXhtml does its best to guess what fictive XHTML Validation Header + the buffer needs, but if the default fictive XHTML validation header + does not fit you can customize the choices. + </p> + <p> + Note: Do not try to set the XML schema directly when the XHTML + headers are missing in the buffer. Use a fictive XHTML + validation header instead. + </p> + + <h3 id="multi-colors">Why Are Colors Different in Multiple Modes?</h3> + <p> + It has been necessary to replace the nxml-mode style + fontification with the sgml-mode style. All other features + of nXml/nXhtml modes should still work however. + In all other cases the normal fontification colors are used. + </p> + <p> + Or perhaps you mean the background colors? These are just a + visual aid about the dividing into chunks with different + major modes and they can be turned off. Do <em>M-x + customize-group RET mumamo RET</em>. + </p> + + <h3 id="part2">More Multiple Modes</h3> + <p> + nXhtml mode handles for example embedded style sheets the + same way as it handles PHP chunks: + </p> + <!-- + <img alt="CSS embedded in XHTML" src="img/embedded-xhtml.png" width="448" height="294" /> + --> + <img alt="CSS embedded in XHTML" src="img/style-in-nxhtml.png" width="448" height="278" /> + <p> + Currently it can handle PHP, CSS, JavaScript, eRuby, JSP and + some other minor cases. If you can program in elisp it is + not a very big deal adding support for other embedded + languages. (I do not use all the languages above myself so + please give me feedback if there is something you think + could be done better.) + </p> + <p> + Please notice also that each major mode handles completion + in its own ways. The popup style completion is currently + only used by nXhtml mode, not the other major modes even if + they are on the same page. + </p> + <p> + The use of multi major modes is not constrained to nXhtml. + You can use that when editing other files too. To see what + multi major modes are currently defined in your Emacs + session see the + variable <i>mumamo-defined-turn-on-functions</i>. + </p> + + <h3 id="tips-multi">Tips When Using Multiple Modes</h3> + <p> + The routines dividing into chunks with different major modes is not that very supersmart. + They do not know much about the languages of the major modes. + So if you write something like this: + </p> + <pre> + <?php + echo '<'?xml version="1.0" encoding="utf-8"?'>'; + ?> + </pre> + <p> + it will get very, very confused. If you are not fond of that + you better write it like this instead: + </p> + <pre> + <?php + echo '<'; echo '?xml version="1.0" encoding="utf-8"?'; echo '>'; + ?> + </pre> + <p> + For a similar problem <a href="nxhtml-changes.html#php-attribute-values">attribute values computed by PHP</a>. + </p> + <p> + When editing PHP sometimes the validation of the XHTML part + gets quite upset. You may even think that it is unuseful + (since trying to complete gives you nothing), but it is not. + Here is what you can do: + </p> + <ul> + <li> + Turn on <em>Fictive XHTML Validation Header</em> from + menus. (In <em>nXhtml - Completion</em>.) That will try + to guess a how to start validation. It shows a fictive + header at the top of the buffer to show you what is goind + on (nothing is inserted in the buffer). + </li> + <li> + If you do not think the red underlines you get are very + pretty then you can hide them. Use the menus again, + <em>Hide Validation Errors</em>. + </li> + </ul> + <p> + And maybe you do not think the background colors when using + Multiple Major Modes is very smart? Then just go ahead and + remove them. Customize. + <em>M-x customize-group RET mumamo RET</em>. + </p> + + <h2 id="file-assoc">File Associations within Emacs</h2> + <p> + Some file associations are changed within Emacs to get + multiple modes to work without requiring the user to do + anything. Good for a new user I guess, but I understand + that old Emacs users may want more control over this. If + you are one of them then please look in + <em>nxhtml-autoload.el</em> which is where the associations + are made. + </p> + + <h2 id="bloggin">Not for Me, I Am Only Blogging</h2> + <p> + Not for you? + Ah, wait a minute. + Blogging, that is exactly one of the things that I myself use this for. + </p> + <p> + When you blog you only write part of an XHTML page, so you + may think that all the nicities of nXhtml mode like + validation and completion does not work. They do. (If you + wonder how, then please read <a href="#dtd-needed">But I + Have No DTD Links In My PHP Files</a>. Though you do not + have to read this to start using nXhtml for writing blog + texts and comments.) + </p> + <p> + The setup for blogging is simple + </p> + <ol> + <li> + <a href="http://www.mozilla.com/en-US/firefox/">Firefox</a> - which you of course already use ... + </li> + <li> + The <a href="https://addons.mozilla.org/en-US/firefox/addon/4125">It's All Text</a> add-on to Firefox. + It should use Emacs client: + <p> + <img alt="It's All Text preferences" src="img/itsalltext-pref.png" width="371" height="352" /> + </p> + </li> + <li> + And finally: Customize the little elisp library that comes with nXhtml: + <p style="padding-left:2em; font-size: 1em; font-weight: 600;"> + M-x customize-group RET as-external RET + </p> + You just need to turn <i>as-external</i> on there. + </li> + </ol> + <p> + With this setup you just press F2 in any text area in + Firefox and then you got the text to edit in Emacs - using + nXhtml for completion etc. Finish and save with <b>C-x + #</b>. + </p> + +<!-- <img alt="Edit part of an XHTML file" src="img/edit-part.png" width="448" height="390" /> --> + + <h2 id="bloggin">And Other Goodies...</h2> + <p> + There are a lot of other things in the package too, please + see the nXhtml menu in Emacs. You can for example find a + n-back-game (if you do not know what it is now, do not + worry, just try it and you will learn - and understand why I + put it there). + </p> + </div> + + <hr align="left" class="footer" /> + <p class="footer"> + Copyright © 2008 OurComments.org + <br style="margin:0; padding:0; line-height: 0;" /> + Design thanks to <a href="http://www.oswd.org/">OSWD</a> + <br /> + </p> + </div> + </body> +</html> diff --git a/emacs/nxhtml/nxhtml/doc/wd/grapes/grapes.css b/emacs/nxhtml/nxhtml/doc/wd/grapes/grapes.css new file mode 100644 index 0000000..c325dfd --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/wd/grapes/grapes.css @@ -0,0 +1,107 @@ +/* Grapes, web template for business or for fun */ +/* By Dave Reeder, www.davereederdesign.com */ + +body {margin: 0; padding: 0; background: #213205} + +* {margin: 0; padding: 0; border: 0; font-family: Arial, Helvetica, sans-serif} + + +/*----------------------------------------------Basic styles------------------------------------------------*/ + +h1, h2, h3, h4 {font-family: Georgia, Georgia, serif; margin: 15px 0 0 5px; color: #fff; font-weight: normal; text-decoration: none} +h1 em, h2 em, h3 em, h4 em {font-family: Georgia, Georgia, serif; font-weight: normal} /* italic words in titles */ + +h1 {position: absolute; right: 0px; top: 30px; font-size: 2.25em; letter-spacing: 0.1em; line-height: 1.00em; padding-right: 10px; border-right: 15px solid #fff} +h1:first-letter {font-family: Georgia, Georgia, serif; font-size: 2.25em} /* styles the first letter of the main title to make it large */ + +p#tagline {position: absolute; right: 0px; top: 125px; font-style: italic; color: #648D20; font-size: 0.90em} /* sits under main title */ + +h2 {font-size: 1.30em; letter-spacing: 0.05em} + +p, ul, ol {margin: 10px 10px 0 7px; font-size: 0.70em; line-height: 1.60em; color: #000; letter-spacing: 0.05em} + +code {font-family: monospace; font-size: 1.20em; color: #E20000} + +p span {font-size: 1.50em; font-weight: bold} /* shouting words */ + +a:link, a:visited {color: #792533; font-weight: bold; text-decoration: none; border-bottom: 1px solid #792533} +a:hover, a:active {color: #fff; border-color: #fff} + +ul {list-style: inside square} /* general lists */ + +acronym {font-weight: bold; border-bottom: 1px dashed #000; cursor: help} + + +/*-----------------------------------------------Layout DIVS------------------------------------------------*/ + +#container { /* keeps everything together */ +position: relative; +margin: 0 auto; +width: 620px; +background: url(images/bkgrnd.gif) 0 0 repeat-y #CCCC33; /* Important image, do not remove */ +overflow: hidden +} + +#hdr { /* div containing h1, nav and grapes image */ +float: left; +width: 620px; +height: 200px; +background: url(images/grapes.jpg) 0 0 no-repeat #CCCC33 /* Image of Grapes */ +} + +#lftcol { /* left column */ +position: absolute; +left: 0px; +top: 200px; +margin-left: 50px; /* leave this so that background image lines up with edge of this div */ +width: 200px; +background: transparent; +overflow: hidden +} + +#rgtcol {float: right; width: 370px; padding-bottom: 30px; background: transparent; overflow: hidden} /* right column */ + +#bttmbar {float: right; text-align: center; font-size: 0.70em; height: 4em; line-height: 4em; width: 570px; background: #CCCC33; border-top: 1px solid #D9D93C} + +#quote { /* Quote box in left column */ + float: left; + margin: 10px 0 20px 10px; + padding: 10px 0; + width: 170px; + text-align: center; + background: url(images/quote.gif) no-repeat 0 0 +} + +#quote p {color: #444; font-size: 0.80em; font-weight: bold; line-height: 2.00em} /* Quote box text */ + + +/*---------------------------------------------Main Navigation-----------------------------------------------*/ + +ul#nav { /* navigation list */ + margin: 53px 0 20px 0; /* the 53px is where the nav begins (margin top) */ + padding: 0; + list-style: none inside +} + +ul#nav li {float: left; display: block} + +ul#nav li a { + width: 170px; + margin: 3px 0 0 0; /* a little top margin */ + border: 0; + border-left: 10px solid #CCCC33; + padding: 10px 5px; + font-family: Georgia, Georgia, serif; + font-weight: normal; + text-decoration: none; + display: block; + color: #450F1F; + background: #D9D93C +} + +ul#nav li a#current {border-color: #fff} /* current page, move id in the xhtml when creating a new page */ + +ul#nav li a:hover {background: #9EA219; color: #fff} + + + \ No newline at end of file diff --git a/emacs/nxhtml/nxhtml/doc/wd/grapes/images/bkgrnd.gif b/emacs/nxhtml/nxhtml/doc/wd/grapes/images/bkgrnd.gif new file mode 100644 index 0000000000000000000000000000000000000000..cdec922f45fbef9e3ae5a7d11f6684286c92aec2 GIT binary patch literal 974 zcmcgrze|*H7=QW&dLbM{+2BRe64g*Wixy2q-KmQ>)SyuW&u}#e6}Sk2Lt#UMgFGab zUG(Fwz`M6D&ju5VI(?!V3__jS99kNp>FM*le?;Hy;d!3VujhTw70z~bU%s|ALw|@o zp1G^LxU)M&W#*=C;>K<iO*L0_6<2npm=$wT7ja=1id8mebrxrKCLlSPlRAkLJD~tJ zpn-*DOjGd0Q!_DRGYVQ%s-|MfrW7jB6g3eOHlYxOSyp2)W@CaztQx727_kvpp&DQi z4V93E9*BVrXkcNP!cf$BqROfi{y>XLM1@r->_P>aEXu4*a1T+KRT3puf<5E`nb<}g z@DCAi2-N_CXsE;}bbuJxfCd&ta?wVO$08I#!XIc+F$)uNg<YsXQ;3C-Ba%h{(1mdX z4Y!CAc|az%5eGEEFdRZPz#tl%kOdte1~#B6P88E<qsAj#3_-#lXi+i6#}T=v_l{<I z!iYJ&O3bD~N9t*Iv6{vaM@St8QYt!blIjTH6dIocu7vR52~?fOcO>)2zOJ6Y=ZNyZ zz0SYew-Bw-kzkB}f?6t6ZSBa<K3p7Y*|q1!;_S@Q?d*Y`seJX(hr4^Zxc;eH`gm{u z>G6(2?QwJB;6Qn>yMJb7@@Q*qs*pVSe821Z=6W-E`sG2}l}v6v`|MjOKXGVi`PK7* z=`*FwXwU2NYUM&w+$i>!&rc36jpusnFMcH1h4QI8^_OdJhJP;aZq$FhYmEHf+*oO^ k480xQwsT+K+;DT@X4~P5Hdnp${%Wpwy020Dev3~211z_vYXATM literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/wd/grapes/images/grapes.jpg b/emacs/nxhtml/nxhtml/doc/wd/grapes/images/grapes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21d98f5c4e3ed839492d5b211078db8059e6c61b GIT binary patch literal 24419 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/wd/grapes/images/quote.gif b/emacs/nxhtml/nxhtml/doc/wd/grapes/images/quote.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed81a2477ad9fe843e291d88998ac3f5bb16adc8 GIT binary patch literal 643 zcmZ?wbhEHbRAo?RxXJ(m|Ns9#ea7(28N*Yj4Nsp2GK@~00y2zFo-{gf!sys>qvOYo zjvX^PdKAbtK7QQz$Pwd1hm8*(Ha>L7_~1bxGC6R-_`m^^{rgS!?K9cC*JRHglij<4 z$aLpU(;YiZ!Isd9Q2fcl$iSe;paZf1<R=EU{|?TH0U8`#uFM}Rbc80lH4EI7ky>~o zHBdpuhx@X==;;!!rH7rB8*{t)xmkC}=*cL};^z?YblT~`B3xN5RG-euAyQRc%@e>D z>fGI1%^RM?B|Eh@w3L-cW=?gT2b*xu9O-4zt~@KJ$}DwSzqnd#jVJqtsp89m*k>=6 z70KDmB)v^mtZ1poVtL`*1XsQbwM$*O4xbHf@Ho^f-#^J$baDU9c<vYVSDg0jn{g#T ze2(~}*sF`r-eh)XzvX%|Rezd9IqRCxR})xx_cHA<a>#Hnl$B6o<}y2Vph2mHeJz*G zhO64qjRo8EuFQ1UB-q;K%CwCo(WBdK60eeDrh)L0r3>^ma(%1KguBm7lbI(VxF~U% zj=fF#uP7<i7kk@XqNSW3J=O5!a$lD6qVnW<1~yy8DUVFKdS<Lq*(-VD*_Y{4mU$f2 z$kEI{Ey!<dXrZ&9VNv2?SxFTE<&?(9Y{KeN@64WGm~J(Fxy{UP7joAfoD=EE_1DGW zMy3y6+QCB-i)Sd$PK+*eXE!|*GqrSI-lAJ7w)ZBaF{kUca3@zK{@Zv-oQ1&}06KBu Ad;kCd literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/doc/wd/grapes/index.html b/emacs/nxhtml/nxhtml/doc/wd/grapes/index.html new file mode 100644 index 0000000..3fd0fe3 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/wd/grapes/index.html @@ -0,0 +1,76 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html> +<head> +<title>Grapes</title> +<link rel="stylesheet" type="text/css" href="grapes.css" /> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> +<meta name="author" content="Your name here" /> +<meta name="Copyright" content="Copyright (c) Your copyright here 2005" /> +</head> +<body> +<div id="container"> +<div id="hdr"> +<h1>grapes</h1> +<p id="tagline">fruit, wine & web design</p> +</div> + +<div id="lftcol"> + <ul id="nav"> + <li><a href="" id="current">Introduction</a></li> + <li><a href="">Our Wines</a></li> + <li><a href="">Important Grapes</a></li> + <li><a href="">Contact Us</a></li> + <li><a href="">Links</a></li> + </ul> + +<div id="quote"> +<p><em>A great source for information...</em></p> +</div> + +<h3>More stuff</h3> + <ul> + <li><a href="http://validator.w3.org/check?uri=referer">Validate XHTML</a></li> + <li><a href="http://jigsaw.w3.org/css-validator/check/referer">Validate CSS</a></li> + <li><a href="http://www.davereederdesign.com/">Authors Website</a></li> + <li><a href="http://www.oswd.org/">OSWD</a></li> + </ul> + +</div> + + + +<div id="rgtcol"> +<h2>Introduction</h2> +<p>Hello and welcome to my latest template called "Grapes". +<br /> +"Grapes" is an Open Source web template which means it can be used without the need to ask permission and you have full rights to use and adapt its images. For more of my work, please see my website which can be found <a href="http://www.davereederdesign.com/">here.</a> +</p> +<p> +I wanted to create a fairly simple yet attractive template which can be used for food or wine related websites, although it can easily be adapted for other uses too. +</p> + + +<h2>But is it <em>easy</em> to Use?</h2> +<p>"Grapes" should be quite easy to use as I have added plenty of comments and tried to make the <acronym title="Cascading Style Sheet">CSS</acronym> as neat and organised as possible. +</p> +<p>There are also plenty of styles for other tags, including:</p> + +<p><code>Text using the code tag, this is ideal for showing code on a page.</code></p> + +<p><acronym title="acronym text">acronym text</acronym></p> + +<p><strong>strong or bold text</strong></p> + +<p><em>em or italic text</em></p> + +<p>This is a paragraph of normal text that contains <span>span</span> tags with a class set to <span>special</span>. This means all the <span>big words</span> in this paragraph are words that are placed between opening and closing <span>span</span> tags. These span tags can be used to add meaning to a block of text or to <span>shout out</span> when needed.</p> +</div> + +<div id="bttmbar">Copyright © Your Copyright Info</div> + + +</div> + +</body> +</html> \ No newline at end of file diff --git a/emacs/nxhtml/nxhtml/doc/wd/grapes/nxhtml-grapes.css b/emacs/nxhtml/nxhtml/doc/wd/grapes/nxhtml-grapes.css new file mode 100644 index 0000000..a241c1e --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/wd/grapes/nxhtml-grapes.css @@ -0,0 +1,252 @@ +/* Grapes, web template for business or for fun */ +/* By Dave Reeder, www.davereederdesign.com */ + +body {margin: 0; padding: 0; background: #213205} + +/* * {margin: 0; padding: 0; border: 0; font-family: Arial, Helvetica, sans-serif} */ +* {font-family: Arial, Helvetica, sans-serif} + +/*----------------------------------------------Basic styles------------------------------------------------*/ + +h1, h2, h3, h4 {font-family: Georgia, Georgia, serif; margin: 15px 0 0 5px; color: #fff; font-weight: normal; text-decoration: none} +h1 em, h2 em, h3 em, h4 em {font-family: Georgia, Georgia, serif; font-weight: normal} /* italic words in titles */ + +h1 {xposition: absolute; right: 0px; top: 30px; font-size: 2.25em; letter-spacing: 0.1em; line-height: 1.00em; padding-right: 10px; border-right: 15px solid #fff} +h1:first-letter {font-family: Georgia, Georgia, serif; font-size: 2.25em} /* styles the first letter of the main title to make it large */ + +p#tagline {position: absolute; right: 0px; top: 125px; font-style: italic; color: #648D20; font-size: 0.90em} /* sits under main title */ + +h2 {font-size: 1.40em; letter-spacing: 0.05em} +h3 {font-size: 1.00em; letter-spacing: 0.05em} + +p { +/* margin: 10px 10px 0 7px; */ +} +p, ul, ol { + font-size: 0.75em; xline-height: 1.60em; color: #000; letter-spacing: 0.05em +} +dt {font-size: 0.9em;} +ul li ul {font-size: 1em;} +ul li ul { + margin-bottom: 0; + margin-top: 0; +} + +code {font-family: monospace; font-size: 1.20em; color: #E20000} + +/* p span {font-size: 1.50em; font-weight: bold} /\* shouting words *\/ */ + +a:link, a:visited { + color: #792533; + /* font-weight: bold; */ + /* I can see why a border-bottom was used, but I do not have time to + fix it now */ + /* text-decoration: none; */ + /* border-bottom: 1px solid #792533; */ +} +a:hover, a:active {color: #fff; border-color: #fff} + +#getit a { + text-decoration: none; +} +#getit a:visited { + color: #792533; +} +#getit a:hover, #getit a:active { + color: red; +} +#nxhtml-home a:hover, #nxhtml-home a:active { + color: red; +} +#nxhtml-home { + margin-bottom:3em; + background-color:white; + padding: 0.5em; +} + +nul {list-style: inside square} /* general lists */ +nul ul {list-style: inside circle} /* general lists */ + +acronym {font-weight: bold; border-bottom: 1px dashed #000; cursor: help} + +p, li, dt, dd { + margin-right: 1em; +} +dt { + margin-top: 1em; + margin-bottom: 0.5em; +} +li ul li { + margin-right: 0; +} +table, td { + margin: 0; + padding: 0; + cell-padding: 0; + //font-size:0.9em; +} + +li p { + font-size: 1em; +} + +/*-----------------------------------------------Layout DIVS------------------------------------------------*/ + +#xgetit { + font-size: 0.6em; + float: left; + width: 20em; + background: white; + text-decoration: none; + padding: 0.5em; + padding-left: 1em; + margin-left: 1em; + margin-top: 1em; +} +/* * { text-decoration: none; } */ +#container { /* keeps everything together */ + position: absolute; + margin: 0 auto; + margin-top: 0; + /* width: 620px; */ + margin-right: 17%; + background: url(images/bkgrnd.gif) 0 0 repeat-y #CCCC33; /* Important image, do not remove */ + xoverflow: hidden; +} + +#hdr { /* div containing h1, nav and grapes image */ + float: left; + width: 260px; + height: 250px; + background: url(images/grapes.jpg) 0 0 no-repeat #CCCC33 /* Image of Grapes */ +} + +#xmainhdr { + xfloat: right; + width: 100px; + height: 100px; +} + +#lftcol table li a { + /* text-decoration: none; */ +} +#lftcol { /* left column */ + /* position: absolute; */ + float: right; + /* left: 0px; */ + /* top: 200px; */ + /* margin-left: 50px; /* leave this so that background image lines up with edge of this div */ + margin-bottom: 50px; /* Quck fix for img menu */ + margin-right: 1em; + background: transparent; +} + +#rgtcol { + xfloat: left; + clear: both; + margin-left: 100px; + max-width: 600px; + padding-bottom: 30px; background: transparent; xoverflow: hidden; /* right column */ +} + +.footer { + float: left; + width: 19em; + clear: both; +} +hr.footer { + width: 19em; + float: left; + text-align: left; + margin-bottom: 0; + margin-left: 0; + padding-left: 0; +} +p.footer { + margin-left: 1em; + margin-right: 1em; + color: #564; + //font-size: 0.8em; + //padding: 0; + //margin-bottom: 1em; + //padding-bottom: 1em; +} + +#bttmbar {float: right; text-align: center; font-size: 0.70em; height: 4em; line-height: 4em; width: 570px; background: #CCCC33; border-top: 1px solid #D9D93C} + +#quote { /* Quote box in left column */ + float: left; + margin: 10px 0 20px 10px; + padding: 10px 0; + width: 170px; + text-align: center; + background: url(images/quote.gif) no-repeat 0 0 +} + +#quote p {color: #444; font-size: 0.80em; font-weight: bold; line-height: 2.00em} /* Quote box text */ + + +/*---------------------------------------------Main Navigation-----------------------------------------------*/ + +ul#nav { /* navigation list */ + margin: 53px 0 20px 0; /* the 53px is where the nav begins (margin top) */ + padding: 0; + list-style: none inside +} + +ul#nav li {float: left; display: block} + +ul#nav li a { + width: 170px; + margin: 3px 0 0 0; /* a little top margin */ + border: 0; + border-left: 10px solid #CCCC33; + padding: 10px 5px; + font-family: Georgia, Georgia, serif; + font-weight: normal; + text-decoration: none; + display: block; + color: #450F1F; + background: #D9D93C +} + +ul#nav li a#current {border-color: #fff} /* current page, move id in the xhtml when creating a new page */ + +ul#nav li a:hover {background: #9EA219; color: #fff} + +#PAGETOC { + float: left; +} +#PAGETOC * { + font-size: 12px; +} +#PAGETOC ul { + margin: 0; + margin-top: 1em; + padding: 0; +} +#PAGETOC li { + font-size: 1em; + list-style-type: none; + margin: 0em; +} +#PAGETOC ul li ul { + padding-left: 1.5em; + margin: 0em; +} +#PAGETOC li, #PAGETOC li ul li { + font-weight: bold; + display: block; +} +#PAGETOC li ul li { + font-weight: 500; +} + +#PAGETOC .tochead { + font-size: 10px; + background-color: #c0ff3e; + background-color: #9acd32; + background-color: #b3ee3a; + padding: 4px; +} + diff --git a/emacs/nxhtml/nxhtml/doc/working-demo.html b/emacs/nxhtml/nxhtml/doc/working-demo.html new file mode 100644 index 0000000..0752f85 --- /dev/null +++ b/emacs/nxhtml/nxhtml/doc/working-demo.html @@ -0,0 +1,60 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + <title>Something</title> + <script type="text/javascript" src="js/smoothgallery/scripts/mootools.uncompressed.js"></script> + <script type="text/javascript" src="js/smoothgallery/scripts/jd.gallery.js"></script> + <link rel="stylesheet" href="js/smoothgallery/css/jd.gallery.css" type="text/css" media="screen" charset="utf-8" /> + </head> + <body> + <h1>My 1st demo</h1> + <script type="text/javascript"> + function startGallery() { + var myGallery = new gallery($('myGallery'), { + timed: true, + delay: 9000, + embedLinks: false, + showArrows: true, + showCarousel: false, + showInfopane: true, + }); + } + window.onDomReady(startGallery); + </script> + + <div class="content"> + <div id="myGallery"> + <div class="imageElement"> + <h3>Popup completion</h3> + <p> + popup stlye completion + popup stlye completion + popup stlye completion + popup stlye completion + popup stlye completion + popup stlye completion + popup stlye completion + popup stlye completion + popup stlye completion + </p> + <img src="img/popup-compl.png" class="full" /> + </div> + <div class="imageElement"> + <h3>Emacs style completion</h3> + <p> emacs stlye completion </p> + <a href="#" title="open image" class="open"></a> + <img src="img/emacs-style-completion.png" class="full" /> + <img src="ximages/brugges2006/1-mini.jpg" class="thumbnail" /> + </div> + <div class="imageElement"> + <h3>Edit part</h3> + <p> edit part </p> + <a href="#" title="open image" class="open"></a> + <img src="img/edit-part.png" class="full" /> + <img src="ximages/brugges2006/1-mini.jpg" class="thumbnail" /> + </div> + </div> + </body> + </html> diff --git a/emacs/nxhtml/nxhtml/html-chklnk.el b/emacs/nxhtml/nxhtml/html-chklnk.el new file mode 100644 index 0000000..6fdbb49 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-chklnk.el @@ -0,0 +1,168 @@ +;;; html-chklnk.el --- Check links in local HTML sites +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed Mar 15 14:46:17 2006 +(defconst html-chklnk:version "0.2") ;; Version: +;; Last-Updated: Tue Apr 10 04:12:32 2007 (7200 +0200) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (add-to-list 'load-path default-directory load-path)) +(eval-when-compile + (when (> emacs-major-version 22) + (let* ((load-path load-path) + (this-file (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + (this-dir (file-name-directory this-file))) + (add-to-list 'load-path (expand-file-name "../../lisp" this-dir)) + (require 'w32shell nil t)))) + + +(eval-when-compile (require 'html-site nil t)) +(require 'compile) + +;;;###autoload +(defgroup html-chklnk nil + "Customization group for html-chklnk." + :group 'nxhtml) + +(defcustom html-chklnk-dir + (file-name-as-directory + (expand-file-name + "html-chklnk" + (file-name-directory + (if load-file-name load-file-name buffer-file-name)))) + + "Directory where the tools needed are located. +" + :type 'directory + :group 'html-chklnk) + +(defun html-chklnk-check-site-links (start-file) + "Check local file web site links. +Currently only internal links are checked." + (interactive + (progn + (html-site-current-ensure-site-defined) + (if (y-or-n-p "Start from a given file and check links from there? ") + (let* ((default-start (if (html-site-current-contains buffer-file-name) + buffer-file-name + (car (directory-files (html-site-current-site-dir) + nil + "\\.html?$")))) + (start-file + (read-file-name "Start checking from file: " + (html-site-current-site-dir) + nil + nil + default-start))) + (unless (html-site-dir-contains (html-site-current-site-dir) start-file) + (error "File %s is not in the site %s" start-file html-site-current)) + (list start-file)) + (list nil)))) + (let* ((default-directory html-chklnk-dir) + (compile-cmd (concat "perl link_checker.pl " + "--site=" + ;;(html-chklnk-convert-file-name + (html-site-current-site-dir) + ;;) + (if start-file + (concat " --start=" + ;;(html-chklnk-convert-file-name + start-file + ;;) + ) + ""))) + (compilation-buffer-name-function + '(lambda (dummy) (concat "** Checking links in site " + html-site-current " **"))) + (compilation-scroll-output t) + (compilation-error-regexp-alist-alist + '( + (html-chklnk + "^\\(.*\\)\\s-+at line \\([0-9]+\\):" + 1 ;; file + 2 ;; line + ))) + (compilation-error-regexp-alist '(html-chklnk)) + ;;(shell-file-name "cmd") + ;;(explicit-shell-file-name "cmd") + ;;(shell (concat exec-directory "cmdproxy.exe")) + ;;(old-w32shell nil) + ) + ;; There are trouble with perl paths +;; (when (featurep 'w32shell) +;; (when w32shell-current-shell-path +;; (setq old-w32shell w32shell-current-shell-path) +;; (w32shell-set-shell "cmd"))) + ;;(message "uses-cygwin=%s" uses-cygwin)(sit-for 8) + + (if (fboundp 'w32shell-save-shell) + (w32shell-save-shell + "cmd" + (compile compile-cmd)) + (compile compile-cmd)) + +;; (when old-w32shell +;; (cond ((string= old-w32shell w32shell-cygwin-bin) +;; (w32shell-set-shell "cygwin")) +;; ((string= old-w32shell w32shell-msys-bin) +;; (w32shell-set-shell "msys")))) + )) + +(defun html-chklnk-convert-file-name (filename) + (let ((uses-cygwin (and (featurep 'w32shell) + (string= w32shell-current-shell-path + w32shell-cygwin-bin))) + (case-fold-search t) + ) + (save-match-data + (if (and uses-cygwin + (string-match "^\\([a-z]\\):" filename)) + (concat "/cygdrive/" (match-string 1 filename) + (substring filename 2)) + filename)))) + + + + +(provide 'html-chklnk) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-chklnk.el ends here diff --git a/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/LinkWalker.pm b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/LinkWalker.pm new file mode 100644 index 0000000..14b0ccb --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/LinkWalker.pm @@ -0,0 +1,774 @@ +### File: LinkWalker.pm +### Author: Lennart Borgman +### All rights reserved + +########################################################## +### UserAgent module +########################################################## +package LWP::WalkerUA; +require LWP::UserAgent; +@ISA = qw(LWP::UserAgent); + +### Mirror to another file (why???) +sub mirror +{ + my($self, $url, $file, $mirr_tmp) = @_; + die "no mirr_tmp" unless defined $mirr_tmp; + + LWP::Debug::trace('()'); + my $request = new HTTP::Request('GET', $url); + + if (-e $file) { + my($mtime) = (stat($file))[9]; + if($mtime) { + $request->header('If-Modified-Since' => + HTTP::Date::time2str($mtime)); + } + } + my $tmpfile = "$file-$$"; + + my $response = $self->request($request, $tmpfile); + if ($response->is_success) { + + my $file_length = (stat($tmpfile))[7]; + my($content_length) = $response->header('Content-length'); + + if (defined $content_length and $file_length < $content_length) { + unlink($tmpfile); + die "Transfer truncated: " . + "only $file_length out of $content_length bytes received\n"; + } elsif (defined $content_length and $file_length > $content_length) { + unlink($tmpfile); + die "Content-length mismatch: " . + "expected $content_length bytes, got $file_length\n"; + } else { + # OK + if (-e $mirr_tmp) { + # Some dosish systems fail to rename if the target exists + chmod 0777, $mirr_tmp; + unlink $mirr_tmp; + } + rename($tmpfile, $mirr_tmp) or + die "Cannot rename '$tmpfile' to '$mirr_tmp': $!\n"; + + if (my $lm = $response->last_modified) { + # make sure the file has the same last modification time + utime $lm, $lm, $mirr_tmp; + } + } + } else { + unlink($tmpfile); + } + return $response; +} + + +########################################################## +### Parser module +########################################################## +package HTML::WalkerParser; +require HTML::ParserTagEnd; +@ISA = qw(HTML::ParserTagEnd); +use strict; +use vars qw(%LINK_ELEMENT); + +# Elements that might contain links and the name of the link attribute +%LINK_ELEMENT = +( + body => 'background', + base => 'href', + a => 'href', + img => [qw(src lowsrc usemap)], # 'lowsrc' is a Netscape invention + form => 'action', + input => 'src', +'link' => 'href', # need quoting since link is a perl builtin + frame => 'src', + applet => [qw(codebase code)], + area => 'href', + iframe => 'src', # Netscape 2.0 extention + embed => 'src', # used in Netscape 2.0 for Shockwave and things like that +); + +my %LINKATTRIBS = ( + "href" => 1, + "src" => 1, + "action" => 1, + "background" => 1, + "usemap" => 1, + "code" => 1, + "codebase" => 1, + "lowsrc" => 1, + ); +my %MAYBECONT = ( + a => 'href', + area => 'href', + form => 'action', + frame => 'src', + iframe => 'src', + ); + +sub maybecont($$) { + my $tag = shift; + my $att = shift; + return unless exists $MAYBECONT{$tag}; + return ($MAYBECONT{$tag} eq $att); +} + +sub new { + my($class, $parsed_fh) = @_; + my $self = $class->SUPER::new; + $self->{parsed_fh} = $parsed_fh; + $self; +} + + + + + + + +########################################################## +### Walker module +########################################################## +package HTML::LinkWalker; +use strict; + +use IO::File; +use File::Copy qw(); +use File::Path qw(); +use PathSubs qw(); +use HTML::Entities; +use FindBin qw(); + + +########################################################## +### Globals +########################################################## +my $ua; +my $m_ua_personality = "LinkWalker/0.9"; +my %m_is_outside; +my %m_is_container; +my $m_bOnlyCont; +my @m_sLinkRoots; +my $m_subReport; +my $m_subAction; +my $m_subMirrorAction; + + +############################# +### Collecting info +############################# +my %m_CheckedLinks; +my %m_MissedLinks; + +sub tell_bad_link($$$$$) { + my $what = shift; + my $file = shift; + my $lnum = shift; + my $link = shift; + my $line = shift; + $file = "START" unless defined $file; + $lnum = "(start)" unless defined $lnum; + my $longMsg = "<<$what>>"; + my $shortMsg = $what; + if (defined $link) { + my @lines = split("\\s+", $line); + my $disp_line = join("\n\t\t ", @lines); + $longMsg .= ",\n\t\tlink=$link\n\t\t$disp_line"; + } + my @msg = ($shortMsg, $longMsg); + $m_CheckedLinks{$file}->{ERR}->{$lnum} = \@msg; + &$m_subReport("\t* Error * " . $what . "\n"); +} # tell_bad_link + + +############################# +### Helpers +############################# + +sub get_contenttype($) { + my $response = shift; + my @rh = $response->header("Content-Type"); + for my $r (@rh) { + my $c = $r; + if ((my $iPos = index($r, ";")) > -1) { + $c = substr($r, 0, $iPos); + } + return $c; + } +} +sub is_linked_contenttype($) { + my $response = shift; + return (get_contenttype($response) eq "text/html"); +} + +sub ending_is_container($) { + my $link_addr = shift; + $link_addr =~ s!#.*$!!; + $link_addr =~ s!\?.*$!!; + return (($link_addr =~ m!\.s?html?$!i) ? 1 : 0); +} + +my $m_sMirrorRoot; +my $m_bMirror = 1; + +sub mk_mirror_name($) { + my $orig_name = shift; + $orig_name =~ tr!\\!/!; + my $mirr_name = $orig_name; + my ($orig_host) = ($orig_name =~ m!(^https?://[^/]*)!i); + if (defined $orig_host) { + my $host = $orig_host; + $host =~ tr!:!_!; + $host =~ tr!/!_!; + $mirr_name =~ s!^$orig_host!$host!; + if (substr($mirr_name, -1) eq "/") { $mirr_name .= "default.html"; } + } else { + die "Can't find host in $orig_name\n"; + } + my $mirr_full = sMirrorRoot() . $mirr_name; + if (!$m_bMirror) { + my $sExt = $mirr_name; $sExt =~ s!.*\.([^\.]*$)!$1!; + $mirr_full = sMirrorRoot() . "temp.$sExt"; + } + my $mirr_fold = $mirr_full; + $mirr_fold =~ s![^/]*$!!; + File::Path::mkpath($mirr_fold, 0, 0777); + return $mirr_full; +} + +############################# +### Checks +############################# +sub is_outside($) { + my $uq_link_addr = shift; + if (!exists $m_is_outside{$uq_link_addr}) { + $m_is_outside{$uq_link_addr} = test_is_outside($uq_link_addr, \@m_sLinkRoots); + } + return $m_is_outside{$uq_link_addr}; +} +sub set_is_container($$) { + my $uq_link_addr = shift; + return if exists $m_is_container{$uq_link_addr}; + $m_is_container{$uq_link_addr} = shift; +} +sub is_outside_container($) { + my $uq_link_addr = shift; + if (exists $m_is_container{$uq_link_addr}) { + if ($m_is_container{$uq_link_addr}) { + return is_outside($uq_link_addr); + } + } +} +sub test_is_outside($$) { + my $uq_link_addr = shift; + my $link_roots = shift; + if (defined $link_roots) { + my $in_roots; + for my $link_root (@$link_roots) { + if (substr($uq_link_addr, 0, length($link_root)) eq $link_root) { + return 0; + } + } + return 1; + } +} # is_outside + + + +########################################################## +### Parsing +########################################################## + + +### Parser subs +sub HTML::WalkerParser::declaration { + my($self, $decl) = @_; + return unless defined $self->{parsed_fh}; + my $fh = $self->{parsed_fh}; + print $fh "<!" . $decl . ">"; +} +my $m_start_cb; +sub HTML::WalkerParser::start { + my($self, $tag, $attr, $ended) = @_; + &$m_start_cb($tag, $attr); + return unless defined $self->{parsed_fh}; + my $t = "<$tag"; + for my $k (keys %$attr) { + my $encoded = encode_entities($$attr{$k}); + $t .= qq( $k="$encoded"); + } + if ($ended) { + $t .= " />"; + } else { + $t .= ">"; + } + my $fh = $self->{parsed_fh}; + print $fh $t; +} +sub HTML::WalkerParser::end { + my ($self, $tag) = @_; + return unless defined $self->{parsed_fh}; + my $fh = $self->{parsed_fh}; + print $fh "</" . $tag . ">"; +} +sub HTML::WalkerParser::text { + my ($self, $txt) = @_; + return unless defined $self->{parsed_fh}; + my $fh = $self->{parsed_fh}; + print $fh $txt; +} +sub HTML::WalkerParser::comment { + my($self, $comment) = @_; + return unless defined $self->{parsed_fh}; + my $fh = $self->{parsed_fh}; + print $fh "<!--" . $comment . "-->"; +} + + + + +### Main parsing routine + +sub parse_file($$$$$$$$$) { + my ($file_name, $parsed_fh, $uq_link_addr, $link_roots, + $ref_links, $ref_anchs, $ref_lines, $ref_tagname, $ref_attname) = @_; + my $fh; + if (-d $file_name) { + $file_name = PathSubs::uniq_dir($file_name) . "default.html"; + $uq_link_addr .= "/" unless substr($uq_link_addr, -1) eq "/"; + $uq_link_addr .= "default.html"; + &$m_subReport("dir => $file_name\n"); + } + $fh = new IO::File($file_name); + die "Can't read $file_name: $!\n" unless defined $fh; + my $base_href; + my $n; + my $line; + my $uq_link_fold = $uq_link_addr; $uq_link_fold =~ s![^/]*$!!; + + my $start_cb = + sub { + my ($tag, $attr_hash) = @_; + for my $k (keys %$attr_hash) { + if (($k eq "id") || ($k eq "name")) { + my $v = $$attr_hash{$k}; + $$ref_anchs{$v} = $n; + $$ref_lines{$n} = $line; + } elsif (exists $LINKATTRIBS{$k}) { + my $v = $$attr_hash{$k}; + next if $v =~ m!^javascript:!; + next if $v =~ m!^ftp://!; + next if $v =~ m!^mailto://!; + if ($tag eq "base") { $base_href = $v if $k eq "href"; next; } + my $v_abs; my $v_rel; + my $v_is_abs = PathSubs::is_abs_path($v); + if ($v_is_abs) { + $v_abs = $v; + $v_rel = PathSubs::mk_relative_link($uq_link_addr, $v_abs); + } else { + $v_rel = $v; + if (defined $base_href) { + $v_abs = PathSubs::mk_abs_link($base_href, $v); + } else { + if (substr($v_rel, 0, 1) ne "#") { + $v_abs = $uq_link_fold . $v_rel; + } else { + $v_abs = $uq_link_addr . $v_rel; + } + $v_abs = PathSubs::resolve_dotdot($v_abs); + } + } + next if exists $m_CheckedLinks{$v_abs}; + if (is_outside($v_abs)) { + if (!$v_is_abs) { + if (ending_is_container($v_abs)) { + $m_CheckedLinks{$v_abs} = {}; + tell_bad_link("Outside relative link ($v_rel)", + $uq_link_addr, $n, $v, $line); + } + } + ### Skip outside absolute links + ### Could be things like banners etc... + next; + } + $$ref_links{$v_rel} = $n; + $$ref_lines{$n} = $line; + if (substr($v_rel, 0, 1) ne "#") { + my $v_rel_name = $v_rel; + $v_rel_name =~ s!#.*$!!; + $v_rel_name =~ s!\?.*$!!; + $$ref_tagname{$v_rel_name} = $tag; + $$ref_attname{$v_rel_name} = $k; + } + if ($v_is_abs && ($v_rel ne $v)) { $$attr_hash{$k} = $v_rel; } + } + } + }; # $start_cb + + $m_start_cb = $start_cb; + my $p = HTML::WalkerParser->new($parsed_fh); + while ($line = <$fh>) { + $n++; + $p->parse($line); + } + $fh->close(); +} # parse_file + + + +########################################################## +### Do the walk... +########################################################## +sub walk_link($$;$$$$) { + die "$#_" unless ($#_ == 1 || $#_ == 5); + my $link_fold = shift; + my $link_file = shift; + my $parent_url = shift; + my $parent_lnum = shift; + my $parent_link = shift; + my $parent_line = shift; + + my $link_addr = $link_fold . $link_file; + my $uq_link_addr; + my $is_file = ($link_addr !~ m!^https?://!i); + if ($is_file) { + $uq_link_addr = PathSubs::uniq_file($link_addr); + } else { + $uq_link_addr = PathSubs::resolve_dotdot($link_addr); + } + return if exists $m_CheckedLinks{$uq_link_addr}; + return if exists $m_MissedLinks{$uq_link_addr}; + $m_CheckedLinks{$uq_link_addr} = {}; + my $link_is_container = ending_is_container($uq_link_addr); + if ($link_is_container) { + set_is_container($uq_link_addr, 1); + return if is_outside($uq_link_addr); + } else { + return if $m_bOnlyCont; + } + my $response; + my $contenttype; + my $bDoRewrite; + my $file_name; + if ($is_file) { + if (!-r $uq_link_addr) { + tell_bad_link("Can't read file ($uq_link_addr)", + $parent_url, $parent_lnum, $parent_link, $parent_line); + $m_MissedLinks{$uq_link_addr} = 1; + return; + } + $file_name = $uq_link_addr; + } else { + $file_name = mk_mirror_name($uq_link_addr); + if (!defined $ua) { + $ua = new LWP::UserAgent; + $ua->agent($m_ua_personality); + #$ua->delay(0.1); + } + if ($m_bMirror) { + $response = $ua->mirror($uq_link_addr, $file_name); + &$m_subMirrorAction($uq_link_addr, $file_name, $response); + } else { + my $request = new HTTP::Request('GET', $uq_link_addr); + $response = $ua->request($request, $file_name); + } + #dump_response($response); exit; + if ($response->code != 304) { + if (!$response->is_success) { + tell_bad_link($response->status_line . " ($uq_link_addr)", + $parent_url, $parent_lnum, $parent_link, $parent_line); + $m_MissedLinks{$uq_link_addr} = 1; + return; + } + $bDoRewrite = $m_bMirror; + $contenttype = get_contenttype($response); + $link_is_container = is_linked_contenttype($response); + } + if ($uq_link_addr ne $response->base) { + if ($m_bMirror) { + my $base_file = mk_mirror_name($response->base); + if (!File::Copy::copy($file_name, $base_file)) { + die "Can't copy($file_name, $base_file): $!\n"; + } + if (my $lm = $response->last_modified) { utime $lm, $lm, $base_file; } + $file_name = $base_file; + } + $uq_link_addr = $response->base; + } + } + ### Test again, could be new info from net! + if ($link_is_container) { + set_is_container($uq_link_addr, 1); + return if is_outside($uq_link_addr); + } else { + return if $m_bOnlyCont; + return; + } + &$m_subReport("$uq_link_addr ..."); + + my %links; + my %anchs; + my %lines; + my %tagname; + my %attname; + my $parsed_fh; + my $parsed_file; + my $file_to_parse = $file_name; + if ($bDoRewrite) { + $parsed_file = $file_to_parse . "-p$$"; + &$m_subReport(" <<GET"); + $parsed_fh = new IO::File("> $parsed_file"); + die "Can't create $parsed_file: $!\n" unless defined $parsed_fh; + print $parsed_fh "<!-- parsed version -->\n"; + } + &$m_subReport("\n"); + parse_file($file_to_parse, $parsed_fh, $uq_link_addr, + \@m_sLinkRoots, + \%links, \%anchs, \%lines, \%tagname, \%attname); + if (defined $parsed_fh) { + $parsed_fh->close(); + if (-e $file_name) { unlink $file_name or die "Can't unlink $file_name: $!"; } + rename($parsed_file, $file_name) or die "Can't rename($parsed_file, $file_name): $!\n"; + if (my $lm = $response->last_modified) { utime $lm, $lm, $file_name; } + } + ### Now we know... + if ($link_is_container) { return if is_outside($uq_link_addr); } + + $m_CheckedLinks{$uq_link_addr}->{ANC} = \%anchs; + my $file_dir; + if ($is_file) { + $file_dir = $uq_link_addr; + $file_dir =~ s![^/]*$!!; + #chdir $file_dir; + } + my $container_folder = $uq_link_addr; $container_folder =~ s![^/]*$!!; + &$m_subAction($uq_link_addr, $file_name, $contenttype); + for my $link (sort keys %links) { + # Next line is for onclick lines in prepared docs + next if ($link eq "#"); + my $lnum = $links{$link}; + my $line = $lines{$lnum}; + if ($link eq "") { + tell_bad_link("Empty link", $uq_link_addr, $lnum, $link, $line); + next; + } + if ($link =~ m!(.*)\?!) { $link = $1; } + my $anchor; + if ($link =~ m!(.*)#(.*)!) { $link = $1; $anchor = $2; } + if ($link eq "") { + if (!exists $anchs{$anchor}) { + tell_bad_link("Anchor not found ($anchor)", $uq_link_addr, $lnum, $link, $line); + } + next; + } + my $sub_fold; + my $sub_file; + my $uq_sublink; + if ($link =~ m!^https?://!i) { + $sub_fold = ""; + $sub_file = $link; + $uq_sublink = $link; + } else { + $sub_file = $link; + if ($is_file) { + $sub_fold = $file_dir; + $uq_sublink = PathSubs::uniq_file($sub_fold . $sub_file); + } else { + $sub_fold = $container_folder; + $uq_sublink = $sub_fold . $sub_file; + } + } + next if (exists $m_CheckedLinks{$uq_sublink}); + if (defined $anchor) { + $m_CheckedLinks{$uq_link_addr}->{EXTANC}->{$uq_sublink} = + { ANC=> $anchor, LINE=>$line, LNUM=>$lnum}; + } + if ($m_bOnlyCont) { + die "link=$link\tattr=$tagname{$link}\n" unless exists $tagname{$link}; + next unless maybecont($tagname{$link}, $attname{$link}); + } + if (is_outside($uq_link_addr)) { + if (maybecont($tagname{$link}, $attname{$link}) ) { + next; + } + } + walk_link($sub_fold, $sub_file, $uq_link_addr, $lnum, $link, $line); + } +} # walk_link + + + + +############################################ +### Some more checks! +############################################ +sub check_external_anchors() { + &$m_subReport("\nChecking external anchors...\n"); + for my $f (sort keys %m_CheckedLinks) { + my $fnode = $m_CheckedLinks{$f}; + if (exists ${$fnode}{"EXTANC"}) { + my $extanc_hash = ${$fnode}{"EXTANC"}; + for my $fx (keys %$extanc_hash) { + next unless (exists $m_CheckedLinks{$fx}); + my $ea_hash = ${$extanc_hash}{$fx}; + my $ea = ${$ea_hash}{ANC}; + my $fxnode = $m_CheckedLinks{$fx}; + my $fx_anc_hash = ${$fxnode}{"ANC"}; + if (!exists ${$fx_anc_hash}{$ea}) { + my $line = ${$ea_hash}{LINE}; + my $lnum = ${$ea_hash}{LNUM}; + &$m_subReport("From $f\n"); + tell_bad_link("Ext anchor not found ($fx#$ea)", + $f, $lnum, "$fx#$ea", $line); + } + } + } + } +} # check_external_anchors + + + +############################# +### Reporting +############################# +sub report_errors($$) { + my $bSum = shift; + my $bDet = shift; + my $errors_reported; + my $errors_found; + for my $f (sort keys %m_CheckedLinks) { + my $fnode = $m_CheckedLinks{$f}; + if (exists ${$fnode}{ERR}) { + $errors_found = 1; + last unless $bSum; + if (!defined $errors_reported) { + $errors_reported = 1; + &$m_subReport("\n\n*********** Summary ERRORS and WARNINGS **********\n"); + } + &$m_subReport("$f\n"); + my $err_hash = ${$fnode}{ERR}; + for my $e (sort keys %$err_hash) { + my $refE = ${$err_hash}{$e}; + &$m_subReport("\t" . ${$refE}[0] . "\n"); + } + } + } + undef $errors_reported; + if ($bDet) { + for my $f (sort keys %m_CheckedLinks) { + my $fnode = $m_CheckedLinks{$f}; + if (exists ${$fnode}{ERR}) { + if (!defined $errors_reported) { + $errors_reported = 1; + &$m_subReport("\n\n*********** Detailed ERRORS and WARNINGS **********\n"); + } + &$m_subReport("$f\n"); + my $err_hash = ${$fnode}{ERR}; + for my $e (sort keys %$err_hash) { + my $refE = ${$err_hash}{$e}; + &$m_subReport("\tat line $e: " . ${$refE}[1] . "\n"); + } + } + } + } + if ($errors_found) { + die "\n*** There where errors ***\n"; + } else { + &$m_subReport("No errors found\n"); + } +} # report_errors + +sub dump_response($) { + my $response = shift; + &$m_subReport( $response->code . " " . $response->message . "\n"); + &$m_subReport( "****************************************\n"); + #&$m_subReport( $response->request . "\n"); + #&$m_subReport( "****************************************\n"); + #&$m_subReport( $response->previous . "\n"); + #&$m_subReport( "****************************************\n"); + &$m_subReport( " i=" . $response->is_info . + ", s=" . $response->is_success . + ", r=" . $response->is_redirect . + ", e=" . $response->is_error . "\n"); + &$m_subReport( "****************************************\n"); + &$m_subReport( "content: " . $response->content . "\n"); + &$m_subReport( "****************************************\n"); + &$m_subReport( "base: " . $response->base . "\n"); + &$m_subReport( "****************************************\n"); + &$m_subReport( $response->as_string); + &$m_subReport( "****************************************\n"); + &$m_subReport( $response->current_age . "\n"); + &$m_subReport( "****************************************\n"); + my @rh = $response->header("Content-Type"); + for my $r (@rh) { &$m_subReport( "ct: $r\n"); } + &$m_subReport( "****************************************\n"); +} # dump_response + + +############################# +### Parameters +############################# +sub sMirrorRoot() { + my $val = shift; + $m_sMirrorRoot = PathSubs::get_temp_path() . "LinkWalker/" unless defined $m_sMirrorRoot; + my $old = $m_sMirrorRoot; + $m_sMirrorRoot = PathSubs::uniq_dir($val) if defined $val; + return $old; +} +sub bMirror(;$) { + my $val = shift; + my $old = $m_bMirror; + $m_bMirror = $val if defined $val; + $old; +} + +sub subReporter(;$) { + my $val = shift; + my $old = $m_subReport; + $m_subReport = $val if defined $val; + $old +} +sub subAction(;$) { + my $val = shift; + my $old = $m_subAction; + $m_subAction = $val if defined $val; + $old +} +sub bOnlyCont(;$) { + my $val = shift; + my $old = $m_bOnlyCont; + $m_bOnlyCont = $val if defined $val; + $old +} +sub ua_personality(;$) { + my $val = shift; + my $old = $m_ua_personality; + $m_ua_personality = $val if defined $val; + $old +} + +sub clear_roots() { @m_sLinkRoots = (); } +sub get_roots() { return \@m_sLinkRoots; } +sub add_root($) { push @m_sLinkRoots, shift; } +sub add_files_root($) { + my $file = shift; + my $default_root; + my ($host) = ($file =~ m!(^https?://[^/]*)!i); + if (defined $host) { + $default_root = $file; + } else { + die "Can't find $file\n" unless -e $file; + $default_root = PathSubs::uniq_file($file); + } + $default_root =~ s![^/]*$!!; + add_root($default_root); +} + +### Default actions +sub default_sub {} +$m_subReport = \&default_sub; +$m_subAction = \&default_sub; +$m_subMirrorAction = \&default_sub; + +1; diff --git a/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/ParserTagEnd.pm b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/ParserTagEnd.pm new file mode 100644 index 0000000..32407d6 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/ParserTagEnd.pm @@ -0,0 +1,448 @@ +package HTML::ParserTagEnd; + +# Author address: <gisle@aas.no> +### Modified for <tag />, Lennart + +use strict; +use HTML::Entities (); + +use vars qw($VERSION); +$VERSION = "2.23"; # $Date: 1999/06/09 10:27:16 $ + + +sub new +{ + my $class = shift; + my $self = bless { '_buf' => '', + '_strict_comment' => 0, + }, $class; + $self; +} + + +# A little note about the observed Netscape behaviour: +# +# It parse <xmp> in the depreceated 'literal' mode, i.e. no tags are +# recognized until a </xmp> is found. +# +# <listing> is parsed like <pre>, i.e. tags are recognized. <listing> +# are presentend in smaller font than <pre> +# +# Netscape does not parse this comment correctly (it terminates the comment +# too early): +# +# <! -- comment -- --> more comment --> +# +# Netscape ignores '<!--' and '-->' within the <SCRIPT> and <STYLE> tag. +# This is used as a trick to make non-script-aware browsers ignore +# the scripts. + + +sub parse +{ + my $self = shift; + my $buf = \ $self->{'_buf'}; + unless (defined $_[0]) { + # signals EOF (assume rest is plain text) + $self->text($$buf) if length $$buf; + $$buf = ''; + return $self; + } + $$buf .= $_[0]; + my $netscape_comment = !$self->{'_strict_comment'}; + + # Parse html text in $$buf. The strategy is to remove complete + # tokens from the beginning of $$buf until we can't deside whether + # it is a token or not, or the $$buf is empty. + + TOKEN: + while (1) { + + # First we try to pull off any plain text (anything before a "<" char) + if ($$buf =~ s|^([^<]+)||) { + if (length $$buf) { + $self->text($1); + } else { + my $text = $1; + # At the end of the buffer, we should not parse white space + # but leave it for parsing on the next round. + if ($text =~ s|(\s+)$||) { + $$buf = $1; + # Same treatment for chopped up entites and words. + # We must wait until we have it all. + } elsif ($text =~ s|(\s*\S+)$||) { + $$buf = $1; + }; + $self->text($text) if length $text; + last TOKEN; + } + + # Netscapes buggy comments are easy to handle + } elsif ($netscape_comment && $$buf =~ m|^<!\s*--|) { + if ($$buf =~ s|^<!\s*--(.*?)--\s*>||s) { + $self->comment($1); + } else { + last TOKEN; # must wait until we see the end of it + } + + # Then, markup declarations (usually either <!DOCTYPE...> or a comment) + } elsif ($$buf =~ s|^(<!)||) { + my $eaten = $1; + my $text = ''; + my @com = (); # keeps comments until we have seen the end + # Eat text and beginning of comment + while ($$buf =~ s|^(([^>]*?)--)||) { + $eaten .= $1; + $text .= $2; + # Look for end of comment + if ($$buf =~ s|^((.*?)--)||s) { + $eaten .= $1; + push(@com, $2); + } else { + # Need more data to get all comment text. + $$buf = $eaten . $$buf; + last TOKEN; + } + } + # Can we finish the tag + if ($$buf =~ s|^([^>]*)>||) { + $text .= $1; + $self->declaration($text) if $text =~ /\S/; + # then tell about all the comments we found + for (@com) { $self->comment($_); } + } else { + $$buf = $eaten . $$buf; # must start with it all next time + last TOKEN; + } + + # Should we look for 'processing instructions' <? ...> ?? + #} elsif ($$buf =~ s|<\?||) { + # ... + + # Then, look for a end tag + } elsif ($$buf =~ s|^</||) { + # end tag + if ($$buf =~ s|^([a-zA-Z][a-zA-Z0-9\.\-]*)(\s*>)||) { + $self->end(lc($1), "</$1$2"); + } elsif ($$buf =~ m|^[a-zA-Z]*[a-zA-Z0-9\.\-]*\s*$|) { + $$buf = "</" . $$buf; # need more data to be sure + last TOKEN; + } else { + # it is plain text after all + $self->text("</"); + } + + # Then, finally we look for a start tag + } elsif ($$buf =~ s|^(<([a-zA-Z]+)>)||) { + # special case plain start tags for slight speed-up (2.5%) + ### mod Lennart + $self->start(lc($2), {}, 0, [], $1); + + } elsif ($$buf =~ s|^<||) { + # start tag + my $eaten = '<'; + + # This first thing we must find is a tag name. RFC1866 says: + # A name consists of a letter followed by letters, + # digits, periods, or hyphens. The length of a name is + # limited to 72 characters by the `NAMELEN' parameter in + # the SGML declaration for HTML, 9.5, "SGML Declaration + # for HTML". In a start-tag, the element name must + # immediately follow the tag open delimiter `<'. + if ($$buf =~ s|^(([a-zA-Z][a-zA-Z0-9\.\-]*)\s*)||) { + $eaten .= $1; + my $tag = lc $2; + my %attr; + my @attrseq; + + # Then we would like to find some attributes + # + # Arrgh!! Since stupid Netscape violates RCF1866 by + # using "_" in attribute names (like "ADD_DATE") of + # their bookmarks.html, we allow this too. + while ($$buf =~ s|^(([a-zA-Z][a-zA-Z0-9\.\-_]*)\s*)||) { + $eaten .= $1; + my $attr = lc $2; + my $val; + # The attribute might take an optional value (first we + # check for an unquoted value) + if ($$buf =~ s|(^=\s*([^\"\'>\s][^>\s]*)\s*)||) { + $eaten .= $1; + $val = $2; + HTML::Entities::decode($val); + # or quoted by " or ' + } elsif ($$buf =~ s|(^=\s*([\"\'])(.*?)\2\s*)||s) { + $eaten .= $1; + $val = $3; + HTML::Entities::decode($val); + # truncated just after the '=' or inside the attribute + } elsif ($$buf =~ m|^(=\s*)$| or + $$buf =~ m|^(=\s*[\"\'].*)|s) { + $$buf = "$eaten$1"; + last TOKEN; + } else { + # assume attribute with implicit value + $val = $attr; + } + $attr{$attr} = $val; + push(@attrseq, $attr); + } + + # At the end there should be a closing ">" +### Modified for <tag />, Lennart + if ($$buf =~ s|^/>||) { + $self->start($tag, \%attr, 1, \@attrseq, "$eaten>"); + } elsif ($$buf =~ s|^>||) { + #if ($$buf =~ s|^>||) { + $self->start($tag, \%attr, 0, \@attrseq, "$eaten>"); + } elsif (length $$buf) { + # Not a conforming start tag, regard it as normal text + $self->text($eaten); + } else { + $$buf = $eaten; # need more data to know + last TOKEN; + } + + } elsif (length $$buf) { + $self->text($eaten); + } else { + $$buf = $eaten . $$buf; # need more data to parse + last TOKEN; + } + + } else { + #die if length($$buf); # This should never happen + last TOKEN; # The buffer should be empty now + } + } + + $self; +} + + +sub eof +{ + shift->parse(undef); +} + + +sub parse_file +{ + my($self, $file) = @_; + no strict 'refs'; # so that a symbol ref as $file works + local(*F); + unless (ref($file) || $file =~ /^\*[\w:]+$/) { + # Assume $file is a filename + open(F, $file) || die "Can't open $file: $!"; + $file = \*F; + } + my $chunk = ''; + while(read($file, $chunk, 512)) { + $self->parse($chunk); + } + close($file); + $self->eof; +} + + +sub strict_comment +{ + my $self = shift; + my $old = $self->{'_strict_comment'}; + $self->{'_strict_comment'} = shift if @_; + return $old; +} + + +sub netscape_buggy_comment # legacy +{ + my $self = shift; + my $old = !$self->strict_comment; + $self->strict_comment(!shift) if @_; + return $old; +} + + +sub text +{ + # my($self, $text) = @_; +} + +sub declaration +{ + # my($self, $decl) = @_; +} + +sub comment +{ + # my($self, $comment) = @_; +} + +sub start +{ +die "hie"; + # my($self, $tag, $attr, $attrseq, $origtext) = @_; + # $attr is reference to a HASH, $attrseq is reference to an ARRAY +} + +sub end +{ + # my($self, $tag, $origtext) = @_; +} + +1; + + +__END__ + + +=head1 NAME + +HTML::Parser - SGML parser class + +=head1 SYNOPSIS + + require HTML::Parser; + $p = HTML::Parser->new; # should really a be subclass + $p->parse($chunk1); + $p->parse($chunk2); + #... + $p->eof; # signal end of document + + # Parse directly from file + $p->parse_file("foo.html"); + # or + open(F, "foo.html") || die; + $p->parse_file(\*F); + +=head1 DESCRIPTION + +The C<HTML::Parser> will tokenize an HTML document when the parse() +method is called by invoking various callback methods. The document to +be parsed can be supplied in arbitrary chunks. + +The external interface the an I<HTML::Parser> is: + +=over 4 + +=item $p = HTML::Parser->new + +The object constructor takes no arguments. + +=item $p->parse( $string ); + +Parse the $string as an HTML document. Can be called multiple times. +The return value is a reference to the parser object. + +=item $p->eof + +Signals end of document. Call eof() to flush any remaining buffered +text. The return value is a reference to the parser object. + +=item $p->parse_file( $file ); + +This method can be called to parse text from a file. The argument can +be a filename or an already opened file handle. The return value from +parse_file() is a reference to the parser object. + +=item $p->strict_comment( [$bool] ) + +By default we parse comments similar to how the popular browsers (like +Netscape and MSIE) do it. This means that comments will always be +terminated by the first occurrence of "-->". This is not correct +according to the "official" HTML standards. The official behaviour +can be enabled by calling the strict_comment() method with a TRUE +argument. + +The return value from strict_comment() is the old attribute value. + +=back + + + +In order to make the parser do anything interesting, you must make a +subclass where you override one or more of the following methods as +appropriate: + +=over 4 + +=item $self->declaration($decl) + +This method is called when a I<markup declaration> has been +recognized. For typical HTML documents, the only declaration you are +likely to find is <!DOCTYPE ...>. The initial "<!" and ending ">" is +not part of the string passed as argument. Comments are removed and +entities will B<not> be expanded. + +=item $self->start($tag, $attr, $attrseq, $origtext) + +This method is called when a complete start tag has been recognized. +The first argument is the tag name (in lower case) and the second +argument is a reference to a hash that contain all attributes found +within the start tag. The attribute keys are converted to lower case. +Entities found in the attribute values are already expanded. The +third argument is a reference to an array with the lower case +attribute keys in the original order. The fourth argument is the +original HTML text. + + +=item $self->end($tag, $origtext) + +This method is called when an end tag has been recognized. The +first argument is the lower case tag name, the second the original +HTML text of the tag. + +=item $self->text($text) + +This method is called when plain text in the document is recognized. +The text is passed on unmodified and might contain multiple lines. +Note that for efficiency reasons entities in the text are B<not> +expanded. You should call HTML::Entities::decode($text) before you +process the text any further. + +A sequence of text in the HTML document can be broken between several +invocations of $self->text. The parser will make sure that it does +not break a word or a sequence of spaces between two invocations of +$self->text(). + +=item $self->comment($comment) + +This method is called as comments are recognized. The leading and +trailing "--" sequences have been stripped off the comment text. + +=back + +The default implementation of these methods do nothing, i.e., the +tokens are just ignored. + +There is really nothing in the basic parser that is HTML specific, so +it is likely that the parser can parse other kinds of SGML documents. +SGML has many obscure features (not implemented by this module) that +prevent us from renaming this module as C<SGML::Parser>. + +=head1 EFFICIENCY + +The parser is fairly inefficient if the chunks passed to $p->parse() +are too big. The reason is probably that perl ends up with a lot of +character copying when tokens are removed from the beginning of the +strings. A chunk size of about 256-512 bytes was optimal in a test I +made with some real world HTML documents. (The parser was about 3 +times slower with a chunk size of 20K). + +=head1 SEE ALSO + +L<HTML::Entities>, L<HTML::TokeParser>, L<HTML::Filter>, +L<HTML::HeadParser>, L<HTML::LinkExtor> + +L<HTML::TreeBuilder> (part of the I<HTML-Tree> distribution) + +=head1 COPYRIGHT + +Copyright 1996-1999 Gisle Aas. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +=cut + + diff --git a/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/datadir.txt b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/datadir.txt new file mode 100644 index 0000000..1ba751d --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/HTML/datadir.txt @@ -0,0 +1 @@ +C:/TEMP/i2data diff --git a/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/PathSubs.pm b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/PathSubs.pm new file mode 100644 index 0000000..e95b8d5 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-chklnk/PerlLib/PathSubs.pm @@ -0,0 +1,207 @@ +# Copyright 2006 Lennart Borgman, http://OurComments.org/. All rights +# reserved. +# +# 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 3, 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. + +package PathSubs; + +##################################################### +### This package contains general path handling +### routines and some win32 specific dito. +### The latter should ev be moved to a new module! +##################################################### +use strict; + +use File::Spec; + +### Absolute path names + +sub is_abs_path ($) { + my $path = shift; + return 0 if $path eq ""; + return 1 if File::Spec->file_name_is_absolute($path); + #return 1 if substr($path, 1, 1) eq ":"; # MSWin32 + #return 1 if substr($path, 0, 1) eq "/"; + return 1 if $path =~ /^https?:/i; + return 1 if $path =~ /^file:/i; + return 1 if $path =~ /^javascript:/i; + return 1 if $path =~ /^mailto:/i; +} +sub is_abs_netpath($) { + my $path = shift; + return 1 if $path =~ /^https?:/i; + # New + return 1 if $path =~ /^ftp:/i; + return 1 if $path =~ /^mailto:/i; +} + + +sub uniq_file($) { + my $fname = shift; + $fname =~ s!^\s+|\s+$!!g; + return "" if ($fname eq ""); + $fname = File::Spec->rel2abs($fname); + if (!File::Spec->file_name_is_absolute($fname)) { + die "File name is not absolute: $fname"; + } + #print STDERR "uniq_file($fname)\n"; + $fname =~ tr!\\!/!; + if (-e $fname) { + #print STDERR "exists $fname\n"; + ### There is an error in 522, compensate for this! + #die substr($fname, -1); + if (substr($fname, -1) eq "/") { chop $fname; } + #print STDERR "exists $fname\n"; + ### Translate .. + if (substr($fname, 1, 1) eq ":") { + my $ffname = Win32::GetFullPathName($fname); + ### Get case + my $lfname = Win32::GetLongPathName($ffname); + #print STDERR "lexists $lfname\n"; + $fname = $lfname if ($lfname ne ""); + } + } else { + #print STDERR "NOT exists $fname\n"; + if (substr($fname, -1) eq "/") { chop $fname; } + my $head = ""; + if (substr($fname, 0, 2) eq "//") { + $head = "//"; + $fname = substr($fname, 2); + } + my @fname = split("/", $fname); + my $tail = pop @fname; + $fname = uniq_dir($head . join("/", @fname)) . $tail; + } + if (substr($fname, 1, 1) eq ":") { + $fname = uc(substr($fname, 0, 1)) . substr($fname, 1); + #print STDERR "fname $fname\n"; + } + $fname =~ tr!\\!/!; + #print STDERR "fname ($fname)\n"; + return $fname; +} +sub uniq_dir($) { + my $dir = shift; + my $uq_dir = uniq_file($dir); + if (substr($uq_dir, -1) ne "/") { $uq_dir .= "/"; } + return $uq_dir; +} + + + +### Relative paths +sub _get_link_root($) { + my $lnk = shift; + if ($lnk =~ m!^(/|ftp://[^/]*|https?://[^/]*|[a-z]:/)!i) { + return $1; + } else { + return ""; + } +} + +sub resolve_dotdot($) { + my $orig_url = shift; + my $root = _get_link_root($orig_url); + return $orig_url if length($root) == length($orig_url); + my $url = substr($orig_url, length($root)); + if (substr($root, -1) eq "/") { + chop $root; + $url = "/$url"; + } + #die "$root\n$url"; + my $iPosSearch = 2; + #print "url=$url\n"; + while ((my $iPos = index($url, "/../", $iPosSearch)) > -1) { + my $sLeft = substr($url, 0, $iPos); + if (substr($sLeft, -2) eq "..") { + $iPosSearch += 3; + next; + } + my $sRight = substr($url, $iPos+3); + #print "url=$url\n"; + #print "iPos=$iPos\n"; + #print "sLeft=$sLeft\n"; + $sLeft =~ s!/[^/]*$!!; + #print "sLeft=$sLeft\n"; + #print "sRight=$sRight\n"; + $url = $sLeft . $sRight; + #print "\t***url=$url\n"; + #print "url=$url\n"; + } + if (index($url, "../") > -1) { + return $orig_url; + } + return $root . $url; +} + +sub mk_relative_link($$;$) { + my $from = shift; + my $to = shift; + my $norm = shift; + if ($norm) { + $from = uniq_file($from); + $to = uniq_file($to); + } + if (-e $from) { + $from = uniq_file($from); + } else { + $from = resolve_dotdot($from); + } + if (-e $to) { + $to = uniq_file($to); + } else { + $to = resolve_dotdot($to); + } + my $root_from = _get_link_root($from); + my $root_to = _get_link_root($to ); + if ($root_from ne $root_to) { + return $to; + } + my @from = split "/", $from; + my @to = split "/", $to; + while (@to) { + last if ($to[0] ne $from[0]); + shift @to; + shift @from; + } + if (@to == 1 && @from == 1) { + if (length($to[0]) > length($from[0])) { + if (substr($to[0], 0, length($from[0])+1) eq ($from[0] . "#")) { + return substr($to[0], length($from[0])); + } + } + } + my $rl; + for (1..$#from) { $rl .= "../"; } + $rl .= join("/", @to); + + return $rl; +} + + + +sub mk_absolute_link($$) { + my $from = shift; + my $rel_to = shift; + my $abs = $from; + $abs =~ s![^/]*$!!; + $abs .= $rel_to; + if (!is_abs_netpath($abs)) { $abs = uniq_file($abs); } + $abs; +} + + +1; diff --git a/emacs/nxhtml/nxhtml/html-chklnk/link_checker.pl b/emacs/nxhtml/nxhtml/html-chklnk/link_checker.pl new file mode 100644 index 0000000..0925b1c --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-chklnk/link_checker.pl @@ -0,0 +1,328 @@ +#! perl + +# Copyright 2006, 2007 Lennart Borgman, http://OurComments.org/. All +# rights reserved. +# +# 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. + +use strict; +use warnings; + +use IO::File; +use File::Spec; +use File::Find; + +sub check_file($); + +############################# +### Collecting info +############################# +my $m_site_dir; # Site root directory (every file should be in this) +my %m_CheckedFiles; +my %m_FilesToCheck; +my %m_MissedFiles; +my $m_errors_found; + +sub tell_bad_link($$$$$) { + my $what = shift; + my $file = shift; + my $lnum = shift; + my $link = shift; + my $line = shift; + $line =~ s/^\s+|\s+$//g; + $m_CheckedFiles{$file}->{"ERR"}->{$lnum} = "$what\n Link: \"$link\"\n"; + #$line"; +} + +############################# +### Helpers +############################# +sub add_file_to_check($) { + $m_FilesToCheck{File::Spec->canonpath(shift)} = 1; +} +# sub full_uq_file($) { +# my $file = shift; +# my $full_file = $file; +# if (! File::Spec->file_name_is_absolute($full_file)) { +# #$full_file = Win32::GetFullPathName($file); +# $full_file = File::Spec->rel2abs($full_file, $m_site_dir); +# } +# if (($^O eq "MSWin32") || ($^O eq "cygwin")) { +# $full_file =~ tr!A-Z!a-z!; +# } +# #print "ull_uq_file: full_file=$file\n"; +# return $full_file; +# } + +############################# +### Checks +############################# +sub check_next_file() { + if (scalar(keys %m_FilesToCheck) > 0) { + my @FilesToCheck = sort keys %m_FilesToCheck; + my $next_file = $FilesToCheck[0]; + delete $m_FilesToCheck{$next_file}; + check_file($next_file); + } +} +sub not_a_local_file($) { + my $url = shift; + ( + $url =~ m!^javascript:! + || + $url =~ m!^mailto:! + || + $url =~ m!^[a-z]+://! + ); +} + +sub check_file($) { + my $fname = shift; + if (! File::Spec->file_name_is_absolute($fname)) { + die "check_file: File is not abs: $fname"; + } + my $only_name = (File::Spec->splitpath($fname))[2]; + print "Checking $fname ... "; + sleep 0.5; + $m_CheckedFiles{$fname} = {}; + my %links; + my %anchs; + my %lines; + my $fh = new IO::File($fname); + die "Can't read $fname: $!\n" unless defined $fh; + my $whole; + my $n; + my $found_errors = 0; + while (my $line = <$fh>) { + $n++; + chomp $line; + $whole = $line; + while ($whole =~ m!(?:\s|^)id="(.*?)"!g) { + $anchs{$1} = $n; + $lines{$n} = $line; + } + while ($whole =~ m!(?:\s|^)name="(.*?)"!g) { + $anchs{$1} = $n; + $lines{$n} = $line; + } + while ($whole =~ m!(?:\s|^)href="(.*?)"!g) { + my $l = $1; + next if not_a_local_file($l); + if ($l =~ m!^#!) { + $l = $only_name . $l; + } + $links{$l} = $n; + $lines{$n} = $line; + } + while ($whole =~ m!(?:\s|^)src="(.*?)"!g) { + my $l = $1; $l =~ tr!A-Z!a-z!; + $links{$l} = $n; + $lines{$n} = $line; + } + } + $fh->close(); + $m_CheckedFiles{$fname}->{ANC} = \%anchs; + my ($fv, $fd, $ff) = File::Spec->splitpath($fname); + my $fdir = File::Spec->catpath($fv, $fd, ""); + for my $link (sort keys %links) { + # Next line is for onclick lines + next if ($link eq "#"); + my $lnum = $links{$link}; + my $line = $lines{$lnum}; + if ($link eq "") { + tell_bad_link("empty link", $fname, $lnum, $link, $line); + $found_errors = 1; + next; + } + if ($link =~ m!(.*)\?!) { $link = $1; } + my $anchor; + if ($link =~ m!(.*)#(.*)!) { $link = $1; $anchor = $2; } + if ($link eq "") { + if (!exists $anchs{$anchor}) { + tell_bad_link("bad internal anchor ref ($anchor)", $fname, $lnum, $link, $line); + $found_errors = 1; + } + next; + } + $link =~ m!([^\.]*)$!; + my $link_file_type = $1; + my $subfile = $link; + if (!File::Spec->file_name_is_absolute($subfile)) { + $subfile = File::Spec->catpath($fv, $fd, $link); + } + $subfile = File::Spec->canonpath($subfile); + die "Contained .." if $subfile =~ m/\.\./; + next if (exists $m_MissedFiles{$subfile}); + if (! -r $subfile) { + tell_bad_link("Can't read linked file: $!", $fname, $lnum, $link, $line); + $found_errors = 1; + $m_MissedFiles{$subfile} = 1; + next; + } + next unless $link_file_type =~ m!^html?$!i; + if (defined $anchor) { + $m_CheckedFiles{$fname}->{EXTANC}->{$subfile} = + { ANC=> $anchor, LINE=>$line, LNUM=>$lnum}; + } + next if (exists $m_CheckedFiles{$subfile}); + #check_file($subfile); + my $rel_root = File::Spec->abs2rel($subfile, $m_site_dir); + if (substr($rel_root, 0, 2) eq "..") { + tell_bad_link("Reference to file outside site", $fname, $lnum, $link, $line); + $found_errors = 1; + } else { + #$m_FilesToCheck{$subfile} = 1; + add_file_to_check($subfile); + } + } + if ($found_errors) { + print "Errors found\n"; + } else { + print "Ok\n"; + } + sleep 0.5; + check_next_file(); +} # check_file + + +sub check_external_anchors() { + for my $f (sort keys %m_CheckedFiles) { + my $fnode = $m_CheckedFiles{$f}; + if (exists ${$fnode}{"EXTANC"}) { + my $extanc_hash = ${$fnode}{"EXTANC"}; + for my $fx (keys %$extanc_hash) { + next unless (exists $m_CheckedFiles{$fx}); + my $ea_hash = ${$extanc_hash}{$fx}; + my $ea = ${$ea_hash}{ANC}; + my $fxnode = $m_CheckedFiles{$fx}; + my $fx_anc_hash = ${$fxnode}{"ANC"}; + if (!exists ${$fx_anc_hash}{$ea}) { + my $line = ${$ea_hash}{LINE}; + my $lnum = ${$ea_hash}{LNUM}; + tell_bad_link("Hash not found", $f, $lnum, "$fx#$ea", $line); + } + } + } + } +} # check_external_anchors + + + +############################# +### Reporting +############################# +sub report_errors() { + for my $f (sort keys %m_CheckedFiles) { + my $fnode = $m_CheckedFiles{$f}; + if (exists ${$fnode}{"ERR"}) { + if (!defined $m_errors_found) { + $m_errors_found = 1; + print "\n\n*********** Error details: **********\n"; + sleep 0.5; + } + #print "\n$f"; + my $err_hash = ${$fnode}{"ERR"}; + for my $e (sort keys %$err_hash) { + print "\n$f"; + print " at line $e:\n " . ${$err_hash}{$e} . "\n"; + sleep 0.5; + } + } + } + if ($m_errors_found) { + die "\n*** There where errors ***\n"; + } else { + print "Everything that was checked is ok\n"; + } +} # report_errors + +############################# +### Help +############################# +sub usage() { + die "Usage: $0 --site=SITE-DIR --start=START-FILE\n"; +} + +############################# +### Parameters +############################# +#my $m_start_file; # File to start checking in +sub get_params() { + usage() unless $#ARGV > -1; + for (my $i = 0; $i <= $#ARGV; $i++) { + my ($k, $v) = ($ARGV[$i] =~ m!-?-?(.*?)=(.*)!); + if ($k eq "site") { + $m_site_dir = $v; + } elsif( $k eq "start") { + #$m_FilesToCheck{$v} = 1; + add_file_to_check($v); + } else { + print STDERR "Unknown parameter: $ARGV[$i]\n"; + usage(); + } + } + foreach my $key (keys %m_FilesToCheck) { + die "Can't find $key\n" unless -e $key; + } + if (! $m_site_dir) { + print STDERR "No site directory given\n"; + usage(); + } + die "Can't find $m_site_dir\n" unless -d $m_site_dir; + if ((scalar keys %m_FilesToCheck) == 0) { + my $add_files = + sub { + return unless m/.html?$/i; + return if -d $_; + #$m_FilesToCheck{$File::Find::name} = 1; + add_file_to_check($File::Find::name); + }; + File::Find::find($add_files, $m_site_dir); + } +} + +sub check_canonpath() { + my $testpath = "/test/../some.txt"; + if ($testpath eq File::Spec->canonpath($testpath)) { + my $errmsg = <<_BADCANON_ + +** Fatal Error: + + File::Spec->canonpath does not clean up path. + + If you are doing this from Emacs with html-chklnk-check-site-links + it may be because you are using Cygwin as your shell. You can cure + this in the following ways: + + 1) Use w32shell.el - this will temporary switch to "cmd" as shell. + 2) Use the default shell on w32. + +_BADCANON_ +; + + die $errmsg; + } +} + +############################# +### Main +############################# + +check_canonpath(); + +$| = 1; # flush or blush! + +print "\n"; +get_params(); + +check_next_file(); +check_external_anchors(); +report_errors(); diff --git a/emacs/nxhtml/nxhtml/html-imenu.el b/emacs/nxhtml/nxhtml/html-imenu.el new file mode 100644 index 0000000..2df1760 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-imenu.el @@ -0,0 +1,101 @@ +;;; html-imenu --- imneu suport for html modes +;; +;; This is a slightly modified version of +;; html-helper-imenu.el. This version comes with nXhtml. +(defconst html-imenu:version "0.9") ;;Version: +;; Last-Updated: 2008-09-30T19:22:05+0200 Tue +;; +;; ~/share/emacs/pkg/html/html-helper-imenu.el --- +;; +;; $Id: html-helper-imenu.el,v 1.11 2004/03/23 07:39:37 harley Exp $ +;; + +;; Author: Harley Gorrell <harley@panix.com> +;; URL: http://www.mahalito.net/~harley/elisp/html-helper-imenu.el +;; License: GPL v2 +;; Keywords: html-helper, imenu, html, table of contents + +;;; Commentary: +;; * Adds an indented table of contents to the menubar +;; * The regexp only matches headers on a single line +;; and well formed tags. (Which is pretty common.) +;; +;; Put somthing like the following in your .emacs: +;; (autoload 'html-helper-imenu-setup "html-helper-imenu") +;; (add-hook 'html-helper-mode-hook 'html-helper-imenu-setup) +;; +;; While this was originaly written for html-helper, +;; It will work with sgml-mode and others. +;; +;; http://www.santafe.edu/~nelson/hhm-beta/html-helper-mode.el + +;;; History: +;; +;; 1998-06-25 : added regexp +;; 2003-03-18 : updated contact info +;; 2004-03-22 : minor clean up +;; 2007-11-23 : changed setup function to do nothing if done already + +;;; Code: + +(eval-when-compile (require 'imenu)) + +(defvar html-imenu-title "Index" + "*Title of the menu which will be added to the menubar.") + +(defvar html-imenu-regexp + "\\s-*<h\\([1-9]\\)[^\n<>]*>\\(<[^\n<>]*>\\)*\\s-*\\([^\n<>]*\\)" + "*A regular expression matching a head line to be added to the menu. +The first `match-string' should be a number from 1-9. +The second `match-string' matches extra tags and is ignored. +The third `match-string' will be the used in the menu.") + +;; Make an index for imenu +(defun html-imenu-index () + "Return an table of contents for an html buffer for use with Imenu." + (let ((space ?\ ) ; a char + (toc-index '()) + toc-str) + (save-excursion + (goto-char (point-min)) + (save-match-data + (while (re-search-forward html-imenu-regexp nil t) + (setq toc-str + (concat + (make-string + (* 6 (- (string-to-number (match-string 1)) 1)) + space) + (match-string 3))) + (beginning-of-line) + (setq toc-index (cons (cons toc-str (point)) toc-index)) + (end-of-line)))) + (nreverse toc-index))) + +(defun html-imenu-setup () + "Setup the variables to support imenu." + (interactive) + ;; Fix-me: It looks like this function has to be called every time + ;; switching to some html mode in mumamo. Values are "survived" by + ;; mumamo, but the menu item disappears. + ;;(message "html-imenu-setup imenu-create-index-function =%s" imenu-create-index-function) + (unless nil ;(eq imenu-create-index-function 'html-imenu-index) + (setq imenu-create-index-function 'html-imenu-index) + (set (make-local-variable 'imenu-sort-function) nil) ; sorting the menu defeats the purpose + (imenu-add-to-menubar html-imenu-title) + ;; Run an update to make it easier to access the menubar + ;;(run-with-idle-timer 5 nil 'html-imenu-update-menubar (current-buffer)) + )) + +(defun html-imenu-update-menubar (buffer) + (condition-case err + (html-imenu-update-menubar-1 buffer) + (error (message "html-imenu-update-menubar error: %s" err)))) + +(defun html-imenu-update-menubar-1 (buffer) + (with-current-buffer buffer + (message "HTML Imenu: update menubar...") + (imenu-update-menubar) + (message ""))) + +(provide 'html-imenu) +;;; html-imenu ends here diff --git a/emacs/nxhtml/nxhtml/html-move.el b/emacs/nxhtml/nxhtml/html-move.el new file mode 100644 index 0000000..4fadf71 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-move.el @@ -0,0 +1,251 @@ +;;; html-move.el --- Move a file in a local file web site. +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Thu Jan 12 08:11:30 2006 +(defconst html-move:version "0.31") ;; Version: +;; Last-Updated: Tue Feb 20 23:59:43 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;;DO NOT USE YET! +;; +;; Functions for moving a file in a local file web site. Moves the +;; file and fixes the local affected links after the move. +;; +;; To use this file you may in your .emacs put +;; +;; (require 'html-move) +;; +;; Call the function `html-move-buffer-file' to move a file. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (add-to-list 'load-path default-directory load-path)) +(eval-when-compile (require 'html-site nil t)) +(require 'url-parse) + +(defun html-move-make-new-url (old-url from-dir to-dir) + "Make new relative url. +If OLD-URL is an absolute path then return it. Otherwise OLD-URL +is assumed to be relative FROM-DIR. Return a new url relative +TO-DIR that gives the same absolute path." + (if (or (file-name-absolute-p old-url) + (char-equal ?# (string-to-char old-url)) + (let ((urlobj (url-generic-parse-url old-url))) + (url-host urlobj))) + (progn + nil) + (let* ( + (relative-path (file-relative-name from-dir to-dir)) + (new-abs-url (expand-file-name (concat relative-path old-url) to-dir)) + (new-url (file-relative-name new-abs-url to-dir))) + new-url))) + + +(defun html-move-in-dir-tree (file tree) + (let ((rel-path (file-relative-name file tree))) + (or (string= "." rel-path) + (not (string= ".." (substring rel-path 0 2)))))) + +(defun html-move-buffer-file (to) + "Move current buffer file to another directory and/or name. +Correct the affected relative links in the moved file and the +links to the file moved in the directory tree +`html-site-current-site-dir'." + ;;(interactive "GMove to: ") + (interactive + (let* ((use-dialog-box nil) + (name (read-file-name "Move to (directory or file name): " + )) + ) + (list (expand-file-name name)))) + (html-site-current-ensure-site-defined) + (let ((from (buffer-file-name)) + (site-directory (html-site-current-site-dir))) + (unless from + (error "No buffer file name, can't move file!")) + (let* ((from-dir (file-name-directory from)) + (from-ext (file-name-extension from)) + to-dir + to-ext + new-name + new-file + new-buffer + relative-path) + (unless (html-move-in-dir-tree from-dir site-directory) + (error "Buffer file is not in site directory tree")) + (if (file-directory-p to) + (progn + (setq to-dir to) + (setq new-name (file-name-nondirectory from)) + ) + (setq to-ext (file-name-extension to)) + (unless (string= to-ext from-ext) + (if (not to-ext) + (error "Can't find directory %s (or missing extension?)" to) + (error "Move must not change file extension"))) + (setq to-dir (file-name-directory to)) + (unless (file-directory-p to-dir) + (if (file-exists-p to-dir) + (error "Not a directory: %s" to-dir) + (error "Can't find directory %s" to-dir))) + (setq new-name (file-name-nondirectory to)) + ) + + (unless (html-move-in-dir-tree to-dir site-directory) + (error "Target is not in site directory tree")) + + + (setq relative-path (file-relative-name to-dir from-dir)) + (when (file-name-absolute-p relative-path) + (error "Can't make a relative path from %s to %s" from to)) + (setq new-file (expand-file-name new-name to)) + (let ((moved-buffer (current-buffer)) + (moved-contents (buffer-substring-no-properties + (point-min) + (point-max)))) + (when (file-exists-p new-file) + (error "File already exists: %s" new-file)) + ;; Open in new location + (find-file new-file) + (setq new-buffer (current-buffer)) + (erase-buffer) + (insert moved-contents) + (goto-char (point-min)) + (while (re-search-forward "\\(?:href\\|src\\)\\s-*=\\s-*\"\\([^\"]*\\)\"" nil t) + (let ((old-url (match-string 1)) + (new-url)) + (unless (or (> 11 (length old-url)) + (string= "javascript:" + (downcase (substring old-url 0 11)))) + (setq new-url (html-move-make-new-url old-url from-dir to-dir)) + (when new-url + (replace-match new-url t t nil 1))))) + (save-buffer) + (html-move-fix-site-backlinks from to-dir from-dir) + ;; Make backup at current location of "from" file + (with-current-buffer moved-buffer + (set-buffer-modified-p t) + (save-buffer)) + (kill-buffer moved-buffer) + ;; Delete moved + (delete-file from)) + (set-buffer new-buffer) + (goto-char (point-min)) + (lwarn '(html-move) :warning "Moved to %s" new-file) + ))) + +(defun html-move-fix-site-backlinks (to-moved-file to-dir from-dir) + "Fix all links back to TO-MOVED-FILE. +This is called by `html-move-buffer-file' to fix all links back +to the moved file. TO-MOVED-FILE is the old location of the +moved file. FROM-DIR is the old directory and TO-DIR the target +directory for the move." + (html-move-fix-all-backlinks to-moved-file (html-site-current-site-dir) to-dir from-dir) + (when (html-move-fix-page-list to-moved-file to-dir from-dir) + (message "Page list for site TOC changed. You need to update TOC.") + (lwarn '(html-move-fix-site-backlinks) :warning "Page list for site TOC changed. You need to update TOC.") + )) + +(defun html-move-fix-all-backlinks (to-moved-file for-dir to-dir from-dir) + ;;(message "for-dir=%s" for-dir);(sit-for 2) + (let ((html-files (directory-files for-dir t ".*\\.html?$")) + (sub-dirs (directory-files-and-attributes for-dir t))) + (dolist (html-file html-files) + (html-move-fix-backlinks to-moved-file html-file to-dir from-dir)) + (dolist (sub-entry sub-dirs) + (let* ((sub-dir (car sub-entry)) + (sub-name (file-name-nondirectory sub-dir))) + (when (and (eq t (car (cdr sub-entry))) + (not (string= "." sub-name)) + (not (string= ".." sub-name))) + (html-move-fix-all-backlinks to-moved-file sub-dir to-dir from-dir)))))) + +(defun html-move-fix-backlinks (to-moved-file for-file to-dir from-dir) + (when (file-exists-p for-file) + (let ((old-file-buffer (get-file-buffer for-file)) + (buffer (find-file-noselect for-file))) + (with-current-buffer buffer + (goto-char (point-min)) + (while + (re-search-forward + "\\(?:href\\|src\\)\\s-*=\\s-*\"\\([^#\"]*\\)\\(?:#[^\"]*\\|\\)\"" + nil t) + (let* ((old-url (match-string 1)) + (old-absolute-url (expand-file-name + old-url + (file-name-directory for-file))) + new-url) + (when (string= old-absolute-url to-moved-file) + (setq new-url (html-move-make-new-url old-url to-dir from-dir)) + ;;(message "new-backlink=%s" new-url);(sit-for 2) + (replace-match new-url t t nil 1) + ))) + (save-buffer) + (unless old-file-buffer + (kill-this-buffer)))))) + +(defun html-move-fix-page-list (to-moved-file to-dir from-dir) + (let ((for-file (html-site-current-page-list)) + some-change) + (when (file-exists-p for-file) + (let ((old-file-buffer (get-file-buffer for-file)) + (buffer (find-file-noselect for-file))) + (with-current-buffer buffer + (goto-char (point-min)) + (while + (re-search-forward + ;;"\\(?:href\\|src\\)\\s-*=\\s-*\"\\([^#\"]*\\)\\(?:#[^\"]*\\|\\)\"" + "\\s-+###\\s-+\\([^#]*?\\)\\(?:#[^#]*\\|\\)[:space:]*$" + nil t) + (let* ((old-url (match-string 1)) + (old-absolute-url (expand-file-name + old-url + (file-name-directory for-file))) + new-url) + (when (string= old-absolute-url to-moved-file) + (setq new-url (html-move-make-new-url old-url to-dir from-dir)) + ;;(message "new-backlink=%s" new-url);(sit-for 2) + (replace-match new-url t t nil 1) + (setq some-change t) + ))) + (save-buffer) + (unless old-file-buffer + (kill-this-buffer))))) + some-change)) + +(provide 'html-move) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-move.el ends here diff --git a/emacs/nxhtml/nxhtml/html-pagetoc.el b/emacs/nxhtml/nxhtml/html-pagetoc.el new file mode 100644 index 0000000..adcdcb7 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-pagetoc.el @@ -0,0 +1,336 @@ +;;; html-pagetoc.el --- Insert/rebuild table of contents for html page +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2005-08-03 +;; Last-Updated: Sat Apr 21 14:11:13 2007 (7200 +0200) +(defconst html-pagetoc:version "0.85") ;; Version: +;; Keywords: tools hypermedia html +;; Features that might be required by this library: +;; +;; None +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This file is not part of 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 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: + +;; html-pagetoc.el has functions for building (and rebuilding) a +;; simple table of contents for a single html file. It is supposed to +;; be a quick tool for this. The table of contents are made from the +;; header tags (H1, H2, H3 etc). If you have ID attributes on the +;; header the table of contents will have links to those. Otherwise it +;; is just text. + +;; To use this module put it in emacs load-path and enter the line +;; below in your .emacs: +;; +;; (require 'html-pagetoc) +;; +;; When editing a html file put your cursor where you want the table +;; of contents and do M-x html-pagetoc-insert-toc. +;; +;; To rebuild the table of contents use M-x html-pagetoc-rebuild-toc. +;; If you want to add styles to it you can use M-x +;; html-pagetoc-insert-style-guide. +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;(define-key global-map [f2] 'eval-buffer) +;;(define-key global-map [f3] 'html-pagetoc-insert-toc) + +;;;###autoload +(defgroup html-pagetoc nil + "Html page local table of contents settings" + :group 'nxhtml + :group 'hypermedia) + +(defcustom html-pagetoc-tocheads + '( + ("" . "On THIS Page:") + ) + "Head titles for table of contents. +The titles are put above the table of contents. + +The value of this variable should be a list of cons cells where +the car is a regexp to match against file names and the cdr is +the head title to use. The first match in the list is used. If +there is no match then no head title is inserted." + :type '(repeat (cons regexp string)) + :group 'html-pagetoc) + +(defcustom html-pagetoc-min 1 + "Default for min header level" + :type 'integer + :group 'html-pagetoc) +(make-variable-buffer-local 'html-pagetoc-min) + +(defcustom html-pagetoc-max 3 + "Default for max header level" + :type 'integer + :group 'html-pagetoc) +(make-variable-buffer-local 'html-pagetoc-max) + +(defconst html-pagetoc-begin-cmnt "<!-- Table of contents BEGIN -->\n") +(defconst html-pagetoc-end-cmnt "<!-- END of Table of contents -->\n") +(defconst html-pagetoc-maxmin-cmnt "<!-- Table of contents min=%s max=%s -->\n") + +;;(defconst html-pagetoc-buffers nil) + +(defun html-pagetoc-get-title (filename) + "Find the head title for filename. +See `html-pagetoc-tocheads'." + (when filename + (let ((ths html-pagetoc-tocheads) + th + re + header) + (while (and ths (not header)) + (setq th (car ths)) + (setq ths (cdr ths)) + (setq re (car th)) + (when (string-match re filename) + (setq header (cdr th)))) + header))) + +;;;###autoload +(defun html-pagetoc-insert-toc (&optional min-level max-level) + "Inserts a table of contents for the current html file. +The html header tags h1-h6 found in the file are inserted into +this table. MIN-LEVEL and MAX-LEVEL specifies the minimum and +maximum level of h1-h6 to include. They should be integers." + (interactive (let* ((maxstr) + (max 0) + (min 1) + (prmax (format "Max header level (%s): " html-pagetoc-max)) + (prmax2 (concat "Please give an integer 1-5. " prmax)) + (prmin "Include header level 1? ") + ) + (while (= max 0) + (setq maxstr (read-string prmax)) + (if (equal maxstr "") + (setq max html-pagetoc-max) + (when (not (string-match "\\." maxstr)) + (setq max (string-to-number maxstr)) )) + (when (> max 5) (setq max 0)) + (when (< max 0) (setq max 0)) + (setq prmax prmax2) ) + (when (> max 1) + (when (not (y-or-n-p prmin)) (setq min 2))) + (list min max))) + + (let* ((curr-buffer (current-buffer)) + (header (html-pagetoc-get-title (buffer-file-name))) + (toc-buffer (get-buffer-create "*html-pagetoc*")) + (toc) + (buffer-val (cons (buffer-file-name) (list min-level max-level))) + ) + (setq html-pagetoc-min min-level) + (setq html-pagetoc-max max-level) + (with-current-buffer toc-buffer (erase-buffer)) + (with-temp-buffer + (insert-buffer-substring curr-buffer) + ;;(replace-regexp "<!--.*?-->" "") + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "<!--.*?-->" nil t) + (replace-match "" nil nil)) + (goto-char (point-min)) + (let ((b (current-buffer)) + (standard-output toc-buffer) + (level (- min-level 1)) + (skip-level (- min-level 1)) + (prev-level) + ) + (princ html-pagetoc-begin-cmnt) + (princ (format + html-pagetoc-maxmin-cmnt + min-level + max-level)) + (princ "<table id=\"PAGETOC\"><tr><td>\n") + (when header + (princ "<span class=\"tochead\">") + (princ header) + (princ "</span>\n")) + (while (re-search-forward + (concat "\\(?:<h\\([1-9]\\)\\([^>]*\\)>\\(.*?\\)</h[1-9]>" + "\\|" + "<!--\\(?:.\\|\n\\)-->\\)") + nil t) + (let ((m0 (match-string 0)) + (m1 (match-string 1)) + (m2 (match-string 2)) + (title (match-string 3)) + (id) + (new-level) + ) + (unless (not m1) + (setq new-level (string-to-number m1)) + (when (and (<= new-level max-level) (<= min-level new-level)) + (setq prev-level level) + (setq level new-level) + (while (< prev-level level) + (princ (make-string (* (- prev-level skip-level) 4) 32)) + ;; class liul is a fix for a problem in IE + (when (> prev-level (- min-level 1)) (princ "<li class=\"liul\">")) + (princ "<ul>\n") + (setq prev-level (+ prev-level 1))) + (while (> prev-level level) + (princ (make-string (* (- prev-level skip-level) 4) 32)) + (princ "</ul></li>\n")(setq prev-level (- prev-level 1))) + (when (nth 3 (match-data t)) + (when (string-match "id=\"\\([^\"]*\\)\"" m2) + (setq id (substring m2 (match-beginning 1) (match-end 1))))) + (princ (make-string (* (- level skip-level) 4) 32)) + (princ "<li>") + (if id + (princ (format "<a href=\"#%s\">%s</a>" id title)) + (princ title)) + (princ "</li>\n") + )))) + (while (> level (- min-level 1)) + (setq level (- level 1)) + (princ (concat (make-string (* (- level skip-level) 4) 32) "</ul>")) + (when (> level (- min-level 1)) (princ "</li>")) + (princ "\n")) + (princ "</td></tr></table>\n") + (princ html-pagetoc-end-cmnt) + (with-current-buffer toc-buffer + (setq toc (buffer-string))) + ) + ) ; save-excursion + ) ; with-temp-buffer + (when toc + (when (re-search-forward "<body.*?>" nil t) + (forward-line)) + (set-mark (point)) + (insert toc) + (let ((start (copy-marker (region-beginning))) + (end (copy-marker (region-end)))) + (indent-region (region-beginning) (region-end) nil) + (set-mark start) + (goto-char end)) + (setq deactivate-mark nil) + (message "Toc created")) + ) + ) + +(defun html-pagetoc-insert-style-guide () + "Inserts a style tag for toc inserted by `html-pagetoc-insert-toc'. +This can be used as a guide for creating your own style sheet for +the table of contents." + (interactive) + (goto-char (point-min)) + (unless (re-search-forward "^\\s-*</head>") + (error "%s" "Can not find ^\\s-*</head>")) + (beginning-of-line) + (set-mark (point)) + (insert "\n") + (insert "<!-- Style for the table of contents. -->\n") + (insert "<style type=\"text/css\">\n") + (insert "#PAGETOC {\n") + (insert " background-color: #df7;\n") + (insert " padding: 0.5em;\n") + (insert "}\n") + ;;(insert "#PAGETOC strong { color: #ac4; }\n") + (insert "#PAGETOC a { color: maroon; display: block; }\n") + (insert "#PAGETOC a:hover { background-color: yellow; }\n") + (insert "#PAGETOC ul {\n") + (insert " list-style-type: none;\n") + (insert " margin-left: 0;\n") + (insert " padding-left: 1.5em;\n") + (insert "}\n") + (insert "#PAGETOC ul li { font-weight: bold; }\n") + (insert "#PAGETOC ul li ul { }\n") + (insert "#PAGETOC ul li ul li { font-weight: normal;}\n") + (insert "#PAGETOC .liul {\n") + (insert " //display:inline; /* IE fix */\n") + (insert "}\n") + (insert "#PAGETOC .tochead {\n") + (insert " font-weight: bold;\n") + (insert " margin-bottom: 0.5em;\n") + (insert "}\n") + (insert "</style>\n") + (insert "\n") + (let ((start (copy-marker (region-beginning))) + (end (copy-marker (region-end)))) + (indent-region (region-beginning) (region-end) nil) + (set-mark start) + (goto-char end)) + (setq deactivate-mark nil) + (message "Please edit the style guide!") + ) + +;;;###autoload +(defun html-pagetoc-rebuild-toc () + "Update the table of contents inserted by `html-pagetoc-insert-toc'." + (interactive) + (let* (;;(old-val (assoc (buffer-file-name) html-pagetoc-buffers)) + ;;(old-min (nth 1 old-val)) + ;;(old-max (nth 2 old-val)) + (old-min html-pagetoc-min) + (old-max html-pagetoc-max) + ) + (goto-char (point-min)) + (if (not (search-forward html-pagetoc-begin-cmnt nil t)) + (when (y-or-n-p "Could not find table of contents. Insert one here? ") + (html-pagetoc-insert-toc)) + (backward-char 4) + (beginning-of-line) + (let ((minmax-patt (format html-pagetoc-maxmin-cmnt "\\([[:alnum:]]+\\)" "\\([[:alnum:]]+\\)"))) + (save-excursion + (when (search-forward-regexp minmax-patt nil t) + (setq old-min (string-to-number (match-string 1))) + (setq old-max (string-to-number (match-string 2)))))) + (let ((start-toc (point))) + (when (search-forward html-pagetoc-end-cmnt) + (beginning-of-line) + (let ((end-toc (point))) + (set-mark start-toc) + (goto-char end-toc) + (when (y-or-n-p "Rebuild this TOC? ") + ;;(unless old-min (setq old-min 1)) + (setq old-min (eval-minibuffer "Min TOC level: " (format "%s" old-min))) + ;;(unless old-max (setq old-max 3)) + (setq old-max (eval-minibuffer "Max TOC level: " (format "%s" old-max))) + (delete-region start-toc end-toc) + (html-pagetoc-insert-toc old-min old-max )))))))) + +;;;###autoload +(defconst html-pagetoc-menu-map + (let ((map (make-sparse-keymap))) + (define-key map [html-pagetoc-rebuild-toc] + (list 'menu-item "Update Page TOC" 'html-pagetoc-rebuild-toc)) + (define-key map [html-pagetoc-insert-style-guide] + (list 'menu-item "Insert CSS Style for Page TOC" 'html-pagetoc-insert-style-guide)) + (define-key map [html-pagetoc-insert-toc] + (list 'menu-item "Insert Page TOC" 'html-pagetoc-insert-toc)) + map)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Ready: +(provide 'html-pagetoc) + +;;; html-pagetoc.el ends here diff --git a/emacs/nxhtml/nxhtml/html-quote.el b/emacs/nxhtml/nxhtml/html-quote.el new file mode 100644 index 0000000..4605a4f --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-quote.el @@ -0,0 +1,71 @@ +;;; html-quote.el --- Simple quoting of html characters +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sun Dec 30 12:55:38 2007 +;; Version: +;; Last-Updated: Sun Dec 30 12:59:43 2007 (3600 +0100) +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Just simple quoting of & < > etc +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + + +(defcustom html-quote-html '((?< . "<") + (?& . "&")) + "*Alist of char -> entity mappings used to make the text html-safe." + :group 'html-qoute + :type '(alist :key-type character + :value-type string)) + + +(defun html-quote-html-char (char) + "Return CHAR as string if safe, otherwise its html entity." + (or (cdr (assoc char html-quote-html)) + (char-to-string char))) + +(defun html-quote-html-string (str) + "Return html escaped STR." + (mapconcat 'html-quote-html-char + (append str nil) + "")) + +;; (html-quote-html-string "is & < s") + +(provide 'html-quote) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-quote.el ends here diff --git a/emacs/nxhtml/nxhtml/html-site.el b/emacs/nxhtml/nxhtml/html-site.el new file mode 100644 index 0000000..64238fc --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-site.el @@ -0,0 +1,801 @@ +;;; html-site.el --- Keeping (X)HTML files together +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed Mar 01 17:25:52 2006 +(defconst html-site:version "0.3");; Version: +;; Last-Updated: 2008-03-22T03:32:06+0100 Sat +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `cl', `html-site', `html-upl', `ietf-drums', `mail-parse', +;; `mail-prsvr', `mailcap', `mm-util', `qp', `rfc2045', `rfc2047', +;; `rfc2231', `time-date', `timer', `timezone', `tls', `url', +;; `url-auth', `url-c', `url-cookie', `url-expand', `url-gw', +;; `url-history', `url-http', `url-methods', `url-parse', +;; `url-privacy', `url-proxy', `url-util', `url-vars'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;; TODO: maybe use browse-url-filename-alist + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'compile)) +(eval-when-compile (require 'dired)) +(eval-when-compile (require 'ffip nil t)) +(eval-when-compile (require 'grep)) +(eval-when-compile (require 'ourcomments-util nil t)) +(eval-when-compile (require 'url-parse)) +;;(defvar html-site-list) ;; Silence compiler +;;(defvar html-site-current) ;; Silence compiler + +;;;###autoload +(defgroup html-site nil + "Customization group for html-site." + :group 'nxhtml) + +;; Fix-me: Rewrite using directory variables +(defcustom html-site-list nil + "Known site directories and corresponding attributes. +Each element in the list is a list containing: + +* Name for the site. +* Site root directory. +* Page list file - Pages for table of contents (TOC). Usually + initially built from the site directory by + `html-toc-create-pages-file'. +* Frames file. +* TOC file for the frames file. +* Output directory - where to put the merged TOC and site + pages. +* Output template file - html template for merging. See `html-wtoc-dir' + for examples. +* Function for additional tasks - for example copying images, style + sheets, scripts etc. +-- +" + :type '(repeat + (list + (string :tag "*** Site name ***") + (directory :tag "Site root directory") + (file :tag "Page list file") + (file :tag "Frames file") + (file :tag "Contents file for frames") + (directory :tag "Output directory for pages with TOC" :help-echo "Where to put the merged files") + (file :tag "Template file for pages with TOC" :help-echo "HTML template for merging") + (choice :tag "Extra function for pages with TOC" + (const nil :tag "Default function") + (function) + ) + (string :tag "Ftp host address") + (string :tag "Ftp user") + (string :tag "Ftp password") + (string :tag "Ftp directory root") + (string :tag "Ftp directory root for pages with TOC") + (string :tag "Web host address") + (string :tag "Web directory root") + (string :tag "Web directory root for pages with TOC") + )) + :set (lambda (symbol value) + ;;(message "sym=%s, value=%s" symbol value) + (set-default symbol value) + (when (featurep 'html-site) + (let ((ok t)) + (dolist (e value) + (let ( + (name (elt e 0)) + (site-dir (elt e 1)) + (pag-file (elt e 2)) + (frm-file (elt e 3)) + (toc-file (elt e 4)) + (out-dir (elt e 5)) + (tpl-file (elt e 6)) + (fun (elt e 7)) + (ftp-host (elt e 8)) + (ftp-user (elt e 9)) + (ftp-pw (elt e 10)) + (ftp-dir (elt e 11)) + (ftp-wtoc-dir (elt e 12)) + (web-host (elt e 13)) + (web-dir (elt e 14)) + (web-wtoc-dir (elt e 15)) + ) + (unless (not (string= "" name)) + (html-site-lwarn '(html-site-list) :error "Empty site name")) + (if (not (file-directory-p site-dir)) + (progn + (html-site-lwarn '(html-site-list) :error "Site directory for %s not found: %s" name site-dir) + (setq ok nil)) + (unless (file-exists-p pag-file) + (html-site-lwarn '(html-site-list) :warning "Pages list file for %s does not exist: %s" name pag-file)) + (unless (file-exists-p tpl-file) + (html-site-lwarn '(html-site-list) :warning "Template file for %s does not exist: %s" name tpl-file))) + (when (< 0 (length out-dir)) + (html-site-chk-wtocdir out-dir site-dir)) + (when fun + (unless (functionp fun) + (html-site-lwarn '(html-site-list) :error "Site %s - Unknown function: %s" name fun) + (setq ok nil) + )) + )) + ))) + :group 'html-site) + +(defcustom html-site-current "" + "Current site name. +Use the entry with this name in `html-site-list'." + :set (lambda (symbol value) + ;;(message "sym=%s, value=%s" symbol value) + (set-default symbol value) + (when (featurep 'html-site) + (or (when (= 0 (length value)) + (message "html-site-current (information): No current site set")) + (let ((site-names)) + (dolist (m html-site-list) + (setq site-names (cons (elt m 0) site-names))) + (or + (unless (member value site-names) + (html-site-lwarn '(html-site-current) :error "Can't find site: %s" value)) + (let ((site-dir (html-site-site-dir value))) + (unless (file-directory-p site-dir) + (html-site-lwarn '(html-site-current) :error "Can't find site directory: %s" value)))))))) + :type 'string + :set-after '(html-site-list) + :group 'html-site) + +(defun html-site-looks-like-local-url (file) + "Return t if this looks like a local file something url." + (require 'url-parse) + (let ((url-type (url-type (url-generic-parse-url file)))) + (not + (and url-type + ;; Test if it really is an url, the is 1 for w32 drive + ;; letters + (or (not (memq system-type '(ms-dos windows-nt))) + (< 1 (length url-type))))))) + +(when nil + (assert (not (html-site-looks-like-local-url "http://www.some.where/"))) + (assert (html-site-looks-like-local-url "/unix/file")) + (when (memq system-type '(windows-nt)) + (assert (html-site-looks-like-local-url "c:/w32/file")))) + +(defun html-site-dir-contains (dir file) + ;;(when (= ?~ (string-to-char file)) (setq file (expand-file-name file))) + ;; + ;; It is not possible to unconditionally expand the file name here + ;; since url file names can be involved. + ;; (url-type (url-generic-parse-url "c:/some/file.txt")) + (let* ((file-is-local (html-site-looks-like-local-url file)) + (dir-is-local (html-site-looks-like-local-url dir)) + (file-is-dir (and file-is-local + (file-directory-p file))) + (true-f (if file-is-local + (if file-is-dir + (file-name-as-directory + (file-truename + (expand-file-name file))) + (file-truename + (expand-file-name file))) + file)) + ;; (file-name-as-directory (expand-file-name "~/")) + (true-d (if dir-is-local + (file-name-as-directory + (file-truename + (expand-file-name dir))) + (if (eq ?/ (car (reverse (append dir nil)))) + dir + (concat dir "/"))))) + (assert (eq file-is-local dir-is-local)) + (if (< (length true-d) (length true-f)) + (string= true-d + (substring true-f 0 (length true-d))) + (when file-is-dir + (string= true-d true-f))))) + +(defun html-site-lwarn (warn-type level format-string &rest args) + (apply 'message (concat "%s:" format-string) warn-type args) + (apply 'lwarn warn-type level args)) + +(defun html-site-chk-wtocdir (out-dir site-dir) + (or + (unless (file-name-absolute-p out-dir) + (html-site-lwarn '(html-site) :error "Output directory is not absolute: %s" out-dir)) + (if (file-exists-p out-dir) + (unless (file-directory-p out-dir) + (html-site-lwarn '(html-site) :error "File %s for output exists but is not a directory" out-dir)) + (unless (string= out-dir (file-name-as-directory out-dir)) + (html-site-lwarn '(html-site) :error "File name could not be a directory: %s" out-dir))) + (when (html-site-dir-contains out-dir site-dir) + (html-site-lwarn '(html-site) :error "Ouput directory for pages with TOC must not contain site dir.")) + (when (html-site-dir-contains site-dir out-dir) + (html-site-lwarn '(html-site) :error "Site dir must not contain ouput directory for pages with TOC.")))) + + +;;;###autoload +(defun html-site-buffer-or-dired-file-name () + "Return buffer file name or file pointed to in dired." + (if (derived-mode-p 'dired-mode) + (dired-get-file-for-visit) + buffer-file-name)) + +;;;###autoload +(defun html-site-set-site (name) + (interactive + (let ((site-names) + (must-contain (when (boundp 'must-contain) must-contain)) + (file (html-site-buffer-or-dired-file-name)) + (use-dialog-box nil)) + (unless (< 0 (length html-site-list)) + (error "No sites defined yet")) + (when (and file + ;;(string-match "ml" (symbol-name major-mode)) + ) + (when (or must-contain + (y-or-n-p "Should site contain current file? ")) + (setq must-contain file))) + (dolist (m html-site-list) + (let* ((name (elt m 0)) + (dir (html-site-site-dir name))) + (when (or (not must-contain) + (html-site-dir-contains dir file)) + (setq site-names (cons name site-names))))) + (unless site-names + (when must-contain + (error "No sites contains %s" must-contain))) + (list (when site-names + (let ((prompt (if (< 0 (length html-site-current)) + (concat "Current site is \"" + html-site-current + "\". " + (if must-contain + "New site containing file: " + "New site's name: ")) + (if must-contain + "Site containing file: " + "Site name: ")))) + (completing-read prompt site-names nil t nil 'site-names)))))) + (unless (or (string= name "") + (string= name html-site-current)) + (setq html-site-current name) + (customize-save-variable 'html-site-current html-site-current))) + +;;;###autoload +(defun html-site-dired-current () + "Open `dired' in current site top directory." + (interactive) + (dired (html-site-current-site-dir))) + +;;;###autoload +(defun html-site-find-file () + "Find file in current site." + (interactive) + ;;(require 'ffip) + (ffip-set-current-project html-site-current + (html-site-current-site-dir) + 'nxhtml) + (call-interactively 'ffip-find-file-in-project)) + +;;;###autoload +(defun html-site-rgrep (regexp files) + "Search current site's files with `rgrep'. +See `rgrep' for the arguments REGEXP and FILES." + (interactive + (progn + (grep-compute-defaults) + (let* ((regexp (grep-read-regexp)) + (files (grep-read-files regexp))) + (list regexp files)))) + ;; fix-me: ask for site + ;;(when (called-interactively-p) ) + (rgrep regexp files (html-site-current-site-dir))) + +;;;###autoload +(defun html-site-query-replace (from to file-regexp delimited) + "Query replace in current site's files." + (interactive + (let ((parameters (dir-replace-read-parameters t t))) + ;; Delete element 3 + ;;(length parameters) + (setcdr (nthcdr 2 parameters) (nthcdr 4 parameters)) + ;;(length parameters) + parameters)) + ;; fix-me: ask for site + ;;(when (called-interactively-p) ) + (rdir-query-replace from to file-regexp + ;;root + (html-site-current-site-dir) + delimited) + ) + +(defun html-site-ensure-site-defined (site-name) + (unless html-site-list + (error "No sites defined. Please customize `html-site-list'.")) + (unless (file-directory-p (html-site-site-dir site-name)) + (error "Local file web site directory does not exists: %s" + (html-site-site-dir site-name)))) +(defun html-site-current-ensure-site-defined () + (unless (and (< 0 (length html-site-current)) + (assoc html-site-current html-site-list)) + (error "No current site set")) + (html-site-ensure-site-defined html-site-current)) + +(defun html-site-remote-contains (site-name url with-toc) + (html-site-dir-contains (html-site-remote-root site-name with-toc) url)) +(defun html-site-current-remote-contains (url with-toc) + (html-site-remote-contains html-site-current url with-toc)) + +(defun html-site-ensure-file-in-site (site-name file-name &optional no-error) + (html-site-ensure-site-defined site-name) + (if (html-site-contains site-name file-name) + t + (if no-error + nil + (error "This file is not in site %s" site-name)))) +(defun html-site-current-ensure-file-in-site (file-name) + ;;(html-site-ensure-file-in-site html-site-current file-name)) + (let ((in-site (html-site-ensure-file-in-site html-site-current + file-name t))) + (while (not in-site) + (if (not (y-or-n-p + (format "This file is not in site %s, change site? " + html-site-current))) + (error "This file is not in site %s" html-site-current) + (let ((must-contain t)) + (call-interactively 'html-site-set-site)) + (setq in-site (html-site-ensure-file-in-site html-site-current + file-name t)))))) + +(defun html-site-ensure-buffer-in-site (site-name) + (unless buffer-file-name + (error "This buffer is not visiting a file")) + (html-site-ensure-file-in-site site-name buffer-file-name)) +(defun html-site-current-ensure-buffer-in-site () + (html-site-ensure-buffer-in-site html-site-current)) + + +(defun html-site-site-dir (site-name) + (file-name-as-directory + (nth 1 (assoc site-name html-site-list)))) +(defun html-site-current-site-dir () (html-site-site-dir html-site-current)) + +(defun html-site-contains (site-name file) + (html-site-dir-contains (html-site-site-dir site-name) file)) +(defun html-site-current-contains (file) + (html-site-contains html-site-current file)) + +(defun html-site-page-list (site-name) + (let ((page-list (nth 2 (assoc site-name html-site-list)))) + (when (< 0 (length page-list)) + page-list))) + +(defun html-site-current-page-list () (html-site-page-list html-site-current)) + +(defun html-site-frames-file (site-name) + (nth 3 (assoc site-name html-site-list))) +(defun html-site-current-frames-file () (html-site-frames-file html-site-current)) + +(defun html-site-toc-file (site-name) + (nth 4 (assoc site-name html-site-list))) +(defun html-site-current-toc-file () (html-site-toc-file html-site-current)) + +(defun html-site-merge-dir (site-name) + (let ((dir (nth 5 (assoc site-name html-site-list)))) + (when (< 0 (length dir)) + dir))) +(defun html-site-current-merge-dir () (html-site-merge-dir html-site-current)) + +(defun html-site-merge-template (site-name) + (nth 6 (assoc site-name html-site-list))) +(defun html-site-current-merge-template () (html-site-merge-template html-site-current)) + +(defun html-site-extra-fun (site-name) + (nth 7 (assoc site-name html-site-list))) +(defun html-site-current-extra-fun () (html-site-extra-fun html-site-current)) + +(defun html-site-ftp-host (site-name) + (nth 8 (assoc site-name html-site-list))) +(defun html-site-current-ftp-host () (html-site-ftp-host html-site-current)) + +(defun html-site-ftp-user (site-name) + (nth 9 (assoc site-name html-site-list))) +(defun html-site-current-ftp-user () (html-site-ftp-user html-site-current)) + +(defun html-site-ftp-password (site-name) + (nth 10 (assoc site-name html-site-list))) +(defun html-site-current-ftp-password () (html-site-ftp-password html-site-current)) + +(defun html-site-ftp-dir (site-name) + (nth 11 (assoc site-name html-site-list))) +(defun html-site-current-ftp-dir () (html-site-ftp-dir html-site-current)) + +(defun html-site-ftp-wtoc-dir (site-name) + (nth 12 (assoc site-name html-site-list))) +(defun html-site-current-ftp-wtoc-dir () (html-site-ftp-wtoc-dir html-site-current)) + +(defun html-site-web-host (site-name) + (nth 13 (assoc site-name html-site-list))) +(defun html-site-current-web-host () (html-site-web-host html-site-current)) + +(defun html-site-web-dir (site-name) + (nth 14 (assoc site-name html-site-list))) +(defun html-site-current-web-dir () (html-site-web-dir html-site-current)) + +(defun html-site-web-wtoc-dir (site-name) + (nth 15 (assoc site-name html-site-list))) +(defun html-site-current-web-wtoc-dir () (html-site-web-wtoc-dir html-site-current)) + +(defun html-site-web-full (site-name with-toc) + (let ((host (html-site-web-host site-name))) + (unless (and host + (< 0 (length host))) + (error "Web site host not known for %s" site-name)) + (save-match-data + (unless (string-match "^https?://" host) + (setq host (concat "http://" host)))) + (concat host + (if with-toc + (html-site-web-wtoc-dir site-name) + (html-site-web-dir site-name))))) +(defun html-site-current-web-full (with-toc) + (html-site-web-full html-site-current with-toc)) + +(defvar html-site-ftp-temporary-passwords nil) +(defun html-site-get-ftp-pw () + (let ((pw (html-site-current-ftp-password))) + (unless (< 0 (length pw)) + (let* ((user-site (concat (html-site-current-ftp-user) + "@" + (html-site-current-ftp-host))) + (site-pw (assoc user-site html-site-ftp-temporary-passwords))) + (if site-pw + (setq pw (cdr site-pw)) + (setq pw (read-string + (concat "Ftp password for " + (html-site-current-ftp-user) + " at " + (html-site-current-ftp-host) + " : "))) + (setq html-site-ftp-temporary-passwords + (cons + (cons user-site pw) + html-site-ftp-temporary-passwords))))) + pw)) + + + + + +(defun html-site-path-in-mirror (site-root path-in-site mirror-root) + (assert (html-site-dir-contains site-root path-in-site) t) + (let ((rel-path (file-relative-name path-in-site site-root))) + (if (string= rel-path ".") + (directory-file-name mirror-root) + (concat (file-name-as-directory mirror-root) rel-path)))) + +;; Some checks to see if html-site-path-in-mirror works: +(when nil + (require 'cl) + ;; Try to make a non-existent directory name to work around Emacs + ;; bug (which was fixed today in CVS): + (let ((local-file "/temp814354/in/hej.html") + (local-dir "/temp814354")) + (when (memq system-type '(ms-dos windows-nt)) + (setq local-file (concat "c:" local-file)) + (setq local-dir (concat "c:" local-dir ))) + (assert (string= + "http://some.site/tempmirror/in/hej.html" + (html-site-path-in-mirror local-dir + local-file + "http://some.site/tempmirror")) + t) + (assert (string= + local-file + (html-site-path-in-mirror "http://some.site/tempmirror" + "http://some.site/tempmirror/in/hej.html" + local-dir)) + t) + (assert (string= + "in/hej.html" + (file-relative-name "http:/temp/in/hej.html" "http:/temp")) + t) + )) + + +(defun html-site-local-to-web (site-name local-file with-toc) + (html-site-ensure-file-in-site site-name local-file) + (html-site-path-in-mirror (html-site-site-dir site-name) + local-file + (html-site-web-full site-name with-toc))) +(defun html-site-current-local-to-web (local-file with-toc) + (html-site-local-to-web html-site-current local-file with-toc)) + +(defun html-site-remote-root (site-name with-toc) + (concat "/ftp:" + (html-site-ftp-user site-name) + "@" (html-site-ftp-host site-name) + ":" + (if with-toc + (html-site-ftp-wtoc-dir site-name) + (html-site-ftp-dir site-name)))) +(defun html-site-current-remote-root (with-toc) + (html-site-remote-root html-site-current with-toc)) + +(defun html-site-local-to-remote (site-name local-file with-toc) + (html-site-ensure-file-in-site site-name local-file) + (html-site-path-in-mirror (html-site-site-dir site-name) + local-file + (html-site-remote-root site-name with-toc))) +(defun html-site-current-local-to-remote (local-file with-toc) + (html-site-local-to-remote html-site-current local-file with-toc)) + +(defun html-site-remote-to-local (site-name remote-file with-toc) + ;;(html-site-ensure-file-in-site remote-file) + ;; Fix-me above + (html-site-path-in-mirror (html-site-remote-root site-name with-toc) + remote-file + (html-site-site-dir site-name))) +(defun html-site-current-remote-to-local (remote-file with-toc) + (html-site-remote-to-local html-site-current remote-file with-toc)) + + +(defvar html-site-files-re "\.x?html?$") + +(defun html-site-edit-pages-file () + "Edit the list of pages to be used for table of contents." + (interactive) + (html-site-current-ensure-site-defined) + (find-file (html-site-current-page-list)) + ) + +(defun html-site-get-sub-files (dir file-patt) + (let ((sub-files) + (sub-dirs) + (dir-files (directory-files dir t "^[^.]"))) + (dolist (f dir-files) + (if (file-directory-p f) + (add-to-list 'sub-dirs f) + (when (string-match file-patt f) + (add-to-list 'sub-files f)))) + (dolist (sub-dir sub-dirs) + (setq sub-files (append sub-files (html-site-get-sub-files sub-dir file-patt))) + ) + sub-files)) + +(defun html-site-file-is-local (filename) + "Return t if FILENAME is a local file name. +No check is done that the file exists." + ;;(find-file-name-handler "/ftp:c:/eclean/" 'file-exists-p) + (null (find-file-name-handler filename 'file-exists-p))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Put subprocess here at the moment ... + +(defconst noshell-procbuf-name "*Noshell process buffer*") + +(defvar noshell-proc-name nil) +(defun noshell-procbuf-setup (procbuf-name) + (unless procbuf-name + (setq procbuf-name noshell-procbuf-name)) + (with-current-buffer (get-buffer-create procbuf-name) + (unless (get-buffer-window (current-buffer)) + (when (one-window-p) (split-window)) + (let ((cb (current-buffer))) + (set-window-buffer (other-window 1) cb))) + ;;(setq buffer-read-only t) + (noshell-process-mode) + (compilation-minor-mode 1) +;; (let ((inhibit-read-only t) +;; (output-buffer (current-buffer))) +;; (goto-char (point-max)) +;; (setq noshell-proc-name name) +;; (let ((s (concat +;; "\n\n\n>>>>>>>>>>>>>>>>>> Starting " +;; noshell-proc-name "\n"))) +;; (put-text-property 0 (length s) +;; 'face (list 'bold '(:foreground "green")) +;; s) +;; (insert s))) + (sit-for 0.01) ;; Display update + (current-buffer))) + +(defun noshell-procbuf-teardown (proc) + (with-current-buffer (process-buffer proc) + (goto-char (point-max)) + (let ((inhibit-read-only t) + (s (concat + "<<<<<<<<<<<<<<<<<<< Finished OK: " + noshell-proc-name "\n"))) + (put-text-property 0 (length s) + 'face (list 'bold '(:foreground "green")) + s) + (insert s)))) + +(defun noshell-procbuf-run (buffer prog &rest args) + (with-current-buffer buffer + (let ((inhibit-read-only t) + (proc nil) + ) + (unwind-protect + (progn + (setq proc (apply 'start-process "myproc" (current-buffer) prog args)) + ) + ) + (save-excursion + (unless proc + (let ((s "\n\n<<<<<<<<<<<<< There was a process starting error!")) + (put-text-property 0 (length s) + 'face (list 'bold '(:foreground "red")) + s) + (insert s)) + (error "Subprocess terminated with error status"))) + (set-process-sentinel proc 'noshell-sentinel) + proc) + ) + ) +(defun noshell-sentinel (process event) + (with-current-buffer (process-buffer process) + (let ((inhibit-read-only t)) + ;;(insert (format "Process: %s recieved %s\n" process event)) + (cond ((string-match "abnormally" event) + (let ((s (concat "\n<<<<<< Error: " + (substring event 0 -1) + " <<<<<<<<<"))) + (put-text-property 0 (length s) + 'face (list 'bold '(:foreground "red")) + s) + (insert s))) + ((string-match "finished" event) + (noshell-procbuf-teardown process)) + (t + (insert event)))))) + +(defun noshell-procbuf-syncrun (prog &rest args) + (with-current-buffer (get-buffer noshell-procbuf-name) + (let ((inhibit-read-only t) + (sts nil)) + (unwind-protect + (progn + ;;(setq sts (apply 'call-process prog nil (current-buffer) t args)) + (setq sts (apply 'call-process prog nil (list (current-buffer) t) t args)) + ) + ) + (save-excursion + (unless (= 0 sts) + (let ((s (format "\n\n<<<<<<<<<<<<< There was a process error: %s" sts))) + (put-text-property 0 (length s) + 'face (list 'bold '(:foreground "red")) + s) + (insert s)) + (error "Subprocess terminated with error status"))) + ) + ) + ) + +(defvar noshell-process-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c)(control ?k)] 'noshell-kill-subprocess) + (define-key map [(control ?g)] 'noshell-quit) + map)) + +(define-derived-mode noshell-process-mode fundamental-mode "Subprocess" + nil + (setq buffer-read-only t) + (buffer-disable-undo (current-buffer))) + +(defun noshell-quit () + (interactive) + (noshell-kill-subprocess) + (keyboard-quit)) + +(defun noshell-kill-subprocess () + (interactive) + (when (eq major-mode 'noshell-process-mode) + (if (get-buffer-process (current-buffer)) + (interrupt-process (get-buffer-process (current-buffer))) + (error "The subprocess is not running")))) + + + +;; Provide here to be able to load the files in any order +(provide 'html-site) + +(eval-when-compile (require 'html-upl nil t)) + +(defvar html-site-mode-menu-map + (let ((map (make-sparse-keymap "html-site-mode-menu-map"))) + + (when (featurep 'html-upl) + (let ((upl-map (make-sparse-keymap))) + (define-key map [html-site-upl-map] + (list 'menu-item "File Transfer" upl-map)) + ;;(define-key upl-map [html-site-upl-edit-remote-wtoc] + ;; (list 'menu-item "Edit Remote File With TOC" 'html-upl-edit-remote-file-with-toc)) + (define-key upl-map [html-site-upl-edit-remote] + (list 'menu-item "Edit Remote File" 'html-upl-edit-remote-file)) + (define-key upl-map [html-site-upl-ediff-buffer] + (list 'menu-item "Ediff Remote/Local Files" 'html-upl-ediff-file)) + (define-key upl-map [html-site-upl-sep] (list 'menu-item "--")) + (define-key upl-map [html-site-upl-upload-site-with-toc] + (list 'menu-item "Upload Site with TOC" 'html-upl-upload-site-with-toc)) + (define-key upl-map [html-site-upl-upload-site] + (list 'menu-item "Upload Site" 'html-upl-upload-site)) + (define-key upl-map [html-site-upl-upload-file] + (list 'menu-item "Upload Single File" 'html-upl-upload-file)) + )) + + (let ((site-map (make-sparse-keymap))) + (define-key map [html-site-site-map] + (list 'menu-item "Site" site-map)) + (define-key site-map [html-site-customize-site-list] + (list 'menu-item "Edit Sites" (lambda () (interactive) + (customize-option 'html-site-list)))) + (define-key site-map [html-site-set-site] + (list 'menu-item "Set Current Site" 'html-site-set-site)) + ) + + map)) + + +(defvar html-site-mode-map + (let ((map (make-sparse-keymap ))) + (define-key map [menu-bar html-site-mode] + (list 'menu-item "Web Site" html-site-mode-menu-map)) + map)) + +(define-minor-mode html-site-mode + "Adds a menu for easy access of setting site, uploading etc." + :init-value nil + :lighter nil + :keymap html-site-mode-map + :group 'html-site) + +(defvar html-site-mode-off-list + '(nxhtml-mode)) + +(define-global-minor-mode html-site-global-mode html-site-mode + (lambda () + (html-site-mode 1) + (when t ;buffer-file-name + (unless (memq major-mode html-site-mode-off-list) + (html-site-mode 1)))) + :group 'html-site) +;; The problem with global minor modes: +(when (and html-site-global-mode + (not (boundp 'define-global-minor-mode-bug))) + (html-site-global-mode 1)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-site.el ends here diff --git a/emacs/nxhtml/nxhtml/html-toc.el b/emacs/nxhtml/nxhtml/html-toc.el new file mode 100644 index 0000000..866b43f --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-toc.el @@ -0,0 +1,363 @@ +;;; html-toc.el --- Building and updating TOC for a site +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed Feb 01 14:40:13 2006 +(defconst html-toc:version "0.4");; Version: +;; Last-Updated: Tue Apr 10 04:09:29 2007 (7200 +0200) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Create table of contents for a static web site. See +;; `html-toc-write-toc-file' and `html-toc-write-frames-file' for +;; more info. +;; +;; To use this you can add (require 'html-toc) to your .emacs. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (add-to-list 'load-path default-directory load-path)) +(eval-when-compile (require 'fupd nil t)) +;;(require 'html-move) +(eval-when-compile (require 'html-site nil t)) +;;(require 'dom) +(require 'xml) + +(defconst html-toc-mark-begin "<!-- html-toc START -->") +(defconst html-toc-mark-middle "<!-- html-toc MIDDLE -->") +(defconst html-toc-mark-end "<!-- html-toc END -->") + +(defun html-toc-create-pages-file () + "Write a list of pages to be used for table of contents. +Return the file name." + (interactive) + (html-site-current-ensure-site-defined) + (let* ( + (site-dir (html-site-current-site-dir)) + (page-file (html-site-current-page-list)) + (page-file-dir (file-name-directory page-file)) + (page-file-exists (file-exists-p page-file)) + (sub-files (html-site-get-sub-files + site-dir + html-site-files-re)) + (pages-text) + ) + (setq sub-files + (sort (mapcar (lambda (full-file) + (assert (file-exists-p full-file)) + (file-relative-name full-file page-file-dir)) + sub-files) + 'string<)) + ;;(setq sub-files (delete html-toc-file-default-name sub-files)) + (with-temp-buffer + (let ((this-level) + (dir-title) + (title) + (full-file)) + (dolist (file sub-files) + (setq full-file (expand-file-name file page-file-dir)) + (setq dir-title (file-name-nondirectory + (substring (file-name-directory full-file) 0 -1))) + (setq title (html-toc-get-title full-file)) + (setq this-level 0) + (mapc (lambda (c) (when (eq c ?/) (setq this-level (1+ this-level)))) file) + (insert (format "%s ### %s ### %s\n" this-level title file)))) + (setq pages-text (buffer-string))) + (with-current-buffer (find-file page-file) + (if (string= pages-text (buffer-string)) + (message "List of pages is already the default list") + (if (= 0 (length (buffer-string))) + (progn + (insert pages-text) + (save-buffer) + ) + (if (y-or-n-p "Replace old list of pages? ") + (progn + (erase-buffer) + (insert pages-text) + (save-buffer) + ) + (message "Keeping old list of pages."))))) + page-file)) +(defun html-toc-dir () + (let* ((this-file (if load-file-name + load-file-name + buffer-file-name)) + (this-dir (file-name-directory this-file)) + ) + (expand-file-name "html-toc" this-dir))) + +;;;###autoload +(defgroup html-toc nil + "Customization group for html-toc." + :group 'nxhtml) + +(defcustom html-toc-template-file + (expand-file-name "html-toc-template.html" (html-toc-dir)) + "Template file for table of contents file." + :type 'file + :group 'html-toc) + + +(defun html-toc-write-toc-file () + "Write a table of contents for a web site. +Build the table of content from the information in +`html-site-current-page-list'. Write it to the file +`html-site-current-toc-file' and return that file name. + +When viewed in a browser the table of contents can be +expanded/collapsed (if JavaScript is allowed)." + (interactive) + (html-site-current-ensure-site-defined) + (let* ((toc-file (html-site-current-toc-file)) + (page-file (html-site-current-page-list)) + page-lines + toc) + (unless (< 0 (length toc-file)) + (error "There is no name for the table of content file in site \"%s\"" + html-site-current)) + (unless (< 0 (length page-file)) + (error "There is no name for the pages file in site \"%s\"" + html-site-current)) + (with-temp-buffer + (insert-file-contents page-file) + (goto-char (point-min)) + (while (not (eobp)) + (let* ((line (buffer-substring (point) (line-end-position))) + (line-parts (split-string line "\\s-+###\\s-+"))) + (setq page-lines (cons line-parts page-lines))) + (forward-line))) + (setq page-lines (reverse page-lines)) + (with-temp-buffer + (html-toc-insert-toc page-lines toc-file) + (setq toc (buffer-substring-no-properties (point-min) (point-max)))) + (with-current-buffer (find-file-noselect toc-file) + (erase-buffer) + (insert-file-contents-literally html-toc-template-file) + (let (toc-start) + (while (search-forward "%%TOC%%" nil t) + (unless toc-start + (setq toc-start (match-beginning 0))) + (replace-match toc t t)) + (forward-line) ;; for indentation + (indent-region toc-start (point-marker))) + (goto-char (point-min)) + (save-buffer)) + toc-file)) + + +(defun html-toc-insert-toc (page-lines toc-file) + (let* ((curr-level) + (min-level 100) + div-levels + (site-directory (html-site-current-site-dir)) + (toc-rel-file (file-relative-name toc-file site-directory))) + (dolist (line page-lines) + (let ((level (string-to-number (nth 0 line)))) + (when (< level min-level) + (setq min-level level)))) + (setq curr-level min-level) + (while page-lines + (let* ((line (car page-lines)) + (file (nth 2 line)) + (title (nth 1 line)) + (this-level (string-to-number (nth 0 line))) + (next-level (progn + ;; Note: + (setq page-lines (cdr page-lines)) + (let ((next-line (car page-lines))) + (when next-line + (string-to-number (nth 0 next-line)))))) + (full-file (expand-file-name file site-directory)) + (dir-title (file-name-nondirectory + (substring (file-name-directory full-file) 0 -1)))) + ;;(insert "<!-- " (format "%s, %s, %s" curr-level this-level div-levels) " -->\n") + ;; Don't insert a link to the toc file + (unless (string= toc-rel-file file) + ;; If there are childs then insert a <div> before them. Save + ;; the level so we can close the div-tag later. + (when (< curr-level this-level) + ;; Save level so we can find the end of the <div>. + (setq div-levels (cons this-level div-levels)) + (insert "<div class=\"html-toc-childs\">\n")) + ;; Close div-tags if this level is lower when the previous. + (when (> curr-level this-level) + (while (and div-levels + (> (car div-levels) this-level)) + (insert "</div>\n") + (setq div-levels (cdr div-levels)))) + (setq curr-level this-level) + (insert "<div class=\"html-toc-link\">" + "<span style=\"display:table-cell; width:15em; background-color:yellow;\">" + "<a style=\"padding-left:" (number-to-string (1+ (- curr-level min-level))) "em;\" " + (format "href=\"%s\">%s</a>" file title) + "</span>") + (when (and next-level (> next-level this-level)) + (insert "<span onclick=\"html_toc_hs(this)\" class=\"html-toc-hs\"" + " style=\"display:table-cell; background-color:white;\">HS</span>")) + (insert "</div>" + "\n") + ))) + (while div-levels + (insert "</div>\n") + (setq div-levels (cdr div-levels))))) + +(defun html-toc-get-title (file) + (save-excursion + (with-temp-buffer + (insert-file-contents file nil 0 1000) + (goto-char (point-min)) + (when (search-forward-regexp "<title>\\(.*\\)</title>" nil t) + (match-string 1))))) + +(defun html-toc-parse-toc (toc-str) + (let ((nodes)) + (with-temp-buffer + (insert toc-str) + (setq nodes (xml-parse-region (point-min) (point-max)))) + )) + +(defun html-toc-get-hrefs (nodes) + (let ((atags (html-toc-get-atags nodes))) + (mapcar (lambda (atag) + (xml-get-attribute atag 'href)) + atags))) +(defun html-toc-get-atags (nodes) + (let ((atags)) + (dolist (node nodes) + (when (listp node) + (setq atags (append atags (xml-get-children node 'a))) + (setq atags (append atags (html-toc-get-atags (xml-node-children node)))))) + atags)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Frames and viewing +(defcustom html-toc-frames-default-name "html-toc-frames.html" + "Default file name sans directory for frames file." + :type 'string + :group 'html-toc) + +(defvar html-toc-frames-contents + "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> + <title>Frames for html-toc</title> + </head> + <frameset cols=\"20%, 80%\"> + <frame name=\"html-toc-TOC\" src=\"%%TOCFILE%%\"/> + <frame name=\"html-toc-Document\" /> + <noframes> + <body> + Html frame support required + </body> + </noframes> + </frameset> +</html> +") + +(defun html-toc-browse-frames-file () + "View frames file written by `html-toc-write-frames-file'." + (interactive) + (html-site-current-ensure-site-defined) + (let ((frames-file (html-site-current-frames-file))) + (unless (< 0 (length frames-file)) + (error "There is no frames file set for site \"%s\"" html-site-current)) + ;;(message "frames-file=%s" frames-file)(sit-for 4) + (unless (file-exists-p frames-file) + (html-toc-write-frames-file)) + (browse-url-of-file frames-file))) + +;; (defun html-toc-frames-file-name () +;; "Return name of file written by `html-toc-write-frames-file'." +;; (html-toc-get-site) +;; (expand-file-name html-toc-frames-default-name html-move-site-directory)) + +(defun html-toc-write-frames-file () + "Write a frames file. +This frames file should load the table of contents build by +`html-toc-write-toc-file' in one frame and shows the documents in +another. + +The contents of the frames file is defined by +`html-toc-frames-contents'. + +Returns the file name of the written or existing frames file. + +You may also want to look at `html-wtoc-write-pages-with-toc'." + (interactive) + ;;(html-toc-get-site) + (html-site-current-ensure-site-defined) + (let* ((frames-file (html-site-current-frames-file)) + (frames-cont html-toc-frames-contents) + (toc-file (html-toc-write-toc-file)) + toc-file-relative) + (when toc-file + (setq toc-file-relative (file-relative-name + toc-file + (file-name-directory frames-file))) + (save-match-data + (unless (string-match "%%TOCFILE%%" frames-cont) + (error "Can't find %%TOCFILE%% in html-toc-frames-contents")) + (setq frames-cont (replace-match toc-file-relative t t frames-cont))) + (with-current-buffer (find-file-noselect frames-file) + (erase-buffer) + (insert frames-cont) + (save-buffer)) + frames-file))) + +;;;###autoload +(defconst html-toc-menu-map + (let ((map (make-sparse-keymap))) + (define-key map [html-toc-browse-frames-file] + (list 'menu-item "Browse Frames File" 'html-toc-browse-frames-file)) + (define-key map [html-toc-write-frames-file] + (list 'menu-item "Write Frames File" 'html-toc-write-frames-file)) + (define-key map [html-toc-write-toc-file] + (list 'menu-item "Write TOC File for Frames" 'html-toc-write-toc-file)) + (define-key map [html-toc-sep1] (list 'menu-item "--")) + (define-key map [html-toc-edit-pages-file] + (list 'menu-item "Edit List of Pages for TOC" 'html-site-edit-pages-file)) + (define-key map [html-toc-create-pages-file] + (list 'menu-item "Write List of Pages for TOC" 'html-toc-create-pages-file)) + map)) + + + +(provide 'html-toc) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-toc.el ends here diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc-template.html b/emacs/nxhtml/nxhtml/html-toc/html-toc-template.html new file mode 100644 index 0000000..5db41da --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-toc/html-toc-template.html @@ -0,0 +1,83 @@ +<?xml version="1.0"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>HEAD</title> + <link rel="stylesheet" href="html-toc/html-toc.css" type="text/css" /> + <link rel="stylesheet" href="html-toc/html-toc-template.css" type="text/css" /> + <script type="text/javascript" src="html-toc/html-toc.js"></script> + <script type="text/javascript" src="html-toc/html-toc-template.js"></script> + <script type="text/javascript"> + var my_old_onload = window.onload; + function my_onload() { + HTML_WTOC_NS.onload_actions(%%PNUM%%); + if (undefined != my_old_onload) { my_old_onload(); } + } + window.onload = my_onload; + </script> + </head> + <body> + + + <table summary="Page columns" cellspacing="0" border="0" cellpadding="0" xwidth="100%" > + <tr valign="top"> + <td id="html-wtoc-id-toccol" class="html-wtoc-contcol"> + <table summary="Contents column" id="html-wtoc-id-toc" class="html-wtoc-contcol" + cellspacing="0" border="1" cellpadding="0" width="100%"> + <tr valign="top"> + <td colspan="2" height="50" > + <table summary="Logo" id="html-wtoc-id-logo"> + <tr> + <td align="right" valign="bottom" > + <a href="http://www.OurComments.org/Emacs/EmacsW32.html" + ><img src="img/gnu-m-x-160.png" width="80" height="80" + alt="Go to EmacsW32 Home Page" + title="Go to EmacsW32 Home Page" + onmouseover="transLbi(this, false);" + onmouseout ="transLbi(this, true);" + style=" + margin-top:10px; + padding-left:20px; + padding-right:20px; + padding-top:10px; + padding-bottom:10px; + " + border="0" + /></a> + </td> + </tr> + </table> + </td> + </tr><tr valign="top"> + <td > + <table border="1"> + <tr> + <td>%%TOC%%</td> + </tr> + <tr> + <td id="nxhtml-link"> + <br /> + Built using Emacs + <br /> + with nxhtml from + <br /> + <a href="http://ourcomments.org/Emacs/Emacs.html" + target="_blank">ourcomments.org</a> + </td> + </tr> + </table> + </td> + </tr><tr> + <td colspan="2" style="background-color:red;"> + + </td> + </tr> + </table> + <table summary="Ensure table width" + cellspacing="0" id="html-wtoc-id-tocwidth"><tr><td></td></tr></table> + </td> + + </tr> + </table> + </body> +</html> diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc-template.css b/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc-template.css new file mode 100644 index 0000000..a6ffabb --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc-template.css @@ -0,0 +1,141 @@ +/* Main structures >>>>>>>>>>>>>>> */ +.html-wtoc-maintop { + font-size: 1px; + font-size: 1em; + margin-top: 0em; + margin-bottom: 0em; +/* background-color:green; */ +} +.html-wtoc-main { +} + +td.html-wtoc-vdivline { + //background-color: #8be; + width: 0px; +} + +.html-wtoc-search-form { + margin-bottom: 0.1em; +} +.html-wtoc-search { + font-size: 0.8em; + color: green; +} +.html-wtoc-search a { + color: green; +} +/* <<<<<<<<<<<<<<<<<<< */ + + + + +/* Table of content >>>>>>>>>>>>>> */ + +#html-wtoc-id-hidetoc { + height: 20px; + border-bottom: 2px inset #ddf; + border-color: #dff; +} + +#html-wtoc-id-tocdiv { + width: 2.5em; + //background-color: #eff; +} +#html-wtoc-id-logo { + width: 100%; + height: 120px; + padding: 0em; + margin: 0em; + border: 0em; +} +#html-wtoc-id-toc { +} +#html-wtoc-id-tocwidth { + width: 18em; + height: 0em; + padding: 0em; + margin: 0em; + border: 0em; + line-height: 0em; +/* background-color: red; */ +} +#html-wtoc-id-toccol { + width: 18em; +} + +.html-wtoc-contcol { + background-color: #dFEfff; + background-color: #dFEfff; + background-color: #cd950c; + background-color: #eead0e; +} +/* <<<<<<<<<<<<<<<<<<< */ + + + + +/* Buttons etc >>>>>>>>>>>>>>> */ +.html-wtoc-button { + font-size: 0.75em; + font-size: 8pt; + color: #5A5D00; + background-color: #9cf; + background-color: #bcee68; + background-color: #a2cd5a; + padding: 0.2em; + Border-Width: 2px; + Border-Style: outset; + text-align: center; + border-color: #ddf; +} +a.html-wtoc-button { + text-decoration: none; + color: #5A5D00; +} +a.html-wtoc-button:hover { + text-decoration:none; + background-color: #6af; + color:#340; +} + +a.html-wtoc-buttonimg img { + width: 16px; + height: 16px; + padding: 4px; + border: 8px; +} +a.html-wtoc-buttonimg { + border:2px; + margin:2px; + margin-left:2px; + margin-right:2px; +} +a.html-wtoc-buttonimg { + font-size:1px; +} +a.html-wtoc-buttonimg:hover { + margin: 6px; + margin-left:0px; + margin-right:0px; + border-color: #ddf; + border-width: 2px; + border-style: outset; + background-color: #595C00; + background-color: #bef; + background-color: #b9ffb9; +} + +/* <<<<<<<<<<<<<<<<<<< */ + + +#nxhtml-link { + font-size: 0.7em; + text-align: center; + padding-top: 2em; + padding: 1em; +} + +.copyright { + color : #872; +} + diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.css b/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.css new file mode 100644 index 0000000..a12cb65 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.css @@ -0,0 +1,84 @@ +body { + margin: 0; +} +td { + font-size: 1em; +} + +/* Added by html-wtoc.pl >>>>>>>>>>>>> */ +.html-wtoc-mark { +/* background-color: #9cf; */ +/* background-color: #bcee68; */ +/* background-color: #a2cd5a; */ + width: 20px; + padding: 0; + border: 0; + text-align: center; +} +.html-wtoc-contline { + width: 100%; +} + +.html-wtoc-margin { + width: 0.6em; +} +.html-wtoc-contents { + font-size: 0.9em; + padding: 1em; + background-color: #9cf; + background-color: #a2cd5a; + background-color: #efffcf; + background-color: #ffffdf; + -moz-border-radius-topleft: 2em; +} +.html-wtoc-contents td { +/* background-color: #9cf; */ +/* background-color: #bcee68; */ +/* background-color: #a2cd5a; */ +} +.html-wtoc-contents-a { + text-decoration: none; + color: #595C00; +/* background-color: #9cf; */ +/* background-color: #bcee68; */ +/* background-color: #a2cd5a; */ + border: 1px #9cf solid; + border: 1px #a2cd5a solid; + border: 1px #ffffc0 solid; + padding-left: 0.25em; + padding-right: 0; + margin: 1px; + display: block; +} +.html-wtoc-contents a:hover { + text-decoration: none; + background-color: #b9ffb9; + border: 1px #6b8e23 solid; +} +.html-wtoc-currcont { + background-color: #738600; + color: #ffff2f; + background-color: #535600; + border: 1px #6b8e23 inset; + padding-left: 0.25em; + padding-right: 0; + margin: 1px; + display: block; +} +a.html-wtoc-currcont { + text-decoration: none; +} +a.html-wtoc-currcont:hover { + background-color: #738600; + background-color: #536600; + background-color: #434620; +} +/* <<<<<<<<<<<<<<<<<<< */ + + + + + + + + diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.js b/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.js new file mode 100644 index 0000000..7f22db7 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-toc/html-toc/html-toc.js @@ -0,0 +1,361 @@ + +// © Copyright 2006 Lennart Borgman, http://www.OurComments.org/. All rights reserved. +// +// 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 3, 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. + + +var HTML_WTOC_NS_sCurrTocId; + + +HTML_WTOC_NS = { + + ///////////////////////////// + //// Basic event functions + ///////////////////////////// + + getEventObject : function (ev) { + var o; + if (window.event) + o = window.event.srcElement; + else if (null != ev) + o = ( ev.target ); + return o; + }, + getEvent : function (ev) { + if (window.event) { + return window.event; + } else if (null != ev) { + return ev; + } + }, + + eventStopPropagation : function (e) { + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble=true; + }, + + eventPreventDefault : function (e) { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue=false; + }, + + ///////////////////////////// + //// TOC hide + ///////////////////////////// + + show_content : function (on) { + var toc = document.getElementById("html-wtoc-id-toccol").style; + var tdv = document.getElementById("html-wtoc-id-tocdiv").style; + var shw = document.getElementById("html-wtoc-id-showtoc").style; + var hid = document.getElementById("html-wtoc-id-hidetoc").style; + if (on) { + toc.display = ""; + tdv.display = ""; + shw.display = "none"; + hid.display = ""; + HTML_WTOC_NS.focus_page_link(0); + } else { + toc.display = "none"; + tdv.display = "none"; + shw.display = ""; + hid.display = "none"; + } + }, + + + + + + ///////////////////////////// + //// Open-Close + ///////////////////////////// + onblur_action : function(ev) { + HTML_WTOC_NS_sCurrTocId = null; + }, + onfocus_action : function(ev) { + var o = HTML_WTOC_NS.getEventObject(ev); + if (!o) return; + + HTML_WTOC_NS_sCurrTocId = o.id; + }, + onclick_action : function(ev) { + var o = HTML_WTOC_NS.getEventObject(ev); + var e = HTML_WTOC_NS.getEvent(ev); + if (13 == e.keyCode) return true; + if (!o) return true; + if ("IMG" == o.tagName) o = o.parentNode; + var iId = HTML_WTOC_NS.getIdnumFromId(o.id); + var sChildId = "toc_child_"+iId; + var sOldCurrTocId = HTML_WTOC_NS_sCurrTocId; + HTML_WTOC_NS.toggle_open(sChildId, o); + HTML_WTOC_NS_sCurrTocId = sOldCurrTocId; + return false; + }, + + toggle_open : function (id, parent) { + var child = document.getElementById(id).style; + var sInner = parent.innerHTML; + var re = new RegExp("[^/]*\.gif", "i"); + if ("none" == child.display) { + child.display = ""; + parent.innerHTML = sInner.replace(re, "down.gif")+""; + } else { + child.display = "none"; + parent.innerHTML = sInner.replace(re, "right.gif")+""; + } + }, + + + + ///////////////////////////// + //// Load + ///////////////////////////// + + onload_actions : function (iPageNum) { + document.body.onkeydown = HTML_WTOC_NS.onkeydown_action; + document.body.onmouseover = HTML_WTOC_NS.onmouseover_action; + var aATags = document.getElementsByTagName("a"); + for(var i = 0; i < aATags.length; i++) { + var o = aATags[i]; + if (null != HTML_WTOC_NS.getIdnumFromId(o.id)) { + o.onfocus = HTML_WTOC_NS.onfocus_action; + o.onblur = HTML_WTOC_NS.onblur_action; + if (o.id.substr(0, 12) == "opener_text_") { + o.onclick = HTML_WTOC_NS.onclick_action; + o.title = "Open/Close"; + } else if (o.id.substr(0, 7) == "opener_") { + o.onclick = HTML_WTOC_NS.onclick_action; + o.className = "html-wtoc-mark"; + o.title = "Open/Close"; + } + } + } + HTML_WTOC_NS.focus_page_link(iPageNum); + }, + focus_page_link : function (iPageNum) { + // Element might be hidden + try { + document.getElementById("toc_link_"+iPageNum).focus(); + } catch (exc) { + } + }, + + + + + + + + ///////////////////// + //// Mouse + ///////////////////// + + onmouseover_action : function (ev) { + if (null == HTML_WTOC_NS_sCurrTocId) return true; + var o = HTML_WTOC_NS.getEventObject(ev); + var iId = HTML_WTOC_NS.getIdnumFromId(o.id); + if (null == iId) return true; + o.focus(); + }, + + + + ///////////////////// + //// Key + ///////////////////// + + onkeydown_action: function (ev) { + var keyDown = 40; + var keyUp = 38; + var keyLeft = 37; + var keyRight = 39; + var keyReturn = 13; + var keyF2 = 113; + var keyInsert = 45; + // Opera + var keyOperaDown = 57386; + var keyOperaUp = 57385; + var keyOperaLeft = 57387; + var keyOperaRight = 57388; + var keyOperaF2 = 57346; + var keyOperaInsert = 57394; + + var SwitchKey = keyInsert; + var SwitchKeyOpera = keyOperaInsert; + + var bUp; + var e = HTML_WTOC_NS.getEvent(ev); + if (null == HTML_WTOC_NS_sCurrTocId) { + switch (e.keyCode) { + case SwitchKey: + case SwitchKeyOpera: + HTML_WTOC_NS.focus_page_link(0); + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + } + return true; + } + switch (e.keyCode) { + case keyLeft: + case keyOperaLeft: + case keyRight: + case keyOperaRight: + HTML_WTOC_NS.handle_leftright_keys(e); + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + case keyDown: + case keyOperaDown: + bUp = false; + break; + case keyUp: + case keyOperaUp: + bUp = true; + break; + case SwitchKey: + case SwitchKeyOpera: + if (null != HTML_WTOC_NS_sCurrTocId) { + var o = document.getElementById(HTML_WTOC_NS_sCurrTocId); + if (o) o.blur(); + HTML_WTOC_NS_sCurrTocId = null; + } + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + default: + //alert(e.keyCode); + return true; + } + var oOpener; + oOpener = HTML_WTOC_NS.getNextVisOpener(HTML_WTOC_NS_sCurrTocId, bUp); + oOpener.focus(); + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + }, + + handle_leftright_keys: function (e) { + var keyLeft = 37; + var keyRight = 39; + var keyOperaLeft = 57387; + var keyOperaRight = 57388; + var iId = HTML_WTOC_NS.getIdnumFromId(HTML_WTOC_NS_sCurrTocId); + if (null == iId) return; + var sId = "opener_" + iId; + var oOpener = document.getElementById(sId); + var sId = HTML_WTOC_NS_sCurrTocId; // It will be cleared before getNextVis + + var bOpenAction; + var bOpened; + var bUp; + var oChild = document.getElementById("toc_child_"+iId); + if (null == oChild) { + } else { + bOpened = (oChild.style.display != "none"); + } + switch (e.keyCode) { + case keyLeft: + case keyOperaLeft: + bUp = true; + bOpenAction = (null != bOpened) && (bOpened); + break; + case keyRight: + case keyOperaRight: + bUp = false; + bOpenAction = (null != bOpened) && (!bOpened); + break; + default: + alert("bad key handling..."); + } + if (bOpenAction) { + oOpener.click(); + HTML_WTOC_NS_sCurrTocId = sId; + } else { + var oPrev = HTML_WTOC_NS.getNextVisOpener(sId, bUp); + oPrev.focus(); + } + }, + + + + + + + ////////////////////// + //// Util + ////////////////////// + getNameFromId: function (sId) { + var re = new RegExp("(.*?_)(\\d+)", "i"); + if (!re.test(sId)) return null; + var iId = sId.replace(re, "$1"); + return iId; + }, + getIdnumFromId: function (sId) { + var re = new RegExp("(.*?_)(\\d+)", "i"); + if (!re.test(sId)) return null; + var iId = sId.replace(re, "$2"); + return iId; + }, + + + getNextVisOpener: function (sId, bUp, bTrace) { + if (bTrace) alert("getNextVisOpener("+sId+","+bUp+")"); + var iId = HTML_WTOC_NS.getIdnumFromId(sId); + if (null == iId) { + alert("getNextVisOpener err iId==null"); + return; + } + var sIdName = HTML_WTOC_NS.getNameFromId(sId); + if (null == sIdName) { + alert("getNextVisOpener err sIdName==null"); + return; + } + var oOpener; + var iLoop = -2; + while (oOpener == null) { + if (bTrace) alert(iId); + if (iLoop++ > iMaxChildNum) { alert("Child num error"); return; } + if (!bUp) { + iId++; + } else { + iId--; + } + if (iId > iMaxChildNum) { iId = 0; } + if (iId < 0) { iId = iMaxChildNum; } + var s = sIdName+iId; + oOpener = document.getElementById(s); + if (oOpener != null) { + if (bTrace) alert(oOpener.offsetLeft); + if (oOpener.style.display == "none") { // All + oOpener = null; + } else if (oOpener.offsetLeft < 0) { // IE + oOpener = null; + } else if (0 == oOpener.scrollWidth) { // Opera + oOpener = null; + } + } + } + return oOpener; + } + + + +}; //HTML_WTOC_NS diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/blank12.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/blank12.gif new file mode 100644 index 0000000000000000000000000000000000000000..0869f9ffe832b7778e8af9dc74cd36f2ef3436ca GIT binary patch literal 825 zcmZ?wbhEHb<YC}p_|Cxa|Nno6Q7{?;BQ*pRf3h%w{H_BcKzV|JLyUouL&jsnf`iQ* T!dfvWHY_~cE+ELp!e9*m$1M(_ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/down.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/down.gif new file mode 100644 index 0000000000000000000000000000000000000000..30d6ecfa57c8839f5acdd97a8ff29d3a84f0ac00 GIT binary patch literal 853 zcmZ?wbhEHb<YC}p_|Cxa|Nnn&*X;9m|Igp`KPD<_@7}!@dHaBZSb>C^m3io7tWu+b zqaiR9LqPE-3nK#%=zs`No?zfGVqoNu@z}87V55MLRt$$@0t2IfBA>yBhJ*%23Elvc aiooQf&5UMpB0mb3oSdu?%*DgOU=0A%U<8f; literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/freeCont.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/freeCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..1c94b60111dd28a2de5e270cbbec1f0146b1f869 GIT binary patch literal 913 zcmZ?wbhEHb6krfw_|5<VEiEno85sU^aQv5$_^+t=UsLnHq2Yf^%l}?p|C5vdXJ`Mf zuKo{HGiT2KwQK+XpYwkdjE2DQ2!VzM#h)yUz{Jm>1Ih`YJi)+`$MF9zv%`i32bh@I z6a+K`7+Tr|82%^=EOcaQ<&kw_d62-s%*G`kaDv0|Q8Oc_lbnP@(c}G7IeB;@E__;e zq+W^p!Wzkmi4C)D8vmu-*svsEfom+6j918F-$eoJQoXlIw5~4kU+)!KwRM5xDn>>I FYXCc(5>5aB literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/gnu-m-x-160.png b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/gnu-m-x-160.png new file mode 100644 index 0000000000000000000000000000000000000000..5254ef110b1fc505925f854d0b582b9ddf094123 GIT binary patch literal 1957 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/gnu-m-x-160.xcf b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/gnu-m-x-160.xcf new file mode 100644 index 0000000000000000000000000000000000000000..f2ce5ceb4e44ba3e0d8365f81cf3018bc084d11d GIT binary patch literal 22466 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/hideCont.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/hideCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..9908895699cf345553771565f1fe8acd047ceed2 GIT binary patch literal 917 zcmZ?wbhEHb6krfw_|5<VEiElmwys^eckkA%TaO((cJJQ3|F{9ee}=vP_g4O|#H|EH z=HLJMD13sPh6aL4Miq>P0JTCu@h1x-1A_sB4k#yp@&p4%5kuku28Rs`9GjUK8zMNE z92(mNxEVZ7Y<PIENkr7l=D^0sjh)QWPB&gmRQ70P;B)Y(RB&jRCa-v6ilk$z=VZa6 zS8HZoT6(&lUDYEY^3xKJCYktuCSDU#F7|Lo{xb2Ls2JGqwpK0l*T$?Xvt!xgWTXWc FtO4p+BFF#$ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/nailCont.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/nailCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..4c1bca4291bafc1443a23d831085dbe3d5d96862 GIT binary patch literal 917 zcmZ?wbhEHb6krfw_|CxapPl_bC+B}IuKzqd|9N@;^YQ)X=l?G){a;4rznt8E1%>}Q zI{)?c|C^ZnH#7ThYy02M?!UeLe-DrU>FNJ-a{gCV{;#Y1-_Y=X=FI<#7X4qo{Qrs- z3`n2>DE0sUzyI@*#73E;Auw1%K=CIFBLjmtgAT|+pgh6AQN*Ah^T1)l0tZ$W783!D z3C$htN)|C50*9Jd7zHJ)T23%BGjNNl*=Q^fOgh5LsL~OWut4QFHy@irf<Z&m>2?{1 zf`*0%2UyyeeP6M7l`QU9=+c;XMbmJlcf0Rgwpz_nt#hlwl#@(XZPmKI!jD_3L`s0c F8UQ@RUC96d literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/nosearch.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/nosearch.gif new file mode 100644 index 0000000000000000000000000000000000000000..e824f5ba3052fafda09da2a8ade818fb978d7a44 GIT binary patch literal 1100 zcmdUu(Tf#T9LG<(#<-MRH+84faJE&OTgIKjaMp_5;nuoS$U1BolhDT81?%=uT(X7Z zgNw7V3r9=+6<Q~_ZXCR{p4OoAq~}4?sn|HUiUUFny|mLyj72aA(KP-Gz4hh8moLBH z%kTT}8y<OSm;Gih+JJI|u&ZOw!c1T$v5;6QEaT9(!=S_sn_5VMkhDT*g&ac8iER_x zA&yNPmv{#84HB57sgqWTL9kA+O+uf5M;IZI1jh!~1lIx20M7(p17C+ghn52v0oDK; zfK9+Q5C=#A;DNvp2~eCiE3|1)Tw>Btr=-NB#G=Hd#G_zQuqkg*fvFHw5{4@byDW4W z(HSuqF&VKK=nP7?8S|M4%9bpOc<6KDa4<NS9Bd8&r-)OHQ;SoZQ%_J$P+d?<P+L$} z+?)7<A;EmfkYu)Gp5#p_LYagSMG+4o&LV*#5k!(iv7?x#I8p*BiBzPkh^mMyRZ)qh zQa6?;j!Ga_G*&!TB33evWdbCTUZQvsmxv@aQqf8kN@JeJDotdXL}^lnI8Ea$MOo>Y zmSt9!C0Ukcxt`@l9#`@V<yo5ND9=mJ@;ooVE2vXQt58M}>qSy2a#ZA5QLYM96k1V~ z;r}UA-v1wE-0iv#p#}6LDs}HCkoFIHWA&yz7uuJPY7bQpOjd3_R<Epm{>s%muXcvt z{dV;1$@=Uk&rWUQuHL<L=BdWtr-!b$zdPPPvE|{$_K!DT-1@<;_dYu{*k0ND#EsFz z6Q`EvM-CoZx8qvtmzBM{S4>w2YA1U1h3?z$4Akyl^HtZ{oqybU`-FL6=hB*b<JTYO zU;g4XYtDzo{-ZOUpO^lcT|d9~({<}7hNG{C_Pm~q{<(Pi#`vM&!=4AGzhC@(;Qi%G zXD{AfzC1E91Dzx7gGctiFm_%)JV_qhF!s#&_4eSZleP1!_g)EZUi)bCj>*n9&X+5W z^}p3njqTdLc6$8jt<}D%tFw>n-!$F#+uiZbbB|Z6^_eYB_uTLGV|_otxffUU+&cHe d*g_53kM{PxQk%OpH#oEr)uuL{>FPqe{{>0koPPiS literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/right.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/right.gif new file mode 100644 index 0000000000000000000000000000000000000000..2400cf102023d1a797370260a959cebdb79632b0 GIT binary patch literal 857 zcmZ?wbhEHb<YC}p_|Cxa|Nnn&*X;9m|Igp`KPD<_@7}!@dHaBZSb>C^m3io7tWu+b zqaiR9LqPE-3nK#%=zs`No?zfGV_;-xP}s1*u~C3Y#)iYO;ZQ3FD^JCa4G$YS1$3nh fJ}g+&&?~FW_kg2N;p8L%r$ss^FC{oIFjxZsK}ZQy literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/search.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/search.gif new file mode 100644 index 0000000000000000000000000000000000000000..9f58dfd4a3b0bdae3dcd29aac5a33fab9070013b GIT binary patch literal 1118 zcmd^;?~4^x7{`yg>g)yM>NR&jg`K?FPH8l?MMFm3@z%P7yREZHGW5gkZo+n7v~s14 z<D0dC*5w%N@+1Xk>27!;gi}@?knq5oHs}VY4P#yo8q|nEvm3$?MAPiw(U%V&zC6#X z=f%_4|H9MuNEh0IGK8?JW6#1&U?#DUSSl=|z_)`&fg3cnfHVTq3ZNBm2skIUO>Boa zHgR0y8N@e8!z4|ev<eJ@b%JdY_yjz{2ni)PHn=9Z4tNH5CioioIy7`>Ie-yh4X^>& z1Z)FwfHVL+5Ew!MiqmG9HVujkOd9Bv6quA)l(>|56f6oh<t-{O6@p5_aG7D31ui2x zBL*WTBNhXlL1CLQpNU3sB@06y_?$Q#3=Sp-n?r+B#Hq%q#i`AyC#WW<E~q7_EvPG2 zCca=uFkdnxnJt+oc~go&#z9C?$QvPNp+KQ%gp!1jqnM^RQUWQ7RH&<vs*o#HR<WfL zH<Bm{3m{T7Qan;3QZkBU3?!Cbtauz1h&VA4(Ml9bBA!GliDeRpNnDgDNuo4CY2j2$ zQ!7p5G)>Y>PctKn%2|rCG|4iQWrfo$%X08?>g3YOm61n!9+&eB<yo2+s~qLImghzJ z-^KX5V-+g0Yeg$RfwX_o>z&*7Uua)>U#mR)%8ByL9rg0YXTQI;bm)t|@ry%qGxgIS zJvFhDyL##8PaYlp=i}O9`|5|)H@hD^aQx_v?Su69YWdFm4^zFHHw-%8u9-AEcKp7R zx8CS$53Q@16U*lpdxqWh;k>o8r&b@>bJ-s~KRi3T=C{$?kKgEi;E@+!d-d+Msp*-C zle<Pn{y4j^ec;o>U*8?=pPnCp>r1<}u^+d(r*;f~w_G}Q_RDqqZZH4!`QWVm_MHoJ zOK<(OwR)mm+P&{weQihQrfu5N!Ut3LAL~BTtBsKjTRNUNve@3ccIL5(%bRHM(1A+V zbMIWdH5Zo7lzL~*O^=Nqs@5h~?>YT0m<Km@RtJB%^y~g7uMWL8^wMOx7HqEn*>!Z` m=4Y!r?+uT?e6Z)#z42N{MK_K-|CRR5Dpa{N-M<&1XZ`~l*`Xo; literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-toc/html-toc/img/showCont.gif b/emacs/nxhtml/nxhtml/html-toc/html-toc/img/showCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..7bd2e7d310bb028a4692f672267a51adab5038ba GIT binary patch literal 909 zcmZ?wbhEHb6krfw_|5<VEiElmwys^eckkA%TaO((cJJQ3|F{9ee}=vP_g4O|#H|EX zrlA3qKgt^ofk6}kia%Kx85k58bU--)lqVQCvKSmWWH^`_4mPuM^05RgSa_I;L4?c2 zV`9RQCU&DNn*u?WmTm^KtUVl!kB=}j1}!p)G-7I*uIO6CBe`(d=?R*}vse@ynVe>- oao5?b3`%uxR!=R{@d!x|Xf<@zi|yF-BDmXOx!;ls0|f?a01IpwjQ{`u literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-upl.el b/emacs/nxhtml/nxhtml/html-upl.el new file mode 100644 index 0000000..1ce2e98 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-upl.el @@ -0,0 +1,329 @@ +;;; html-upl.el --- Uploading of web sites +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Mon Mar 06 19:09:19 2006 +(defconst html-upl:version "0.3") ;; Version: +;; Last-Updated: 2008-03-22T01:23:01+0100 Sat +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `cl', `html-site', `html-upl', `mail-prsvr', `mm-util', `timer', +;; `url-c', `url-parse', `url-vars'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: +(eval-when-compile (add-to-list 'load-path default-directory load-path)) +(eval-when-compile (require 'html-site nil t)) + +;;;###autoload +(defgroup html-upl nil + "Customization group for html-upl." + :group 'nxhtml) + +(defcustom html-upl-dir + (file-name-as-directory + (expand-file-name + "html-upl" + (file-name-directory + (if load-file-name load-file-name buffer-file-name)))) + + "Directory where the tools needed are located. +The tools for html-upl includes: + +- ftpsync.pl +" + :type 'directory + :group 'html-upl) + +(defun html-upl-browse-remote () + (interactive) + (let ((url (html-site-local-to-web html-site-current + ;;buffer-file-name + (html-site-buffer-or-dired-file-name) + nil))) + (browse-url url))) +(defun html-upl-browse-remote-with-toc () + (interactive) + (let ((url (html-site-local-to-web html-site-current + ;;buffer-file-name + (html-site-buffer-or-dired-file-name) + t))) + (browse-url url))) +(defun html-upl-browse-remote-frames () + (interactive) + (let ((url (html-site-local-to-web (html-site-current-frames-file) + ;;buffer-file-name + (html-site-buffer-or-dired-file-name) + nil))) + (browse-url url))) + +;;;###autoload +(defun html-upl-upload-site-with-toc () + (interactive) + (html-upl-upload-site1 t)) + +;;;###autoload +(defun html-upl-upload-site () + (interactive) + (html-upl-upload-site1 nil)) +(defun html-upl-upload-site1(with-toc) + (html-site-current-ensure-site-defined) + (html-upl-ensure-site-has-host) + (let ((local-dir (if with-toc + (html-site-current-merge-dir) + (html-site-current-site-dir))) + (ftp-host (html-site-current-ftp-host)) + (ftp-user (html-site-current-ftp-user)) + (ftp-pw (html-site-current-ftp-password)) + (ftp-dir (if with-toc + (html-site-current-ftp-wtoc-dir) + (html-site-current-ftp-dir))) + (ftpsync-pl (expand-file-name "ftpsync.pl" html-upl-dir)) + ) + (unless (< 0 (length ftp-host)) + (error "Ftp host not defined")) + (unless (< 0 (length ftp-user)) + (error "Ftp user not defined")) + (unless (< 0 (length ftp-dir)) + (if with-toc + (error "Ftp remote directory for pages with TOC not defined") + (error "Ftp remote directory not defined"))) + (unless (< 0 (length ftp-pw)) + (setq ftp-pw (html-site-get-ftp-pw))) + (let* ( + (buffer (noshell-procbuf-setup "subprocess for upload")) + (remote-url (concat "ftp://" ftp-user ":" ftp-pw "@" ftp-host ftp-dir)) + (opt (list + "-v" + "-p" + local-dir + remote-url))) + (apply 'noshell-procbuf-run + buffer + "perl" "-w" + ftpsync-pl + opt + )))) + +(defun html-upl-ensure-site-has-host () + (let ((host (html-site-current-ftp-host))) + (unless (and host (< 0 (length host))) + (error "Site %s has no ftp host defined" html-site-current)))) + +;;;###autoload +(defun html-upl-remote-dired (dirname) + "Start dired for remote directory or its parent/ancestor." + (interactive (list + (read-directory-name "Local directory: " nil nil t))) + (html-site-current-ensure-file-in-site dirname) + (html-upl-ensure-site-has-host) + (let* ((local-dir dirname) + (remote-dir (html-site-current-local-to-remote local-dir nil)) + to-parent + res + msg) + (while (not res) + (condition-case err + (progn + (dired remote-dir) + (setq res t)) + (error ;;(lwarn 't :warning "err=%s" err) + (setq msg (error-message-string err)))) + ;; It does not look like we always get an error. Check where we are: + (when res + (unless (string= default-directory remote-dir) + (setq res nil) + (setq msg ""))) + (unless res + ;; 450 Requested file action not taken File unavailable (e.g. file busy). + ;; 550 Requested action not taken File unavailable (e.g. file not found, no access). + (if (or (string= msg "") + (save-match-data (string-match " \\(?:550\\|450\\) " msg))) + (progn + (if (not to-parent) + (setq to-parent (concat + (file-name-nondirectory remote-dir) + "/..")) + (setq to-parent (concat + (file-name-nondirectory remote-dir) + "/" + to-parent "/.."))) + ;;(setq local-dir (directory-file-name (file-name-directory (directory-file-name local-dir)))) + ;;(html-site-current-ensure-file-in-site local-dir) + ;;(setq remote-dir (html-site-current-local-to-remote local-dir nil)) + (setq remote-dir (directory-file-name (file-name-directory remote-dir))) + ) + (setq res msg)))) + (if (stringp res) + (error "%s" msg) + (when to-parent + (message "Remote dir not found, showing ancestor %s" to-parent))))) + +;;;###autoload +(defun html-upl-upload-file (filename) + "Upload a single file in a site. +For the definition of a site see `html-site-current'." + (interactive (list + (let ((use-dialog-box nil) + (f (file-relative-name + ;;(if (derived-mode-p 'dired-mode) (dired-get-file-for-visit) buffer-file-name) + (html-site-buffer-or-dired-file-name) + ))) + (read-file-name "File: " nil nil t f)) + )) + (html-site-current-ensure-file-in-site filename) + (html-upl-ensure-site-has-host) + (let* ((buffer (get-file-buffer filename)) + (remote-file (html-site-current-local-to-remote filename nil)) + (remote-buffer (get-file-buffer remote-file)) + (local-file filename)) + (when (or (not buffer-file-name) + (not (buffer-modified-p buffer)) + (and + (y-or-n-p (format "Buffer %s is modified. Save buffer and copy? " + (buffer-name buffer))) + (with-current-buffer buffer + (save-buffer) + (not (buffer-modified-p))))) + (when (= ?~ (string-to-char local-file)) + (setq local-file (expand-file-name local-file))) + (when (and (fboundp 'w32-short-file-name) + (string-match " " local-file)) + (setq local-file (w32-short-file-name local-file))) + (copy-file local-file + ;;(html-site-current-local-to-remote filename nil) + remote-file + 0) + (when remote-buffer + (with-current-buffer remote-buffer + (revert-buffer nil t t))) + (message "Upload ready") + ))) + +;;;###autoload +(defun html-upl-edit-remote-file () + (interactive) + (html-upl-edit-remote-file1 nil)) + +;;;###autoload +(defun html-upl-edit-remote-file-with-toc () + (interactive) + (html-upl-edit-remote-file1 t)) + +(defun html-upl-edit-remote-file1(with-toc) + (html-site-current-ensure-buffer-in-site) + (html-upl-ensure-site-has-host) + (let* ((remote-root (concat "/ftp:" + (html-site-current-ftp-user) + "@" (html-site-current-ftp-host) + ":" + (if with-toc + (html-site-current-ftp-wtoc-dir) + (html-site-current-ftp-dir)))) +;; (remote-file (html-site-path-in-mirror (html-site-current-site-dir) +;; buffer-file-name +;; remote-root)) + (remote-file (html-site-current-local-to-remote buffer-file-name nil)) + ) + (find-file remote-file))) + +;;;###autoload +(defun html-upl-ediff-file (filename) + "Run ediff on local and remote file. +FILENAME could be either the remote or the local file." + ;;(interactive "fFile (local or remote): ") + (interactive (list + (or (html-site-buffer-or-dired-file-name) + (read-file-name "File: ")))) + (html-upl-ensure-site-has-host) + (let* ((is-local (html-site-file-is-local filename)) + remote-name + local-name) + (if is-local + (progn + (html-site-current-ensure-file-in-site filename) + (setq remote-name (html-site-current-local-to-remote filename nil)) + (setq local-name filename)) + (setq local-name (html-site-current-remote-to-local filename nil)) + (html-site-current-ensure-file-in-site local-name) + (setq remote-name filename)) + (let ((local-buf (find-file local-name)) + (remote-buf (find-file remote-name))) + (ediff-buffers local-buf remote-buf)))) + +;;(defun html-site-buffer-or-dired-file-name () +;; (defun html-upl-ediff-buffer () +;; "Run ediff on local and remote buffer file. +;; The current buffer must contain either the local or the remote file." +;; (interactive) +;; (html-upl-ediff-file (buffer-file-name))) + +(provide 'html-upl) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-upl.el ends here + +;; (defun html-site-local-to-remote-path (local-file protocol with-toc) +;; (let ((remote-dir (if (eq protocol 'ftp) +;; (if with-toc +;; (html-site-current-ftp-wtoc-dir) +;; (html-site-current-ftp-dir)) +;; (if with-toc +;; (html-site-current-web-wtoc-dir) +;; (html-site-current-web-dir))))) +;; (html-site-path-in-mirror +;; (html-site-current-site-dir) local-file remote-dir))) + +;; (defun html-site-local-to-web (local-file with-toc) +;; (let ((web-file (html-site-local-to-remote-path local-file 'http with-toc)) +;; (web-host (html-site-current-web-host))) +;; (save-match-data +;; (unless (string-match "^https?://" web-host) +;; (setq web-host (concat "http://" web-host)))) +;; (when (string= "/" (substring web-host -1)) +;; (setq web-host (substring web-host 0 -1))) +;; (concat web-host web-file) +;; )) +;; +;;; Use tramp-tramp-file-p instead: +;; (defun html-upl-file-name-is-local (file-name) +;; "Return nil unless FILE-NAME is a Tramp file name." +;; (save-match-data +;; (not (string-match "^/[a-z]+:" file-name)))) + +;; (defun html-upl-remote-to-local (remote-file) +;; (let ((remote-site-dir (html-site-current-web-dir))) +;; (unless (html-site-dir-contains remote-site-dir remote-file) +;; (error ""))) +;; ) + diff --git a/emacs/nxhtml/nxhtml/html-upl/COPYING b/emacs/nxhtml/nxhtml/html-upl/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-upl/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + GNU GENERAL PUBLIC LICENSE + 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 a brief idea of what it does.> + Copyright (C) <year> <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) year 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. diff --git a/emacs/nxhtml/nxhtml/html-upl/Changes b/emacs/nxhtml/nxhtml/html-upl/Changes new file mode 100644 index 0000000..0bfd93c --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-upl/Changes @@ -0,0 +1,115 @@ + +1.26 => 1.27 (2004-08-23) +========================= + + * Proposed and partially provided by Samuel Marshall <sam@leafdigital.com> + * enhanced timezone handling, should be perfect now + * new option -c, like -i but then asks interactively to let do it + * if FTP user/password are set to ?, they are asked for interactively + + +1.25 => 1.26 (2004-03-31) +========================= + + * fixed "dangerous" algorithm of synchronization direction + + +1.24 => 1.25 (2004-03-20) +========================= + + * fixed some 1.24 bugs + * clock offset computation now more resistant against very slow connections + * clock offset computation disabled for GET mode, so mirroring of foreign + stuff is now possible again + * default localdir of . disabled, therefore + * using . as localdir parameter does not cause a parsing error any more + * replaced damn indentation tabs in sourcecode by appropriate number of + spaces, so code is readable independent of tab settings + * enabled handling of ftpdir / + * handling of relative ftpdir corrected + + +1.23 => 1.24 (2003-10-11) +========================= + + By Michiel Steltman <Msteltman@disway.nl> + + * handle files with blanks etc in names + * clock offset remote-local to reduce unnecessary transfers + * error handling + + +1.22 => 1.23 (2003-09-28) +========================= + + * New parameter timeout + + +1.21 => 1.22 (2003-03-24) +========================= + + * Now cuts of / at directory spec's end, to avoid pwd() being different + from target of cwd() (which lead to unneccesarry abortions) + + +1.20 => 1.21 (2003-03-24) +========================= + + * version information in sourcefile and output of -h command + + +1.11 => 1.20 (2003-03-22) +========================= + + * generally, most foreseeable problems are beeing checked, in particular: + + - unability to connect to FTP server + - unability to login into FTP server + - unability to change to local or remote base directory + - unability to change to remote subdirectory + - unability to create local or remote subdirectory + - unability to remove local or remote subdirectory + - unability to put or get a file within 3 trials + + All these errors (except the last one) leads to immediate abortion. + + +1.10 => 1.11 (2002-05-10) +========================= + + * Some optical corrections concerning output + + * Files are now automatically re-transferred until the size on both ends + matches + + * -? now corrrectly recognized + + +1.00 => 1.10 (2001-10-28) +========================= + + * config file support + This is mportant to avoid putting ftp passwords in the process list! + + * much more informative standard and verbose/debug output, including kind + of a advance information + + * better FTP-URL parsing supporting such without user/password + + * much better default values, e.g. ftp://ftp:anonymous@localhost/., ... + + * softlinks are now detected (locally and remote) and treated somewhat + correctly, i.e. they are ignored correctly ;-)) + + + +=> 1.00 (2001-10-26) +==================== + +* 1.0 created 2001-10-20 23:10 by Christoph Lechleitner <lech@ibcl.at> + +Quite good for a 5 hour hack, isn't it? +O.K., I have already written similar programs for local file systems +in Pascal for DOS, Win3x and OS/2, and in VisualBasic for Win95b. + + diff --git a/emacs/nxhtml/nxhtml/html-upl/README b/emacs/nxhtml/nxhtml/html-upl/README new file mode 100644 index 0000000..3f9f505 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-upl/README @@ -0,0 +1,111 @@ +# README file for ftpsync.pl + + +Contents: +========= + +- Overview +- Why use ftpsync.pl instead of mirror, sitecopy, ...? +- Requirements/Restrictions +- Bug reports, Contact +- License +- Updates + + +Overview: +--------- + +ftpsync.pl synchronizes a local directory tree and a remote FTP directory tree. + +It was initally written to automize web publishing, but might be useful for +some other purposes, like mirroring not-too-large public sites, data +replication, and more. + +Call "ftpsync.pl -h" to get a short parameter explanation. + + +Why use ftpsync.pl instead of mirror, sitecopy, ...? +---------------------------------------------------- + +Yes, there are similar projects, so some comments on them: + +Compared to mirror, ftpsync.pl is capable of PUTing, not only GETing stuff +(Don't blame me if mirror is able to PUT, I could'nt find a way). + +Compared to sitecopy, ftpsync.pl has no problems, if the remote site has been +changed since its last run by other tools and activites. Unless network +problems or bugs occur, ftpsync.pl does a reliable synchronization. + +Compared to both, ftpsync.pl is very lightweight ;-)) + + +Requirements / Restrictions: +---------------------------- + +- Perl 5.6+ + ftpsync.pl was initially developed on Perl 5.6.0-81 on SuSE Linux 7.2, + older Perl 5.x version might work. Test reports welcome at ftpsync@ibcl.at! + +- File::Find, IO::Handle + IMHO parts of the basic perl package. + +- Net::FTP + Part of the perl-libnet package. + +- UNIX like operating systems on local system + Porting to DOS based systems should be easily done by changing the + directory separator. + +- Perhaps, the script does not work with all FTP servers + It is beeing tested only against UNIX based FTP servers. + + +Bug-Reports, Contact: +--------------------- + +Besides ftpsync.sourceforge.net, ftpsync@ibcl.at is a good target for comments +of any kind. + + +License: +-------- + +FTPSync.pl is GNU/GPL software and eMail ware. + + +FTPSync.pl as GNU/GPL software: +------------------------------- + +FTPSync.pl (ftpsync.pl) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +See attached file COPYING. + + +FTPSync.pl as eMail ware: +------------------------- + +FTPSync.pl is also eMail-Ware, which means that the initial author +(Christoph Lechleitner) would like to get an eMail (to ftpsync@ibcl.at), +- if anyone uses the script on production level, +- if anyone distributes or advertises it in any way, +- if anyone starts to (try to) improve it. + + +Updates +------- + +The software and updates should be available from +http://ftpsync.sourceforge.net/ +http://www.ibcl.at/ossw/FTPSync diff --git a/emacs/nxhtml/nxhtml/html-upl/TODO b/emacs/nxhtml/nxhtml/html-upl/TODO new file mode 100644 index 0000000..923583d --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-upl/TODO @@ -0,0 +1,2 @@ + +Nothing as of now. diff --git a/emacs/nxhtml/nxhtml/html-upl/ftpsync.pl b/emacs/nxhtml/nxhtml/html-upl/ftpsync.pl new file mode 100644 index 0000000..729d964 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-upl/ftpsync.pl @@ -0,0 +1,700 @@ +#!/usr/bin/perl +# +# ftpsync.pl +# +# See attached README file for any details, or call +# ftpsync.pl -h +# for quick start. +# +# LICENSE +# +# FTPSync.pl (ftpsync) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# FTPSync.pl (ftpsync) is also eMail-Ware, which means that the initial author +# (Christoph Lechleitner) would like to get an eMail at ftpsync@ibcl.at, if +# - if anyone uses the script on production level, +# - if anyone distributes or advertises it in any way, +# - if anyone starts to (try to) improve it. +# +# +################################################################################ + +# +# Options etc. +# +#print "Starting imports.\n"; # For major problem debugging +printf STDERR "argv=@ARGV\n"; + +use File::Find; +use File::Listing; +use Net::FTP; +use strict; +# flushing ... +use IO::Handle; +STDOUT->autoflush(1); +STDERR->autoflush(1); + +sub dosync(); +sub print_syntax(); +sub print_options(); +sub buildremotetree(); +sub buildlocaltree(); +sub listremotedirs(); +sub parseRemoteURL(); + +# Option Variables +#print "Defining variables.\n"; # For major problem debugging +# meta +my $returncode=0; +my $configfile=$ENV{"HOME"}."/.ftpsync"; +# basics +my $localdir=""; +my $remoteURL=""; +my $syncdirection=""; +my $ftpuser="ftp"; +my $ftppasswd="anonymous"; +my $ftpserver="localhost"; +my $ftpdir=""; +my $ftptimeout=120; +my $syncoff=0; +# verbosity +my $doverbose=1; +my $dodebug=0; +my $doquiet=0; +my $doinfoonly=0; +my $infotext=""; +my $docheckfirst=0; + +# Read command line options/parameters +#print "Reading command line options.\n"; # For major problem debugging +my $curopt; +my @cloptions=(); +for $curopt (@ARGV) { + if ($curopt =~ /^cfg=/) { + $configfile=$'; + if (! -r $configfile) { print "Config file does not exist: ".$configfile."\n"; $returncode+=1; } + } else { + push @cloptions, $curopt; + } +} + +# Read Config File, if given +my @cfgfoptions=(); +if ($configfile ne "") { + if (-r $configfile) { + #print "Reading config file.\n"; # For major problem debugging + open (CONFIGFILE,"<$configfile"); + while (<CONFIGFILE>) { + $_ =~ s/([ \n\r]*$|\.\.|#.*$)//gs; + if ($_ eq "") { next; } + if ( ($_ =~ /[^=]+=[^=]+/) || ($_ =~ /^-[a-zA-Z]+$/) ) { push @cfgfoptions, $_; } + } + close (CONFIGFILE); + } # else { print "Config file does not exist.\n"; } # For major problem debugging +} # else { print "No config file to read.\n"; } # For major problem debugging + +# Parse Options/Parameters +print "Parsing all options.\n"; # For major problem debugging +my $noofopts=0; +for $curopt (@cfgfoptions, @cloptions) { + if ($curopt =~ /^-[a-zA-Z]/) { + my $i; + for ($i=1; $i<length($curopt); $i++) { + my $curoptchar=substr($curopt,$i,1); + $noofopts++; + if ($curoptchar =~ /[cC]/) { $docheckfirst=1; } + elsif ($curoptchar =~ /[dD]/) { $dodebug=1; $doverbose=1; $doquiet=0; } + elsif ($curoptchar =~ /[gG]/) { $syncdirection="get"; } + elsif ($curoptchar =~ /[hH?]/) { print_syntax(); exit 0; } + elsif ($curoptchar =~ /[iI]/) { $doinfoonly=1; } + elsif ($curoptchar =~ /[pP]/) { $syncdirection="put"; } + elsif ($curoptchar =~ /[qQ]/) { $dodebug=0; $doverbose=0; $doquiet=1; } + elsif ($curoptchar =~ /[vV]/) { $doverbose++; } + else { print "ERROR: Unknown option: \"-".$curoptchar."\"\n"; $returncode+=1; } + } + } + elsif ($curopt =~ /^ftp:\/\/(([^@\/\\\:]+)(:([^@\/\\\:]+))?@)?([a-zA-Z01-9\.]+)\/(.*)/) { + $remoteURL = $curopt; + parseRemoteURL(); + if ( $syncdirection eq "" ) + { $syncdirection="get"; } + } + elsif ($curopt =~ /^[a-z]+=.+/) { + my ($fname, $fvalue) = split /=/, $curopt, 2; + if ($fname eq "cfg") { next; } + elsif ($fname eq "ftpdir") { $ftpdir =$fvalue; + if ($ftpdir ne "/") { $ftpdir=~s/\/$//; } + if ( $syncdirection eq "" ) { $syncdirection="get"; } + } + elsif ($fname =~ m/ftppass(w(or)?d)?/i) + { $ftppasswd=$fvalue; + if ( $syncdirection eq "" ) { $syncdirection="get"; } + } + elsif ($fname eq "ftpserver") { $ftpserver =$fvalue; + if ( $syncdirection eq "" ) { $syncdirection="get"; } + } + elsif ($fname eq "ftpuser") { $ftpuser =$fvalue; + if ( $syncdirection eq "" ) { $syncdirection="get"; } + } + elsif ($fname eq "localdir") { $localdir =$fvalue; $localdir=~s/\/$//; + if ( $syncdirection eq "" ) { $syncdirection="put"; } + } + elsif ($fname eq "timeout") { if ($fvalue>0) { $ftptimeout =$fvalue; } } + } + else { + if ($localdir eq "") { + $localdir = $curopt; + if ( $syncdirection eq "" ) + { $syncdirection="put"; } + } else { + print "ERROR: Unknown parameter: \"".$curopt."\"\n"; $returncode+=1 + } + } +} +if ($noofopts == 0) { print_syntax(); exit 0; } + +if($ftpuser eq "?") { print "User: "; $ftpuser=<STDIN>; chomp($ftpuser); } +if($ftppasswd eq "?") { print "Password: "; $ftppasswd=<STDIN>; chomp($ftppasswd); } + +if ($dodebug) { print_options(); } +# check options +if ( ($localdir eq "") || (! -d $localdir) ) +{ print "ERROR: Local directory does not exist: ".$localdir."\n"; $returncode+=1; } +#if ($localdir eq "") { print "ERROR: No localdir given.\n"; $returncode+=1; } +#if ( ($remoteURL eq "") { print "ERROR: No remoteURL given.\n"; $returncode+=1; } +if ($ftpserver eq "") { print "ERROR: No FTP server given.\n"; $returncode+=1; } +if ($ftpdir eq "") { print "ERROR: No FTP directory given.\n"; $returncode+=1; } +if ($ftpuser eq "") { print "ERROR: No FTP user given.\n"; $returncode+=1; } +if ($ftppasswd eq "") { print "ERROR: No FTP password given.\n"; $returncode+=1; } +if ($returncode > 0) { die "Aborting due to missing or wrong options! Call ftpsync -? for more information.\n"; } + + +#print "Exiting.\n"; exit 0; + +if ($dodebug) { print "\nFind out if ftp server is online & accessible.\n"; } +my $doftpdebug=($doverbose > 2); +my $ftpc = Net::FTP->new($ftpserver,Debug=>$doftpdebug,Timeout=>$ftptimeout) || die "Could not connect to $ftpserver\n"; +if ($dodebug) { print "Logging in as $ftpuser with password $ftppasswd.\n" } +$ftpc->login($ftpuser,$ftppasswd) || die "Could not login to $ftpserver as $ftpuser\n"; +my $ftpdefdir=$ftpc->pwd(); +if ($dodebug) { print "Remote directory is now ".$ftpdefdir."\n"; } +if ($ftpdir !~ /^\//) # insert remote login directory into relative ftpdir specification +{ if ($ftpdefdir eq "/") + { $ftpdir = $ftpdefdir . $ftpdir; } + else + { $ftpdir = $ftpdefdir . "/" . $ftpdir; } + if (!$doquiet) + { print "Absolute remote directory is $ftpdir\n"; } +} +if (substr($ftpdir, -1) eq "/") { + if (!$doquiet) + { print " Remote directory ends in /, removing this\n"; } + chop($ftpdir); +} +if ($dodebug) { print "Changing to remote directory $ftpdir.\n" } +$ftpc->binary() + or die "Cannot set binary mode :\n\t" . $ftpc->message; +$ftpc->cwd($ftpdir) + or die "Cannot cwd to $ftpdir :\n\t" . $ftpc->message; +if ($ftpc->pwd() ne $ftpdir) { + my $pwd = $ftpc->pwd(); + die "Could not change to remote base directory $ftpdir (at $pwd)\n"; } +if ($dodebug) { print "Remote directory is now ".$ftpc->pwd()."\n"; } + +if (! $doquiet) { print "\nDetermine s offset.\n"; } +if ($syncdirection eq "put") { clocksync($ftpc,"syncfile"); } + +# local & remote tree vars +#chdir $localdir; +my $ldl=length($localdir) + 1; +#my $ldl=length($localdir); +my %localfiledates=(); +my %localfilesizes=(); +my %localdirs=(); +my %locallinks=(); + +my %remotefilesizes=(); +my %remotefiledates=(); +my %remotedirs=(); +my %remotelinks=(); +my $curremotesubdir=""; + +# Build local & remote tree +if (! $doquiet) { print "\nBuilding local file tree.\n"; } +buildlocaltree(); +if (! $doquiet) { print "\nBuilding remote file tree.\n"; } +buildremotetree(); +listremotedirs(); +#if ($dodebug) { print "Quitting FTP connection.\n" } +#$ftpc->quit(); + +#print "Exiting.\n"; exit 0; + +# Work ... +if ($doinfoonly) { $docheckfirst=0; } +if ($docheckfirst) +{ print "Simulating synchronization.\n"; + $doinfoonly=1; + dosync(); + $doinfoonly=0; + print "\nOK to really update files? (y/n) [n] "; + my $yn=<STDIN>; + if ($yn =~ /^y/i) + { print "OK, going to do it.\n"; + } + else + { print "OK, exiting without actions.\n"; + exit 1; + } +} +if ($doinfoonly) { print "\nSimulating synchronization.\n"; } +elsif (! $doquiet) { print "\nStarting synchronization.\n"; } +dosync(); + +if (!$doquiet) { print "Done.\n"; } + +if ($dodebug) { print "Quitting FTP connection.\n" } +$ftpc->quit(); + +exit 0; + + + +# +# Subs +# + +sub buildlocaltree() { + find (\¬icelocalfile, $localdir."/"); + sub noticelocalfile { + if ($ldl > length($File::Find::name)) { return; } + #printf "name=%s, length(name)=%d, ldl=$ldl\n", $File::Find::name, length($File::Find::name); + my $relfilename=substr($File::Find::name,$ldl); + if (length($relfilename) == 0) { return; } + if (-d $_) { + if ($dodebug) { print "Directory: ".$File::Find::name."\n"; } + elsif (! $doquiet) { print ":"; } + $localdirs{$relfilename}="$relfilename"; + } + elsif (-f $_) { + #my @curfilestat=lstat $File::Find::name; + my @curfilestat=lstat $_; + my $curfilesize=$curfilestat[7]; + my $curfilemdt=$curfilestat[9]; + if ($dodebug) { print "File: ".$File::Find::name."\n"; + print "Modified ".$curfilemdt."\nSize ".$curfilesize." bytes\n"; } + elsif (! $doquiet) { print "."; } + $localfiledates{$relfilename}=$curfilemdt; + $localfilesizes{$relfilename}=$curfilesize; + } + elsif (-l $_) { + if ($dodebug) { print "Link: ".$File::Find::name."\n"; } + elsif (! $doquiet) { print ","; } + $locallinks{$relfilename}="$relfilename"; + } else { + #print "u ".$File::Find::name."\n"; + if (! $doquiet) { print "Ignoring file of unknown type: ".$File::Find::name."\n"; } + } + #if (! ($doquiet || $dodebug)) { print "\n"; } + #print "File mode is ".@curfilestat[2]."\n"; + } + if ($dodebug) { + print "Local dirs (relative to ".$localdir."/):\n"; + my $curlocaldir=""; + foreach $curlocaldir (keys(%localdirs)) + { print $curlocaldir."/\n"; } + print "Local files (relative to ".$localdir."/):\n"; + my $curlocalfile=""; + foreach $curlocalfile (keys(%localfiledates)) + { print $curlocalfile."\n"; } + } +} + + +sub buildremotetree() { + my @currecursedirs=(); + #$ftpc->ls() + # or die $ftpc->message . "\nCannot ls remote dir " . $ftpc->pwd(); + my @rfl = $ftpc->dir(); + # or @rfl=(); # we have to survive empty remote directories !!! + my $currf=""; + my $curyear = (gmtime(time))[5] + 1900; + my %monthtonr=(); + $monthtonr{"Jan"}=1; $monthtonr{"Feb"}=2; $monthtonr{"Mar"}=3; $monthtonr{"Apr"}=4; $monthtonr{"May"}=5; $monthtonr{"Jun"}=6; + $monthtonr{"Jul"}=7; $monthtonr{"Aug"}=8; $monthtonr{"Sep"}=9; $monthtonr{"Oct"}=10; $monthtonr{"Nov"}=11; $monthtonr{"Dec"}=12; + if ($dodebug) { print "Remote pwd is ".$ftpc->pwd()."\nDIRing.\n"; } + my $curlsline; + foreach $curlsline (parse_dir(\@rfl)) { + my ($cfname,$cftype,$cfsize,$cftime,$mode)=@$curlsline; + #if ($dodebug) { print "Analysing remote file/dir ".$currf."\n" }; + if ( $cftype ) { + if ($cfname eq ".") { next; } + if ($cfname eq "..") { next; } + if (substr($cftype,0,1) eq 'l') { # link, rest of string = linkto + my $curnrl; + if ($curremotesubdir eq "") { $curnrl = $cfname; } + else { $curnrl = $curremotesubdir."/".$cfname; } + $remotelinks{$curnrl}=$cfname; + if ($dodebug) { print "Link: ".$curnrl." -> ".$cfname."\n"; } + } + elsif ($cftype eq 'd') { + my $curnewrsd; + if ($curremotesubdir eq "") { $curnewrsd = $cfname; } + else { $curnewrsd = $curremotesubdir."/".$cfname; } + $remotedirs{$curnewrsd}=$curnewrsd; + if ($dodebug) { print "Directory: ".$curnewrsd."\n"; } + elsif (! $doquiet) { print ":"; } + push @currecursedirs, $cfname; + } + elsif ($cftype eq 'f') { #plain file + my $curnewrf; + if ($curremotesubdir eq "") { $curnewrf = $cfname; } + else { $curnewrf = $curremotesubdir."/".$cfname; } + #$remotefiledates{$curnewrf}=$cftime; + $remotefiledates{$curnewrf}=$ftpc->mdtm($cfname)+$syncoff; + if ($remotefiledates{$curnewrf} le 0) { die "Timeout detecting modification time of $curnewrf\n"; } + $remotefilesizes{$curnewrf}=$cfsize; + if ($remotefilesizes{$curnewrf} lt 0) { die "Timeout detecting size of $curnewrf\n"; } + if ($dodebug) { print "File: ".$curnewrf."\n"; } + elsif (! $doquiet) { print "."; } + } + elsif (! $doquiet) { print "Unkown file: $curlsline\n"; } + } + elsif ($dodebug) { print "Ignoring.\n"; } + } + #recurse + my $currecurseddir; + foreach $currecurseddir (@currecursedirs) + { my $oldcurremotesubdir; + $oldcurremotesubdir=$curremotesubdir; + if ($curremotesubdir eq "") { $curremotesubdir = $currecurseddir; } + else { $curremotesubdir .= "/".$currecurseddir; } + my $curcwddir=""; + if ($ftpdir eq "/") + { $curcwddir=$ftpdir.$curremotesubdir; } + else + { $curcwddir=$ftpdir."/".$curremotesubdir; } + if ($dodebug) { print "Change dir: ".$curcwddir."\n"; } + $ftpc->cwd($curcwddir) + or die "Cannot cwd to $curcwddir :\n\t" . $ftpc->message ; + if ($ftpc->pwd() ne $curcwddir) { + die "Could not cwd to $curcwddir :\n\t" . $ftpc->message ; } + if (! $doquiet) { print "\n"; } + buildremotetree(); + $ftpc->cdup(); + $curremotesubdir = $oldcurremotesubdir; + } +} + + +# Synchronize clocks. +sub clocksync { + my $conn = shift @_; + my $fn = shift @_; + my $fndidexist=1; + + if(! -f $fn) { + open(SF, ">$fn") or die "Cannot create $fn for time sync option"; + close(SF); + $fndidexist=0; + } + -z $fn or + die "File $fn for time sync must be empty."; + my $putsyncok=1; + $conn->put($fn) or $putsyncok=0; + if (!$putsyncok) + { unlink($fn); # cleanup! + die "Cannot send timesync file $fn"; + } + + my $now_here1 = time(); + my $now_there = $conn->mdtm($fn) or + die "Cannot get write time of timesync file $fn"; + my $now_here2 = time(); + + if ($now_here2 < $now_there) # remote is in the future + { $syncoff=($now_there - $now_here1); + $syncoff -= $syncoff % 60; + $syncoff = 0-$syncoff; + } + else + #if ($now_here1 > $now_there) # remote is the past # or equal + { $syncoff=($now_here2 - $now_there); + $syncoff -= $syncoff % 60; + } + + $conn->delete($fn); + + my $hrs = int(abs($syncoff)/3600); + my $mins = int(abs($syncoff)/60) - $hrs*60; + my $secs = abs($syncoff) - $hrs*3600 - $mins*60; + if (! $doquiet) { + printf("Clock sync offset: %d:%02d:%02d\n", $hrs, $mins, $secs); + } + unlink ($fn) unless $fndidexist; +} + + +sub dosync() +{ + chdir $localdir || die "Could not change to local base directory $localdir\n"; + if ($syncdirection eq "put") { + # create dirs missing at the target + if ($doinfoonly) { print "\nWould create new remote directories.\n"; } + elsif (! $doquiet) { print "\nCreating new remote directories.\n"; } + my $curlocaldir; + foreach $curlocaldir (sort { return length($a) <=> length($b); } keys(%localdirs)) + { if (! exists $remotedirs{$curlocaldir}) + { if ($doinfoonly) { print $curlocaldir."\n"; next; } + if ($doverbose) { print $curlocaldir."\n"; } + elsif (! $doquiet) { print "d"; } + if ($ftpc->mkdir($curlocaldir) ne $curlocaldir) { die "Could not create remote subdirectory $curlocaldir\n"; } + } + } + # copy files missing or too old at the target, synchronize timestamp _after_ copying + if ($doinfoonly) { print "\nWould copy new(er) local files.\n"; } + elsif (! $doquiet) { print "\nCopying new(er) local files.\n"; } + my $curlocalfile; + foreach $curlocalfile (sort { return length($b) <=> length($a); } keys(%localfiledates)) + { my $dorefresh=0; + if (! exists $remotefiledates{$curlocalfile}) { + $dorefresh=1; + $infotext="New: ".$curlocalfile." (".$localfilesizes{$curlocalfile}." bytes)\n"; + if ($doinfoonly) { print $infotext; next; } + elsif ($doverbose) { print $infotext; } + elsif (! $doquiet) { print "n"; } + } + elsif ($remotefiledates{$curlocalfile} < $localfiledates{$curlocalfile}) { + $dorefresh=1; + $infotext="Newer: ".$curlocalfile." (".$localfilesizes{$curlocalfile}." bytes, ".$localfiledates{$curlocalfile}." versus ".$remotefiledates{$curlocalfile}.")\n"; + if ($doinfoonly) { print $infotext; next; } + if ($doverbose) { print $infotext; } + elsif (! $doquiet) { print "u"; } + } + elsif ($remotefilesizes{$curlocalfile} != $localfilesizes{$curlocalfile}) { + $dorefresh=1; + $infotext="Changed (different sized): ".$curlocalfile." (".$localfilesizes{$curlocalfile}." versus ".$remotefilesizes{$curlocalfile}." bytes)\n"; + if ($doinfoonly) { print $infotext; next; } + if ($doverbose) { print $infotext; } + elsif (! $doquiet) { print "u"; } + } + if (! $dorefresh) { next; } + if ($dodebug) { print "Really PUTting file ".$curlocalfile."\n"; } + if ($ftpc->put($curlocalfile, $curlocalfile) ne $curlocalfile) + { print STDERR "Could not put localfile $curlocalfile\n"; } + my $retries = 3; + while ( ($ftpc->size($curlocalfile) != (lstat $curlocalfile)[7]) and ($retries-- > 0) ) + { if (! $doquiet) { print "Re-Transfering $curlocalfile\n"; } + if ($ftpc->put($curlocalfile, $curlocalfile) ne $curlocalfile) + { print STDERR "Could not re-put localfile $curlocalfile\n"; } + } + my $newremotemdt=$ftpc->mdtm($curlocalfile)+$syncoff; + utime ($newremotemdt, $newremotemdt, $curlocalfile); + } + # delete files too much at the target + if ($doinfoonly) { print "\nWould delete obsolete remote files.\n"; } + elsif (! $doquiet) { print "\nDeleting obsolete remote files.\n"; } + my $curremotefile; + foreach $curremotefile (keys(%remotefiledates)) + { if (not exists $localfiledates{$curremotefile}) + { if ($doinfoonly) { print $curremotefile."\n"; next; } + if ($doverbose) { print $curremotefile."\n"; } + elsif (! $doquiet) { print "r"; } + if ($ftpc->delete($curremotefile) ne 1) { die "Could not delete remote file $curremotefile\n"; } + } + } + # delete dirs too much at the target + if ($doinfoonly) { print "\nWould delete obsolete remote directories.\n"; } + elsif (! $doquiet) { print "\nDeleting obsolete remote directories.\n"; } + my $curremotedir; + foreach $curremotedir (sort { return length($b) <=> length($a); } keys(%remotedirs)) + { if (! exists $localdirs{$curremotedir}) + { if ($doinfoonly) { print $curremotedir."\n"; next; } + if ($doverbose) { print $curremotedir."\n"; } + elsif (! $doquiet) { print "R"; } + if ($ftpc->rmdir($curremotedir) ne 1) { die "Could not remove remote subdirectory $curremotedir\n"; } + } + } + } else { # $syncdirection eq "GET" + # create dirs missing at the target + if ($doinfoonly) { print "\nWould create new local directories.\n"; } + elsif (! $doquiet) { print "\nCreating new local directories.\n"; } + my $curremotedir; + foreach $curremotedir (sort { return length($a) <=> length($b); } keys(%remotedirs)) + { if (! exists $localdirs{$curremotedir}) + { if ($doinfoonly) { print $curremotedir."\n"; next; } + if ($doverbose) { print $curremotedir."\n"; } + elsif (! $doquiet) { print "d"; } + mkdir($curremotedir) || die "Could not create local subdirectory $curremotedir\n"; + } + } + # copy files missing or too old at the target, synchronize timestamp _after_ copying + if ($doinfoonly) { print "\nWould copy new(er) remote files.\n"; } + elsif (! $doquiet) { print "\nCopying new(er) remote files.\n"; } + my $curremotefile; + foreach $curremotefile (sort { return length($b) <=> length($a); } keys(%remotefiledates)) + { my $dorefresh=0; + if (! exists $localfiledates{$curremotefile}) { + $dorefresh=1; + $infotext="New: ".$curremotefile." (".$remotefilesizes{$curremotefile}." bytes)\n"; + if ($doinfoonly) { print $infotext; next; } + if ($doverbose) { print $infotext; } + elsif (! $doquiet) { print "n"; } + } + elsif ($remotefiledates{$curremotefile} > $localfiledates{$curremotefile}) { + $dorefresh=1; + $infotext="Newer: ".$curremotefile." (".$remotefilesizes{$curremotefile}." bytes, ".$remotefiledates{$curremotefile}." versus ".$localfiledates{$curremotefile}.")\n"; + if ($doinfoonly) { print $infotext; next; } + if ($doverbose) { print $infotext; } + elsif (! $doquiet) { print "u"; } + } + elsif ($remotefilesizes{$curremotefile} != $localfilesizes{$curremotefile}) { + $dorefresh=1; + $infotext="Changed (different sized): ".$curremotefile." (".$remotefilesizes{$curremotefile}." bytes)\n"; + if ($doinfoonly) { print $infotext; next; } + if ($doverbose) { print $infotext; } + elsif (! $doquiet) { print "c"; } + } + if (! $dorefresh) { next; } + if ($dodebug) { print "Really GETting file ".$curremotefile."\n"; } + my $rc=$ftpc->get($curremotefile, $curremotefile); + if ( ($rc eq undef) or ($rc ne $curremotefile) ) + { print STDERR "Could not get file ".$curremotefile."\n"; } + my $retries=3; + while ( ($ftpc->size($curremotefile) != (lstat $curremotefile)[7]) and ($retries-- > 0) ) + { if (! $doquiet) { print "Re-Transfering $curremotefile\n"; } + if ( ($rc eq undef) or ($rc ne $curremotefile) ) + { print STDERR "Could not get file ".$curremotefile."\n"; } + } + my $newlocalmdt=$remotefiledates{$curremotefile}; + utime ($newlocalmdt, $newlocalmdt, $curremotefile); + } + # delete files too much at the target + if ($doinfoonly) { print "\nWould delete obsolete local files.\n"; } + elsif (! $doquiet) { print "\nDeleting obsolete local files.\n"; } + my $curlocalfile; + foreach $curlocalfile (sort { return length($b) <=> length($a); } keys(%localfiledates)) + { if (not exists $remotefiledates{$curlocalfile}) + { if ($doinfoonly) { print $curlocalfile."\n"; next; } + if ($doverbose) { print $curlocalfile."\n"; } + elsif (! $doquiet) { print "r"; } + if (unlink($curlocalfile) ne 1) { die "Could not remove local file $curlocalfile\n"; } + } + } + # delete dirs too much at the target + if ($doinfoonly) { print "\nWould delete obsolete local directories.\n"; } + elsif (! $doquiet) { print "\nDeleting obsolete local directories.\n"; } + my $curlocaldir; + foreach $curlocaldir (keys(%localdirs)) + { if (! exists $remotedirs{$curlocaldir}) + { if ($doinfoonly) { print $curlocaldir."\n"; next; } + if ($doverbose) { print $curlocaldir."\n"; } + elsif (! $doquiet) { print "d"; } + rmdir($curlocaldir) || die "Could not remove local subdirectory $curlocaldir\n"; + } + } + } +} + + +sub listremotedirs() { + if ($dodebug) { + print "Remote dirs (relative to ".$ftpdir."):\n"; + my $curremotedir=""; + foreach $curremotedir (keys(%remotedirs)) + { print $curremotedir."/\n"; } + print "Remote files (relative to ".$ftpdir."):\n"; + my $curremotefile=""; + foreach $curremotefile (keys(%remotefiledates)) + { print $curremotefile."\n"; } + print "Remote links (relative to ".$ftpdir."):\n"; + my $curremotelink=""; + foreach $curremotelink (keys(%remotelinks)) + { print $curremotelink." -> ".$remotelinks{$curremotelink}."\n"; } + } +} +sub parseRemoteURL() { + if ($remoteURL =~ /^ftp:\/\/(([^@\/\\\:]+)(:([^@\/\\\:]+))?@)?([a-zA-Z01-9\.]+)\/(.*)/) { + #print "DEBUG: parsing ".$remoteURL."\n"; + #print "match 1 = ".$1."\n"; + #print "match 2 = ".$2."\n"; + #print "match 3 = ".$3."\n"; + #print "match 4 = ".$4."\n"; + #print "match 5 = ".$5."\n"; + #print "match 6 = ".$6."\n"; + #print "match 7 = ".$7."\n"; + if (length($2) > 0) { $ftpuser=$2; } + if (length($4) > 0) { $ftppasswd=$4; } + $ftpserver=$5; + $ftpdir=$6; + #if ($ftpdir eq "") { $ftpdir="/"; } + } +} + + +sub print_syntax() { + print "\n"; + print "FTPSync.pl 1.27 (2004-08-23)\n"; + print "\n"; + print " ftpsync [ options ] [ localdir remoteURL ]\n"; + print " ftpsync [ options ] [ remoteURL localdir ]\n"; + print " options = [-dgpqv] [ cfg|ftpuser|ftppasswd|ftpserver|ftpdir=value ... ] \n"; + print " localdir local directory, defaults to \".\".\n"; + print " ftpURL full FTP URL, scheme\n"; + print ' ftp://[ftpuser[:ftppasswd]@]ftpserver/ftpdir'."\n"; + print " ftpdir is relative, so double / for absolute paths as well as /\n"; + print " -c | -C like -i, but then prompts whether to actually do work\n"; + print " -d | -D turns debug output (including verbose output) on\n"; + print " -g | -G forces sync direction to GET (remote to local)\n"; + print " -h | -H turns debugging on\n"; + print " -i | -I forces info mode, only telling what would be done\n"; + print " -p | -P forces sync direction to PUT (local to remote)\n"; + print " -q | -Q turnes quiet operation on\n"; + print " -v | -V turnes verbose output on\n"; + print " cfg= read parameters and options from file defined by value.\n"; + print " ftpserver= defines the FTP server, defaults to \"localhost\".\n"; + print " ftpdir= defines the FTP directory, defaults to \".\" (/wo '\"') \n"; + print " ftpuser= defines the FTP user, defaults to \"ftp\".\n"; + print " ftppasswd= defines the FTP password, defaults to \"anonymous\".\n"; + print "\n"; + print " Later mentioned options and parameters overwrite those mentioned earlier.\n"; + print " Command line options and parameters overwrite those in the config file.\n"; + print " Don't use '\"', although mentioned default values might motiviate you to.\n"; + print "\n"; +} + + +sub print_options() { + print "\nPrinting options:\n"; + # meta + print "returncode = ", $returncode , "\n"; + print "configfile = ", $configfile , "\n"; + # basiscs + print "syncdirection = ", $syncdirection , "\n"; + print "localdir = ", $localdir , "\n"; + # FTP stuff + print "remoteURL = ", $remoteURL , "\n"; + print "ftpuser = ", $ftpuser , "\n"; + print "ftppasswd = ", $ftppasswd , "\n"; + print "ftpserver = ", $ftpserver , "\n"; + print "ftpdir = ", $ftpdir , "\n"; + # verbsityosity + print "doverbose = ", $doverbose , "\n"; + print "dodebug = ", $dodebug , "\n"; + print "doquiet = ", $doquiet , "\n"; + # + print "doinfoonly = ", $doinfoonly , "\n"; + print "\n"; +} diff --git a/emacs/nxhtml/nxhtml/html-wtoc.el b/emacs/nxhtml/nxhtml/html-wtoc.el new file mode 100644 index 0000000..94533da --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc.el @@ -0,0 +1,200 @@ +;;; html-wtoc.el --- Creating pages with site TOC +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Feb 11 00:06:14 2006 +(defconst html-wtoc:version "0.2") ;; Version: +;; Last-Updated: Sun Nov 04 21:49:34 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (add-to-list 'load-path default-directory load-path)) +(eval-when-compile (require 'html-site nil t)) + +;;;###autoload +(defgroup html-wtoc nil + "Customization group for html-wtoc." + :group 'nxhtml) + +(defcustom html-wtoc-dir + (file-name-as-directory + (expand-file-name + "html-wtoc" + (file-name-directory + (if load-file-name load-file-name buffer-file-name)))) + + "Directory where the tools needed are located. +The tools for html-wtoc includes: + +- html-wtoc.pl +- html-wtoc.js +- html-wtoc.css +- html-wtoc-template.htm +- html-wtoc-template.js +- html-wtoc-template.css +- img/ + +" + :type 'directory + :group 'html-wtoc) + +;; (defun html-wtoc-get-parsed-html-toc () +;; (save-excursion +;; (let ((toc-file (html-toc-file))) +;; (unless (file-exists-p toc-file) +;; (html-toc-write-toc-file)) +;; (with-current-buffer (find-file-noselect toc-file) +;; (goto-char (point-min)) +;; (let ((toc-begin (search-forward html-toc-mark-begin nil t)) +;; (toc-middle (search-forward html-toc-mark-middle nil t)) +;; toc-parsed) +;; (unless (and toc-begin toc-middle) +;; (error "Can't find table of contents in %s" toc-file)) +;; (setq toc-parsed (html-toc-parse-toc +;; (buffer-substring-no-properties +;; toc-begin toc-middle)))))))) + +;; (defun html-wtoc-get-atags (parsed-ul level) +;; (assert (eq 'ul (car parsed-ul))) +;; (let (atags) +;; (dolist (l parsed-ul) +;; (when (and (listp l) +;; (eq 'li (car l))) +;; (dolist (ll l) +;; (when (listp ll) +;; (when (eq 'a (car ll)) +;; (setq atags +;; (cons +;; (list level +;; (caddr ll) +;; (cdaadr ll)) +;; atags))) +;; (when (eq 'ul (car ll)) +;; (let ((subs (html-wtoc-get-atags ll (1+ level)))) +;; (dolist (s subs) +;; (setq atags (cons s atags))))))))) +;; (reverse atags))) + +;; (defcustom html-wtoc-pages-default-name "html-wtoc-pages.txt" +;; "Default file name sans directory for list of pages file. +;; This file is located in the same directory as `html-toc-file'." +;; :type 'string) + +;; (defun html-wtoc-pages-file () +;; (expand-file-name html-wtoc-pages-default-name +;; (file-name-directory (html-toc-file)))) + +(defun html-wtoc-browse-page-with-toc () + (interactive) + (unless buffer-file-name + (error "This buffer is not visiting a file")) + (html-site-current-ensure-site-defined) + (let ((merge-dir (html-site-current-merge-dir)) + merged-file + (in-site (html-site-dir-contains + (html-site-current-site-dir) + buffer-file-name))) + (unless merge-dir + (error "There is no output dir for pages with TOC defined for the site %s" + html-site-current)) + (unless in-site + (error "This buffer's file is not in %s" (html-site-current-site-dir))) + (setq merged-file + (expand-file-name + (file-relative-name buffer-file-name + (html-site-current-site-dir)) + (html-site-current-merge-dir))) + (unless (file-exists-p merged-file) + (error "The file %s does not yet exist.\nPlease do use `html-wtoc-write-merged' to create it." + merged-file)) + (browse-url-of-file merged-file))) + + +(defun html-wtoc-write-pages-with-toc (allow-overwrite) + "Merge the TOC with the pages. + +If an entry with the name MERGE-NAME exists in `html-wtoc-merges' +then this is chosen. Otherwise a new entry is created and added +to `html-wtoc-merges'. The entry has all necessary information to +do the merge. + +If `html-move-site-directory' has a non-nil value then the list +of completions when prompting for MERGE-NAME contains only those +merge names from `html-wtoc-merges' where the site directory has +the same value. Otherwise the completion list contains all merge +names and `html-move-site-directory' will be set to the chosen +merge's site directory. + +The merging of the pages and the table of contents is done in a +subprocess using a Perl script named html-wtoc.pl the directory +`html-wtoc-dir'. +" + (interactive (list (y-or-n-p "Allow overwrite? "))) + (html-site-current-ensure-site-defined) + (let ((pag-file (html-site-current-page-list)) + (out-dir (html-site-current-merge-dir)) + (tpl-file (html-site-current-merge-template)) + (html-wtoc-pl (expand-file-name "html-wtoc.pl" html-wtoc-dir)) + ) + (unless (< 0 (length pag-file)) + (error "Page list file not defined for site %s" html-site-current)) + (unless (file-exists-p pag-file) + (error "Can't find page file for site %s.\nHave you done M-x html-toc-create-pages-file?" + html-site-current)) + (unless (< 0 (length tpl-file)) + ;;(error "Template file not defined for site %s.\nPlease use customize to add this in `html-site-list'." html-site-current) + (setq tpl-file (expand-file-name "html-wtoc-template.html" html-wtoc-dir)) + ) + (let ( + (buffer (noshell-procbuf-setup "*Merging pages and TOC*")) + (opt (list + (concat "pages=" pag-file) + (concat "outroot=" out-dir) + (concat "template=" tpl-file)))) + (when allow-overwrite + (setq opt (cons "update=1" opt))) + (apply 'noshell-procbuf-run + buffer + "perl" "-w" + html-wtoc-pl "merge" + opt + )))) + +(provide 'html-wtoc) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-wtoc.el ends here diff --git a/emacs/nxhtml/nxhtml/html-wtoc/PerlLib/PathSubs.pm b/emacs/nxhtml/nxhtml/html-wtoc/PerlLib/PathSubs.pm new file mode 100644 index 0000000..e95b8d5 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc/PerlLib/PathSubs.pm @@ -0,0 +1,207 @@ +# Copyright 2006 Lennart Borgman, http://OurComments.org/. All rights +# reserved. +# +# 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 3, 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. + +package PathSubs; + +##################################################### +### This package contains general path handling +### routines and some win32 specific dito. +### The latter should ev be moved to a new module! +##################################################### +use strict; + +use File::Spec; + +### Absolute path names + +sub is_abs_path ($) { + my $path = shift; + return 0 if $path eq ""; + return 1 if File::Spec->file_name_is_absolute($path); + #return 1 if substr($path, 1, 1) eq ":"; # MSWin32 + #return 1 if substr($path, 0, 1) eq "/"; + return 1 if $path =~ /^https?:/i; + return 1 if $path =~ /^file:/i; + return 1 if $path =~ /^javascript:/i; + return 1 if $path =~ /^mailto:/i; +} +sub is_abs_netpath($) { + my $path = shift; + return 1 if $path =~ /^https?:/i; + # New + return 1 if $path =~ /^ftp:/i; + return 1 if $path =~ /^mailto:/i; +} + + +sub uniq_file($) { + my $fname = shift; + $fname =~ s!^\s+|\s+$!!g; + return "" if ($fname eq ""); + $fname = File::Spec->rel2abs($fname); + if (!File::Spec->file_name_is_absolute($fname)) { + die "File name is not absolute: $fname"; + } + #print STDERR "uniq_file($fname)\n"; + $fname =~ tr!\\!/!; + if (-e $fname) { + #print STDERR "exists $fname\n"; + ### There is an error in 522, compensate for this! + #die substr($fname, -1); + if (substr($fname, -1) eq "/") { chop $fname; } + #print STDERR "exists $fname\n"; + ### Translate .. + if (substr($fname, 1, 1) eq ":") { + my $ffname = Win32::GetFullPathName($fname); + ### Get case + my $lfname = Win32::GetLongPathName($ffname); + #print STDERR "lexists $lfname\n"; + $fname = $lfname if ($lfname ne ""); + } + } else { + #print STDERR "NOT exists $fname\n"; + if (substr($fname, -1) eq "/") { chop $fname; } + my $head = ""; + if (substr($fname, 0, 2) eq "//") { + $head = "//"; + $fname = substr($fname, 2); + } + my @fname = split("/", $fname); + my $tail = pop @fname; + $fname = uniq_dir($head . join("/", @fname)) . $tail; + } + if (substr($fname, 1, 1) eq ":") { + $fname = uc(substr($fname, 0, 1)) . substr($fname, 1); + #print STDERR "fname $fname\n"; + } + $fname =~ tr!\\!/!; + #print STDERR "fname ($fname)\n"; + return $fname; +} +sub uniq_dir($) { + my $dir = shift; + my $uq_dir = uniq_file($dir); + if (substr($uq_dir, -1) ne "/") { $uq_dir .= "/"; } + return $uq_dir; +} + + + +### Relative paths +sub _get_link_root($) { + my $lnk = shift; + if ($lnk =~ m!^(/|ftp://[^/]*|https?://[^/]*|[a-z]:/)!i) { + return $1; + } else { + return ""; + } +} + +sub resolve_dotdot($) { + my $orig_url = shift; + my $root = _get_link_root($orig_url); + return $orig_url if length($root) == length($orig_url); + my $url = substr($orig_url, length($root)); + if (substr($root, -1) eq "/") { + chop $root; + $url = "/$url"; + } + #die "$root\n$url"; + my $iPosSearch = 2; + #print "url=$url\n"; + while ((my $iPos = index($url, "/../", $iPosSearch)) > -1) { + my $sLeft = substr($url, 0, $iPos); + if (substr($sLeft, -2) eq "..") { + $iPosSearch += 3; + next; + } + my $sRight = substr($url, $iPos+3); + #print "url=$url\n"; + #print "iPos=$iPos\n"; + #print "sLeft=$sLeft\n"; + $sLeft =~ s!/[^/]*$!!; + #print "sLeft=$sLeft\n"; + #print "sRight=$sRight\n"; + $url = $sLeft . $sRight; + #print "\t***url=$url\n"; + #print "url=$url\n"; + } + if (index($url, "../") > -1) { + return $orig_url; + } + return $root . $url; +} + +sub mk_relative_link($$;$) { + my $from = shift; + my $to = shift; + my $norm = shift; + if ($norm) { + $from = uniq_file($from); + $to = uniq_file($to); + } + if (-e $from) { + $from = uniq_file($from); + } else { + $from = resolve_dotdot($from); + } + if (-e $to) { + $to = uniq_file($to); + } else { + $to = resolve_dotdot($to); + } + my $root_from = _get_link_root($from); + my $root_to = _get_link_root($to ); + if ($root_from ne $root_to) { + return $to; + } + my @from = split "/", $from; + my @to = split "/", $to; + while (@to) { + last if ($to[0] ne $from[0]); + shift @to; + shift @from; + } + if (@to == 1 && @from == 1) { + if (length($to[0]) > length($from[0])) { + if (substr($to[0], 0, length($from[0])+1) eq ($from[0] . "#")) { + return substr($to[0], length($from[0])); + } + } + } + my $rl; + for (1..$#from) { $rl .= "../"; } + $rl .= join("/", @to); + + return $rl; +} + + + +sub mk_absolute_link($$) { + my $from = shift; + my $rel_to = shift; + my $abs = $from; + $abs =~ s![^/]*$!!; + $abs .= $rel_to; + if (!is_abs_netpath($abs)) { $abs = uniq_file($abs); } + $abs; +} + + +1; diff --git a/emacs/nxhtml/nxhtml/html-wtoc/PerlLib/html_tags.pm b/emacs/nxhtml/nxhtml/html-wtoc/PerlLib/html_tags.pm new file mode 100644 index 0000000..ecdfd53 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc/PerlLib/html_tags.pm @@ -0,0 +1,127 @@ +# Copyright 2006 Lennart Borgman, http://OurComments.org/. All rights +# reserved. +# +# 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 3, 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. + + +package html_tags; +use strict; + +use vars qw($AUTOLOAD); + +sub _make_attributes { + my($self,$attr) = @_; + return () unless $attr && ref($attr) && ref($attr) eq 'HASH'; + my(@att); + foreach (keys %{$attr}) { + my($key) = $_; + $key=~s/^\-//; # get rid of initial - if present + #$key=~tr/a-z_/A-Z-/; # parameters are upper case, use dashes + $key=~tr/A-Z_/a-z-/; # parameters are lower case in XHTML + push(@att,defined($attr->{$_}) ? qq/$key="$attr->{$_}"/ : qq/$key/); + } + return @att; +} + +sub _tag { + my $tag_name = shift; + my $part = shift; + my($attr) = ''; + if (ref($_[0]) && ref($_[0]) eq 'HASH') { + my(@attr) = html_tags::_make_attributes( '',shift() ); + $attr = " @attr" if @attr; + } + #return "<$tag_name$attr />" unless @_; + return "<$tag_name$attr />" if $part == 1; + return "<$tag_name$attr>" if $part == 2; + my($tag,$untag) = ("<$tag_name$attr\n>","</$tag_name\n>"); + my @result = map { "$tag$_$untag" } (ref($_[0]) eq 'ARRAY') ? @{$_[0]} : "@_"; + return $result[0] if $part == 1; + return "@result"; +} + +sub _mk_tag_sub($$) { + my $name = shift; + my $package = shift; + my $caller = caller; + my $sep = ($name =~ s/^\*//); + my $lc_name = lc $name; + my $code = + ($lc_name =~ m/^(?:br|hr|input|img)$/ ? + "sub $package\:\:$name(;\$\$) { return $caller\:\:_tag('$lc_name',1,\@_); }\n" + : + "sub $package\:\:$name(\$;\$) { return $caller\:\:_tag('$lc_name',0,\@_); }\n" + ); + if ($sep) { + if ($lc_name eq "html") { + $code .= "sub $package\:\:start_$name(\$;\$\$) + {return $caller\:\:_start_html(\@_);}\n"; + $code .= "sub $package\:\:end_$name {return $caller\:\:_end_html();}\n"; + } else { + $code .= "sub $package\:\:start_$name(;\$\$) + {return $caller\:\:_tag('$lc_name',1,\@_);}\n"; + $code .= "sub $package\:\:end_$name {'</$lc_name>';}\n"; + } + } + $code; +} +sub _start_html { + my $title = shift; + my $head_tags = shift; + my $body_attr = shift; + # compensate for perl laziness... (will not detect undef sub) + $head_tags = $head_tags . _tag("title", 0, $title); + my $start = + _tag("html", 2) . + _tag("head", 0, $head_tags) . + _tag("body", 2, $body_attr); +} +sub _end_html { + return '</body></html>'; +} + +sub header(@) { + my @lines = @_; + my $header; + my $type; + while (@lines) { + my $key = shift @lines; my $value = shift @lines; + $header .= "$key: $value\n"; + $type = $value if $key =~ m/content-type/i; + } + $header .= "Content-type: text/html\n" unless defined $type; + $header .= "\n"; +} +sub import { + shift; + my %exported; + $exported{$_}++ for (@_); + my $caller = caller; + my $to_eval = "package $caller;\n"; + for my $name (keys %exported) { + die "Will not redefine $caller\:\:$name" if $caller->can($name); + my $func; + if ($name eq "header") { + $func = "sub header { html_tags::header(); }"; + } + $func = _mk_tag_sub($name, $caller) unless defined $func; + $to_eval .= "$func\n"; + } + eval $to_eval; + die $@ if $@; +} + +1; diff --git a/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.css b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.css new file mode 100644 index 0000000..a6ffabb --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.css @@ -0,0 +1,141 @@ +/* Main structures >>>>>>>>>>>>>>> */ +.html-wtoc-maintop { + font-size: 1px; + font-size: 1em; + margin-top: 0em; + margin-bottom: 0em; +/* background-color:green; */ +} +.html-wtoc-main { +} + +td.html-wtoc-vdivline { + //background-color: #8be; + width: 0px; +} + +.html-wtoc-search-form { + margin-bottom: 0.1em; +} +.html-wtoc-search { + font-size: 0.8em; + color: green; +} +.html-wtoc-search a { + color: green; +} +/* <<<<<<<<<<<<<<<<<<< */ + + + + +/* Table of content >>>>>>>>>>>>>> */ + +#html-wtoc-id-hidetoc { + height: 20px; + border-bottom: 2px inset #ddf; + border-color: #dff; +} + +#html-wtoc-id-tocdiv { + width: 2.5em; + //background-color: #eff; +} +#html-wtoc-id-logo { + width: 100%; + height: 120px; + padding: 0em; + margin: 0em; + border: 0em; +} +#html-wtoc-id-toc { +} +#html-wtoc-id-tocwidth { + width: 18em; + height: 0em; + padding: 0em; + margin: 0em; + border: 0em; + line-height: 0em; +/* background-color: red; */ +} +#html-wtoc-id-toccol { + width: 18em; +} + +.html-wtoc-contcol { + background-color: #dFEfff; + background-color: #dFEfff; + background-color: #cd950c; + background-color: #eead0e; +} +/* <<<<<<<<<<<<<<<<<<< */ + + + + +/* Buttons etc >>>>>>>>>>>>>>> */ +.html-wtoc-button { + font-size: 0.75em; + font-size: 8pt; + color: #5A5D00; + background-color: #9cf; + background-color: #bcee68; + background-color: #a2cd5a; + padding: 0.2em; + Border-Width: 2px; + Border-Style: outset; + text-align: center; + border-color: #ddf; +} +a.html-wtoc-button { + text-decoration: none; + color: #5A5D00; +} +a.html-wtoc-button:hover { + text-decoration:none; + background-color: #6af; + color:#340; +} + +a.html-wtoc-buttonimg img { + width: 16px; + height: 16px; + padding: 4px; + border: 8px; +} +a.html-wtoc-buttonimg { + border:2px; + margin:2px; + margin-left:2px; + margin-right:2px; +} +a.html-wtoc-buttonimg { + font-size:1px; +} +a.html-wtoc-buttonimg:hover { + margin: 6px; + margin-left:0px; + margin-right:0px; + border-color: #ddf; + border-width: 2px; + border-style: outset; + background-color: #595C00; + background-color: #bef; + background-color: #b9ffb9; +} + +/* <<<<<<<<<<<<<<<<<<< */ + + +#nxhtml-link { + font-size: 0.7em; + text-align: center; + padding-top: 2em; + padding: 1em; +} + +.copyright { + color : #872; +} + diff --git a/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.html b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.html new file mode 100644 index 0000000..440ece7 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc-template.html @@ -0,0 +1,143 @@ +<?xml version="1.0"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>HEAD</title> + <link rel="stylesheet" href="html-wtoc.css" type="text/css" /> + <link rel="stylesheet" href="html-wtoc-template.css" type="text/css" /> + <script type="text/javascript" src="html-wtoc.js"></script> + <script type="text/javascript" src="html-wtoc-template.js"></script> + <script type="text/javascript"> + var my_old_onload = window.onload; + function my_onload() { + HTML_WTOC_NS.onload_actions(%%PNUM%%); + if (undefined != my_old_onload) { my_old_onload(); } + } + window.onload = my_onload; + </script> + + </head> +<body> + + + + + <table summary="Page columns" cellspacing="0" border="0" cellpadding="0" width="100%" > + <tr valign="top"> + <td id="html-wtoc-id-toccol" class="html-wtoc-contcol"> + <table summary="Contents column" id="html-wtoc-id-toc" class="html-wtoc-contcol" + cellspacing="0" border="0" cellpadding="0" width="100%"> + <tr valign="top"> + <td colspan="2" height="50" > + <table summary="Contents displaying buttons" id="html-wtoc-id-hidetoc" + border="0" cellpadding="0" cellspacing="0" width="100%"> + <tr> + <td width="70%"> + <a href="javascript:HTML_WTOC_NS.show_content(0); void(0);" + class="html-wtoc-buttonimg" + ><img src="img/showCont.gif" + alt="Show table of content" + border="0" /></a> + + <a style="display:none;" + href="javascript:toggle_toc_nailing()" + class="html-wtoc-buttonimg" + ><img id="html-wtoc-id-nailimg" + src="img/freeCont.gif" + alt="Let table of content move with page" + border="0" /></a> + + </td> + </tr> + </table> + <table summary="Logo" id="html-wtoc-id-logo"> + <tr> + <td align="right" valign="bottom" > + <a href="http://www.OurComments.org/Emacs/EmacsW32.html" + ><img src="img/gnu-m-x-160.png" width="80" height="80" + alt="Go to EmacsW32 Home Page" + title="Go to EmacsW32 Home Page" + onmouseover="transLbi(this, false);" + onmouseout ="transLbi(this, true);" + style=" + margin-top:10px; + padding-left:20px; + padding-right:20px; + padding-top:10px; + padding-bottom:10px; + " + border="0" + /></a> + </td> + </tr> + </table> + </td> + </tr><tr valign="top"> + <td > + <table> + <tr> + <td>%%TOC%%</td> + </tr> + <tr> + <td id="nxhtml-link"> + <br /> + Built using Emacs + <br /> + with nxhtml from + <br /> + <a href="http://ourcomments.org/Emacs/Emacs.html" + target="_blank">ourcomments.org</a> + </td> + </tr> + </table> + </td> + <td class="html-wtoc-vdivline" width="1"></td> + </tr><tr> + <td colspan="2"> + </td> + </tr> + </table> + <table summary="Ensure table width" + cellspacing="0" id="html-wtoc-id-tocwidth"><tr><td></td></tr></table> + </td> + <td id="html-wtoc-id-tocdiv" ></td> + <td align="left" > + <table summary="Right column outermost" + cellspacing="0" border="0" cellpadding="0" width="100%"> + <tr valign="top"> + <td > </td> + <td align="left" class="html-wtoc-main"> + <p class="html-wtoc-maintop"> + <a href="javascript:HTML_WTOC_NS.show_content(1); void(0);" + id="html-wtoc-id-showtoc" style="display:none;" + class="html-wtoc-buttonimg" + ><img src="img/hideCont.gif" + alt="Hide table of content" + border="0" + /></a> + + </p> + %%PAGE%% + <p> </p> + <!-- + <hr style="clear:both" width="50%" class="copyright" /> + <span class="copyright" + > + © Copyright 2006 OurComments.org, + <a href="http://www.OurComments.org/" target="_blank" + class="copyright" + >http://www.OurComments.org/</a>. + All rights reserved. + </span> + --> + <br /> + <br /> + </td> + <td width="10"> </td> + </tr> + </table> + </td> + </tr> + </table> + </body> +</html> diff --git a/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.css b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.css new file mode 100644 index 0000000..a12cb65 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.css @@ -0,0 +1,84 @@ +body { + margin: 0; +} +td { + font-size: 1em; +} + +/* Added by html-wtoc.pl >>>>>>>>>>>>> */ +.html-wtoc-mark { +/* background-color: #9cf; */ +/* background-color: #bcee68; */ +/* background-color: #a2cd5a; */ + width: 20px; + padding: 0; + border: 0; + text-align: center; +} +.html-wtoc-contline { + width: 100%; +} + +.html-wtoc-margin { + width: 0.6em; +} +.html-wtoc-contents { + font-size: 0.9em; + padding: 1em; + background-color: #9cf; + background-color: #a2cd5a; + background-color: #efffcf; + background-color: #ffffdf; + -moz-border-radius-topleft: 2em; +} +.html-wtoc-contents td { +/* background-color: #9cf; */ +/* background-color: #bcee68; */ +/* background-color: #a2cd5a; */ +} +.html-wtoc-contents-a { + text-decoration: none; + color: #595C00; +/* background-color: #9cf; */ +/* background-color: #bcee68; */ +/* background-color: #a2cd5a; */ + border: 1px #9cf solid; + border: 1px #a2cd5a solid; + border: 1px #ffffc0 solid; + padding-left: 0.25em; + padding-right: 0; + margin: 1px; + display: block; +} +.html-wtoc-contents a:hover { + text-decoration: none; + background-color: #b9ffb9; + border: 1px #6b8e23 solid; +} +.html-wtoc-currcont { + background-color: #738600; + color: #ffff2f; + background-color: #535600; + border: 1px #6b8e23 inset; + padding-left: 0.25em; + padding-right: 0; + margin: 1px; + display: block; +} +a.html-wtoc-currcont { + text-decoration: none; +} +a.html-wtoc-currcont:hover { + background-color: #738600; + background-color: #536600; + background-color: #434620; +} +/* <<<<<<<<<<<<<<<<<<< */ + + + + + + + + diff --git a/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.js b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.js new file mode 100644 index 0000000..7f22db7 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.js @@ -0,0 +1,361 @@ + +// © Copyright 2006 Lennart Borgman, http://www.OurComments.org/. All rights reserved. +// +// 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 3, 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. + + +var HTML_WTOC_NS_sCurrTocId; + + +HTML_WTOC_NS = { + + ///////////////////////////// + //// Basic event functions + ///////////////////////////// + + getEventObject : function (ev) { + var o; + if (window.event) + o = window.event.srcElement; + else if (null != ev) + o = ( ev.target ); + return o; + }, + getEvent : function (ev) { + if (window.event) { + return window.event; + } else if (null != ev) { + return ev; + } + }, + + eventStopPropagation : function (e) { + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble=true; + }, + + eventPreventDefault : function (e) { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue=false; + }, + + ///////////////////////////// + //// TOC hide + ///////////////////////////// + + show_content : function (on) { + var toc = document.getElementById("html-wtoc-id-toccol").style; + var tdv = document.getElementById("html-wtoc-id-tocdiv").style; + var shw = document.getElementById("html-wtoc-id-showtoc").style; + var hid = document.getElementById("html-wtoc-id-hidetoc").style; + if (on) { + toc.display = ""; + tdv.display = ""; + shw.display = "none"; + hid.display = ""; + HTML_WTOC_NS.focus_page_link(0); + } else { + toc.display = "none"; + tdv.display = "none"; + shw.display = ""; + hid.display = "none"; + } + }, + + + + + + ///////////////////////////// + //// Open-Close + ///////////////////////////// + onblur_action : function(ev) { + HTML_WTOC_NS_sCurrTocId = null; + }, + onfocus_action : function(ev) { + var o = HTML_WTOC_NS.getEventObject(ev); + if (!o) return; + + HTML_WTOC_NS_sCurrTocId = o.id; + }, + onclick_action : function(ev) { + var o = HTML_WTOC_NS.getEventObject(ev); + var e = HTML_WTOC_NS.getEvent(ev); + if (13 == e.keyCode) return true; + if (!o) return true; + if ("IMG" == o.tagName) o = o.parentNode; + var iId = HTML_WTOC_NS.getIdnumFromId(o.id); + var sChildId = "toc_child_"+iId; + var sOldCurrTocId = HTML_WTOC_NS_sCurrTocId; + HTML_WTOC_NS.toggle_open(sChildId, o); + HTML_WTOC_NS_sCurrTocId = sOldCurrTocId; + return false; + }, + + toggle_open : function (id, parent) { + var child = document.getElementById(id).style; + var sInner = parent.innerHTML; + var re = new RegExp("[^/]*\.gif", "i"); + if ("none" == child.display) { + child.display = ""; + parent.innerHTML = sInner.replace(re, "down.gif")+""; + } else { + child.display = "none"; + parent.innerHTML = sInner.replace(re, "right.gif")+""; + } + }, + + + + ///////////////////////////// + //// Load + ///////////////////////////// + + onload_actions : function (iPageNum) { + document.body.onkeydown = HTML_WTOC_NS.onkeydown_action; + document.body.onmouseover = HTML_WTOC_NS.onmouseover_action; + var aATags = document.getElementsByTagName("a"); + for(var i = 0; i < aATags.length; i++) { + var o = aATags[i]; + if (null != HTML_WTOC_NS.getIdnumFromId(o.id)) { + o.onfocus = HTML_WTOC_NS.onfocus_action; + o.onblur = HTML_WTOC_NS.onblur_action; + if (o.id.substr(0, 12) == "opener_text_") { + o.onclick = HTML_WTOC_NS.onclick_action; + o.title = "Open/Close"; + } else if (o.id.substr(0, 7) == "opener_") { + o.onclick = HTML_WTOC_NS.onclick_action; + o.className = "html-wtoc-mark"; + o.title = "Open/Close"; + } + } + } + HTML_WTOC_NS.focus_page_link(iPageNum); + }, + focus_page_link : function (iPageNum) { + // Element might be hidden + try { + document.getElementById("toc_link_"+iPageNum).focus(); + } catch (exc) { + } + }, + + + + + + + + ///////////////////// + //// Mouse + ///////////////////// + + onmouseover_action : function (ev) { + if (null == HTML_WTOC_NS_sCurrTocId) return true; + var o = HTML_WTOC_NS.getEventObject(ev); + var iId = HTML_WTOC_NS.getIdnumFromId(o.id); + if (null == iId) return true; + o.focus(); + }, + + + + ///////////////////// + //// Key + ///////////////////// + + onkeydown_action: function (ev) { + var keyDown = 40; + var keyUp = 38; + var keyLeft = 37; + var keyRight = 39; + var keyReturn = 13; + var keyF2 = 113; + var keyInsert = 45; + // Opera + var keyOperaDown = 57386; + var keyOperaUp = 57385; + var keyOperaLeft = 57387; + var keyOperaRight = 57388; + var keyOperaF2 = 57346; + var keyOperaInsert = 57394; + + var SwitchKey = keyInsert; + var SwitchKeyOpera = keyOperaInsert; + + var bUp; + var e = HTML_WTOC_NS.getEvent(ev); + if (null == HTML_WTOC_NS_sCurrTocId) { + switch (e.keyCode) { + case SwitchKey: + case SwitchKeyOpera: + HTML_WTOC_NS.focus_page_link(0); + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + } + return true; + } + switch (e.keyCode) { + case keyLeft: + case keyOperaLeft: + case keyRight: + case keyOperaRight: + HTML_WTOC_NS.handle_leftright_keys(e); + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + case keyDown: + case keyOperaDown: + bUp = false; + break; + case keyUp: + case keyOperaUp: + bUp = true; + break; + case SwitchKey: + case SwitchKeyOpera: + if (null != HTML_WTOC_NS_sCurrTocId) { + var o = document.getElementById(HTML_WTOC_NS_sCurrTocId); + if (o) o.blur(); + HTML_WTOC_NS_sCurrTocId = null; + } + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + default: + //alert(e.keyCode); + return true; + } + var oOpener; + oOpener = HTML_WTOC_NS.getNextVisOpener(HTML_WTOC_NS_sCurrTocId, bUp); + oOpener.focus(); + HTML_WTOC_NS.eventStopPropagation(e); + HTML_WTOC_NS.eventPreventDefault(e); + return false; + }, + + handle_leftright_keys: function (e) { + var keyLeft = 37; + var keyRight = 39; + var keyOperaLeft = 57387; + var keyOperaRight = 57388; + var iId = HTML_WTOC_NS.getIdnumFromId(HTML_WTOC_NS_sCurrTocId); + if (null == iId) return; + var sId = "opener_" + iId; + var oOpener = document.getElementById(sId); + var sId = HTML_WTOC_NS_sCurrTocId; // It will be cleared before getNextVis + + var bOpenAction; + var bOpened; + var bUp; + var oChild = document.getElementById("toc_child_"+iId); + if (null == oChild) { + } else { + bOpened = (oChild.style.display != "none"); + } + switch (e.keyCode) { + case keyLeft: + case keyOperaLeft: + bUp = true; + bOpenAction = (null != bOpened) && (bOpened); + break; + case keyRight: + case keyOperaRight: + bUp = false; + bOpenAction = (null != bOpened) && (!bOpened); + break; + default: + alert("bad key handling..."); + } + if (bOpenAction) { + oOpener.click(); + HTML_WTOC_NS_sCurrTocId = sId; + } else { + var oPrev = HTML_WTOC_NS.getNextVisOpener(sId, bUp); + oPrev.focus(); + } + }, + + + + + + + ////////////////////// + //// Util + ////////////////////// + getNameFromId: function (sId) { + var re = new RegExp("(.*?_)(\\d+)", "i"); + if (!re.test(sId)) return null; + var iId = sId.replace(re, "$1"); + return iId; + }, + getIdnumFromId: function (sId) { + var re = new RegExp("(.*?_)(\\d+)", "i"); + if (!re.test(sId)) return null; + var iId = sId.replace(re, "$2"); + return iId; + }, + + + getNextVisOpener: function (sId, bUp, bTrace) { + if (bTrace) alert("getNextVisOpener("+sId+","+bUp+")"); + var iId = HTML_WTOC_NS.getIdnumFromId(sId); + if (null == iId) { + alert("getNextVisOpener err iId==null"); + return; + } + var sIdName = HTML_WTOC_NS.getNameFromId(sId); + if (null == sIdName) { + alert("getNextVisOpener err sIdName==null"); + return; + } + var oOpener; + var iLoop = -2; + while (oOpener == null) { + if (bTrace) alert(iId); + if (iLoop++ > iMaxChildNum) { alert("Child num error"); return; } + if (!bUp) { + iId++; + } else { + iId--; + } + if (iId > iMaxChildNum) { iId = 0; } + if (iId < 0) { iId = iMaxChildNum; } + var s = sIdName+iId; + oOpener = document.getElementById(s); + if (oOpener != null) { + if (bTrace) alert(oOpener.offsetLeft); + if (oOpener.style.display == "none") { // All + oOpener = null; + } else if (oOpener.offsetLeft < 0) { // IE + oOpener = null; + } else if (0 == oOpener.scrollWidth) { // Opera + oOpener = null; + } + } + } + return oOpener; + } + + + +}; //HTML_WTOC_NS diff --git a/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.pl b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.pl new file mode 100644 index 0000000..56c0e21 --- /dev/null +++ b/emacs/nxhtml/nxhtml/html-wtoc/html-wtoc.pl @@ -0,0 +1,1395 @@ +#! perl + +# Copyright 2006, 2007 Lennart Borgman, http://OurComments.org/. All +# rights reserved. +# +# 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. + +use strict; +use File::Copy; +use File::Spec; +#use File::Path qw(); +use File::Path; +use File::Find qw(); +use FindBin; + +use lib "$FindBin::Bin/PerlLib"; +use PathSubs qw(); +use html_tags qw( +*html header +div +table Tr td +p hr br +a span img b +); + +### Script start parameters +my $m_param_action; +my $m_param_files = 1; +my $m_param_pnum = 0; +my $m_param_single = 0; +my $m_param_Template; +my $m_param_InPages; +my $m_param_OutRoot; +my @m_param_InRoot; +my $m_param_Overwrite; + +### Globals +my $m_iAlwaysOpenedLevel = 0; +my $m_sCommonIn; +my $m_sInPagesFolder; +my $m_sTemplateFolder; +my $m_sStartTemplate; +my $m_sBodyTemplate; +#my $m_sEndTemplate; +my $m_bBorders = 0; +my @pages; +my %page_num; +my %js_show_page; +my $m_TemplateTime; +my $m_InPagesTime; +my %m_linked_files; + +sub get_params(); +sub get_template(); +sub read_page_list($); +sub find_pages($$); +sub write_pages(); +sub send_page(); +sub find_template_files(); +sub find_linked_from_pages(); +sub copy_wtoc_files(); +sub copy_linked_files(); + +#push @pages, [$ind, $tit, $full_fil, $anc, $hrf, $trg, $tip]; +sub IND { 0 } +sub TIT { 1 } +sub FULL_FIL { 2 } +sub ANC { 3 } +sub HRF { 4 } +sub TRG { 5 } +sub TIP { 6 } + +########################################################## +### Main +########################################################## +print "\n"; +get_params(); +if ($m_param_action eq "FIND") { + find_pages(\@m_param_InRoot, $m_param_InPages); +} elsif($m_param_action eq "MERGE") { + get_template(); + read_page_list($m_param_InPages); + find_template_files(); + copy_wtoc_files(); + if ($m_param_files) { + write_pages(); + } else { + send_page(); + } + find_linked_from_pages(); + copy_linked_files(); +} elsif($m_param_action eq "TOC") { +} +exit; + +sub copy_if_newer_or_overwrite($$) { + my $in_file = shift; + my $out = shift; + my $out_file = $out; + if (-d $out) { + my ($in_v, $in_d, $in_f) = File::Spec->splitpath( $in_file ); + my ($out_v,$out_d,$out_f) = File::Spec->splitpath( $out, 1 ); + $out_file = File::Spec->catpath( $out_v, $out_d, $in_f ); + } + my $should_write = 1; + if (-e $out_file) { + if ($m_param_Overwrite) { + my $in_mdt = (stat $in_file)[9]; + my $outmdt = (stat $out_file)[9]; + if (($outmdt > $in_mdt)) { + $should_write = 0; + } + } else { + $should_write = 0; + } + } + if ($should_write) { + if (!File::Copy::syscopy($in_file, $out_file)) { + die "syscopy($in_file, $out_file): $!"; + } else { + print " $in_file => $out_file\n"; + } + } +} # copy_if_newer_or_overwrite + +sub copy_wtoc_files() { + print "\n**** Copy html-wtoc files\n"; + mkdir $m_param_OutRoot, 0777; + my $css_file = $FindBin::Bin . "/html-wtoc.css"; + copy_if_newer_or_overwrite($css_file, $m_param_OutRoot); + my $js_file = $FindBin::Bin . "/html-wtoc.js"; + copy_if_newer_or_overwrite($js_file, $m_param_OutRoot); + my $OutRootImg = $m_param_OutRoot . "img/"; + mkpath($OutRootImg); + my $imgsrc = $FindBin::Bin . "/img/"; + opendir(IMGDIR, $imgsrc) or die "Can't opendir $imgsrc: $!"; + while (my $imgfile = readdir(IMGDIR)) { + my $outimg = $OutRootImg . $imgfile; + $imgfile = $imgsrc . $imgfile; + #print STDERR ">>>$imgfile\n"; + if (-f $imgfile) { + copy_if_newer_or_overwrite($imgfile, $outimg); + } + } + closedir(IMGDIR); +} # copy_wtoc_files + +sub add_to_linked_files($$) { + my $from_file = shift; + my $to_file = shift; + if (exists $m_linked_files{$to_file}) { + my $old_from = $m_linked_files{$to_file}; + unless ($old_from eq $from_file) { + die "Both $from_file and $old_from should be copied to $to_file"; + } + } + $m_linked_files{$to_file} = $from_file; +} # add_to_linked_files + +sub copy_linked_files() { + print "\n**** Copy linked files\n"; + my %pages; + for my $pnum (0..$#pages) { + $pages{ full_in_name($pnum) } = 1; + } + for my $to_file (keys %m_linked_files) { + my $from_file = $m_linked_files{$to_file}; + unless (exists $pages{$from_file}) { + if (-e $from_file) { + mkpath4file($to_file); + copy_if_newer_or_overwrite($from_file, $to_file); + } + } + } +} # copy_linked_files + +sub find_linked_files($;$) { + my $in_file = shift; + my $out_file = shift; + $out_file = in2out($in_file) unless ($out_file); + my $whole = get_file($in_file); + while ($whole =~ m!(?:\s|^)(?:href|src)="(.*?)"!gis) { + my $l = $1; + next unless $l =~ m!\.(?:css|js|jpg|jpeg|gif|png)$!; + if (!File::Spec->file_name_is_absolute($l)) { + next if $l =~ m!^javascript:!; + next if $l =~ m!^http://!; + next if $l =~ m!^ftp://!; + next if $l =~ m!^mailto:!; + } + my $rel_l = $l; + my $full_in = $l; + if (File::Spec->file_name_is_absolute($l)) { + $rel_l = PathSubs::mk_relative_link($in_file, $l); + } else { + $full_in = PathSubs::mk_absolute_link($in_file, $l); + } + my $full_out = PathSubs::mk_absolute_link($out_file, $rel_l); + add_to_linked_files($full_in, $full_out); + } +} # find_linked_files + +sub find_template_files() { + print "\n**** Find files referenced in template file\n"; + my $in_file = $m_param_Template; + my $out_file = $m_param_OutRoot . "dummy.htm"; + find_linked_files($in_file, $out_file); +} +sub find_linked_from_pages() { + for my $pnum (0..$#pages) { + next unless defined $pages[$pnum][FULL_FIL]; + next unless $pages[$pnum][FULL_FIL] ne ""; + next if defined $pages[$pnum][TRG]; + find_linked_files( full_in_name($pnum) ); + } +} + +sub should_write_merged($$) { + my $pnum = shift; + my $out_file = shift; + my $should_write = 1; + if (-e $out_file) { + if ($m_param_Overwrite) { + my $srcmdt = page_src_time($pnum); + my $outmdt = (stat $out_file)[9]; + if (($outmdt > $srcmdt) + && ($outmdt > $m_TemplateTime) + && ($outmdt > $m_InPagesTime)) { + $should_write = 0; + } + } else { + $should_write = 0; + } + } + return $should_write; +} +sub write_pages() { + #print STDERR "*** param_OutRoot=$m_param_OutRoot\n"; + if ($m_param_single) { + my $out_file = $m_param_OutRoot . "single_$m_param_pnum.html"; + if (should_write_merged($m_param_pnum, $out_file)) { + my $page = create_single_page($m_param_pnum); + $page = shrink($page); + create_file_and_path($out_file, $page); + } + } else { + my $iPages = 0; + print "\n*** Creating pages:\n"; + for my $pnum (0..$#pages) { + next unless defined $pages[$pnum][FULL_FIL]; + next unless $pages[$pnum][FULL_FIL] ne ""; + next if defined $pages[$pnum][TRG]; + $iPages++; + my $out_file = full_out_name($pnum); + if (should_write_merged($pnum, $out_file)) { + my $page = create_page($pnum); + next unless $page; + print " Creating page $iPages: " . full_in_name($pnum) . "\n"; + $page = shrink($page); + print "\t=> $out_file\n"; + create_file_and_path($out_file, $page); + } + } + } +} # write_pages + +sub send_page() { + my $page = ($m_param_single ? + create_single_page($m_param_pnum) + : + create_page($m_param_pnum) ); + print $page; +} # send_page + +########################################################## +### Params +########################################################## +sub die_usage() { + my $sScript = $0; + $sScript =~ tr!\\!/!; + $sScript =~ s!.*/(.*)!$1!; + die qq(Usage: + Making preliminary file list: + $sScript find in="in-dir" pages="pages-file" [overwrite=1] + + Merging pages and table of contents: + $sScript merge pages="pages-file" outroot="out-dir" template="template-file" [overwrite=1] + + \n); +} +#use Getopt::Long; +sub get_params() { + $| = 1; + for my $arg (@ARGV) { print " "; print $arg; } print "\n\n"; + die_usage() unless $#ARGV > 0; + $m_param_action = $ARGV[0]; + $m_param_action =~ tr/a-z/A-Z/; + #push @m_param_InRoot, $FindBin::Bin . "/doc/"; + #$m_param_OutRoot = $FindBin::Bin . "/tmp/"; + #$m_param_Template = $FindBin::Bin . "/doc/home_template.htm"; + #$m_param_InPages = $FindBin::Bin . "/doc/toc_pages.txt"; + for (my $i = 1; $i <= $#ARGV; $i++) { + my ($k, $v) = ($ARGV[$i] =~ m!(.*?)=(.*)!); + $v =~ tr!\\!/!; + if ($k eq "in") { + $v = PathSubs::uniq_file($v); + $v .= "/" unless substr($v, -1) eq "/"; + push @m_param_InRoot, $v; + } elsif( $k eq "outroot") { + $v = PathSubs::uniq_dir($v); + $v .= "/" unless substr($v, -1) eq "/"; + $m_param_OutRoot = $v; + } elsif( $k eq "pages") { + $v = PathSubs::uniq_file($v); + $m_param_InPages = $v; + } elsif( $k eq "template") { + $v = PathSubs::uniq_file($v); + $m_param_Template = $v; + } elsif( $k eq "overwrite" ) { + $m_param_Overwrite = $v; + } elsif( $k eq "openedlevel" ) { + $m_iAlwaysOpenedLevel = $v * 1; + } else { + die "Unknown parameter: $ARGV[$i]\n"; + } + } + if($m_param_action eq "FIND") { + if ($#m_param_InRoot < 0) { die_usage(); } + if (! defined $m_param_InPages) { die_usage(); } + } elsif($m_param_action eq "MERGE") { + if (! defined $m_param_InPages) { die_usage(); } + if (! defined $m_param_OutRoot) { die_usage(); } + if (! defined $m_param_Template) { die_usage(); } + $m_sTemplateFolder = $m_param_Template; + $m_sTemplateFolder =~ s![^/]*$!!; + } else { + die_usage(); + } + + $m_sInPagesFolder = $m_param_InPages; + $m_sInPagesFolder =~ s![^/]*$!!; + print "Parameters:\n"; + print " " . $m_param_action . "\n"; + print " pages=" . $m_param_InPages . "\n"; + print " outroot=" . $m_param_OutRoot . "\n"; + print " template=" . $m_param_Template . "\n"; + if (defined $m_param_Overwrite) { + print " overwrite=" . $m_param_Overwrite . "\n"; + } + #if ($#m_param_InRoot == -1) { push @m_param_InRoot,$m_sInPagesFolder; } +} + +sub get_template() { + my $sTemplate = get_file($m_param_Template, 1); + $m_TemplateTime = (stat $m_param_Template)[9]; + $m_InPagesTime = (stat $m_param_InPages)[9]; + $sTemplate =~ s/<!--.*?-->//gs; + if ( $sTemplate =~ m!(.*?<body.*?>)(.*)</body>!si ) { + $m_sStartTemplate = $1; + $m_sBodyTemplate = $2; + #$m_sEndTemplate = $3; + } else { + die "Can't find body of template\n"; + } +} # get_template + +sub read_page_list($) { + my $sPagesFile = shift; + my @in_files; + open(P,$sPagesFile) or die "Can't open toc list file $sPagesFile: $!\n"; + while (my $sLine = <P>) { + chomp $sLine; + $sLine =~ s/^\s+|\s+$//g; + next if $sLine eq ""; + next if substr($sLine, 0, 1) eq ";"; + #print STDERR "$sLine\n"; + my ($ind, $tit, $ref, $tip, $trg, $ico) + = map { s/^\s+|\s+$//g; $_; } split("###", $sLine); + #warn "trg=$trg\n" if defined $trg; + my ($fil, $anc) = ("", ""); + my $hrf = ""; + my $full_fil = ""; + #$ref = "" unless defined $ref; + #print STDERR "ref=$ref\n"; + if (defined $ref) { + if (defined $trg) { undef $trg unless $trg ne ""; } + if ((defined $trg) || ($ref =~ m/https?:/i)) { + $hrf = $ref; + } else { + ($fil, $anc) = split('#', $ref); + if ($ind >= 0) { + if (File::Spec->file_name_is_absolute($fil)) { + $full_fil = $fil; + } else { + $full_fil = PathSubs::uniq_file($m_sInPagesFolder . $fil); + } + } + } + } + if ((!$tip) && ($full_fil ne "")) { + $tip = get_title($full_fil); + } + push @pages, [$ind, $tit, $full_fil, $anc, $hrf, $trg, $tip]; + push @in_files, $full_fil if !defined $trg; + } + close P; + $m_sCommonIn = get_common_root(\@in_files). "/"; +} # read_page_list + + + +sub get_common_root($) { + my $psRoots = shift; + my @sCommon; + for my $s (@$psRoots) { + my $full_s = PathSubs::uniq_file($s); + my @full_s = split("/", $full_s); + if ($#sCommon == -1) { + @sCommon = @full_s; + } else { + my $iMax = $#sCommon; if ($#full_s < $iMax) { $iMax = $#full_s; } + for (my $i = 0; $i <= $iMax; $i++) { + if ($sCommon[$i] ne $full_s[$i]) { + #print STDERR "$i: $sCommon[$i] != $full_s[$i]\n"; + @sCommon = @sCommon[0..$i-1]; + last; + } + } + } + } + my $sCommon = join("/", @sCommon); + return $sCommon; +} # get_common_root + + +sub find_pages($$) { + my $pasInRoot = shift; + my $sOutFile = shift; + if (!$m_param_Overwrite) { + die "Don't want to overwrite existing output file $sOutFile!\n" if -e $sOutFile; + } + my $root_level; + my $sList; + my $handle_file = + sub { + return unless m/.html?/i; + return if -d $_; + my $fname = PathSubs::uniq_file($_); + die "Can't read $fname\n" unless -r $_; + my $title = get_title($_); + my $level = $fname =~ tr!/!!; + $level -= $root_level; + my $rel_fname = PathSubs::mk_relative_link($sOutFile, $fname); + $sList .= "$level ### $title ### $rel_fname\n"; + }; + for my $sInRoot (@$pasInRoot) { + $sInRoot = PathSubs::uniq_file($sInRoot); + chop($sInRoot) if (substr($sInRoot, -1) eq "/"); + $root_level = $sInRoot =~ tr!/!!; + File::Find::find($handle_file, $sInRoot); + } + create_file($sOutFile, $sList); +} # find_pages + + +########################################################## +### File - page helpers +########################################################## + +sub file_name($) { + my $num = shift; + return $pages[$num][FULL_FIL]; +} +sub file_anchor($) { + my $num = shift; + return $pages[$num][ANC]; +} +sub file_href($) { + my $num = shift; + #die $pages[$num][HRF] if defined $pages[$num][HRF]; + return $pages[$num][HRF]; +} +sub file_target($) { + my $num = shift; + return $pages[$num][TRG]; +} +sub file_title($) { + my $num = shift; + return $pages[$num][TIT]; +} +sub file_tip($) { + my $num = shift; + return $pages[$num][TIP]; +} +sub full_in_name($) { + my $num = shift; + my $name = file_name($num); + return $name; +} +sub full_out_href($) { + my $num = shift; + my $anchor = file_anchor($num); + my $full_href = full_out_name($num); + warn "full_href is null" unless $full_href; + if ((defined $anchor) && ($anchor ne "")) { $full_href .= "#" . $anchor; } + return $full_href; +} +sub full_out_name($) { + my $num = shift; + my $in_name = file_name($num); + return unless $in_name; + my $anchor = file_anchor($num); + #$m_param_OutRoot . $name; + $anchor = ""; + my $name = substr($in_name, length($m_sCommonIn)); + if ($anchor) { + my $base; + my $ext; + for (my $i = length($name);$i>0;$i--) { + if (substr($name, $i, 1) eq ".") { + $base = substr($name, 0, $i-1); + $ext = substr($name, $i); + $name = $base . "_sharp_" . $anchor . $ext; + last; + } + } + } + $m_param_OutRoot . $name; +} +sub replace_name_link($) { + my $page = shift; + for my $k (keys %page_num) { + my $num = $page_num{$k}; + my $href = ($m_param_single ? "javascript:ShowPage($num)" : file_name($num)); + $page =~ s!%%$k%%!$href!gs; + } + return $page; +} + +########################################################## +### File name helpers +########################################################## +sub in2out($) { + my $in_name = shift; + die "in2out: File name is not abs: $in_name" unless File::Spec->file_name_is_absolute($in_name); + my $name = substr($in_name, length($m_sCommonIn)); + $m_param_OutRoot . $name; +} + +########################################################## +### File reading/writing +########################################################## + +sub mkpath4file($) { + my $file = shift; + my $path = $file; + $path =~ s|[^/]*$||; + File::Path::mkpath($path); +} +sub create_file($$) { + my ($out_file, $page) = @_; + if (!$m_param_Overwrite) { + if (-e $out_file) { die "Will not overwrite $out_file\n"; } + } + open(OUT, ">$out_file") or die "Can't create $out_file: $!"; + print OUT $page; + close OUT; + chmod 0111|((stat $out_file)[2]&07777), $out_file +} +sub create_file_and_path($$) { + my ($out_file, $page) = @_; + mkpath4file($out_file); + create_file($out_file, $page); +} + + +sub get_file($$) { + my ($file, $need) = @_; + if (open(FL, $file)) { + local $/; + my $whole = <FL>; + close FL; + return $whole; + } else { + my $err = $!; + die "Can't open $file: $err\n" if $need; + return ""; + } +} + +sub get_title($) { + my $file = shift; + open(H, $file) or die "Can't open and get title from $file: $!"; + while (my $line = <H>) { + if ($line =~ m!<title>(.*?)</title>!i) { close H; return $1; } + } + close H; +} + + + +########################################################## +### Html parsing etc +########################################################## + +sub get_head_from_file($) { + my $fname = shift; + my $err; + my $head = get_head(get_file($fname, 1), \$err); + die "\n\n$fname\n\t" . $err if defined $err; + return $head; +} +# BUG: These actually requires parsing of the file, but it does not +# seem very important: +sub get_head($$) { + my $html = shift; + my $perr = shift; + return "" unless $html; + $html =~ s/<!--.*?-->//g; + if ($html =~ m!<head.*?>(.*)</head>!is) { + return $1; + } + $$perr = "Can't find <head>-tag in $html\n"; +} +sub get_body($) { + my $html = shift; + return "" unless $html; + $html =~ s/<!--.*?-->//gs; + if ($html =~ m!<body[^>]*>(.*)</body>!is) { + return $1; + } + die "Can't find <body>-tag in $html\n"; +} + +sub shrink($) { + my $str = shift; + my $out_str = ""; + my @str = split("\n", $str); + my $in_pre = 0; + for my $s (@str) { + if ($s =~ m!<pre>!i) { $in_pre = 1; } + if ($s =~ m!</pre>!i) { $in_pre = 0; } + $s =~ s!^(\s*)!! unless $in_pre; + $out_str .= $s . "\n"; + } + return $out_str; + $str =~ s!^(\s*)!!gm; + $str; +} + + +########################################################## +### Making what we see +########################################################## + +sub mk_search() { + return "" if ! $m_param_single; + return qq[ + <a href="javascript:show_search()" xstyle="font-size: 8pt" + title="Show Search Form" + ><img src="img/search.gif" border="$m_bBorders" align="left"></a> + <a href="javascript:show_search()" xstyle="font-size: 8pt" + title="Show Search Form" + class="html-wtoc-search" + >Sök</a> + ]; +} +sub mk_main_table($$$$$) { + my $left = shift; + my $main = shift; + my $srch_table = shift; + my $sFile = shift; + my $pNum = shift; + my $search_tr = ""; + if ($m_param_single) { + $search_tr = + Tr( + td(" ") + . td({-valign=>'bottom', }, mk_search(), ) ) + } + my $cont_table = + table( + { -border=>"$m_bBorders", -cellpadding=>0, -cellspacing=>0, + -width=>"100%", + -id=>"html-wtoc-contents", + #-style=>"display:", + -summary=>"Table of contents", + }, + Tr( + #td(" ") + td({-class=>"html-wtoc-margin"}) + . td({-valign=>'top'}, $left) ) + . $search_tr + ) + ; + my $page = $m_sBodyTemplate; + $page = replace_template_links($m_sBodyTemplate, $sFile); + $page =~ s!%%TOC%%!$cont_table!; + $page =~ s!%%PAGE%%!$main!; + return $page; +} # mk_main_table + + +sub find_ind_level_prev($) { + my $lThis = shift; + for (my $i = $lThis - 1; $i > 0; $i--) { + my $ind_lev = $pages[$i][IND]; + if ($ind_lev < 50) { return $ind_lev; } + } + return undef; +} +sub find_ind_level_next($) { + my $lThis = shift; + #print "find_ind_level_next($lThis)"; + #print ", "; + #print file_title($lThis); + #print "\n"; + #for (my $i = $lThis; $i < $#pages; $i++) { + for (my $i = $lThis + 1; $i <= $#pages; $i++) { + my $ind_lev = $pages[$i][IND]; + if ($ind_lev < 50) { return $ind_lev; } + } + return undef; +} + + + + + + + + +sub mk_opener_elem($$$) { + my $iPi = shift; + my $sHref = shift; + my $bOpened = shift; + my $Aattrib = + { + -id =>"opener_$iPi", + }; + if ($sHref) { $$Aattrib{href} = $sHref; } + my $sImg; + my $sAlt; + if ($bOpened) { + $sImg = "down"; + $sAlt = "Close"; + } else { + $sImg = "right"; + $sAlt = "Open"; + } + return + a( + $Aattrib, + img({ + -src=>"img/$sImg.gif", + -alt=>$sAlt, + -border=>0, + -width=>12, + -height=>12, + }, + ), + ); +} # mk_opener_elem + +sub mk_content($) { + my $pnum = shift; + if (!$pages[$pnum]) { + return br(); + } + my $cont; + my @father; + my @child_trace; + my $this_indent = $pages[$pnum][IND]; + my $this_file = $pages[$pnum][FULL_FIL]; + if ($this_indent == -2) { + return ""; + } + my $this_href = full_out_name($pnum); + #my $anchor = file_anchor($pnum); + #if (defined $anchor) { $this_href .= "#" . $anchor; } + my @size; + $size[0] = "1em"; + $size[1] = "0.8em"; + $size[2] = "0.8em"; + + + + ### Open all main level nodes + my @opened; # rename to visible!!!!! + for my $pi (0..$#pages) { + my $indent = $pages[$pi][IND]; + if ($indent <= $m_iAlwaysOpenedLevel) { + $opened[$pi] = 1; + } else { + $opened[$pi] = 0; # more simple to handle + } + } + + + + ### Open ancestors and older sisters (if not a standalone node) + my $pnum_indent = $pages[$pnum][IND]; + my $high_open = $pnum_indent; + my $standalone_open = 10; + if ($high_open < $standalone_open) { ### Not a standalone node + for (my $pi = $pnum; $pi >= 0; $pi--) { + my $pi_indent = $pages[$pi][IND]; + if ($high_open >= $pi_indent) { + $opened[$pi] = 1; + $high_open = $pi_indent; + for (my $ps = $pi+1; $ps <= $#pages; $ps++) { + my $ps_indent = $pages[$ps][IND]; + last if $ps_indent < $pi_indent; + $opened[$ps] = 1 if $ps_indent == $pi_indent; + } + } + last if $pi_indent == 0; + } + } + + + + + ### Open direct childs and younger sisters + my $maybe_child = 1; + my $more_sisters = 1; + my $max_open_indent = $pnum_indent; + for my $pi ($pnum+1..$#pages) { + my $pi_indent = $pages[$pi][IND]; + if ($pi_indent <= $max_open_indent) { $maybe_child = 0; } + if ($pi_indent < $pnum_indent) { $more_sisters = 0; } + if ($pi_indent == $pnum_indent) { + if ($more_sisters) { $opened[$pi] = 1; } + $maybe_child = 0; + } elsif ($pi_indent == $pnum_indent+1) { + if ($maybe_child) { $opened[$pi] = 1; } + } + } + #exit if $pnum == 3; + + + + + ### Open all in the same file (necessary for non-JavaScript) + for my $pi (0..$#pages) { + my $file = $pages[$pi][FULL_FIL]; + #printf STDERR "file - open=(%s)\n", $file; + #if ($file eq $this_file) { + if ($file eq $this_file) { + $opened[$pi] = 1; + } + if ($file eq "") { + if ($pi < $#pages) { + if ($pages[$pi][IND] < $pages[$pi+1][IND]) { + $opened[$pi+1] = 1; + } + } + } + if ($pages[$pi][IND] > 10) { + $opened[$pi] = 0; + #print ">>>>>>>>\$opened[$pi] = 0;\n"; + } + #print STDERR "+++++++++\$opened[$pi] = $opened[$pi]\n"; + } + + + + + ### Make the actual contents + my $tooltip; + my $child_id; + for my $pi (0..$#pages) { +# if (!$pages[$pi][FULL_FIL] && !$pages[$pi][HRF]) { +# my $txt = file_title($pi); #$pages[$pi][TIT]; +# $txt = qq(</p><hr width="50%" align="left" /><p style='margin-top:0'>) if $txt eq "-"; +# $cont .= $txt; +# $cont .= br(); +# next; +# } + my $txt = file_title($pi); #$pages[$pi][TIT]; + if ($txt eq "-") { + $txt = qq(</p><hr width="50%" align="left" /><p style='margin-top:0'>); + $cont .= $txt; + $cont .= br(); + next; + } + #if ($pages[$pi][TRG]) { + # next; + #} + #next if ! defined $opened[$pi]; + #next if ! $opened[$pi]; + my $ind_lev = $pages[$pi][IND]; + next if $ind_lev > 50; + my $ind_lev_next = find_ind_level_next($pi); + #my $ind_lev_prev = find_ind_level_prev($pi); + + my $this_entry = ""; + + ### Child id from previous row + if (defined $child_id) { + my $display = ""; + if (!$opened[$pi]) { + $display = qq(style="display:none"); + } else { + } + $this_entry .= "\n<div id=\"$child_id\" $display>\n"; + undef $child_id; + } + my $opener_elem = ""; #qq(<img src="img/blank12.gif" width=12 height=12 alt=" ">); + my $childs_are_visible = ($pi == $pnum); + if ($pi < $#pages) { + if ($pages[$pi][IND] < $pages[$pi+1][IND]) { + if ($opened[$pi+1]) { $childs_are_visible = 1; } + } + } + #if ($pages[$pi][IND] < $m_iAlwaysOpenedLevel) { $childs_are_visible = 1; } + + my $file_href; + my $target; + my $href; + my $href_self; + my $target_attrib; + my $title = file_title($pi); + my $file_name = file_name($pi); + if ($title) { + $file_href = file_href($pi); # || ""; + $target = file_target($pi); + $href = + ($file_name ? + ($m_param_files ? + ($m_param_single ? "JavaScript:ShowPage($pi);" : + ($file_href ne ""? $file_href + : + PathSubs::mk_relative_link($this_href, full_out_href($pi)))) + : + ($m_param_single ? "JavaScript:ShowPage($pi)" : "?pnum=$pi") + ) + : + (File::Spec->splitpath($this_href))[2]); + if ($pi == $pnum) { + $href_self = $this_href; + if ($href_self =~ m!([^/\\]*$)!) { + $href_self = $1; + } + } + $target_attrib = (defined $target? qq(target="$target"): ""); + } else { + $href = ""; + $target_attrib = ""; + } + + if (defined $ind_lev_next && $ind_lev_next > $ind_lev) { + $child_id = "toc_child_$pi"; + #print " child_id=$child_id\n"; + push @child_trace, $child_id; + $opener_elem = mk_opener_elem($pi, + ($href? $href : $href_self), + $childs_are_visible); + } + $title =~ s/_/ /go; + my $indent = ($ind_lev ? " " x (($ind_lev-1) * 4) : ""); + my $size = $size[$ind_lev]; + $title = b($title) if $ind_lev == 0; + + my $Aattrib = + { + id=>"toc_link_$pi", + onclick=>"html_wtoc_nailing(this)", + }; + if (!$file_name) { + $Aattrib = + { + id=>"opener_text_$pi", + }; + } + if ($pi == $pnum) { + ### Current page + $$Aattrib{class} = "html-wtoc-currcont"; + $$Aattrib{title} = "You are here"; + $$Aattrib{href} = $href_self; + $this_entry .= + table({ + -cellspacing=>0, + -cellpadding=>0, + -class=>"html-wtoc-contline", + -border=>0, + -summary=>"Formatter", + }, + Tr({ + }, + td({ + }, + a( + $Aattrib, + $indent . $title . " " + ) + ) + . td({ + -class=>"html-wtoc-mark", + }, + $opener_elem + ) + ) + ); + + + + + } else { + ### Link to other page + if (file_title($pi)) { + $tooltip = $pages[$pi][TIP]; + if (!defined $tooltip) { $tooltip = "Go to the page $title"; } + $$Aattrib{class} = "html-wtoc-contents-a"; + my $a_or_span; + if (!defined $href) { + $a_or_span = span($Aattrib, $indent . $title); + } else { + $$Aattrib{title} = $tooltip; + $$Aattrib{href} = $href; + if (defined $target) { $$Aattrib{target} = $target; } + $a_or_span = a($Aattrib, $indent . $title); + } + $this_entry .= + table({ + -cellspacing=>0, + -cellpadding=>0, + -class=>"html-wtoc-contline", + -border=>0, + -summary=>"Formatter", + }, + Tr({ + }, + td({ + }, + $a_or_span + ) + . td({ + -class=>"html-wtoc-mark", + }, + $opener_elem + ) + ) + ); + } else { + $this_entry .= $indent . " " . $title; + #die $this_entry; + } + } + if ((!defined $ind_lev_next) || $ind_lev_next <= $ind_lev) { + my $ind_end = $ind_lev; + if (defined $ind_lev_next) { $ind_end = $ind_lev_next+1; } + for (my $i = $ind_end; $i <= $ind_lev; $i++) { + my $end_id = pop @child_trace; + if (defined $end_id) { + $this_entry .= "</div><!-- end child $end_id -->"; # end childs' span + #print " end $end_id\n"; + } + } + } + $cont .= $this_entry; + $father[$ind_lev] = $pi; + } #for my $pi (0..$#pages) + + $cont = div({-class=>"html-wtoc-contents"}, $cont) . p(" "); + #$cont =~ s|<|\n<|gms; + #$cont =~ tr!\n\r! !; + $cont =~ s{ + (\ssrc=)"(.*?)" + } + { + my $s1 = $1; + my $src = $2; + if (!PathSubs::is_abs_path($src)) { + my $srcabs = PathSubs::mk_absolute_link(full_out_name(0), $src); + $src = PathSubs::mk_relative_link(full_out_name($pnum), $srcabs); + }; + "${s1}\"$src\""; + }egsmx; + $cont; +} # mk_content + +sub mk_main_window($) { + my $pnum = shift; + my $full_name = full_in_name($pnum); + return unless defined $full_name; + return get_body(get_file($full_name, 1)); +} + + + + + + + + +########################################################## +### The JavaScripts and styles we need +########################################################## + +sub mk_style($) { + return ""; + my $pnum = shift; + my $rel_link = + PathSubs::mk_relative_link(full_out_name($pnum), $m_param_OutRoot . "html-wtoc.css"); + return qq(<link rel="stylesheet" href="$rel_link" type="text/css">\n); +} +sub mk_js($) { + my $pnum = shift; + return <<__HTML_END_JS_PNUM__; + <script type="text/JavaScript"> + var iCurrentChild = $pnum; + var iMaxChildNum = $#pages; + </script> +__HTML_END_JS_PNUM__ + return ""; + my $single_js = ""; + if ($m_param_single) { + $single_js = qq[if (!document.all) { navigate("0.html"); }]; + my $page_info = "var page_name = new Array;\n"; + for my $i (0..$#pages) { + my $page_name = file_title($i); #$pages[$i][TIT]; + $page_info .= qq[ page_name[$i] = "$page_name";\n]; + } + $single_js .= $page_info; + } + my $sch_link = + PathSubs::mk_relative_link(full_out_name($pnum), $m_param_OutRoot . "search.js"); + my $top_link = + PathSubs::mk_relative_link(full_out_name($pnum), $m_param_OutRoot . "html-wtoc.js"); + return <<__HTML_END_JS__; + <script type="text/JavaScript" src="$sch_link"></script> + <script type="text/JavaScript" src="$top_link"></script> + <script type="text/JavaScript"> + $single_js + </script> +__HTML_END_JS__ +} + +########################################################## +### Page creation +########################################################## + +sub replace_template_links($$) { + my $template = shift; + my $sFile = shift; + $template =~ s{\ssrc="(.*?)"} + { + my $sSrc = $m_param_OutRoot . $1; + my $sRelSrc = PathSubs::mk_relative_link($sFile, $sSrc); + qq( src="$sRelSrc"); + }exg; + $template =~ s{\shref="(.*?)"} + { + my $sOld = $1; + if ((lc substr($sOld, 0, 11)) eq "javascript:") { + qq( href="$sOld"); + } elsif (PathSubs::is_abs_netpath($sOld)) { + qq( href="$sOld"); + } else { + my $sSrc = $m_param_OutRoot . $sOld; + my $sRelSrc = PathSubs::mk_relative_link($sFile, $sSrc); + qq( href="$sRelSrc"); + } + }exg; + return $template; +} # replace_template_links + +sub mk_start_of_page($) { + my $pnum = shift; + my $page = ""; + my $page_style = mk_style($pnum); + my $page_js = mk_js($pnum); + my $sFile = full_out_name($pnum); + my $head = ""; + $head .= $page_js; + $head .= $page_style; + $head .= get_head_from_file(full_in_name($pnum)); + $page .= header if !$m_param_files; + $page .= replace_template_links($m_sStartTemplate, $sFile); + $page =~ s!<title>HEAD</title>!$head!; + my $focus_pnum = $pnum; + my $ind_lev = $pages[$pnum][IND]; + if ($ind_lev > 50) { $focus_pnum = 0; } + $page =~ s!%%PNUM%%!$focus_pnum!; + return $page; +} # mk_start_of_page + +my %m_sCreatedPages; +sub page_src_time($) { + my $pnum = shift; + my $src_file = $pages[$pnum][FULL_FIL]; + return (stat $src_file)[9]; +} +sub create_page($) { + my $pnum = shift; + return unless $pages[$pnum][FULL_FIL]; + + my $out_name = full_out_name($pnum); + return if exists $m_sCreatedPages{$out_name}; + $m_sCreatedPages{$out_name} = 1; + + my $page = mk_start_of_page($pnum); + my $cont_win = mk_content($pnum); + my $main_win = mk_main_window($pnum); + $page .= mk_main_table( + $cont_win, + $main_win, + "", + $out_name, + $pnum, + ); + $page .= end_html; + $page = replace_name_link($page); + return $page; +} # create_page + + +__END__ + + + ########################################################## + ### Unused currently + ########################################################## + + sub build_ShowPage() { + for my $num (0..$#pages) { + $page_num{$pages[$num][FULL_FIL]} = $num; + my $fon = full_out_name($num); + if ($fon) { $js_show_page{$fon} = "ShowPage($num);"; } + } +} +build_ShowPage(); + + +sub mk_meta_enter_exit() { + return <<__HTML_EE__; + <meta HTTP-EQUIV="Page-Enter" content="RevealTrans (Duration=0.1, Transition=31)"> + <meta HTTP-EQUIV="Page-Exit" content="RevealTrans (Duration=1, Transition=23)"> +__HTML_EE__ +} + +########################################################## +### Single page +########################################################## + +sub mk_noscript() { + return <<__HTML_END_NOSCRIPT__; + <noScript> + Sorry, there is not yet any version for non-JavaScript browsers. + You need to enable JavaScript to see the rest of the pages! +__HTML_END_NOSCRIPT__ +} + +sub create_single_page($) { + my $pnum = shift; + + my $page = mk_start_of_page($pnum); + my $left_col = ""; + my $main = ""; + for my $pi (0..$#pages) { + next unless $pages[$pi][FULL_FIL]; + my $display = ($pi == $pnum ? 'style="display: block"' : 'Style="display: none"'); + my $pi_left_col = replace_rel_link(mk_content($pi), full_out_name($pi)); + my $pi_main = replace_rel_link(mk_main_window($pi), full_out_name($pi)); + my $pi_margin = ""; + $left_col .= "\n<div id='left_col_$pi' $display>" . $pi_left_col . "</div>\n"; + $main .= "\n<div id='main_$pi' $display>" . $pi_main . "</div>\n"; + } + my $search_table = qq[ + <table border="0" width="100%" height="200" + cellpadding="0" cellspacing="0" + xbgcolor="yellow" + class="html-wtoc-search" + id="search" style="display:none"> + <tr> + <td> </td> + <td align="left" valign="top" height="1"> + <form onsubmit="return do_search(input.value);" + class="html-wtoc-search-form" + > + <input id="input" size="14" + ><input type="image" name="Search" value="Search" + title="Search" + src="img/search.gif" + align="top" + > + </td> + </form> + </tr> + <tr valign="top"> + <td> </td> + <td id="hits" valign="top"> + </td> + </tr> + <tr> + <td> </td> + <td valign="bottom"> + + <a href="javascript:hide_search()" xstyle="font-size: 8pt" + title="Show Menu" + ><img src="img/nosearch.gif" border=0 align="left"></a> + <a href="javascript:hide_search()" + title="Show Menu" + >Göm sökning</a> + </td> + </tr> + </table> + ]; + $page .= mk_main_table( + $left_col, + $main, + $search_table, + full_out_name($pnum), + $pnum, + ); + $page .= mk_noscript(); + $page .= end_html; + $page =~ s/(\d+)\.html/javascript:ShowPage($1);/gs; + #$page =~ s/<body(.*?)>/<body$1 onload="ShowPage(0)">/gis; + $page =~ s/<body(.*?)>/<body$1 onload="HTML_WTOC_NS.onload_actions()">/gis; + $page = replace_name_link($page); + return $page; +} # create_single_page + +my $abs_pos_tbl = + qq( + <table border="$m_bBorders" cellpadding=0 cellspacing=0 + width="100%" height=70 + bgcolor="white" + style=" + position: absolute; + left: 0; + top: 0; + " + > + <tr> + <td> + </td> + </tr> + </table> + ); + + +########################################################## +### Index.htm +########################################################## + +# sub mk_index_page($) { +# my $page = shift; +# my $check_browser = qq[ //if (document.all) { navigate("single_0.html"); }\n]; +# #$page =~ s/(<script.*?>)/$1\n$check_browser/s; +# mkdir $m_param_OutRoot, 0777; +# my $out_file = $m_param_OutRoot . "index.htm"; +# create_file_and_path($out_file, $page); +# } + + + + +########################################################## +### Links handling +########################################################## + + +sub replace_rel_link($$) { + my ($page, $page_file) = @_; + my $qr; + $page =~ + s{ + (src|href)="(.*?)" + }{ + my $src_href = $1; + my $href = $2; + if (!PathSubs::is_abs_path($href)) { + $href = PathSubs::mk_absolute_link($page_file, $href); + $href =~ tr|\\|/|; + if (exists $js_show_page{$href}) { + $href = "javascript:$js_show_page{$href}"; + } + } + qq($src_href="$href"); + }xegsm; + + $page; +} + diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/blank12.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/blank12.gif new file mode 100644 index 0000000000000000000000000000000000000000..0869f9ffe832b7778e8af9dc74cd36f2ef3436ca GIT binary patch literal 825 zcmZ?wbhEHb<YC}p_|Cxa|Nno6Q7{?;BQ*pRf3h%w{H_BcKzV|JLyUouL&jsnf`iQ* T!dfvWHY_~cE+ELp!e9*m$1M(_ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/down.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/down.gif new file mode 100644 index 0000000000000000000000000000000000000000..30d6ecfa57c8839f5acdd97a8ff29d3a84f0ac00 GIT binary patch literal 853 zcmZ?wbhEHb<YC}p_|Cxa|Nnn&*X;9m|Igp`KPD<_@7}!@dHaBZSb>C^m3io7tWu+b zqaiR9LqPE-3nK#%=zs`No?zfGVqoNu@z}87V55MLRt$$@0t2IfBA>yBhJ*%23Elvc aiooQf&5UMpB0mb3oSdu?%*DgOU=0A%U<8f; literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/freeCont.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/freeCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..1c94b60111dd28a2de5e270cbbec1f0146b1f869 GIT binary patch literal 913 zcmZ?wbhEHb6krfw_|5<VEiEno85sU^aQv5$_^+t=UsLnHq2Yf^%l}?p|C5vdXJ`Mf zuKo{HGiT2KwQK+XpYwkdjE2DQ2!VzM#h)yUz{Jm>1Ih`YJi)+`$MF9zv%`i32bh@I z6a+K`7+Tr|82%^=EOcaQ<&kw_d62-s%*G`kaDv0|Q8Oc_lbnP@(c}G7IeB;@E__;e zq+W^p!Wzkmi4C)D8vmu-*svsEfom+6j918F-$eoJQoXlIw5~4kU+)!KwRM5xDn>>I FYXCc(5>5aB literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/gnu-m-x-160.png b/emacs/nxhtml/nxhtml/html-wtoc/img/gnu-m-x-160.png new file mode 100644 index 0000000000000000000000000000000000000000..5254ef110b1fc505925f854d0b582b9ddf094123 GIT binary patch literal 1957 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/gnu-m-x-160.xcf b/emacs/nxhtml/nxhtml/html-wtoc/img/gnu-m-x-160.xcf new file mode 100644 index 0000000000000000000000000000000000000000..f2ce5ceb4e44ba3e0d8365f81cf3018bc084d11d GIT binary patch literal 22466 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/hideCont.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/hideCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..9908895699cf345553771565f1fe8acd047ceed2 GIT binary patch literal 917 zcmZ?wbhEHb6krfw_|5<VEiElmwys^eckkA%TaO((cJJQ3|F{9ee}=vP_g4O|#H|EH z=HLJMD13sPh6aL4Miq>P0JTCu@h1x-1A_sB4k#yp@&p4%5kuku28Rs`9GjUK8zMNE z92(mNxEVZ7Y<PIENkr7l=D^0sjh)QWPB&gmRQ70P;B)Y(RB&jRCa-v6ilk$z=VZa6 zS8HZoT6(&lUDYEY^3xKJCYktuCSDU#F7|Lo{xb2Ls2JGqwpK0l*T$?Xvt!xgWTXWc FtO4p+BFF#$ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/nailCont.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/nailCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..4c1bca4291bafc1443a23d831085dbe3d5d96862 GIT binary patch literal 917 zcmZ?wbhEHb6krfw_|CxapPl_bC+B}IuKzqd|9N@;^YQ)X=l?G){a;4rznt8E1%>}Q zI{)?c|C^ZnH#7ThYy02M?!UeLe-DrU>FNJ-a{gCV{;#Y1-_Y=X=FI<#7X4qo{Qrs- z3`n2>DE0sUzyI@*#73E;Auw1%K=CIFBLjmtgAT|+pgh6AQN*Ah^T1)l0tZ$W783!D z3C$htN)|C50*9Jd7zHJ)T23%BGjNNl*=Q^fOgh5LsL~OWut4QFHy@irf<Z&m>2?{1 zf`*0%2UyyeeP6M7l`QU9=+c;XMbmJlcf0Rgwpz_nt#hlwl#@(XZPmKI!jD_3L`s0c F8UQ@RUC96d literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/nosearch.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/nosearch.gif new file mode 100644 index 0000000000000000000000000000000000000000..e824f5ba3052fafda09da2a8ade818fb978d7a44 GIT binary patch literal 1100 zcmdUu(Tf#T9LG<(#<-MRH+84faJE&OTgIKjaMp_5;nuoS$U1BolhDT81?%=uT(X7Z zgNw7V3r9=+6<Q~_ZXCR{p4OoAq~}4?sn|HUiUUFny|mLyj72aA(KP-Gz4hh8moLBH z%kTT}8y<OSm;Gih+JJI|u&ZOw!c1T$v5;6QEaT9(!=S_sn_5VMkhDT*g&ac8iER_x zA&yNPmv{#84HB57sgqWTL9kA+O+uf5M;IZI1jh!~1lIx20M7(p17C+ghn52v0oDK; zfK9+Q5C=#A;DNvp2~eCiE3|1)Tw>Btr=-NB#G=Hd#G_zQuqkg*fvFHw5{4@byDW4W z(HSuqF&VKK=nP7?8S|M4%9bpOc<6KDa4<NS9Bd8&r-)OHQ;SoZQ%_J$P+d?<P+L$} z+?)7<A;EmfkYu)Gp5#p_LYagSMG+4o&LV*#5k!(iv7?x#I8p*BiBzPkh^mMyRZ)qh zQa6?;j!Ga_G*&!TB33evWdbCTUZQvsmxv@aQqf8kN@JeJDotdXL}^lnI8Ea$MOo>Y zmSt9!C0Ukcxt`@l9#`@V<yo5ND9=mJ@;ooVE2vXQt58M}>qSy2a#ZA5QLYM96k1V~ z;r}UA-v1wE-0iv#p#}6LDs}HCkoFIHWA&yz7uuJPY7bQpOjd3_R<Epm{>s%muXcvt z{dV;1$@=Uk&rWUQuHL<L=BdWtr-!b$zdPPPvE|{$_K!DT-1@<;_dYu{*k0ND#EsFz z6Q`EvM-CoZx8qvtmzBM{S4>w2YA1U1h3?z$4Akyl^HtZ{oqybU`-FL6=hB*b<JTYO zU;g4XYtDzo{-ZOUpO^lcT|d9~({<}7hNG{C_Pm~q{<(Pi#`vM&!=4AGzhC@(;Qi%G zXD{AfzC1E91Dzx7gGctiFm_%)JV_qhF!s#&_4eSZleP1!_g)EZUi)bCj>*n9&X+5W z^}p3njqTdLc6$8jt<}D%tFw>n-!$F#+uiZbbB|Z6^_eYB_uTLGV|_otxffUU+&cHe d*g_53kM{PxQk%OpH#oEr)uuL{>FPqe{{>0koPPiS literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/CompFaceLogoTemp4.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/other/CompFaceLogoTemp4.gif new file mode 100644 index 0000000000000000000000000000000000000000..40b72201fa58e7a1121dc95a3b6664453476aeb8 GIT binary patch literal 3202 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 Y=47~V-n6iZ{b74DF2M`}PFunM1*Hj&eE<Le literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/CompFaceLogoTemp4.png b/emacs/nxhtml/nxhtml/html-wtoc/img/other/CompFaceLogoTemp4.png new file mode 100644 index 0000000000000000000000000000000000000000..ad6505e52895eb5742d14b5eabff9f63d1311885 GIT binary patch literal 6710 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 M07*qoM6N<$g3uuC`v3p{ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/blue_left_top.png b/emacs/nxhtml/nxhtml/html-wtoc/img/other/blue_left_top.png new file mode 100644 index 0000000000000000000000000000000000000000..e7da4024c35351a253fc7f69ef0d582a110533bf GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^#Xy|L!3-pouilvmq_j(1BTAf$QWHxu^Yau!GILWI ze1Qy01+UUP1tS9kV+8{PD+41d0|NzZ149D?E@RhMKyB<Lp1!W^m)SVPST#+btZD@c zaTa()0*&Vu0%68WckBKD1zFM^eH|GXHuiJ>Nn{1`*#dk*T>t<7Kl9B0x4!D<fFg_~ zL4Lsu4$p3+0Xf?|T^vIyZoNJ0$j788;&SlYzv*W0dfX%*T()ft7uT@;^W<M#&c)eZ z51R)EmzTv&e*VC$%CD69`Je0M*J^Cj?^e8B^Jm@MtI5CD$VWf#+E}<w^Qrv*Ij4`^ ze|{*a5fy&oTfR7C!I}B<jOu2c`tnkX-zN8I<?{75?@Xr6sh)T4(}v4YMMc-<+?zCc z^5<vEcRm4vKQ?z&)j{An+w#3n?!5gneGU+)S22lKviV)mP`wNE0fVQjpUXO@geCx~ C^qP?X literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/close-cross.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/other/close-cross.gif new file mode 100644 index 0000000000000000000000000000000000000000..e5cb1420b8229093053af8abe26cdd6a0cd041ef GIT binary patch literal 866 zcmZ?wbhEHb<YC}p_|Cxa|Nnn&*X;9m|Igp`KPD<_@7}!@dHaBZ$e^XE<=Ek4{~H=4 z)U3=yCnHOZvPVN;NQZ#pPZmZ720jKI1|R_C2?h>(238IkkAMRV&CEhtAsGx0o!S^> z>|_!Y79C>XGz{9ZLV$^-L&&yi&kVyv*G_(aKbg!0OTDK{XtT}moSf#sz+epkL6`-) literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbiinfo_and_blue.png b/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbiinfo_and_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..d524ff10631195a6ce47f76ed19c301ab17ef5e7 GIT binary patch literal 3763 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbiinfo_and_blue1.png b/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbiinfo_and_blue1.png new file mode 100644 index 0000000000000000000000000000000000000000..d111473b340034698192b5db93ed65774b076e8f GIT binary patch literal 4012 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbinfo_col1.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbinfo_col1.gif new file mode 100644 index 0000000000000000000000000000000000000000..d3777aeef9b70854f3e9292a069f8341d4039819 GIT binary patch literal 3732 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbinfo_col1_30.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/other/lbinfo_col1_30.gif new file mode 100644 index 0000000000000000000000000000000000000000..1df04d4d3daa5fe9d77eef00f2acd903bb1f58ae GIT binary patch literal 1299 zcmV+u1?>7qNk%w1VHf}#0QUd@|NsC0|Nr^;_SMzR@bB*K?B(9w*5={X-{0Q$_3z-^ z(Uyx{LqHGn@aVt3yirRZ@a^2TwWhtguAGc|g?tKuY&>pjR6jc_VOk<;Wm~0tLxX{6 zGcq50Y&wjEV<8|1PD??^$isAPOm=f#jEa4WgnX}mF@}6J`}_K?t)|z|!{_GZ+}XaI zngS;!38S54m5hC>qKT@3DD39fl#^`R*2c1|k*}|;tdv?wLnE@Xu3cMJj&ec5z_@&C zG}O+uys?X;p*w16X3D>^zPx>fbX=#JdG6xX%DbhZos7+|aV{(if`D<+%)M7sPLOpa zmUcmHUMn^;5!u(k)U}R`c`8~^D~NAKy0e9tl60t+Sy)gTtEYjns!nEH7KMFO!MB>s z%58peUc!`6v8<a?OBf#?07pVB=F+!!Zeh{T%6)uN$;rB4RvC_m283-u^X%PmZz@DT z9JQiy=H=p%hZux_LZqX6etdeLeI!3VIyW>V!?Kg5r3QX>33Fp0OGOh_Q45%bRM5+c z#Jj7TmSN=MwKOs;Nk~Y%l0kNJQ#?8oWLGS*e>ULIyohc&*w@v0W-pSD0<4KI?d;W@ zg=M+8vA(&detuqgZA;YCl&zRkQAsR_a#M|YTC%XFetIi@YALUkZcRoSgMm(qb0O5j zsj8fW$;qq5vwW_tn=dRBXJZU)V-tpgUBSS(bz~|&IUk#skg=wRhi@o^Y%@7HGhbRu zc5Vyn<I#3)MMgt5jD%H0LqUFWIZ;kW&CABCo^9*u=YMfXCnXN&<k#Wa!jXw|kaIMR zc3R5Ev`a-9n0Y3XgIcwMEUtY%HZvJuU|@T34%pYn+SST&aAkFB5pZNL_44d{cweoo zg=S(Ci*iekbSG6&FK=Nmk$6O2U0a-+igt2EmXQQSKpxh=o={CeSx_IEm3D)DS3Ect zwzHWzHYF}A6-s-BQIe@`rN@)j*B^d{6`P|;k(Xk(yEm4dxZdR;Q&uWyYC)E{J&eA2 z&CeK)m;wNSA^8LW00000EC2ui02lxp000R800969)5nm&g9za$N#tw{8iW8Kv}mCT z;z0<LWXLdKq7fB@gUCsuWKm$MJh={<dv@et7dJsl3f#mjz`+?B90?3ihXN6q0JL-y zaL|;70|FsX@WTQq5LyWUG~fe8luZCXq~VGx6G$jQwI1={f#fO{YbSsL@Bu55j|y+D zaI2&Oz>8Le)Lx5X;{Y{6r#y8^He`VpE^2i#Du6J+gd!7owXvbrgB8XIC5VCXWs57d zNjM2ZNT5WTAtD|uQxsu<>j>h85covm3>^R~fXT{`p+o=?IpnO9vc!d%4=zXy;Lz^E zIS?RzIoW}S000X)VnJI)>;s2tAp|<`*m20#u3m_u-5?5pfTa{EbPTX=afJgN4iKmX ziU5*K0^#T<(+#`qaltJHSR{ZD0$LP;J4_6q#t1O%XORUX925Y1GQDyY01|Al$OaK8 zfPz2<#1Ml50<mX6IoWul3IGOV!vF(-l%Wm)Dtyy{5f%IZz%dd4K!$1$Fu;aDYtS$N zJIVym!2&GS08RjzTmnEA=%j<fI2aH`11Sd;@CQ-=B!CPy!!!Ya2N=`<z%+r}0f07f zXm~;}1r#s`4gfSW3jhoFa+Mw1B!CJlAF@zIDNo?g000Mo0e}L<95e+e0toQJhf*0c J!$AQ706V{ZJ}v+N literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/other/up.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/other/up.gif new file mode 100644 index 0000000000000000000000000000000000000000..c4795d96bb865ce05aa021d9d20d39693b10d65b GIT binary patch literal 851 zcmZ?wbhEHb<YC}p_|Cxa|Nnn&*X;9m|Igp`KPD<_@7}!@dHaBZSb>C^m3io7tWu+b zqaiR9LqPE-3nK#%=zs`No?zfGU|{5s@z}87U^9oXQp*B?rUnLXRvrU}jSCJlN@xm| YXdGy8?-y0Hk?`EK<j`amW+nz}0N^nMQ~&?~ literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/right.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/right.gif new file mode 100644 index 0000000000000000000000000000000000000000..2400cf102023d1a797370260a959cebdb79632b0 GIT binary patch literal 857 zcmZ?wbhEHb<YC}p_|Cxa|Nnn&*X;9m|Igp`KPD<_@7}!@dHaBZSb>C^m3io7tWu+b zqaiR9LqPE-3nK#%=zs`No?zfGV_;-xP}s1*u~C3Y#)iYO;ZQ3FD^JCa4G$YS1$3nh fJ}g+&&?~FW_kg2N;p8L%r$ss^FC{oIFjxZsK}ZQy literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/search.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/search.gif new file mode 100644 index 0000000000000000000000000000000000000000..9f58dfd4a3b0bdae3dcd29aac5a33fab9070013b GIT binary patch literal 1118 zcmd^;?~4^x7{`yg>g)yM>NR&jg`K?FPH8l?MMFm3@z%P7yREZHGW5gkZo+n7v~s14 z<D0dC*5w%N@+1Xk>27!;gi}@?knq5oHs}VY4P#yo8q|nEvm3$?MAPiw(U%V&zC6#X z=f%_4|H9MuNEh0IGK8?JW6#1&U?#DUSSl=|z_)`&fg3cnfHVTq3ZNBm2skIUO>Boa zHgR0y8N@e8!z4|ev<eJ@b%JdY_yjz{2ni)PHn=9Z4tNH5CioioIy7`>Ie-yh4X^>& z1Z)FwfHVL+5Ew!MiqmG9HVujkOd9Bv6quA)l(>|56f6oh<t-{O6@p5_aG7D31ui2x zBL*WTBNhXlL1CLQpNU3sB@06y_?$Q#3=Sp-n?r+B#Hq%q#i`AyC#WW<E~q7_EvPG2 zCca=uFkdnxnJt+oc~go&#z9C?$QvPNp+KQ%gp!1jqnM^RQUWQ7RH&<vs*o#HR<WfL zH<Bm{3m{T7Qan;3QZkBU3?!Cbtauz1h&VA4(Ml9bBA!GliDeRpNnDgDNuo4CY2j2$ zQ!7p5G)>Y>PctKn%2|rCG|4iQWrfo$%X08?>g3YOm61n!9+&eB<yo2+s~qLImghzJ z-^KX5V-+g0Yeg$RfwX_o>z&*7Uua)>U#mR)%8ByL9rg0YXTQI;bm)t|@ry%qGxgIS zJvFhDyL##8PaYlp=i}O9`|5|)H@hD^aQx_v?Su69YWdFm4^zFHHw-%8u9-AEcKp7R zx8CS$53Q@16U*lpdxqWh;k>o8r&b@>bJ-s~KRi3T=C{$?kKgEi;E@+!d-d+Msp*-C zle<Pn{y4j^ec;o>U*8?=pPnCp>r1<}u^+d(r*;f~w_G}Q_RDqqZZH4!`QWVm_MHoJ zOK<(OwR)mm+P&{weQihQrfu5N!Ut3LAL~BTtBsKjTRNUNve@3ccIL5(%bRHM(1A+V zbMIWdH5Zo7lzL~*O^=Nqs@5h~?>YT0m<Km@RtJB%^y~g7uMWL8^wMOx7HqEn*>!Z` m=4Y!r?+uT?e6Z)#z42N{MK_K-|CRR5Dpa{N-M<&1XZ`~l*`Xo; literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/html-wtoc/img/showCont.gif b/emacs/nxhtml/nxhtml/html-wtoc/img/showCont.gif new file mode 100644 index 0000000000000000000000000000000000000000..7bd2e7d310bb028a4692f672267a51adab5038ba GIT binary patch literal 909 zcmZ?wbhEHb6krfw_|5<VEiElmwys^eckkA%TaO((cJJQ3|F{9ee}=vP_g4O|#H|EX zrlA3qKgt^ofk6}kia%Kx85k58bU--)lqVQCvKSmWWH^`_4mPuM^05RgSa_I;L4?c2 zV`9RQCU&DNn*u?WmTm^KtUVl!kB=}j1}!p)G-7I*uIO6CBe`(d=?R*}vse@ynVe>- oao5?b3`%uxR!=R{@d!x|Xf<@zi|yF-BDmXOx!;ls0|f?a01IpwjQ{`u literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/nxhtml/nxhtml-autoload.el b/emacs/nxhtml/nxhtml/nxhtml-autoload.el new file mode 100644 index 0000000..48a0459 --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtml-autoload.el @@ -0,0 +1,147 @@ +;; nxhtml-autoload.el -- Autoloading of nxthml-mode +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Feb 11 00:06:14 2006 +;; Version: 0.51 +;; Last-Updated: 2008-02-13T01:21:14+0100 Wed +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when (load) + (message "nxhtml-autoload starting ... (hm, should maybe be renamed ...)")) + +(eval-when-compile (require 'majmodpri nil t)) +(eval-when-compile (require 'moz nil t)) + +;;; Convenient moving by tags: +(eval-after-load 'nxml-mode + '(progn + (define-key nxml-mode-map [C-M-left] 'nxml-backward-element) + (define-key nxml-mode-map [C-M-right] 'nxml-forward-element) + (define-key nxml-mode-map [C-M-up] 'nxml-backward-up-element) + (define-key nxml-mode-map [C-M-down] 'nxml-down-element))) + +;; MozLab support, for more info see moz.el +;;(autoload 'inferior-moz-mode "moz" "MozRepl Inferior Mode" t) +;;(autoload 'moz-minor-mode "moz" "MozRepl Minor Mode" t) +(defun javascript-moz-setup () (moz-minor-mode 1)) +(add-hook 'javascript-mode-hook 'javascript-moz-setup) +;;(add-hook 'js2-fl-mode-hook 'javascript-moz-setup) + + +(defun nxhtml-setup-file-assoc () + "Setup file associations for nXhtml. +Add nXhtml entries similar to those that are already there for +html-mode and xml-mode. + +Add multi major mode entries. + +Finally run `majmodpri-sort-lists' to get everything in the right +order." + ;; Add nXhtml entries similar to those that are already there for + ;; html-mode and xml-mode. + (dolist (mode-list '(auto-mode-alist magic-fallback-mode-alist magic-mode-alist)) + (dolist (rec (symbol-value mode-list)) + (when (eq (cdr rec) 'html-mode) + (add-to-list mode-list (cons (car rec) 'nxhtml-mode))) + (when (eq (cdr rec) 'html-mode) + (add-to-list mode-list (cons (car rec) 'nxhtml-mumamo-mode))) + ;; (when (eq (cdr rec) 'html-mode) + ;; (add-to-list mode-list (cons (car rec) 'html-mumamo-mode))) + (when (eq (cdr rec) 'xml-mode) + (add-to-list mode-list (cons (car rec) 'nxml-mode))) + )) + + ;; Add multi major mode entries. + (add-to-list 'magic-mode-alist + '("\\(?:.\\|\n\\)\\{,500\\}xmlns:py=\"http://genshi.edgewall.org/\"" + . genshi-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.htm\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.html\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.xhtm\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.xhtml\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.html\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.htmlf\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.xhtml\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.xhtmlf\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.php\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.phtml\\'" . nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.jsp\\'" . jsp-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.gsp\\'" . gsp-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.asp\\'" . asp-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . django-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.rhtml\\'" . eruby-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.erb\\'" . eruby-javascript-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.phps\\'" . smarty-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.epl\\'" . embperl-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.ghtml\\'" . genshi-nxhtml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.mhtml\\'" . mason-nxhtml-mumamo-mode)) + + ;; Add html-mumamo style entry if there is an nxhtml-mumamo style entry. + (save-match-data + (dolist (mode-list '(auto-mode-alist magic-fallback-mode-alist magic-mode-alist)) + (dolist (rec (symbol-value mode-list)) + (let* ((mode (cdr rec)) + (name (when (symbolp mode) (symbol-name mode))) + nxmode) + (when (and name + (string-match "nxhtml-mumamo" name)) + (setq name (replace-regexp-in-string "nxhtml-mumamo" "html-mumamo" name t t)) + (setq nxmode (intern-soft name)) + (when nxmode + (add-to-list mode-list (cons (car rec) nxmode)))))))) + + (add-to-list 'auto-mode-alist '("\\.lzx\\'" . laszlo-nxml-mumamo-mode)) + (add-to-list 'auto-mode-alist '("\\.js\\'" . javascript-mode)) + (add-to-list 'auto-mode-alist '("\\.css\\'" . css-mode)) + (add-to-list 'auto-mode-alist '("\\.rnc\\'" . rnc-mode)) + + (majmodpri-sort-lists) + ;;(message "nxhtml-autoload finished") + ) + +;;(defvar nxhtml-src-dir (file-name-directory (if load-file-name load-file-name buffer-file-name))) + +;;(eval-when (load) (nxhtml-setup-file-assoc)) +(nxhtml-setup-file-assoc) + +(provide 'nxhtml-autoload) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-autoload.el ends here diff --git a/emacs/nxhtml/nxhtml/nxhtml-bug.el b/emacs/nxhtml/nxhtml/nxhtml-bug.el new file mode 100644 index 0000000..5ccfd73 --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtml-bug.el @@ -0,0 +1,332 @@ +;;; nxhtml-bug.el --- Reporting nXhtml bugs +;; +;; Author: Lennar Borgman +;; Maintainer: +;; Created: Wed Mar 07 15:57:15 2007 +;; Version: +;; Lxast-Updated: Wed Mar 07 16:00:22 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Fxeatures that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'nxhtml-menu nil t)) + +(require 'sendmail) + +;;(require 'emacsbug) +(autoload 'report-emacs-bug-info "emacsbug" "Go to the Info node on reporting Emacs bugs." t) + +(defvar nxhtml-report-bug-orig-text nil + "The automatically-created initial text of bug report.") + +(defvar nxhtml-report-bug-no-confirmation nil + "*If non-nil, suppress the confirmations asked for the sake of novice users.") + +(defvar nxhtml-report-bug-no-explanations nil + "*If non-nil, suppress the explanations given when reporting bugs.") + +;; (defvar nxhtml-bug-launchpad-mode-map +;; (let ((map (make-sparse-keymap))) +;; (define-key map [(control ?c) (control ?c)] 'nxhtml-bug-maybe-to-launchpad) +;; map)) + +;; (define-minor-mode nxhtml-bug-launchpad-mode +;; "Changes C-c C-c to ask to report on Launchpad." +;; nil +;; :keymap 'nxhtml-bug-launchpad-mode-map +;; nil) + +;; (defun nxhtml-bug-maybe-to-launchpad () +;; (interactive) +;; (if (y-or-n-p "Do you want to report bug on Launchad (preferred): ") +;; (browse-url "https://bugs.launchpad.net/nxhtml") +;; (mail-send-and-exit))) + +;;;###autoload +(defun nxhtml-report-bug () + "Report a bug in nXhtml." + (interactive) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'nxhtml-report-bug) (interactive-p)) + (with-current-buffer (help-buffer) + (let ((here (point))) + (insert + "A lot of things can interfere with nXhtml/MuMaMo to cause bugs.\n" + "Therefore when reporting a bug please try to describe\n" + "how to show it without your own Emacs initializations.\n" + "To do that start from") + (fill-region here (point)) + (insert "\n\n M-x `emacs-Q-nxhtml'\n\n") + (setq here (point)) + (insert + "If you want to find out if your initialization files interfere\n" + "then you can try the both test commands `nxhtmltest-run' and\n" + "`nxhtmltest-run-Q' and see if there is any difference.\n\n") + (fill-region here (point)) + (setq here (point)) + (insert + "You may also want to look at the installation part of the ") + (insert-text-button "The Quick Guide" + 'action (lambda (btn) + (browse-url + (concat + (nxhtml-docfile-url) + "#qg")))) + (insert " or the file ") + (insert-text-button + "nxhtml/readme.txt" + 'action (lambda (btn) + (find-file-other-window + (expand-file-name "../readme.txt" + (file-name-directory + (symbol-file 'nxhtml-report-bug)))))) + (insert ".\n\n") + (fill-region here (point)) + (setq here (point)) + (insert + "If you know Emacs lisp and are reporting a bug it would be nice " + "if you wrote a new unit test case.\n" + "Please see the file ") + (insert-text-button "nxhtmltest-suites.el" + 'help-echo "Visit file" + 'action (lambda (button) + (find-file (symbol-file 'nxhtmltest-run)))) + (insert " for examples.\n\n") + (fill-region here (point)) + (setq here (point)) + (insert + "There are several ways to report a bug, use the links below:\n" + "- By visiting URL `https://bugs.launchpad.net/nxhtml'.\n") + (setq here (point)) + (insert + "- By ") + (insert-text-button "email to Launchpad" + 'help-echo "Send email to Launchpad bug system" + 'action (lambda (button) + (call-interactively + 'nxhtml-report-bug-by-mail))) + (insert + ".\n") + (insert + " This requires PGP signing the email\n" + " and that you have told your PGP key to Launchpad.\n") + (fill-region here (point)) + (setq here (point)) + (insert + "- The above ways are best since the bug get into the database,\n" + " and it is easy to communicate about it, but if they does\n" + " not work for you please go to \n" + " URL `http://www.emacswiki.org/cgi-bin/wiki/NxhtmlMode'.\n") + (fill-region here (point)) + (setq here (point)) + ) + (with-no-warnings (print-help-return-message))))) + +(defun nxhtml-report-bug-by-mail (topic) + "Report a bug by mail. +Prompts for bug subject. Leaves you in an Emacs mail +buffer. However when you send the bug your normal mail client +will take over the job (with your help)." + (interactive (list (read-string "nXhtml Bug Subject: "))) + ;; If there are four numbers in emacs-version, this is a pretest + ;; version. + (require 'nxhtml-menu) + (let* ((pretest-p (string-match "\\..*\\..*\\." emacs-version)) + (from-buffer (current-buffer)) + ;;(reporting-address "lennart.borgman@gmail.com") + ;;(reporting-address "emacs-nxml-mode@yahoogroups.com") + (reporting-address "new@bugs.launchpad.net") + ;; Put these properties on semantically-void text. + (prompt-properties '(field nxhtml-bug-prompt + intangible but-helpful + rear-nonsticky t)) + user-point message-end-point) + (setq message-end-point + (with-current-buffer (get-buffer-create "*Messages*") + (point-max-marker))) + (compose-mail reporting-address + topic) + ;; The rest of this does not execute + ;; if the user was asked to confirm and said no. + (rfc822-goto-eoh) + (forward-line 1) + + (let ((signature (buffer-substring (point) (point-max)))) + (delete-region (point) (point-max)) + (insert signature) + (backward-char (length signature))) + ;;(nxhtml-bug-launchpad-mode 1) + (insert + "\nThis is a bug report for nXhtml mode.\n") + (unless nxhtml-report-bug-no-explanations + ;; Insert warnings for novice users. + (when (string-match "nxml-mode" reporting-address) + (insert "This bug report will be sent to the nXhtml maintainers,\n") + (let ((pos (point))) + (insert "not to your local site managers!\n") + (put-text-property pos (point) 'face 'highlight))) + (insert "\nPlease write in ") + (let ((pos (point))) + (insert "English") + (put-text-property pos (point) 'face 'highlight)) + (insert " if possible, because the nXhtml maintainers +usually do not have translators to read other languages for them.\n\n") + ) + (insert "Please describe exactly what actions triggered the bug\n" + "and the precise symptoms of the bug, preferrably starting\n" + "from `M-x emacs-Q-nxhtml'\n" + "(it may also be helpful to include an *EXAMPLE FILE*!).\n\n") + (add-text-properties (point) (save-excursion (mail-text) (point)) + prompt-properties) + + (setq user-point (point)) + (insert "\n\n") + + (insert "\n\nnXhtml version " nxhtml-menu:version ", " (emacs-version) "\n\n") + (insert (format "Major mode: %s\n" + (buffer-local-value 'mode-name from-buffer))) + (insert "\n") + (insert "Minor modes in effect:\n") + (dolist (mode minor-mode-list) + (and (boundp mode) (buffer-local-value mode from-buffer) + (insert (format " %s: %s\n" mode + (buffer-local-value mode from-buffer))))) + (insert "\n") + (let ((message-buf (get-buffer "*Messages*"))) + (if message-buf + (let (beg-pos + (end-pos message-end-point)) + (with-current-buffer message-buf + (goto-char end-pos) + (forward-line -10) + (setq beg-pos (point))) + (insert "\n\nRecent messages:\n") + (insert-buffer-substring message-buf beg-pos end-pos)))) + ;; This is so the user has to type something + ;; in order to send easily. + (use-local-map (nconc (make-sparse-keymap) (current-local-map))) + (define-key (current-local-map) "\C-c\C-i" 'report-emacs-bug-info) + (unless nxhtml-report-bug-no-explanations + (with-output-to-temp-buffer "*Bug Help*" + (if (eq mail-user-agent 'sendmail-user-agent) + (princ (substitute-command-keys + "Type \\[mail-send-and-exit] to send the bug report.\n"))) + (princ (substitute-command-keys + "Type \\[kill-buffer] RET to cancel (don't send it).\n")) + (terpri) + (princ (substitute-command-keys + "Type \\[report-emacs-bug-info] to visit in Info the Emacs Manual section +about when and how to write a bug report, +and what information to supply so that the bug can be fixed. + +When there type SPC to scroll through this section and its subsections. + +Please notice that you are now reporting a bug for nXhtml, not +Emacs itself, so everyting in that manual section might not +apply.")))) + ;; Make it less likely people will send empty messages. + (make-local-variable 'mail-send-hook) + (add-hook 'mail-send-hook 'nxhtml-report-bug-hook) + (save-excursion + (goto-char (point-max)) + (skip-chars-backward " \t\n") + (make-local-variable 'nxhtml-report-bug-orig-text) + (setq nxhtml-report-bug-orig-text (buffer-substring (point-min) (point)))) + (goto-char user-point))) + + +(defun nxhtml-report-bug-hook () + (save-excursion + (save-excursion + (goto-char (point-max)) + (skip-chars-backward " \t\n") + (if (and (= (- (point) (point-min)) + (length nxhtml-report-bug-orig-text)) + (equal (buffer-substring (point-min) (point)) + nxhtml-report-bug-orig-text)) + (error "No text entered in bug report"))) + + ;; Check the buffer contents and reject non-English letters. + (save-excursion + (goto-char (point-min)) + (skip-chars-forward "\0-\177") + (if (not (eobp)) + (if (or nxhtml-report-bug-no-confirmation + (y-or-n-p "Convert non-ASCII letters to hexadecimal? ")) + (while (progn (skip-chars-forward "\0-\177") + (not (eobp))) + (let ((ch (following-char))) + (delete-char 1) + (insert (format "=%02x" ch))))))) + + ;; The last warning for novice users. + (if (or nxhtml-report-bug-no-confirmation + (yes-or-no-p + "Send this bug report to the nXhtml maintainers? ")) + ;; Just send the current mail. + nil + (goto-char (point-min)) + (if (search-forward "To: ") + (let ((pos (point))) + (end-of-line) + (delete-region pos (point)))) + (kill-local-variable 'mail-send-hook) + (with-output-to-temp-buffer "*Bug Help*" + (princ (substitute-command-keys "\ +You invoked the command nxhtml-report-bug, +but you decided not to mail the bug report to the nXhtml maintainer. + +If you want to mail it to someone else instead, +please insert the proper e-mail address after \"To: \", +and send the mail again using \\[mail-send-and-exit]."))) + (error "M-x nxhtml-report-bug was cancelled, please read *Bug Help* buffer")) + + ;; Unclutter + (mail-text) + (insert + "Next line tells Launchpad bug system what this is. Don't change it!\n" + " affects nxhtml\n\n") + (mail-text) + (let ((pos (1- (point)))) + (while (setq pos (text-property-any pos (point-max) + 'field 'nxhtml-bug-prompt)) + (delete-region pos (field-end (1+ pos))))))) + +(provide 'nxhtml-bug) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-bug.el ends here diff --git a/emacs/nxhtml/nxhtml/nxhtml-menu.el b/emacs/nxhtml/nxhtml/nxhtml-menu.el new file mode 100644 index 0000000..09c7f4b --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtml-menu.el @@ -0,0 +1,1658 @@ +;;; nxhtml-menu.el --- Defines menus for nXhtml +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Apr 21 2007 +;; Moved version to autostart.el. +;; Last-Updated: 2010-01-04 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Menus for nXhtml to be used in different major modes. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'cus-edit)) +(eval-when-compile (require 'dired)) +(eval-when-compile (require 'gimpedit nil t)) +(eval-when-compile (require 'html-site nil t)) +(eval-when-compile (when (fboundp 'nxml-mode) (require 'nxhtml-mode nil t))) +(eval-when-compile (require 'css-color nil t)) +(eval-when-compile (require 'flymake)) +;;(eval-when-compile (require 'flymake-php)) +(eval-when-compile (require 'flymake-js nil t)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'nxhtml-base)) +(eval-when-compile (require 'udev-ecb nil t)) +;;(eval-when-compile (require 'udev-cedet)) +(eval-when-compile (require 'udev-rinari nil t)) + +(defun nxhtml-nxhtml-in-buffer () + (or (derived-mode-p 'nxhtml-mode) + (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (let ((major-mode (mumamo-main-major-mode))) + (derived-mode-p 'nxhtml-mode))))) + +(defun nxhtml-nxml-in-buffer () + (or (derived-mode-p 'nxml-mode) + (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (let ((major-mode (mumamo-main-major-mode))) + (derived-mode-p 'nxml-mode))))) + +(defun nxhtml-html-in-buffer () + (or (derived-mode-p 'html-mode) + (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (let ((major-mode (mumamo-main-major-mode))) + (derived-mode-p 'html-mode))) + (nxhtml-nxhtml-in-buffer))) + +(defun nxhtml-nxml-html-in-buffer () + (or (derived-mode-p 'html-mode) + (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (let ((major-mode (mumamo-main-major-mode))) + (derived-mode-p 'html-mode))) + (nxhtml-nxml-in-buffer))) + +(defun buffer-or-dired-file-name () + "Return buffer file name or file pointed to in dired." + (if (derived-mode-p 'dired-mode) + (dired-get-file-for-visit) + buffer-file-name)) + +(defun nxhtml-this-file-can-have-toc (&optional file) + (unless file + (setq file (buffer-or-dired-file-name))) + (and (nxhtml-buffer-possibly-local-viewable file) + (html-site-current-merge-dir) + (html-site-current-ensure-file-in-site file))) + +(defun nxhtml-buffer-possibly-local-viewable (&optional file) + (unless file + (setq file (buffer-or-dired-file-name))) + (or (and file + (member (file-name-extension file) + '("html" "htm" "gif" "png"))))) + +(defun nxhtml-buffer-possibly-remote-viewable () + ;; Fix-me + (let* ((fmt "nxhtml-buffer-possibly-remote-viewable.dgffv: %s") + (file (or buffer-file-name + (and (derived-mode-p 'dired-mode) + (condition-case err + (dired-get-file-for-visit) + (error + (message fmt (error-message-string err)) + nil)))))) + (and (featurep 'html-upl) + file + (member (downcase (file-name-extension file)) + '("html" "htm" "gif" "png" "pl" "php"))))) + +;; (nxhtml-insert-menu-dynamically 'temp) +(defun nxhtml-insert-menu-dynamically (real-binding) + (or (and (symbolp real-binding) + (boundp real-binding) + (symbol-value real-binding)) + (let ((map (make-sparse-keymap "Not loaded yet"))) + (define-key map [dummy] + (list 'menu-item "Not loaded yet" 'ignore)) + map) + ;; (easy-menu-filter-return + ;; (easy-menu-create-menu + ;; "Not ready" + ;; '(["Not Loaded Yet" ignore t]))) + )) + +(defun nxhtml-menu-image-file () + (or (get-char-property (point) 'image-file) + buffer-file-name)) + +(defun nxhtml-gimp-can-edit () + (or (not (featurep 'gimp)) + (gimpedit-can-edit (nxhtml-menu-image-file)))) + +;;;###autoload +(defun nxhtml-edit-with-gimp () + "Edit with GIMP buffer or file at point." + (interactive) + (gimpedit-edit-file (nxhtml-menu-image-file))) + +;;;###autoload +(defun nxhtml-browse-file (file) + "View file in web browser." + (interactive (list + (or (buffer-or-dired-file-name) + (read-file-name "File: ")))) + (let* ((buf (if (buffer-file-name) + (current-buffer) + (find-buffer-visiting file))) + (use-temp (and (buffer-file-name) + (or (and (boundp 'nxhtml-current-validation-header) + nxhtml-current-validation-header) + (buffer-modified-p) + (not buffer-file-name) + (not (file-exists-p buffer-file-name))))) + (file-to-browse file)) + (when use-temp + (setq file-to-browse (nxhtml-save-browseable-temp-file nil nil use-temp))) + ;; Fix-me: Workaround for Emacs bug on w32 + ;; http://emacsbugs.donarmstrong.com/cgi-bin/bugreport.cgi?bug=4015 + (if (eq system-type 'windows-nt) + (w32-shell-execute nil (concat "file:///" file-to-browse) nil 1) + (browse-url-of-file file-to-browse)) + )) + +;;;###autoload +(defun nxhtml-browse-region () + "View region in web browser." + (interactive) + (unless mark-active + (error "The region is not active")) + (browse-url (nxhtml-save-browseable-temp-file (region-beginning) (region-end)))) + +;;(defvar nxhtml-browseable-buffer-name "*nXhtml Browsing Buffer*") +(defvar nxhtml-browseable-buffer-file "~/.temp-nxhtml-browse.htm") +;; Fix-me: Handle base href here! +(defun nxhtml-save-browseable-temp-file (start end &optional doit-anyway) + "Return a temporary file for viewing in web browser." + ;; When using this either region should be active or there should be + ;; a validation header or both. + (or doit-anyway + (and start end) ;mark-active + (and (boundp 'nxhtml-validation-header-mode) + nxhtml-validation-header-mode + nxhtml-current-validation-header) + (error "Neither region nor validation header")) + (save-excursion + (let ((curbuf (current-buffer)) + (view-buffer (find-file-noselect nxhtml-browseable-buffer-file)) + header + content) + ;; Get header and content + (save-restriction + (widen) + (setq header + (if nxhtml-validation-header-mode + (let* ((key nxhtml-current-validation-header) + (rec (unless (listp key) + (assoc key nxhtml-validation-headers))) + (header (cdr rec))) + header) + (if (and doit-anyway (not start)) + "" + (goto-char (point-min)) + (save-match-data + (let ((body (re-search-forward "<body[^>]*>"))) + (if body + (buffer-substring-no-properties (point-min) (match-end 0)) + "")))))) + (setq content + (if start + (buffer-substring-no-properties start end) + (buffer-substring-no-properties (point-min) (point-max)))) + ) + ;; Switch to view buffer + (set-buffer view-buffer) + ;; (unless buffer-file-name + ;; (set-visited-file-name nxhtml-browseable-buffer-file) + ;; (rename-buffer nxhtml-valhead-view-buffer-name)) + (erase-buffer) + (insert header content) + ;;(when (fboundp 'emacsw32-eol-set) (emacsw32-eol-set nil)) + (nxhtml-mode) + (save-buffer) + ;;(current-buffer) + (kill-buffer view-buffer) + (expand-file-name nxhtml-browseable-buffer-file) + ))) + + + +(defvar nxhtml-menu-mode-menu-map + (let ((map (make-sparse-keymap "nxhtml-menu-mode-menu"))) + + (let ((help-map (make-sparse-keymap))) + (define-key help-map [emacs-Q-nxhtml] + (list 'menu-item "Start 'emacs -Q' and load nXhtml" 'emacs-Q-nxhtml)) + (define-key help-map [nxhtmltest-run] + (list 'menu-item "Run nXhtml Tests in Current Emacs" 'nxhtmltest-run)) + (define-key help-map [nxhtmltest-run-Q] + (list 'menu-item "Run nXhtml Tests in a Fresh Emacs" 'nxhtmltest-run-Q)) + (define-key help-map [nxhtml-report-bug] + (list 'menu-item "Report a Bug in nXhtml ..." 'nxhtml-report-bug)) + (define-key help-map [nxhtml-help-separator2] (list 'menu-item "--")) + (define-key help-map [nxhtml-byte-compile-nxhtml] + (list 'menu-item "Byte Compile nXhtml" 'nxhtmlmaint-start-byte-compilation)) + ;; Downloads + (let ((download-map (make-sparse-keymap))) + (define-key help-map [nxhtml-downloading] + (list 'menu-item "Download nXhtml Updates" download-map)) + (define-key download-map [nxhtml-web-download-log] + (list 'menu-item "View Download Log" 'web-vcs-log-edit)) + (define-key download-map [nxhtml-view-dl-log-separator] + (list 'menu-item "--" nil)) + (define-key download-map [nxhtml-web-auto-download] + (list 'menu-item "Auto download from Devel Sources" + 'nxhtml-autoload-web + :button '(:toggle . (and (boundp 'nxhtml-autoload-web) + nxhtml-autoload-web)))) + (define-key download-map [nxhtml-web-download] + (list 'menu-item "Update nXhtml (from devel sources)" 'nxhtml-update-existing-files)) + ) + (define-key help-map [nxhtml-features-check] + (list 'menu-item "Check Optional Features" 'nxhtml-features-check)) + (define-key help-map [nxhtml-list-multi-modes] + (list 'menu-item "List Available Multi Major Modes" 'mumamo-list-defined-multi-major-modes)) + (define-key help-map [nxhtml-customize] + (list 'menu-item "Customize nXhtml ..." 'nxhtml-customize)) +;;; (define-key help-map [nxhtml-quick-customize] +;;; (list 'menu-item "Quick Customize nXhtml ..." 'nxhtml-quick-customize)) + (define-key help-map [nxhtml-help-separator3] (list 'menu-item "--")) +;;; (define-key help-map [nxhtml-help] +;;; (list 'menu-item "nXhtml Help" 'nxhtml-help)) + (define-key help-map [nxhtml-tutorials] + (list 'menu-item "nXhtml Tutorials" 'nxhtml-tutorials)) + (define-key help-map [nxhtml-overview] + (list 'menu-item (concat "nXhtml Version " + (if (boundp 'nxhtml-menu:version) + nxhtml-menu:version + "(unknown)") + " Overview") + 'nxhtml-overview)) + (define-key help-map [nxhtml-welcome] + (list 'menu-item "Welcome to nXhtml" 'nxhtml-welcome)) + (define-key map [nxhtml-help-map] + (list 'menu-item "nXhtml Help and Setup" help-map)) + (define-key map [nxhtml-info-separator] (list 'menu-item "--")) + ) + + + + + (let ((tools-map (make-sparse-keymap))) + (define-key map [nxhtml-tools-map] + (list 'menu-item "Tools" tools-map)) + (define-key tools-map [nxhtml-last-resort] + (list 'menu-item "Last Resort" 'n-back-game)) + (define-key tools-map [nxhtml-pause] + (list 'menu-item "Life Reminder" 'pause-start-in-new-emacs)) + (define-key tools-map [nxhtml-last-resort-separator] + (list 'menu-item "--" nil)) + (define-key tools-map [nxhtml-viper-tut] + (list 'menu-item "Viper Try-Out Tutorial" + 'viper-tutorial)) + (define-key tools-map [nxhtml-viper-separator] + (list 'menu-item "--" nil)) + ;;(define-key tools-map [nxhtml-frame-win-separator] (list 'menu-item "--" nil)) + (define-key tools-map [nxhtml-resize-windows] + (list 'menu-item "Resize Windows" + 'resize-windows)) + + + + (define-key tools-map [nxhtml-ecb-separator] + (list 'menu-item "--" nil)) + + + (let ((ecb-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-ecb-map] + (list 'menu-item "ECB" ecb-map)) + (define-key ecb-map [nxhtml-custom-important-ecb] + (list 'menu-item "Customize important ECB things" + (lambda () + "Customize group `ecb-most-important'." + (interactive) + (customize-group-other-window 'ecb-most-important)) + :enable '(featurep 'ecb))) + (define-key ecb-map [nxhtml-ecb-mode] + (list 'menu-item "ECB Minor Mode" + 'ecb-minor-mode + :button '(:toggle . (and (boundp 'ecb-minor-mode) + ecb-minor-mode)) + :enable '(boundp 'ecb-minor-mode))) + (define-key ecb-map [nxhtml-ecb-show-help] + (list 'menu-item "ECB Help" + 'ecb-show-help + :enable '(fboundp 'ecb-show-help))) + (define-key ecb-map [nxhtml-ecb-custom-separator] + (list 'menu-item "--" nil)) + (define-key ecb-map [nxhtml-custom-ecb] + (list 'menu-item "Customize ECB dev startup from nXhtml" + 'udev-ecb-customize-startup)) + (define-key ecb-map [nxhtml-update-ecb] + (list 'menu-item "Fetch/update ECB dev sources" + 'udev-ecb-update)) + (define-key ecb-map [nxhtml-ecb-home-separator] + (list 'menu-item "--" nil)) + (define-key ecb-map [nxhtml-rinari-homepage] + (list 'menu-item "ECB Home Page" + (lambda () + "Open ECB home page in your web browser." + (interactive) + (browse-url "http://ecb.sourceforge.net/")))) + ) + + + ;; (let ((cedet-map (make-sparse-keymap))) + ;; (define-key tools-map [nxhtml-cedet-map] + ;; (list 'menu-item "CEDET" cedet-map)) + ;; (define-key cedet-map [nxhtml-custom-cedet] + ;; (list 'menu-item "Customize CEDET dev startup from nXhtml" + ;; 'udev-cedet-customize-startup)) + ;; (define-key cedet-map [nxhtml-cedet-utest] + ;; (list 'menu-item "Run CEDET unit tests" + ;; 'udev-cedet-utest)) + ;; (define-key cedet-map [nxhtml-update-cedet] + ;; (list 'menu-item "Fetch/update and install CEDET dev sources" + ;; 'udev-cedet-update)) + ;; (define-key cedet-map [nxhtml-cedet-home-separator] + ;; (list 'menu-item "--" nil)) + ;; (define-key cedet-map [nxhtml-rinari-homepage] + ;; (list 'menu-item "CEDET Home Page" + ;; (lambda () + ;; "Open CEDET home page in your web browser." + ;; (interactive) + ;; (browse-url "http://cedet.sourceforge.net/")))) + ;; ) + + + (let ((rinari-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-rinari-map] + (list 'menu-item "Rinari" rinari-map)) + (define-key rinari-map [nxhtml-custom-rinari] + (list 'menu-item "Customize Rinari startup from nXhtml" + (lambda () + "Customize Rinari dev nXhtml startup options." + (interactive) + (customize-group-other-window 'udev-rinari)))) + (define-key rinari-map [nxhtml-update-rinari] + (list 'menu-item "Fetch/update Rinari dev sources" + 'udev-rinari-update)) + (define-key rinari-map [nxhtml-rinari-home-separator] + (list 'menu-item "--" nil)) + (define-key rinari-map [nxhtml-rinari-homepage] + (list 'menu-item "Rinari Home Page" + (lambda () + "Open Rinari home page in your web browser." + (interactive) + (browse-url "http://rubyforge.org/projects/rinari/")))) + ) + (let ((mozrepl-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-mozrepl-map] + (list 'menu-item "MozRepl - control Firefox" mozrepl-map)) + + (let ((mozrepl-low-map (make-sparse-keymap))) + (define-key mozrepl-map [nxhtml-mozrepl-map] + (list 'menu-item "MozRepl Basic Functions" mozrepl-low-map)) + (define-key mozrepl-low-map [nxhtml-mozrepl-run-mozilla] + (list 'menu-item "Display/Start MozRepl Process" 'run-mozilla + :enable '(fboundp 'moz-minor-mode))) + (define-key mozrepl-low-map [nxhtml-mozrepl-separator1] + (list 'menu-item "--" nil)) + (define-key mozrepl-low-map [nxhtml-mozrepl-save-and-send] + (list 'menu-item "Save Buffer and Send it" 'moz-save-buffer-and-send + :enable '(or (not (boundp 'mumamo-multi-major-mode)) + (not mumamo-multi-major-mode)))) + (define-key mozrepl-low-map [nxhtml-mozrepl-send-defun-and-go] + (list 'menu-item "Send Current Function, Go to MozRepl" + 'moz-send-defun-and-go + :enable '(and (boundp 'moz-minor-mode) moz-minor-mode))) + (define-key mozrepl-low-map [nxhtml-mozrepl-send-defun] + (list 'menu-item "Send Current Function" 'moz-send-defun + :enable '(and (boundp 'moz-minor-mode) moz-minor-mode))) + (define-key mozrepl-low-map [nxhtml-mozrepl-send-region] + (list 'menu-item "Send the Region" 'moz-send-region + :enable '(and mark-active + (boundp 'moz-minor-mode) moz-minor-mode)))) + + (define-key mozrepl-map [nxhtml-mozrepl-separator2] + (list 'menu-item "--" nil)) + (define-key mozrepl-map [nxhtml-mozrepl-refresh] + (list 'menu-item "Refresh Firefox on Save" 'mozadd-refresh-edited-on-save-mode + :button '(:toggle . (and (boundp 'mozadd-refresh-edited-on-save-mode) + mozadd-refresh-edited-on-save-mode)))) + (define-key mozrepl-map [nxhtml-mozrepl-mirror] + (list 'menu-item "Mirror Buffer in Firefox" 'mozadd-mirror-mode + :button '(:toggle . (and (boundp 'mozadd-mirror-mode) + mozadd-mirror-mode)))) + (define-key mozrepl-map [nxhtml-mozrepl-separator3] + (list 'menu-item "--" nil)) + (define-key mozrepl-map [nxhtml-mozrepl-home-page] + (list 'menu-item "MozLab/MozRepl Home Page" + (lambda () + "Open MozLab/MozRepl home page in your web browser." + (interactive) + (browse-url "http://hyperstruct.net/projects/mozlab")))) + ) + + (define-key tools-map [nxhtml-ediff-url] + (list 'menu-item "Compare download file" 'ediff-url)) + (define-key tools-map [nxhtml-investigate-elisp] + (list 'menu-item "Investigate Elisp File" 'web-vcs-investigate-elisp-file)) + + (define-key tools-map [nxhtml-tidy-separator] + (list 'menu-item "--" nil)) + (define-key tools-map [nxhtml-flymake] + (list 'menu-item "Flymake Mode" 'flymake-mode + :button '(:toggle . (and (boundp 'flymake-mode) + flymake-mode)) + :enable '(and buffer-file-name + (require 'flymake) + (fboundp 'flymake-get-init-function) + (flymake-get-init-function buffer-file-name) + ))) + (let ((flyspell-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-flyspell-map] + (list 'menu-item "Flyspell" flyspell-map)) + (define-key flyspell-map [nxhtml-flyspell-goto-next] + (list 'menu-item "Flyspell Go To Next Error" 'flyspell-goto-next-error + :enable 'flyspell-mode)) + (define-key flyspell-map [nxhtml-flyspell-region] + (list 'menu-item "Flyspell Region" 'flyspell-region + :enable 'flyspell-mode)) + (define-key flyspell-map [nxhtml-flyspell-div-1] + (list 'menu-item "--")) + (define-key flyspell-map [nxhtml-flyspell] + (list 'menu-item "Flyspell Mode" 'flyspell-mode + :button '(:toggle . (and (boundp 'flyspell-mode) + flyspell-mode)))) + ) + (define-key tools-map [nxhtml-flyspell-separator] + (list 'menu-item "--")) + (let ((img-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-img-map] + (list 'menu-item "Images" img-map)) + (define-key img-map [nxhtml-chartg] + (list 'menu-item "Make Chart" 'chartg-make-chart)) + (define-key img-map [nxhtml-chartg-separator] (list 'menu-item "--")) + (define-key img-map [nxhtml-gimp-edit] + (list 'menu-item "Edit with GIMP" 'nxhtml-edit-with-gimp + :enable '(nxhtml-gimp-can-edit))) + (define-key img-map [nxhtml-gimp-separator] (list 'menu-item "--")) + (define-key img-map [nxhtml-inlimg-toggle-display] + (list 'menu-item "Toggle Display of Image" 'inlimg-toggle-display)) + (define-key img-map [nxhtml-inlimg-toggle-slicing] + (list 'menu-item "Toggle Slicing of Image" 'inlimg-toggle-slicing)) + (define-key img-map [nxhtml-inlimg-mode] + (list 'menu-item "Show <img ...> Images" 'inlimg-mode + :button '(:toggle . (and (boundp 'inlimg-mode) + inlimg-mode))))) + (define-key tools-map [nxhtml-img-separator] + (list 'menu-item "--")) + (let ((some-help-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-some-help-map] + (list 'menu-item "Help for Item at Point" some-help-map)) + (define-key some-help-map [nxhtml-css-help] + (list 'menu-item "CSS Help" 'xhtml-help-show-css-ref)) + (define-key some-help-map [nxhtml-tag-help] + (list 'menu-item "XHTML Tag Help" 'nxhtml-short-tag-help))) + + (let ((cssclr-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-css-color] + (list 'menu-item "Color Help" cssclr-map)) + (define-key cssclr-map [nxhtml-css-color-mode] + (list 'menu-item "Css Color Mode" 'css-color-mode + :enable '(and font-lock-mode + ;; (or (not (boundp 'mumamo-multi-major-mode)) + ;; (not mumamo-multi-major-mode)) + ;; (featurep 'css-color) + ) + :button '(:toggle . (and (boundp 'css-color-mode) + css-color-mode)))) + (define-key cssclr-map [nxhtml-css-color-test] + (list 'menu-item "Color Test" 'css-color-test + ;; :enable '(featurep 'css-color) + ))) + + (define-key tools-map [nxhtml-help-separator] + (list 'menu-item "--")) + + + (let ((html-link-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-link-map] + (list 'menu-item "HTML Links" html-link-map + :enable '(nxhtml-html-in-buffer))) + + (define-key html-link-map [nxhtml-chklnk] + (list 'menu-item "Check Links" 'html-chklnk-check-site-links + :enable '(featurep 'html-chklnk))) + + (let ((move-map (make-sparse-keymap))) + (define-key html-link-map [move-map] + (list 'menu-item "Moving Files" move-map)) + (define-key move-map [html-move-buffer-file] + (list 'menu-item "Move Buffer File" 'html-move-buffer-file + :help "Move buffer file and update links" + :enable '(and buffer-file-name + (featurep 'html-move)))) + (define-key html-link-map [move-map-separator] (list 'menu-item "--")) + ) + + + (define-key html-link-map [nxhtml-paste-link] + (list 'menu-item "Paste Saved Relative Link" 'nxhtml-paste-link + :help "Paste link" + :enable '(and (boundp 'nxhtml-saved-link-file) + nxhtml-saved-link-file))) + (define-key html-link-map [nxhtml-paste-link-as-a-tag] + (list 'menu-item "Paste Saved Relative Link as <a href=...>" 'nxhtml-paste-link-as-a-tag + :help "Paste link as <a ...> tag" + :enable '(and (boundp 'nxhtml-saved-link-file) + nxhtml-saved-link-file + (nxhtml-nxml-html-in-buffer)))) + (define-key html-link-map [nxhtml-save-link-to-here] + (list 'menu-item "Save Relative Link to Current File" 'nxhtml-save-link-to-here + :help "Save link info for current file" + :enable 'buffer-file-name)) + ) + + (let ((quick-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-quick-map] + (list 'menu-item "Quick Inserts etc" quick-map + :visible '(or (derived-mode-p 'html-mode) + (nxhtml-nxhtml-in-buffer)))) + (let ((sometoc-map (make-sparse-keymap))) + (let ((toc-map (make-sparse-keymap))) + (define-key sometoc-map [nxhtml-toc-map] + (list 'menu-item "For Site" toc-map + :enable '(featurep 'html-toc))) + (define-key toc-map [nxhtml-html-wtoc] + (list 'menu-item "Merge Pages and TOC" + 'html-wtoc-write-pages-with-toc + :enable '(or (not (featurep 'html-site)) + (html-site-current-page-list)))) + (define-key toc-map [nxthml-html-toc] + (list 'menu-item "With Frames" 'html-toc-menu-map + :filter 'nxhtml-insert-menu-dynamically))) + (define-key sometoc-map [nxhtml-html-pagetoc] + (list 'menu-item "For Page" 'html-pagetoc-menu-map + :enable (boundp 'html-pagetoc-menu-map) + :filter 'nxhtml-insert-menu-dynamically + )) + (define-key quick-map [nxhtml-sometoc-map] + (list 'menu-item "Table of Contents" sometoc-map + :visible '(or (derived-mode-p 'html-mode) + (nxhtml-nxhtml-in-buffer))))) + (define-key quick-map [nxhtml-quick-sep-1] + (list 'menu-item "--")) + (define-key quick-map [nxhtml-spec-chars] + (list 'menu-item "Insert special character" + 'nxml-insert-named-char)) + (define-key quick-map [nxhtml-css-rollover] + (list 'menu-item "Insert CSS Rollover Images" + 'nxhtml-rollover-insert-2v))) + + + (define-key tools-map [nxhtml-html-write-mode] + (list 'menu-item "HTML Write Mode" + 'html-write-mode + :enable '(nxhtml-html-in-buffer) + :button '(:toggle . (and (boundp 'html-write-mode) + html-write-mode)))) + (define-key tools-map [nxhtml-tidy-map] + (list 'menu-item "Tidy XHTML" 'tidy-menu-symbol + ;; Seems like :visible is called before :filter so we + ;; can compute things in :visible. + :filter 'nxhtml-insert-menu-dynamically + :visible '(or (and (or (derived-mode-p 'html-mode) + (nxhtml-nxhtml-in-buffer)) + (fboundp 'tidy-build-menu) (tidy-build-menu)) + t) + :enable '(and (or (derived-mode-p 'html-mode) + (nxhtml-nxhtml-in-buffer)) + (fboundp 'tidy-build-menu) (tidy-build-menu)) + )) + (define-key tools-map [zencoding] + (list 'menu-item "Zen coding for HTML/CSS" 'zencoding-mode + :button '(:toggle . (and (boundp 'zencoding-mode) + zencoding-mode)) + :enable '(nxhtml-html-in-buffer))) + + (let ((where-map (make-sparse-keymap))) + (define-key tools-map [nxml-where] + (list 'menu-item "XML Path" where-map + :enable '(and (fboundp 'nxml-where-mode) + (or (derived-mode-p 'nxml-mode) + (nxhtml-nxhtml-in-buffer))))) + (define-key where-map [nxhtml-nxml-where-cust] + (list 'menu-item "Customize display of XML Path" + (lambda () + "Customize XML path, ie group `nxml-where'." + (interactive) + (customize-group-other-window 'nxml-where)))) + (define-key where-map [where-separator-2] (list 'menu-item "--")) + (define-key where-map [nxml-where-inner] + (list 'menu-item "Show inly inner tag" 'nxml-where-only-inner-toggle + :enable '(boundp 'nxml-where-only-inner) + :button '(:toggle . (and (boundp 'nxml-where-only-inner) + nxml-where-only-inner)))) + (define-key where-map [nxml-where-id] + (list 'menu-item "Show tag ids in path" 'nxml-where-tag+id-toggle + :enable '(boundp 'nxml-where-tag+id) + :button '(:toggle . (and (boundp 'nxml-where-tag+id) + nxml-where-tag+id)))) + (define-key where-map [nxml-where-header] + (list 'menu-item "Show XML path in header" 'nxml-where-header-toggle + :enable '(boundp 'nxml-where-header) + :button '(:toggle . (and (boundp 'nxml-where-header) + 'nxml-where-header)))) + (define-key where-map [nxml-where-marks] + (list 'menu-item "Show XML path marks" 'nxml-where-marks-toggle + :enable '(boundp 'nxml-where-marks) + :button '(:toggle . (and (boundp 'nxml-where-marks) + nxml-where-marks)))) + (define-key where-map [where-separator] (list 'menu-item "--")) + (define-key where-map [nxml-where-global-toggle] + (list 'menu-item "Show XML path" 'nxml-where-global-mode + :button '(:toggle . (and (boundp 'nxml-where-global-mode) + nxml-where-global-mode)))) + (define-key where-map [nxml-where-toggle] + (list 'menu-item "Show XML path in buffer" 'nxml-where-mode + :button '(:toggle . (and (boundp 'nxml-where-mode) + nxml-where-mode)))) + ) + + + (let ((cmpl-map (make-sparse-keymap))) + (define-key tools-map [nxhtml-cmpl-map] + (list 'menu-item "XHTML Completion and Validation" cmpl-map + ;; :enable '(or (derived-mode-p 'nxml-mode) (nxhtml-nxhtml-in-buffer)) + :visible `(not (derived-mode-p 'dired-mode)) + :enable ' (or (derived-mode-p 'nxml-mode) + (nxhtml-nxhtml-in-buffer)) + )) + (let ((val-map (make-sparse-keymap))) + (define-key cmpl-map [nxhtml-cmpl-val-map] + (list 'menu-item "Validation Helpers (for php etc)" val-map + :enable '(nxhtml-nxhtml-in-buffer) + :visible '(nxhtml-nxml-html-in-buffer))) +;;; (define-key val-map [nxhtml-strval-mode] +;;; (list 'menu-item "Allow attr=\"<?php...?>\" etc" +;;; 'nxhtml-strval-mode +;;; :button '(:toggle . nxhtml-strval-mode))) + (define-key val-map [mumamo-alt-php-tags] + (list 'menu-item "Use <?php -> (?php" + 'mumamo-alt-php-tags-mode + :button '(:toggle . (and (boundp 'mumamo-alt-php-tags-mode) + mumamo-alt-php-tags-mode)))) + (define-key val-map [mumamo-alt-tags-separator] (list 'menu-item "--")) + (define-key val-map [nxhtml-toggle-warnings] + (list 'menu-item "Hide Validation Errors" + 'nxhtml-toggle-visible-warnings + :button '(:toggle . (not (nxhtml-warnings-are-visible))) + )) + (define-key val-map [nxhtml-error-separator] (list 'menu-item "--")) + (define-key val-map [nxhtml-remove-saved-validation-header] + (list 'menu-item "Remove File's Fictive XHTML Validation Header" + 'nxhtml-remove-saved-validation-header + ;; Fix-me: maybe a better enable here? + :enable 'nxhtml-validation-header-mode)) + (define-key val-map [nxhtml-save-validation-header] + (list 'menu-item "Save File's Fictive XHTML Validation Header" + 'nxhtml-save-validation-header + :enable 'nxhtml-validation-header-mode)) + (define-key val-map [nxhtml-set-validation-header] + (list 'menu-item "Choose Fictive XHTML Validation Header for Buffer" + 'nxhtml-set-validation-header)) + (define-key val-map [nxhtml-update-validation-header] + (list 'menu-item "Update Fictive XHTML Validation Header for Buffer" + 'nxhtml-update-validation-header)) + (define-key val-map [nxhtml-use-saved-val-separator] (list 'menu-item "--")) +;;; (let ((afic-map (make-sparse-keymap))) +;;; (define-key val-map [nxhtml-afic-map] +;;; (list 'menu-item "Automatic Fictive XHTML Validation Header" afic-map)) +;;; (define-key afic-map [nxhtml-validation-header-mumamo-set] +;;; (list 'menu-item "Customize Automatic XHTML Validation Turn On" +;;; (lambda () (interactive) (customize-option 'nxhtml-validation-header-mumamo-modes)))) +;;; (define-key afic-map [nxhtml-validation-header-mumamo] +;;; (list 'menu-item "Turn on Fictive XHTML Validation Header with MuMaMo" +;;; 'nxhtml-validation-header-if-mumamo-toggle +;;; :button '(:toggle . nxhtml-validation-header-if-mumamo)))) + (define-key val-map [nxhtml-show-validation-header] + (list 'menu-item "Display Fictive XHTML Validation Header" + 'rngalt-display-validation-header-toggle + :help-echo "Displays the Fictive XHTML validation header (if any) at top of buffer" + :button '(:toggle . (and (boundp 'rngalt-display-validation-header) + rngalt-display-validation-header)))) + (define-key val-map [nxhtml-recheck-validation-header] + (list 'menu-item "Recheck Fictive XHTML Validation Header in Buffer" + 'nxhtml-recheck-validation-header + :enable 'nxhtml-validation-header-mode)) + (define-key val-map [nxhtml-validation-header-mode] + (list 'menu-item "Use Fictive XHTML Validation Header in Buffer" + 'nxhtml-validation-header-mode + :button '(:toggle . (and (boundp 'nxhtml-validation-header-mode) + nxhtml-validation-header-mode)))) + ) + (define-key cmpl-map [nxhtml-validation-separator] + (list 'menu-item "--" nil + :visible '(nxhtml-nxml-html-in-buffer))) + (let ((style-map (make-sparse-keymap))) + (define-key cmpl-map [nxhtml-cmpl-style-map] + (list 'menu-item "Completion Style" style-map + :visible '(nxhtml-nxml-html-in-buffer) + :enable '(nxhtml-nxhtml-in-buffer))) + (define-key style-map [popcmp-customize] + (list 'menu-item "Customize Completion Style" + (lambda () (interactive) (customize-group-other-window 'popcmp)))) + (define-key style-map [popcmp-style-div2] + (list 'menu-item "--")) + ;;(defun nxhtml-nxml-html-in-buffer () + (define-key style-map [popcmp-with-help] + (list 'menu-item "Show Short Help Beside Alternatives" + 'popcmp-short-help-beside-alts-toggle + :button '(:toggle . (and (boundp 'popcmp-short-help-beside-alts) + popcmp-short-help-beside-alts)))) + (define-key style-map [nxhtml-tag-do-also] + (list 'menu-item "Complete Tag Extras" + 'nxhtml-tag-do-also-toggle + :button '(:toggle . (and (boundp 'nxhtml-tag-do-also) + nxhtml-tag-do-also)))) + (define-key style-map [popcmp-group-alternatives] + (list 'menu-item "Group Alternatives" + 'popcmp-group-alternatives-toggle + :button '(:toggle . (and (boundp 'popcmp-group-alternatives) + popcmp-group-alternatives)))) + (define-key style-map [popcmp-style-div1] + (list 'menu-item "--")) + (define-key style-map [popcmp-anything-completion] + (list 'menu-item "Anything Style Completion" + (lambda () (interactive) (customize-set-variable 'popcmp-completion-style 'anything)) + :enable `(fboundp 'anything) + :button `(:radio . (eq popcmp-completion-style 'anything)))) + (define-key style-map [popcmp-company-completion] + (list 'menu-item "Company Mode Style Completion" + (lambda () (interactive) (customize-set-variable 'popcmp-completion-style 'company-mode)) + :enable `(fboundp 'company-mode) + :button `(:radio . (eq popcmp-completion-style 'company-mode)))) + (define-key style-map [popcmp-emacs-completion] + (list 'menu-item "Emacs Default Style Completion" + (lambda () (interactive) (customize-set-variable 'popcmp-completion-style 'emacs-default)) + :button `(:radio . (eq popcmp-completion-style 'emacs-default)))) + (define-key style-map [popcmp-popup-completion] + (list 'menu-item "Popup Style Completion" + (lambda () (interactive) (customize-set-variable 'popcmp-completion-style 'popcmp-popup)) + :button `(:radio . (eq popcmp-completion-style 'popcmp-popup)))) + ) + (define-key cmpl-map [nxhtml-cmpl-separator] + (list 'menu-item "--" nil + :visible '(nxhtml-nxml-html-in-buffer))) + (define-key cmpl-map [nxhtml-untag-element] + (list 'menu-item "Untag Element" 'nxml-untag-element + :enable '(nxhtml-nxhtml-in-buffer) + :visible '(nxhtml-nxml-html-in-buffer))) + (define-key cmpl-map [rngalt-finish-element] + (list 'menu-item "Insert End Tag" 'rngalt-finish-element + :enable '(nxhtml-nxhtml-in-buffer) + :visible '(nxhtml-nxml-html-in-buffer))) + (define-key cmpl-map [nxhtml-complete] + (list 'menu-item "Complete tag, attribute etc" 'nxml-complete + :enable '(nxhtml-nxml-in-buffer) + :visible '(nxhtml-nxml-html-in-buffer))) + ) + + + ) + + (let ((options-map (make-sparse-keymap))) + (define-key map [nxhtml-options-map] + (list 'menu-item "Options" options-map)) + + (define-key options-map [nxhtml-save-opt] + (list 'menu-item "Save All Changed Options" 'customize-save-customized)) + + (define-key options-map [nxhtml-save-sep] (list 'menu-item "--")) + + (define-key options-map [nxhtml-load-flymake] + (list 'menu-item "Use nXhtml CSS/JS Flymake" + 'nxhtml-flymake-setup + :button '(:toggle . (and (boundp 'nxhtml-flymake-setup) + nxhtml-flymake-setup)))) + + (define-key options-map [nxhtml-save-sep] (list 'menu-item "--")) + + (define-key options-map [nxhtml-winsav-mode] + (list 'menu-item "Save/restore Frames and Windows" + 'winsav-save-mode + :button '(:toggle . (and (boundp 'winsav-save-mode) + winsav-save-mode)))) + (define-key options-map [nxhtml-win-sep] (list 'menu-item "--")) + (define-key options-map [nxhtml-images-global] + (list 'menu-item "Display Images Inline" 'inlimg-global-mode + :button '(:toggle . (and (boundp 'inlimg-global-mode) + inlimg-global-mode)))) + (define-key options-map [nxhtml-opt-sep] (list 'menu-item "--")) + (define-key options-map [nxhtml-hl-needed-mode] + (list 'menu-item "Tell Me Where I Am" 'hl-needed-mode + :button '(:toggle . (and (boundp 'hl-needed-mode) + hl-needed-mode)))) + (define-key options-map [nxhtml-mark-nonascii] + (list 'menu-item "Mark Special Chars (default non-IDN)" 'markchars-global-mode + :button '(:toggle . (and (boundp 'markchars-global-mode) + markchars-global-mode)))) + (define-key options-map [nxhtml-sml-modeline-mode] + (list 'menu-item "Mode Line Scroll Indicator" 'sml-modeline-mode + :button '(:toggle . (and (boundp 'sml-modeline-mode) + sml-modeline-mode)))) + (define-key options-map [rebind-keys] + (list 'menu-item "Rebind My Choosen Keys" 'rebind-keys-mode + :button '(:toggle . (and (boundp 'rebind-keys-mode) + rebind-keys-mode)))) + (define-key options-map [nxhtml-appmenu] + (list 'menu-item "Context Sensitive AppMenu" + 'appmenu-mode + :button '(:toggle . (and (boundp 'appmenu-mode) + appmenu-mode)))) + (define-key options-map [nxhtml-menu-to-m-x] + (list 'menu-item "Add Menu Commands to M-x history" + 'ourcomments-M-x-menu-mode + :button '(:toggle . (and (boundp 'ourcomments-M-x-menu-mode) + ourcomments-M-x-menu-mode)))) + (define-key options-map [nxhtml-patch-converting] + (list 'menu-item "Paste with Convert" + 'ourcomments-paste-with-convert-mode + :button '(:toggle . (and (boundp 'ourcomments-paste-with-convert-mode) + ourcomments-paste-with-convert-mode)))) + + (define-key options-map [nxhtml-tab-separator] + (list 'menu-item "--" nil)) + (define-key options-map [nxhtml-ctrl-tab] + (list 'menu-item "Ctrl-TAB Buffer Switching" + 'ourcomments-ido-ctrl-tab + :button '(:toggle . (and (boundp 'ourcomments-ido-ctrl-tab) + ourcomments-ido-ctrl-tab)))) + (define-key options-map [nxhtml-tab-complete] + (list 'menu-item "Indent and then Complete (TabKey2 mode)" 'tabkey2-mode + :button '(:toggle . (and (boundp 'tabkey2-mode) + tabkey2-mode)))) + + + + (define-key options-map [nxhtml-majpri-separator] + (list 'menu-item "--" nil)) + (define-key options-map [nxhtml-as-external] + (list 'menu-item "External Editor Setup" + 'as-external-mode + :button '(:toggle . (and (boundp 'as-external-mode) + as-external-mode)))) + (define-key options-map [nxhtml-sex-mode] + (list 'menu-item "Open Files in External Apps" + 'sex-mode + :button '(:toggle . (and (boundp 'sex-mode) + sex-mode)))) + (let ((majpri-map (make-sparse-keymap))) + (define-key options-map [nxhtml-majpri-map] + (list 'menu-item "Major Modes Priorities" majpri-map)) + (define-key majpri-map [nxhtml-majpri-act] + (list 'menu-item "Apply Major Modes Priorities" + 'majmodpri-apply-priorities)) + (define-key majpri-map [nxhtml-majpri-cust] + (list 'menu-item "Customize Major Mode Priorities" + (lambda () + "Customize group Major Mode priorities." + (interactive) + (customize-group-other-window 'majmodpri)))) + ) + ) + + (let ((edit-map (make-sparse-keymap))) + (define-key map [nxhtml-edit-map] + (list 'menu-item "Edit" edit-map)) + + (let ((folding-map (make-sparse-keymap))) + (define-key edit-map [nxhtml-folding-map] + (list 'menu-item "Folding" folding-map)) + (define-key folding-map [nxhtml-fold-unhide-all] + (list 'menu-item "Unhide Everything" + 'fold-dwim-unhide-hs-and-outline)) + (define-key folding-map [nxhtml-fold-dwim] + (list 'menu-item "Maybe DWIM Folding" + 'fold-dwim-toggle)) + (define-key folding-map [nxhtml-separator2] (list 'menu-item "--" nil)) + (define-key folding-map [nxhtml-hs] + (list 'menu-item "Turn On Hide/Show and Hide" + 'fold-dwim-turn-on-hs-and-hide)) + (define-key folding-map [nxhtml-outline] + (list 'menu-item "Turn On Outline and Hide All" + 'fold-dwim-turn-on-outline-and-hide-all)) + (define-key folding-map [nxhtml-separator1] (list 'menu-item "--" nil)) + (define-key folding-map [nxhtml-foldit-mode] + (list 'menu-item "Folding Markers in Buffer" + 'foldit-mode + :button '(:toggle . (and (boundp 'foldit-mode) + foldit-mode)))) + (define-key folding-map [nxhtml-foldit-global-mode] + (list 'menu-item "Folding Markers Everywhere" + 'foldit-global-mode + :button '(:toggle . (and (boundp 'foldit-global-mode) + foldit-global-mode)))) + ) + + (define-key edit-map [nxhtml-folding-sep] (list 'menu-item "--")) + + (define-key edit-map [nxhtml-wrap-to-fill-column-mode] + (list 'menu-item "Wrap To Fill Column Mode" + 'wrap-to-fill-column-mode + :button '(:toggle . (and (boundp 'wrap-to-fill-column-mode) + wrap-to-fill-column-mode)))) + (define-key edit-map [nxhtml-fill-dwim] + (list 'menu-item "Fill DWIM" 'fill-dwim)) + + (define-key edit-map [nxhtml-fill-sep] (list 'menu-item "--")) + + + (let ((link-map (make-sparse-keymap))) + (define-key edit-map [nxhtml-link-map] + (list 'menu-item "Links" link-map + :enable '(not (derived-mode-p 'dired-mode)) + )) + + (define-key link-map [mlinks-goto-link-other-frame] + (list 'menu-item "Follow MLink Link in New Frame" 'mlinks-goto-other-frame + :enable '(and (boundp 'mlinks-mode) + mlinks-mode) + :help "Follow MLinks Link in New Frame")) + (define-key link-map [mlinks-goto-link-other-window] + (list 'menu-item "Follow MLink Link in Other Window" 'mlinks-goto-other-window + :enable '(and (boundp 'mlinks-mode) + mlinks-mode) + :help "Follow MLinks Link in Other Window")) + (define-key link-map [mlinks-goto-link] + (list 'menu-item "Follow MLink Link" 'mlinks-goto + :enable '(and (boundp 'mlinks-mode) + mlinks-mode) + :help "Follow MLinks Link")) + (define-key link-map [nxhtml-separator-follow-mlink] (list 'menu-item "--")) + (define-key link-map [mlinks-next-link] + (list 'menu-item "Next MLink Link" 'mlinks-forward-link + :enable '(and (boundp 'mlinks-mode) + mlinks-mode) + :help "Go to next MLinks link")) + (define-key link-map [mlinks-prev-link] + (list 'menu-item "Previous MLink Link" 'mlinks-backward-link + :enable '(and (boundp 'mlinks-mode) + mlinks-mode) + :help "Go to previous MLinks link")) + + ) + (define-key edit-map [nxhtml-edit-sep1] (list 'menu-item "--")) + (define-key edit-map [nxhtml-grep-replace] + (list 'menu-item "Replace in Grepped Files" 'grep-query-replace)) + (define-key edit-map [nxhtml-rdir-replace] + (list 'menu-item "Replace in Files in Tree" 'rdir-query-replace)) + (define-key edit-map [nxhtml-ldir-replace] + (list 'menu-item "Replace in Files in Directory" 'ldir-query-replace)) + + (define-key edit-map [nxhtml-edit-sep2] (list 'menu-item "--")) + (define-key edit-map [nxhtml-multi-occur] + (list 'menu-item "Occur in File Buffers" 'multi-occur-in-matching-buffers)) + (define-key edit-map [nxhtml-occur] + (list 'menu-item "Occur" 'occur)) + (define-key edit-map [nxhtml-edit-sep3] (list 'menu-item "--")) + (define-key edit-map [nxhtml-re-builder] + (list 'menu-item "Re-Builder" 're-builder)) + (define-key edit-map [nxhtml-edit-sep4] (list 'menu-item "--")) + (let ((copy+paste-map (make-sparse-keymap "copy+paste"))) + (define-key edit-map [nxhtml-copy+paste-map] + (list 'menu-item "Copy+Paste" copy+paste-map)) + (define-key copy+paste-map [nxhtml-copy+paste-do] + (list 'menu-item "Do Copy+Paste" 'ourcomments-copy+paste + :enable '(and (boundp 'ourcomments-copy+paste-mode) + ourcomments-copy+paste-mode))) + (define-key copy+paste-map [nxhtml-copy+paste-set] + (list 'menu-item "Start Copy+Paste" 'ourcomments-copy+paste-set-point + :button '(:toggle . (and (boundp 'ourcomments-copy+paste-mode) + ourcomments-copy+paste-mode)))) + ) + (define-key edit-map [nxhtml-anchored-transpose] + (list 'menu-item "Transpose Regions" 'anchored-transpose + :button '(:toggle . (and mouse-secondary-overlay + (overlay-buffer mouse-secondary-overlay))))) + ) + + (define-key map [nxhtml-help-tools-separator] + ;; Notice that removing nil below gives an error that is quite + ;; hard to catch: + ;; + ;; Wrong type argument: arrayp, not + (list 'menu-item "--" nil + :visible `(not (derived-mode-p 'dired-mode)) + )) + + + (let ((upl-map (make-sparse-keymap "html-upl"))) + (define-key map [nxhtml-upl-map] + (list 'menu-item "File Transfer" upl-map + ;;:enable '(featurep 'html-upl))) + :enable '(fboundp 'html-upl-upload-file))) + (define-key upl-map [nxhtml-upl-remote-dired] + (list 'menu-item "Remote Dired" 'html-upl-remote-dired)) + (define-key upl-map [nxhtml-upl-dired-sep] (list 'menu-item "--")) + (define-key upl-map [nxhtml-upl-edit-remote-wtoc] + (list 'menu-item "Edit Remote File With TOC" 'html-upl-edit-remote-file-with-toc + :visible '(or (not (featurep 'html-site)) + (nxhtml-this-file-can-have-toc)))) + (define-key upl-map [nxhtml-upl-edit-remote] + (list 'menu-item "Edit Remote File" 'html-upl-edit-remote-file)) + (define-key upl-map [nxhtml-upl-ediff-file] + (list 'menu-item "Ediff Remote/Local Files" 'html-upl-ediff-file)) + (define-key upl-map [nxhtml-upl-sep] (list 'menu-item "--")) + (define-key upl-map [nxhtml-upl-upload-site-with-toc] + (list 'menu-item "Upload Site with TOC" 'html-upl-upload-site-with-toc + :visible '(or (not (featurep 'html-site)) + (and (html-site-current-merge-dir) + (html-site-current-ensure-file-in-site file))))) + (define-key upl-map [nxhtml-upl-upload-site] + (list 'menu-item "Upload Site" 'html-upl-upload-site)) + (define-key upl-map [nxhtml-upl-upload-file] + (list 'menu-item "Upload Single File" 'html-upl-upload-file)) + ) + + + (let ((browse-map (make-sparse-keymap))) + (define-key map [nxhtml-browse-map] + (list 'menu-item "Browse" browse-map + '(or buffer-file-name + (eq major-mode 'nxhtml-mode)) + :enable '(nxhtml-buffer-possibly-local-viewable))) + (define-key browse-map [nxhtml-browse-region] + (list 'menu-item "Browse the Region Only" 'nxhtml-browse-region + :enable 'mark-active)) + (define-key browse-map [nxhtml-upl-sep3] (list 'menu-item "--")) + (define-key browse-map [nxhtml-upl-browse-remote-wtoc] + (list 'menu-item "Browse Uploaded File With TOC" 'html-upl-browse-remote-with-toc + :visible '(and (nxhtml-buffer-possibly-local-viewable) + (featurep 'html-wtoc) + (html-site-current-merge-dir) + (html-site-current-ensure-file-in-site file) + (nxhtml-buffer-possibly-remote-viewable) + ))) + (define-key browse-map [nxhtml-upl-browse-remote-frame-file] + (list 'menu-item "Browse Uploaded Frames File" 'html-upl-browse-remote-frames + :enable '(nxhtml-buffer-possibly-remote-viewable))) + (define-key browse-map [nxhtml-upl-browse-remote] + (list 'menu-item "Browse Uploaded File" 'html-upl-browse-remote + :enable '(nxhtml-buffer-possibly-remote-viewable))) + (define-key browse-map [nxhtml-upl-sep2] + (list 'menu-item "--")) + (define-key browse-map [nxhtml-browse-merged-file] + (list 'menu-item "Browse File With TOC" 'html-wtoc-browse-page-with-toc + :visible '(and (nxhtml-buffer-possibly-local-viewable) + (featurep 'html-wtoc) + (html-site-current-merge-dir) + (html-site-current-ensure-file-in-site file) + ))) + (define-key browse-map [nxhtml-browse-frame-file] + (list 'menu-item "Browse Frames File" 'html-toc-browse-frames-file + :enable '(and (featurep 'html-toc) + (nxhtml-buffer-possibly-local-viewable)))) + (define-key browse-map [nxhtml-browse-file] + (list 'menu-item "Browse File" 'nxhtml-browse-file + :enable '(nxhtml-buffer-possibly-local-viewable))) + ) + + + + (let ((site-map (make-sparse-keymap))) + (define-key map [nxhtml-site-map] + (list 'menu-item "Site" site-map)) + (define-key site-map [html-site-global-mode] + (list 'menu-item "HTML Site Global Mode" + 'html-site-global-mode + :button '(:toggle . (and (boundp 'html-site-global-mode) + html-site-global-mode)))) + (define-key site-map [nxhtml-site-separator] (list 'menu-item "--")) + (define-key site-map [nxhtml-customize-site-list] + (list 'menu-item "Edit Sites" (lambda () + "Customize option `html-size-list'." + (interactive) + (customize-option-other-window 'html-site-list)))) + (define-key site-map [nxhtml-set-site] + (list 'menu-item "Set Current Site" 'html-site-set-site)) + (define-key site-map [nxhtml-site-separator-1] (list 'menu-item "--")) + (define-key site-map [nxhtml-dired-site-top] + (list 'menu-item "Dired Site" 'html-site-dired-current)) + (define-key site-map [nxhtml-find-site-file] + (list 'menu-item "Find File in Site" 'html-site-find-file)) + (define-key site-map [nxhtml-site-search-separator] + (list 'menu-item "--" nil)) + (define-key site-map [nxhtml-replace-in-site] + (list 'menu-item "Replace in Site Files" 'html-site-query-replace)) + (define-key site-map [nxhtml-rgrep-in-site] + (list 'menu-item "Search Site Files" 'html-site-rgrep)) + ) + + (define-key map [nxhtml-insert-separator] + (list 'menu-item "--" nil + :visible `(not (derived-mode-p 'dired-mode)) + )) + (let ((chunk-map (make-sparse-keymap))) + (define-key map [nxhtml-chunk-map] + (list 'menu-item "Multi Major Modes" chunk-map + :visible `(not (derived-mode-p 'dired-mode)) + )) + (define-key chunk-map [nxhtml-customize-mumamo] + (list 'menu-item "Customize MuMaMo" + (lambda () (interactive) (customize-group-other-window 'mumamo)))) + (define-key chunk-map [nxhtml-list-mumamo] + (list 'menu-item "List defined Multi Major Modes" + 'mumamo-list-defined-multi-major-modes)) + (define-key chunk-map [nxhtml-chunks-separator2] + (list 'menu-item "--" nil)) + (define-key chunk-map [nxhtml-chunk-no-colors] + (list 'menu-item "Remove Chunk Colors Temporarily" + 'mumamo-no-chunk-coloring + :button '(:toggle . (and (boundp 'mumamo-no-chunk-coloring) + mumamo-no-chunk-coloring)))) + (define-key chunk-map [nxhtml-chunk-margin-info] + (list 'menu-item "Display Chunk Info in Margin" + 'mumamo-margin-info-global-mode + :button '(:toggle . (and (boundp 'mumamo-margin-info-global-mode) + mumamo-margin-info-global-mode)))) + (define-key chunk-map [nxhtml-chunks-separator1] + (list 'menu-item "--" nil)) + (let ((region-map (make-sparse-keymap))) + (define-key chunk-map [nxhtml-region-map] + (list 'menu-item "Temprary Region Chunks" region-map)) + (define-key region-map [mumamo-clear-all-regions] + (list 'menu-item "Clear Region Chunks" + 'mumamo-clear-all-regions + :enable '(and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode + (fboundp 'mumamo-clear-all-regions)))) + (define-key region-map [mumamo-clear-region] + (list 'menu-item "Clear Region Chunk at Point" + 'mumamo-clear-region + :enable '(fboundp 'mumamo-clear-region))) + (define-key region-map [nxhtml-region-separator2] + (list 'menu-item "--" nil)) + (define-key region-map [mumamo-region-major] + (list 'menu-item "Set Region Chunk Major Mode" + 'mumamo-region-set-major + :enable '(fboundp 'mumamo-region-set-major))) + (define-key region-map [mumamo-add-region-from-string] + (list 'menu-item "Add Region Chunk from String" + 'mumamo-add-region-from-string)) + (define-key region-map [mumamo-add-region] + (list 'menu-item "Add Region Chunk from Selection" + 'mumamo-add-region))) + (define-key chunk-map [nxhtml-region-separator] + (list 'menu-item "--" nil)) + (define-key chunk-map [mumamo-mark-chunk] + (list 'menu-item "Mark Chunk" + 'mumamo-mark-chunk + :enable '(and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode))) + (define-key chunk-map [nxhtml-separator-mark-chunk] (list 'menu-item "--")) + (define-key chunk-map [mumamo-backward-chunk] + (list 'menu-item "Backward Chunk" + 'mumamo-backward-chunk + :enable '(and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode))) + (define-key chunk-map [mumamo-forward-chunk] + (list 'menu-item "Forward Chunk" + 'mumamo-forward-chunk + :enable '(and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode)))) + (let ((tag-map (make-sparse-keymap))) + (define-key map [nxhtml-tag-map] + (list 'menu-item "Move by Tag" tag-map + :visible '(or (derived-mode-p 'nxml-mode) + (derived-mode-p 'sgml-mode)) + :enable '(or (derived-mode-p 'nxml-mode) + (nxhtml-nxhtml-in-buffer)))) + (define-key tag-map [nxml-forward-par] + (list 'menu-item "Forward Paragraph" + 'nxml-forward-paragraph)) + (define-key tag-map [nxml-backward-par] + (list 'menu-item "Backward Paragraph" + 'nxml-backward-paragraph)) + (define-key tag-map [nxml-insert-separator-move2] (list 'menu-item "--")) + (define-key tag-map [nxml-down] + (list 'menu-item "Forward Into Tag" + 'nxml-down-element)) + (define-key tag-map [nxml-backward-up] + (list 'menu-item "Backward Out of Tag" + 'nxml-backward-up-element)) + (define-key tag-map [nxml-insert-separator-move] (list 'menu-item "--")) + (define-key tag-map [nxml-forward] + (list 'menu-item "Forward Balanced Tag" + 'nxml-forward-element)) + (define-key tag-map [nxml-backward] + (list 'menu-item "Backward Balanced Tag" + 'nxml-backward-element)) + ) + + + map)) + +(defvar nxhtml-menu-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?? ?x] 'nxhtml-short-tag-help) + (define-key map [(control ?c) ?? ?c] 'xhtml-help-show-css-ref) + (define-key map [(control ?c) ?_] 'nxhtml-toggle-visible-warnings) + (define-key map [menu-bar nxhtml-menu-mode] + (list 'menu-item "nXhtml" nxhtml-menu-mode-menu-map)) + map)) + +;;;###autoload +(define-minor-mode nxhtml-menu-mode + "Minor mode to turn on some key and menu bindings. +See `nxhtml-mode' for more information. + +This minor mode adds the entry 'nXhtml' to the menu bar. This +submenu gives easy access to most of the important features of +nXhtml. + +To see an \(incomplete) overview in html format do +\\[nxhtml-overview]. + +* Note: Please observe that when loading nXhtml some file + associations are done, see `nxhtml-setup-file-assoc'. + +Here are some important features: + +- multiple major modes, see `define-mumamo-multi-major-mode' +- easy uploading and viewing of files, see for example + `html-upl-upload-file' + +- validation in XHTML part for php etc, see + `nxhtml-validation-header-mode' (you probably also want to know + about `nxhtml-toggle-visible-warnings' for this!) + +- converting of html to xhtml, see `tidy-buffer' + +Some smaller, useful, but easy-to-miss features: + +* Following links. The href and src attribute names are + underlined and a special keymap is bound to + them:\\<mlinks-mode-map> + + \\[mlinks-backward-link], \\[mlinks-forward-link] Move + between underlined href/src attributes + + \\[mlinks-goto], Mouse-1 Follow link inside Emacs + (if possible) + + It is even a little bit quicker when the links are in an active + state (marked with the face `isearch'):\\<mlinks-active-hilight-keymap> + + \\[mlinks-backward-link], \\[mlinks-forward-link] Move + between underlined href/src attributes + \\[mlinks-goto], Mouse-1 Follow link inside Emacs (if possible) + + If the link is not into a file that you can edit (a mailto link + for example) you will be prompted for an alternative action. + +* Creating links. To make it easier to create links to id/name + attribute in different files there are two special + functions:\\<nxhtml-mode-map> + + \\[nxhtml-save-link-to-here] copy link to id/name (you must + be in the tag to get the link) + \\[nxhtml-paste-link-as-a-tag] paste this as an a-tag. + +This minor mode also adds some bindings: + +\\{nxhtml-menu-mode-map} + +--------- +* Note: Some of the features supported are optional and available + only if other Emacs modules are found. Use + \\[nxhtml-features-check] to get a list of these optional + features and modules needed. You should however have no problem + with this if you have followed the installation instructions + for nXhtml." + :keymap nxhtml-menu-mode-map + :group 'nxhtml + :global t + ) + +(defalias 'nxhtml-minor-mode 'nxhtml-menu-mode) +(defalias 'nxhtml-global-minor-mode 'nxhtml-menu-mode) + +;; (defcustom nxhtml-menu-mode-modes +;; '( +;; nxhtml-mode +;; nxml-mode +;; html-mode +;; sgml-mode +;; xml-mode +;; php-mode +;; css-mode +;; javascript-mode +;; java-mode ;; jsp +;; groovy-mode ;; gsp +;; image-mode +;; ;; +;; dired-mode +;; ) +;; "List for turning on `nxhtml-menu-mode'. +;; If the buffer's major modes is any of those in this list then +;; `nxhtml-global-minor-mode' will turn on `nxhtml-menu-mode' in +;; the buffer." +;; :type '(repeat (symbol :tag "Major mode")) +;; :group 'nxhtml) + +;; (defun nxhtml-maybe-turn-on-minor-mode () +;; "Maybe turn on `nxhtml-menu-mode'. +;; See `nxhtml-menu-mode-modes'." +;; (nxhtml-menu-mode 1)) +;; (unless (or (minibufferp (current-buffer)) +;; (string= " " (substring (buffer-name) 0 1)) +;; (string= "*" (substring (buffer-name) 0 1)) +;; ) +;; (let ((on (and (boundp 'mumamo-multi-major-mode) +;; mumamo-multi-major-mode))) +;; (dolist (major nxhtml-menu-mode-modes) +;; (when (derived-mode-p major) +;; (setq on t))) +;; (when on +;; (nxhtml-menu-mode 1))))) + +;; (define-globalized-minor-mode nxhtml-global-minor-mode +;; nxhtml-menu-mode +;; nxhtml-maybe-turn-on-minor-mode +;; ;;:require 'nxhtml-menu +;; :group 'nxhtml) +;;(message "nxhtml-menu:here A") +;;(custom-reevaluate-setting 'nxhtml-global-minor-mode) +;;(message "nxhtml-menu:here B") +;;(when nxhtml-global-minor-mode (nxhtml-global-minor-mode 1)) +;;(message "nxhtml-menu:here C") + + +;; (file-exists-p (nxhtml-docfile)) +;; (find-file (nxhtml-docfile)) +(defun nxhtml-docfile () + (expand-file-name "nxhtml/doc/nxhtml.html" nxhtml-install-dir)) + +(defun nxhtml-docfile-url () + (let ((local-docfile (concat "file://" (nxhtml-docfile)))) + (if (and nxhtml-autoload-web + (not (file-exists-p local-docfile))) + "http://ourcomments.org/Emacs/nXhtml/doc/nxhtml.html" + local-docfile))) + +;;;###autoload +(defun nxhtml-overview () + "Show a HTML page with an overview of nXhtml." + (interactive) + (browse-url (nxhtml-docfile-url))) + +(defun nxhtml-tutorials () + "Show a HTML page with a list of tutorials for nXhtml'." + (interactive) + (browse-url "http://ourcomments.org/Emacs/nXhtml/tut/tutorials.html")) + +(defun nxhtml-custom-valfaced (value &optional bgcolor) + (let ((v (if (sequencep value) + (copy-seq value) + value)) + (bgcolor (if bgcolor bgcolor "RGB:FF/FF/AA"))) + (put-text-property 0 (length v) + 'face (list + 'bold + (cons 'background-color bgcolor) + ) + v) + v)) +(defun nxhtml-custom-insert-nxhtml-row (symbol nxhtml-value description) + (let ((desc (if description + (format "%s (%s)" description symbol) + (format "%s" (custom-unlispify-tag-name symbol))))) + (widget-insert " " description " (") + (nxhtml-custom-describe-defun symbol) + (widget-insert "): " + (nxhtml-custom-valfaced + (format "%s" (symbol-value symbol)) + (if (eq (symbol-value symbol) + nxhtml-value) + "GreenYellow" + "gainsboro")) + "\n"))) + +(defun nxhtml-custom-h1(title &optional divider top-newline) + (let ((s title)) + (put-text-property 0 (length s) + 'face '(:weight bold + :height 1.4 + :foreground "DarkGreen" + ;;:underline t + ) + s) + (when top-newline (widget-insert "\n")) + ;;(when divider (widget-insert (nxhtml-custom-divider (length s)))) + (widget-insert s) + )) + +(defun widget-button-notify (widget &rest ignore) + (apply (widget-get widget 'function) (widget-get widget 'data))) + +(defun widget-insert-link (txt function data) + (widget-insert-button txt function data + :button-face 'link + :mouse-face 'highlight + :button-prefix "" + :button-suffix "")) + +(defun widget-insert-button (txt function data &rest keywords) + (let ((btn (apply 'widget-create + (append + '(push-button + :notify + widget-button-notify) + keywords + (list txt))))) + (widget-put btn 'data data) + (widget-put btn 'function function))) + +(defun nxhtml-custom-url-link (txt url) + (let ((plain-url (substring-no-properties url))) + (unless (equal txt url) + (put-text-property 0 (length txt) 'help-echo plain-url txt)) + (put-text-property 0 (length txt) 'mouse-face 'highlight txt) + (widget-insert-link txt 'browse-url (list url)))) + +(defun nxhtml-custom-describe-defun (sym &optional help) + (let ((txt (symbol-name sym))) + (when help + (put-text-property 0 (length txt) 'help-echo help txt)) + (put-text-property 0 (length txt) 'mouse-face 'highlight txt) + (widget-insert-link txt 'describe-function (list sym)))) + +;; (defun nxhtml-quick-customize (&optional same-window) +;; "Show page for Quick Customize of nXhtml." +;; (interactive) +;; (require 'nxhtml) +;; (require 'custom) +;; (require 'cus-edit) +;; (if same-window +;; (switch-to-buffer "*Quick Customize nXhtml*") +;; (switch-to-buffer-other-window "*Quick Customize nXhtml*")) +;; (kill-all-local-variables) +;; (custom-mode) +;; (let ((inhibit-read-only t)) +;; (erase-buffer)) +;; (let ((sFound "found") +;; (sError "error")) +;; (put-text-property 0 (length sFound) +;; 'face '(bold +;; (foreground-color . "green")) sFound) +;; (put-text-property 0 (length sError) +;; 'face '(bold +;; (foreground-color . "red")) sError) +;; (let* ( +;; (default-used "(not set yet - default used)") +;; ) +;; (nxhtml-custom-h1 "Quick Customize for nXhtml" t) +;; (widget-insert " + +;; This page is for a quick and easy setup of some ") +;; (nxhtml-custom-url-link "nXhtml" (nxhtml-docfile-url)) +;; (widget-insert " features +;; that I did not want to turn on by default since they alter what +;; happens when you open a file. I suggest however that you turn +;; them on since they are quite useful if you just understands what +;; is happening. + +;; The values you set here are saved so that they will be used next +;; time you start Emacs too.") +;; ;;(widget-insert-link "customize nXhtml" 'customize-group (list 'nxhtml)) +;; (widget-insert "\n\n") + +;; (nxhtml-custom-insert-nxhtml-row 'nxhtml-global-minor-mode t "Show the nXhtml menu in all relevant buffers\n\t") +;; ;;(nxhtml-custom-insert-nxhtml-row 'mumamo-global-mode t "Turn on Multiple Major Mode in all relevant buffers\n\t") +;; ;;(nxhtml-custom-insert-nxhtml-row 'mlinks-global-mode t "Make link of lins, for example href=\"...\"\n\t") +;; ;;(nxhtml-custom-insert-nxhtml-row 'indent-region-mode t "Use TAB to indent region when it is selected\n\t") + +;; (widget-insert "\n") +;; (widget-insert-button " Turn them all on " +;; (lambda () +;; (nxhtml-quick-all t) +;; (nxhtml-quick-customize t)) +;; nil) +;; (widget-insert " ") +;; (widget-insert-button " Turn them all off " +;; (lambda () +;; (nxhtml-quick-all nil) +;; (nxhtml-quick-customize t)) +;; nil) +;; (beginning-of-line) +;; ))) + +;; (defun nxhtml-quick-all (on) +;; (custom-set-and-prepare-save 'nxhtml-global-minor-mode on) +;; ;;(custom-set-and-prepare-save 'mumamo-global-mode on) +;; (custom-set-and-prepare-save 'indent-region-mode on) +;; (when custom-file +;; (custom-save-all))) + +(defun custom-set-and-prepare-save (symbol value) + "Set SYMBOL to VALUE and add to customize. +Both the current value and the value to save is set, but +`custom-save-all' must be called to save customization." + (customize-set-variable symbol value) + (customize-set-value symbol value) + (customize-mark-to-save symbol)) + + +;;(nxhtml-quick-customize) + +(defun nxhtml-welcome () + "Show welcome information." + (interactive) + (require 'cus-edit) + (let* ((bufnam "*nXhtml Welcome*") + (oldbuf (get-buffer bufnam)) + (curwin (selected-window))) + (switch-to-buffer-other-window bufnam) + (unless oldbuf + (let ((inhibit-read-only t) + (here (point))) + (Custom-mode) + (nxhtml-menu-mode 1) + (setq cursor-in-non-selected-windows nil) + (nxhtml-custom-h1 "Welcome to nXhtml - a package for web editing" t) + (insert "\n\n") + (setq here (point)) + (insert "If you have not done it already it might " + "be a good time to read at least The Quick Guide in the ") + (nxhtml-custom-url-link "nXhtml overview" (nxhtml-docfile-url)) + (insert " now.\n\n") + (fill-region here (point)) + (setq here (point)) + (insert "And oh, wait! If you are new to Emacs too you might want " + "to take a quick ") + (nxhtml-custom-url-link + "Emacs tour" + "http://www.gnu.org/software/emacs/tour/") + (insert ". And then perhaps the Emacs tutorial " + "(which is in the Help menu above).\n\n") + (fill-region here (point)) + (setq here (point)) + + (unless (nxhtml-skip-welcome) + (insert "Click to ") + (widget-insert-link "remove this message" + (lambda () + "Customize `nxhtml-skip-welcome'." + (customize-option 'nxhtml-skip-welcome)) + nil) + (insert " at startup. (This page is still " + "available in the nXhtml menu, at the bottom.)")) + (fill-region here (point)) + (setq here (point)) + (goto-char (point-min)))) + (select-window curwin))) + +(defcustom nxhtml-skip-welcome nil + "Turn this on to always skip the nXhtml welcome message." + :type 'boolean + :group 'nxhtml) + +(defun nxhtml-skip-welcome () + "Return t if nXhtml welcome message should be skipped. +If nil then the message will be shown when you open the first +file using nxhtml-mode." + (or nxhtml-skip-welcome + (and nxhtml-menu-mode + ;;mumamo-global-mode + ;;indent-region-mode + ))) + +(defun nxhtml-say-welcome-unless-skip () + (condition-case err + (unless (nxhtml-skip-welcome) + (save-match-data + (nxhtml-welcome))) + (error (message "ERROR nxhtml-say-welcome-unless-skip: %s" err)))) + +;; Show welcome screen once after loading nxhtml: +;;(unless (boundp 'bytecomp-filename) +(eval-when '(load) + (eval-after-load 'nxhtml + ;; Use a short delay if something like desktop is used: + '(run-with-idle-timer 0.5 nil 'nxhtml-say-welcome-unless-skip))) + +(provide 'nxhtml-menu) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-menu.el ends here diff --git a/emacs/nxhtml/nxhtml/nxhtml-mode.el b/emacs/nxhtml/nxhtml/nxhtml-mode.el new file mode 100644 index 0000000..063be3c --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtml-mode.el @@ -0,0 +1,2796 @@ +;;; nxhtml-mode.el --- Edit XHTML files +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Parts are from Peter Heslin (see below) +;; Created: 2005-08-05 +;;Version: +;; Last-Updated: 2008-12-28 Sun +;; Keywords: languages +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; The purpose of nxhtml.el is to add some features that are useful +;; when editing XHTML files to nxml-mode. For more information see +;; `nxhtml-mode'. +;; +;; +;; Usage: +;; +;; See the file readme.txt in the directory above this file. Or, if +;; you do not have that follow the instructions below. + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; History: +;; +;; 2006-04-25: Added completion for href, src etc. Removed xhtmlin. + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This file is not part of 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 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. + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'hideshow)) + +(eval-when-compile (require 'appmenu-fold nil t)) +(eval-when-compile (require 'fold-dwim nil t)) +(eval-when-compile (require 'foldit nil t)) +(eval-when-compile (require 'html-pagetoc nil t)) +(eval-when-compile (require 'html-toc nil t)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'mlinks nil t)) +(eval-when-compile (require 'nxhtml-base)) +;;(eval-when-compile (require 'nxhtml-menu)) ;; recursive load +(eval-when-compile (require 'ourcomments-util nil t)) +(eval-and-compile (require 'typesetter nil t)) +(eval-when-compile (require 'xhtml-help nil t)) +(eval-when-compile (require 'popcmp nil t)) +;; (eval-when-compile +;; (unless (or (< emacs-major-version 23) +;; (boundp 'nxhtml-menu:version) +;; (featurep 'nxhtml-autostart)) +;; (let ((efn (expand-file-name +;; "../autostart.el" +;; (file-name-directory +;; (or load-file-name +;; (when (boundp 'bytecomp-filename) bytecomp-filename) +;; buffer-file-name))))) +;; (message "efn=%s" efn) +;; (load efn)) +;; (require 'rng-valid) +;; (require 'rng-nxml))) + +(require 'button) +(require 'loadhist) +(require 'nxml-mode nil t) +(require 'rng-nxml nil t) +(require 'rng-valid nil t) + +;; Require nxml things conditionally to silence byte compiler under +;; Emacs 22. +(eval-and-compile (require 'rngalt nil t)) + +(require 'url-parse) +(require 'url-expand) +(require 'popcmp nil t) +(eval-when-compile (require 'html-imenu nil t)) +(eval-when-compile (require 'tidy-xhtml nil t)) +(eval-when-compile (require 'html-quote nil t)) + +(defun nxhtml-version () + "Show nxthml version." + (interactive) + (message "nXhtml mode version %s" nxhtml-menu:version)) + +;;(defun nxhtml-nxml-fontify-attribute (att &optional namespace-declaration) +;;"Holds the original `nxml-fontify-attribute' function.") +;;(fset 'nxhtml-nxml-fontify-attribute (symbol-function 'nxml-fontify-attribute)) + + +(defun nxhtml-turn-onoff-tag-do-also (on) + (add-hook 'nxhtml-mode-hook 'nxhtml-check-tag-do-also) + (dolist (b (buffer-list)) + (when (with-current-buffer b + (eq major-mode 'nxhtml-mode)) + (if on + (progn + (add-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t t) + ) + (remove-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t) + )))) + +;;(define-toggle nxhtml-tag-do-also t +(define-minor-mode nxhtml-tag-do-also + "When completing tag names do some more if non-nil. +For some tag names additional things can be done at completion to +speed writing up. For example for an <img ...> tag `nxhtml-mode' +can prompt for src attribute and add width and height attributes +if this attribute points to a local file. + +You can add additional elisp code for completing to +`nxhtml-complete-tag-do-also'." + :global t + :init-value t + :group 'nxhtml + (nxhtml-turn-onoff-tag-do-also nxhtml-tag-do-also)) +(when nxhtml-tag-do-also (nxhtml-tag-do-also 1)) + +(defun nxhtml-tag-do-also-toggle () + "Toggle `nxhtml-tag-do-also'." + (interactive) + (nxhtml-tag-do-also (if nxhtml-tag-do-also -1 1))) + +(defun nxhtml-check-tag-do-also () + (when nxhtml-tag-do-also + (nxhtml-turn-onoff-tag-do-also t))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Folding etc. + + +;; This part is origially taken from +;; http://www.emacswiki.org/cgi-bin/wiki/NxmlModeForXHTML and was +;; originally written by Peter Heslin, but has been changed rather +;; much. + +;; (defun nxhtml-hs-adjust-beg-func (pos) +;; (save-excursion +;; (save-match-data +;; ;; (search-backward "<" nil t) +;; ;; (forward-char) +;; ;; (search-forward ">" nil t) +;; ) +;; (point))) + +(defun nxhtml-hs-forward-sexp-func (pos) + (nxhtml-hs-forward-element)) + +(defun nxhtml-hs-forward-element () + (let ((nxml-sexp-element-flag)) + (setq nxml-sexp-element-flag (not (looking-at "<!--"))) + (unless nil ;;(looking-at outline-regexp) + ;;(condition-case nil + (nxml-forward-balanced-item 1) + ;;(error nil)) + ))) + +(defun nxhtml-setup-for-fold-dwim () + (make-local-variable 'outline-regexp) + (setq outline-regexp "\\s *<\\([h][1-6]\\|html\\|body\\|head\\)\\b") + (make-local-variable 'outline-level) + (setq outline-level 'nxhtml-outline-level) + ;;(outline-minor-mode 1) + ;;(hs-minor-mode 1) + (setq hs-special-modes-alist (assq-delete-all 'nxhtml-mode hs-special-modes-alist)) + (add-to-list 'hs-special-modes-alist + '(nxhtml-mode + ;;"<!--\\|<[^/>]>\\|<[^/][^>]*[^/]>" + "<!--\\|<[^/>]>\\|<[^/][^>]*" + "</\\|-->" + "<!--" ;; won't work on its own; uses syntax table + nxhtml-hs-forward-sexp-func + nil ;nxhtml-hs-adjust-beg-func + )) + (set (make-local-variable 'hs-set-up-overlay) 'nxhtml-hs-set-up-overlay) + (put 'hs-set-up-overlay 'permanent-local t) + (when (featurep 'appmenu-fold) + (appmenu-fold-setup)) + (foldit-mode 1)) + +(defun nxhtml-hs-start-tag-end (beg) + (save-excursion + (save-match-data + (goto-char beg) + (or (search-forward ">" (line-end-position) t) + (line-end-position))))) + +(defun nxhtml-hs-set-up-overlay (ovl) + (overlay-put ovl 'priority (1+ mlinks-link-overlay-priority)) + (when foldit-mode + (setq foldit-hs-start-tag-end-func 'nxhtml-hs-start-tag-end) + (foldit-hs-set-up-overlay ovl))) + +(defun nxhtml-outline-level () + ;;(message "nxhtml-outline-level=%s" (buffer-substring (match-beginning 0) (match-end 0)))(sit-for 2) + ;; Fix-me: What did I intend to do??? + ;; (let ((tag (buffer-substring (match-beginning 1) (match-end 1)))) + ;; (if (eq (length tag) 2) + ;; (- (aref tag 1) ?0) + ;; 0)) + 8) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + +(defcustom nxhtml-use-imenu t + "Use imenu in nxhtml-mode." + :type 'boolean + :group 'nxhtml) + + + +(defcustom nxhtml-default-encoding 'iso-8859-1 + "Default encoding." + :type 'coding-system + :group 'nxhtml) + +(defun nxhtml-insert-empty-frames-page () + "Insert an empty frames page." + (interactive) + ;;(unless (= 0 (buffer-size)) + (unless (nxhtml-can-insert-page-here) + (error "Buffer is not empty")) + (insert + "<?xml version=\"1.0\" encoding=\"" + (symbol-name nxhtml-default-encoding) + "\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" + \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> + <title></title> + </head> + <frameset cols=\"50%, 50%\"> + <frame src=\"about:blank\" /> + <frame src=\"about:blank\" /> + </frameset> +</html>") + (search-backward "</title>")) + +(defun nxhtml-insert-empty-page () + "Insert an empty XHTML page." + (interactive) + ;;(unless (= 0 (buffer-size)) + (unless (nxhtml-can-insert-page-here) + (error "Buffer is not empty")) + (insert + "<?xml version=\"1.0\" encoding=\"" + (symbol-name nxhtml-default-encoding) + "\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> + <title></title> + </head> + <body> + </body> +</html>") + (search-backward "</title>")) + +(defun nxhtml-empty-page-completion () + ;;(unless (= 0 (buffer-size)) (error "Buffer is not empty")) + (let* ((frames "Frameset page") + (normal "Normal page") + ;;(vlhead "Validation header") + ;;popcmp-popup-completion + (initial nil) ;;(unless popcmp-popup-completion normal)) + (hist (if (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + ;;(list vlhead frames normal) + (list frames normal) + (list frames normal))) + res + (completion-ignore-case t)) + (setq res (popcmp-completing-read "Insert: " hist nil t initial (cons 'hist (length hist)))) + (cond ((string= res frames) + (nxhtml-insert-empty-frames-page)) + ((string= res normal) + (nxhtml-insert-empty-page)) + ;;((string= res vlhead) + ;; (nxhtml-validation-header-mode)) + (t + (error "Bad res=%s" res)))) + (rng-auto-set-schema)) + + + +(defvar nxhtml-mode-hook nil) +;;(add-hook 'nxhtml-mode-hook 'nxml-fontify-buffer) + +(defun nxhtml-help () + (interactive) + (describe-function 'nxhtml-mode)) + +(defvar nxhtml-current-validation-header nil) +(make-variable-buffer-local 'nxhtml-current-validation-header) +(put 'nxhtml-current-validation-header 'permanent-local t) + + +;; FIX-ME: When should this be done? Get tidy-menu-symbol: +(when (featurep 'tidy-xhtml) + (tidy-build-menu)) + + +;; (eval-after-load 'css-mode +;; '(when (featurep 'xhtml-help) +;; (define-key css-mode-map [(control ?c) ?? ?c] 'xhtml-help-show-css-ref) +;; )) +;; (add-hook 'css-mode-hook +;; (lambda () +;; (and (featurep 'xhtml-help) +;; (boundp 'css-mode-map) +;; (define-key css-mode-map [(control ?c) ?? ?c] +;; 'xhtml-help-show-css-ref)))) + +;; This should be run in `change-major-mode-hook'." +;; (defun nxhtml-change-mode () +;; (when (fboundp 'mlinks-mode) +;; (mlinks-mode 0))) + +(when (< emacs-major-version 23) + (defun nxml-change-mode () + ;; Remove overlays used by nxml-mode. + (save-excursion + (save-restriction + (widen) + (rng-validate-mode -1) + (let ((inhibit-read-only t) + (buffer-undo-list t) + (modified (buffer-modified-p))) + (nxml-with-invisible-motion + (remove-text-properties (point-min) (point-max) '(face nil))) + (set-buffer-modified-p modified)))))) + +(defcustom nxhtml-heading-element-name-regexp "[a-z]*" + "Used for `nxml-heading-element-name-regexp." + :type 'regexp + :group 'nxhtml) + +;; Fix-me: Put this is a separate file and load it only if nxml is +;; availabe. +(put 'nxhtml-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify) +;;;###autoload +(define-derived-mode nxhtml-mode nxml-mode "nXhtml" + "Major mode for editing XHTML documents. +It is based on `nxml-mode' and adds some features that are useful +when editing XHTML files.\\<nxhtml-mode-map> + +The XML menu contains functionality added by `nxml-mode' \(on +which this major mode is based). There is also a popup menu +added to the \[apps] key. + +The most important features are probably completion and +validation, which is inherited from `nxml-mode' with some small +addtions. In very many situation you can use completion. To +access it type \\[nxml-complete]. Completion has been enhanced in +the following way: + +- If region is active and visible then completion will surround the + region with the chosen tag's start and end tag. However only the + starting point is checked for validity. If something is wrong after + insertion you will however immediately see it if you have validation + on. +- It can in some cases give assistance with attribute values. +- Completion can be customized, see the menus XHTML - Completion: + * You can use a menu popup style completion. + * You can have alternatives grouped. + * You can get a short help text shown for each alternative. +- There does not have to be a '<' before point for tag name + completion. (`nxml-mode' requires a '<' before point for tag name + completion.) +- Completes xml version and encoding. +- Completes in an empty buffer, ie inserts a skeleton. + +Here are all key bindings in nxhtml-mode itself: + +\\{nxhtml-mode-map} + +Notice that other minor mode key bindings may also be active, as +well as emulation modes. Do \\[describe-bindings] to get a list +of all active key bindings. Also, *VERY IMPORTANT*, if mumamo is +used in the buffer each mumamo chunk has a different major mode +with different key bindings. You can however still see all +bindings with \\[describe-bindings], but you have to do that with +point in the mumamo chunk you want to know the key bindings in." + (set (make-local-variable 'nxml-heading-element-name-regexp) + nxhtml-heading-element-name-regexp) + (when (fboundp 'nxml-change-mode) + (add-hook 'change-major-mode-hook 'nxml-change-mode nil t)) + ;;(add-hook 'change-major-mode-hook 'nxhtml-change-mode nil t) + (when (featurep 'rngalt) + (add-hook 'nxml-completion-hook 'rngalt-complete nil t)) + ;;(define-key nxhtml-mode-map [(meta tab)] 'nxml-complete) + ;;(nxhtml-menu-mode 1) + (when (and nxhtml-use-imenu + (featurep 'html-imenu)) + (add-hook 'nxhtml-mode-hook 'html-imenu-setup nil t)) + ;;(mlinks-mode 1) + (nxhtml-setup-for-fold-dwim) + (when (featurep 'rngalt) + (set (make-local-variable 'rngalt-completing-read-tag) 'nxhtml-completing-read-tag) + (set (make-local-variable 'rngalt-completing-read-attribute-name) 'nxhtml-completing-read-attribute-name) + (set (make-local-variable 'rngalt-completing-read-attribute-value) 'nxhtml-completing-read-attribute-value) + (set (make-local-variable 'rngalt-complete-first-try) 'nxhtml-complete-first-try) + (set (make-local-variable 'rngalt-complete-last-try) 'nxhtml-complete-last-try) + )) + +;; Fix-me: The nxhtml-mode-map is define by define-derived-mode, but +;; how should keys be added? + +;; Replace the Insert End Tag function: +(define-key nxhtml-mode-map [(control ?c) (control ?f)] 'rngalt-finish-element) + +;; Put completion on the normal key? +(define-key nxhtml-mode-map [(meta tab)] 'nxml-complete) +;; Paragraphs (C-p mnemonic for paragraph) +(define-key nxhtml-mode-map [(control ?c) (control ?p) ?l] 'longlines-mode) +(define-key nxhtml-mode-map [(control ?c) (control ?p) ?f] 'fill-paragraph) +(define-key nxhtml-mode-map [(control ?c) (control ?p) ?u] 'unfill-paragraph) +;; Html related (C-h mnemonic for html) +(define-key nxhtml-mode-map [(control ?c) (control ?h) ?c] 'nxhtml-save-link-to-here) +(define-key nxhtml-mode-map [(control ?c) (control ?h) ?v] 'nxhtml-paste-link-as-a-tag) +(define-key nxhtml-mode-map [(control ?c) (control ?h) ?b] 'nxhtml-browse-file) +(define-key nxhtml-mode-map [(control ?c) ?<] 'nxml-untag-element) +(when (featurep 'html-quote) + (define-key nxhtml-mode-map [(control ?c) (control ?q)] 'nxhtml-quote-html) + ) +;; Fix-me: Is pagetoc really that important to have its own keybindings? +(when (featurep 'html-pagetoc) + (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?i] 'html-pagetoc-insert-toc) + (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?r] 'html-pagetoc-rebuild-toc) + (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?s] 'html-pagetoc-insert-style-guide) + ) + +(defun nxhtml-quote-html() + "Quote character(s) unsafe in html text parts. +If region is visible quote all characters in region. Otherwise +just quote current char. + +Note to CUA users: See `cua-mode' for how to prevent CUA from +just copying region when you press C-c." + (interactive) + (if (and mark-active + transient-mark-mode) + (let* ((rb (region-beginning)) + (re (region-end)) + (qr (html-quote-html-string + (buffer-substring-no-properties rb re)))) + (delete-region rb re) + (insert qr)) + (let ((cs (html-quote-html-char (char-after)))) + (delete-char 1) + (insert cs)))) + +(defvar nxhtml-single-tags + '("base" + "meta" + "link" + "br" + "hr" + "frame" + "img" + "input" + "option" + "param")) + +(defun nxthml-is-single-tag (tag) + (member tag nxhtml-single-tags)) + +(defvar nxhtml-help-attribute-name + '(("title" "Element title") + ("class" "Style class of element") + ("charset" "Encoding of target") + ("coords" "Defining shape") + ("href" "Target URL") + ("hreflang" "Language of target") + ("name" "(DEPRECEATED)") + ("rel" "Target's relation to document") + ("rev" "Document's relation to target") + ("shape" "Area shape") + ("target" "Where to open target") + ("type" "MIME type of target") + + ("id" "Unique id of element") + ("lang" "Language code") + ("dir" "Text direction") + ("accesskey" "Keyboard shortcut") + ("tabindex" "Tab order of element") + + ("style" "Inline style") + ("disabled" "Tag initially disabled") + ("readonly" "User can not modify") + ;;("" "") + + ("alink" "(DEPRECEATED)") + ("background" "(DEPRECEATED)") + ("bgcolor" "(DEPRECEATED)") + ("link" "(DEPRECEATED)") + ("text" "(DEPRECEATED)") + ("vlink" "(DEPRECEATED)") + ("xml:lang" "Tag content language") + ("cite" "URL with more info") + ("method" "HTTP method for sending") + ("accept" "Content types") + ("accept-charset" "Character sets") + ("enctype" "Encoding") + )) +(defvar nxhtml-help-attribute-name-tag + '(("textarea" + ("name" "Name for textarea") + ) + )) + +(defvar nxhtml-help-tag + (let ((h (make-hash-table :test 'equal))) + (puthash "html" "Document" h) + (puthash "head" "Document head" h) + (puthash "title" "Document title" h) + (puthash "base" "Base URL/target" h) + (puthash "meta" "Meta information" h) + (puthash "style" "Inline style sheet" h) + (puthash "link" "Style sheet etc" h) + (puthash "script" "(Java)Script code" h) + (puthash "noscript" "Script disabled part" h) + (puthash "isindex" "(DEPRECEATED)" h) + + (puthash "iframe" "Inline frame" h) + (puthash "frameset" "Organize frames" h) + (puthash "frame" "Sub window" h) + (puthash "noframes" "Substitute for frames" h) + + (puthash "bdo" "Text direction" h) + + (puthash "body" "Document body" h) + (puthash "a" "Link" h) + (puthash "p" "Paragraph" h) + (puthash "span" "Group inline elements" h) + (puthash "br" "Line break" h) + (puthash "hr" "Horizontal rule" h) + (puthash "div" "Division/section" h) + (puthash "img" "Image" h) + (puthash "h1" "Header 1" h) + (puthash "del" "Deleted text" h) + (puthash "strike" "(DEPRECEATED)" h) + (puthash "u" "(DEPRECEATED)" h) + (puthash "s" "(DEPRECEATED)" h) + (puthash "ins" "Inserted text" h) + (puthash "sup" "Superscript text" h) + (puthash "center" "(DEPRECEATED)" h) + (puthash "dir" "(DEPRECEATED)" h) + + (puthash "blockquote" "Long quotation" h) + (puthash "q" "Short quotation" h) + (puthash "pre" "Preformatted text" h) + (puthash "applet" "(DEPRECEATED)" h) + (puthash "basefont" "(DEPRECEATED)" h) + (puthash "font" "(DEPRECEATED)" h) + + ;; The following elements are all font style elements. They are + ;; not deprecated, but it is possible to achieve richer effects + ;; using style sheets. + (puthash "tt" "Renders as teletype or mono spaced text" h) + (puthash "i" "Renders as italic text" h) + (puthash "b" "Renders as bold text" h) + (puthash "big" "Renders as bigger text" h) + (puthash "small" "Renders as smaller text" h) + + + ;; The following tags are not deprecated, but it is possible to + ;; achieve a much richer effect using style sheets: + (puthash "em" "Renders as emphasized text" h) + (puthash "strong" "Renders as strong emphasized text" h) + (puthash "dfn" "Defines a definition term" h) + (puthash "code" "Defines computer code text" h) + (puthash "samp" "Defines sample computer code" h) + (puthash "kbd" "Defines keyboard text" h) + (puthash "var" "Defines a variable" h) + (puthash "cite" "Defines a citation" h) + + (puthash "ul" "Unordered list" h) + (puthash "ol" "Ordered list" h) + (puthash "li" "List element" h) + (puthash "dl" "Definition list" h) + (puthash "dt" "Definition term" h) + (puthash "dd" "Definition description" h) + + + (puthash "fieldset" "Draw box around" h) + (puthash "form" "User input form" h) + (puthash "input" "Input field/checkbox etc" h) + (puthash "textarea" "Input multiline field" h) + (puthash "button" "Push button" h) + (puthash "label" "Label for control" h) + (puthash "map" "Client side image map" h) + (puthash "select" "Drop down list" h) + (puthash "option" "Option in drop down list" h) + (puthash "menu" "(DEPRECEATED)" h) + + (puthash "object" "Embedded object" h) + (puthash "param" "Object settings" h) + + (puthash "abbr" "Abbreviation" h) + (puthash "address" "For addresses etc" h) + (puthash "acronym" "May be used for lookup etc" h) + + (puthash "table" "Table" h) + (puthash "caption" "Table caption" h) + (puthash "col" "Table column attributes" h) + (puthash "colgroup" "Table column group" h) + (puthash "thead" "Table header" h) + (puthash "tbody" "Table body" h) + (puthash "tfoot" "Table footer" h) + (puthash "tr" "Table row" h) + (puthash "td" "Table cell" h) + + h)) + +;;;###autoload +(defun nxhtml-short-tag-help (tag) + "Display description of tag TAG. If TAG is omitted, try tag at point." + (interactive + (let ((tag (xhtml-help-tag-at-point))) + (unless (stringp tag) + (setq tag (read-string "No tag at point. Give tag name: "))) + (list tag))) + (setq tag (downcase tag)) + (let ((desc (gethash tag nxhtml-help-tag)) + (use-dialog-box nil)) + (unless desc + (setq desc (concat tag " -- No short description available"))) + (when (y-or-n-p (concat desc ". Fetch more information from the Internet? ")) + ;; Loaded by the autoloading of `xhtml-help-tag-at-point' above: + (xhtml-help-browse-tag tag)))) + +(defvar nxhtml-no-single-tags nil) +(defvar nxhtml-no-end-tags nil) + +(defadvice rng-complete-qname-function (around nxhtml-rng-complete-qname-function-ad + (string predicate flag) + disable) + ;;(if (not (eq major-mode 'nxhtml-mode)) + (if (not nxhtml-completing-with-help) + ad-do-it + (setq ad-return-value + (let ((alist (mapcar (lambda (name) (cons name nil)) + (nxhtml-rng-generate-qname-list string)))) + (cond ((not flag) + (try-completion string alist predicate)) + ((eq flag t) + (all-completions string alist predicate)) + ((eq flag 'lambda) + (and (assoc string alist) t))))))) + + + + +(defvar nxhtml-predicate-error nil) + +(defun nxhtml-find-ids (file) + (let ((buf (find-file-noselect file))) + (when buf + (with-current-buffer buf + (when (eq major-mode 'nxhtml-mode) + (save-excursion + (let ((ids nil) + (id-ptrn + (rx space + "id" + (0+ space) + ?= + (0+ space) + ?\" + (submatch + (1+ (not (any ?\"))) + ) + ?\" + ))) + (goto-char (point-min)) + (while (re-search-forward id-ptrn nil t) + (add-to-list 'ids (match-string-no-properties 1))) + ids))))))) + +(defun nxhtml-read-url (&optional allowed-types initial-contents extra-predicate prompt-prefix) + (popcmp-mark-completing initial-contents) + (let ((local-ovl popcmp-mark-completing-ovl)) + (setq popcmp-mark-completing-ovl nil) + (unwind-protect + (let* ((url-type (nxhtml-read-url-type allowed-types initial-contents)) + (base-prompt (cond ((eq url-type 'local-file-url) + "File: ") + ((eq url-type 'id-url) + "Id: ") + ((eq url-type 'web-url) + "Web URL: ") + ((eq url-type 'mail-url) + "e-Mail address: ") + ((eq url-type 'any-url) + "Any URL-type: ") + (t + ;;(error "Internal error: bad url-type=%s" url-type) + "Unknown URL-type: ") + )) + prompt + type-predicate + url + (bad-url initial-contents) + (default-directory (if buffer-file-name + (file-name-directory buffer-file-name) + default-directory))) + (when prompt-prefix + (setq base-prompt (concat prompt-prefix " " base-prompt))) + (setq nxhtml-predicate-error "") + (cond ((eq url-type 'local-file-url) + ) + ((eq url-type 'web-url) + ) + ((eq url-type 'mail-url) + (setq type-predicate 'nxhtml-mailto-predicate) + (when (and (stringp bad-url) + (<= 7 (length bad-url)) + (string= "mailto:" (substring bad-url 0 7))) + (setq bad-url (substring bad-url 7))))) + (while (not url) + (setq prompt (concat nxhtml-predicate-error " " base-prompt)) + (cond ((eq url-type 'local-file-url) + (setq url (read-file-name prompt nil "" nil bad-url extra-predicate)) + (when (< 0 (length url)) + ;; Fix-me: prompt for id here + (setq url (file-relative-name + (expand-file-name url))))) + ((eq url-type 'id-url) + (setq url (completing-read prompt (nxhtml-find-ids buffer-file-name))) + (when url + (setq url (concat "#" url)))) + ((eq url-type 'web-url) + (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil + 'nxhtml-read-web-url-history + t))) + ((eq url-type 'mail-url) + (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil + 'nxhtml-read-mail-url-history + t))) + (t + (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil + 'nxhtml-read-url-history + t)))) + (when (or (and type-predicate + (not (funcall type-predicate url))) + (and extra-predicate + (not (funcall extra-predicate url)))) + (setq bad-url url) + (setq url))) + (when (eq url-type 'mail-url) + (setq url (concat "mailto:" url))) + url) + (delete-overlay local-ovl) + ))) + +(defun nxhtml-read-url-type (allowed url-beginning) + (assert (or (listp allowed) (eq t allowed)) t) + (let* ((prompt "URL-type: ") + (parsed-url (url-generic-parse-url url-beginning)) + (beg-type (url-type parsed-url)) + (allowed-u allowed) + (completion-ignore-case t) + choices + choice) + ;; (url-type (url-generic-parse-url "#some-id")) + ;;(lwarn t :warning "url-type=%s, pu=%s" (url-type parsed-url) parsed-url) + ;; Emacs 23 bug workaround Sat Jan 26 2008 + ;;(when (eq beg-type 'cl-struct-url) (setq beg-type (elt parsed-url 1))) + (cond ((string= "mailto" beg-type) + (setq allowed-u '(?m))) + ((or (string= "http" beg-type) + (string= "https" beg-type) + (string= "ftp" beg-type)) + (setq allowed-u '(?w))) + ((= 1 (length beg-type)) ;; w32 + (setq allowed-u '(?f))) + ((and (null beg-type) + url-beginning + (= ?# (string-to-char url-beginning))) + (setq allowed-u '(?i))) + ) + ;; Be a bit picky and hopefully helpful, check if really allowed: + (unless (or (eq allowed t) + (equal allowed allowed-u)) + (let ((temp-u (copy-sequence allowed-u))) + (dolist (a allowed) + (setq temp-u (delq a temp-u))) + (dolist (u temp-u) + (setq allowed-u (delq u allowed-u))))) + (if allowed-u + (when (eq allowed-u t) + (setq allowed-u '(?f ?i ?w ?m))) + (setq allowed-u '(?f ?w))) + (dolist (a allowed-u) + (cond + ((= a ?f) + (setq choices (cons "File" choices))) + ((= a ?i) + (setq choices (cons "Id" choices))) + ((= a ?w) (setq choices (cons "Url" choices))) + ((= a ?m) (setq choices (cons "Mail" choices))) + )) + (if (= 1 (length allowed-u)) + (setq choice (car choices)) + (setq choice (popcmp-completing-read prompt choices nil t + "" nil nil t))) + (cond ((string= choice "Id") + 'id-url) + ((string= choice "File") + 'local-file-url) + ((string= choice "Url") + 'web-url) + ((string= choice "Mail") + 'mail-url) + ))) + +(defvar nxhtml-read-url-history nil) +(defvar nxhtml-read-web-url-history nil) +(defvar nxhtml-read-mail-url-history nil) + +(defconst nxhtml-in-xml-attribute-value-regex + (replace-regexp-in-string + "w" + xmltok-ncname-regexp + ;;"<w\\(?::w\\)?\ + "<\\?xml\ +\\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\ +\[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\ +\[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\ +\\(\"[^\"]*\\|'[^']*\\)\\=" + t + t)) + +(defun nxhtml-mailto-predicate (url) + "Tries to match a mailto url. +This is not supposed to be entirely correct." + (setq nxhtml-predicate-error nil) + ;; Local pattern copied from gnus. + (let ((r (concat "^" + ;;"mailto:" + "[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*" + "\@" + "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}$")) + (case-fold-search t)) + ;;(message "mailpred") (sit-for 1) + (if (string-match r url) + t + (setq nxhtml-predicate-error "Malformed email address.") + nil))) + +(defcustom nxhtml-image-completion-pattern + "\\.\\(?:png\\|jpg\\|jpeg\\|gif\\)$" + "Pattern for matching image URLs in completion." + :type 'regexp + :group 'nxhtml) + +(defun nxhtml-image-url-predicate (url) + (setq nxhtml-predicate-error nil) + (if (or (file-directory-p url) + (string-match nxhtml-image-completion-pattern url)) + t + (setq nxhtml-predicate-error "Does not match image file name pattern.") + nil + )) + +(defcustom nxhtml-css-completion-pattern + "\\.\\(?:css\\)$" + "Pattern for matching css URLs in completion." + :type 'regexp + :group 'nxhtml) + +(defun nxhtml-css-url-predicate (url) + (setq nxhtml-predicate-error nil) + (if (or (file-directory-p url) + (string-match nxhtml-css-completion-pattern url)) + t + (setq nxhtml-predicate-error "Does not match css file name pattern.") + nil + )) + +(defcustom nxhtml-script-completion-pattern + "\\.\\(?:js\\)$" + "Pattern for matching src URLs in completion in script tags." + :type 'regexp + :group 'nxhtml) + +(defun nxhtml-script-url-predicate (url) + (setq nxhtml-predicate-error nil) + (if (or (file-directory-p url) + (string-match nxhtml-script-completion-pattern url)) + t + (setq nxhtml-predicate-error "Does not match script file name pattern.") + nil + )) + +(defun nxhtml-coding-systems-complete (init default) + (let (coding-systems + hist-num + (n 0) + hist) + (unless (and init (< 0 (length init))) + (setq init default)) + (mapc (lambda (coding-system) + (let ((mime-charset (coding-system-get coding-system 'mime-charset))) + (when mime-charset + (setq coding-systems (cons + (symbol-name mime-charset) + coding-systems))))) + (coding-system-list t)) + (setq coding-systems (sort coding-systems 'string=)) + (mapc (lambda (coding-system) + (unless (< 0 (length coding-system)) + (error "len=0")) + (setq n (1+ n)) + (when (string= coding-system init) (setq hist-num n))) + coding-systems) + (if hist-num + (setq hist (cons 'coding-systems hist-num)) + (setq hist 'coding-systems)) + (completing-read "Encoding (coding system): " + coding-systems nil t init hist))) + + +;; Note: This function does not currently use the state provided by +;; the nxml and rng functions directly. Instead it searches the +;; environment near point to decide what to do. +;; (defun nxhtml-complete-and-insert () +;; "Perform XHTML completion at point. +;; This is merely an extended version of `nxml-complete' with the following changes: + +;; - If region is visible and active then completion will surround the +;; region with the chosen tag's start and end tag. However only the +;; starting point is checked for validity. If something is wrong after +;; insertion you will however immediately see it if you have validation +;; on. +;; - Can in some cases give completion help inside attribute values. +;; - There does not have to be a '<' before point for tag name +;; completion. (`nxml-mode' requires a '<' before point for tag name +;; completion.) +;; - For tag names there is a popup style completion available. This +;; gives a bit more guiding since it groups the alternative tags. Set +;; `popcmp-popup-completion' to use this. +;; - Completes xml version and encoding. +;; - Completes an empty file, ie inserts a skeleton." +;; (interactive) +;; (let (res +;; (where (nxhtml-check-where))) +;; (or (when (eq where 'in-empty-page) +;; (nxhtml-empty-page-completion)) +;; (when (and mark-active +;; transient-mark-mode +;; (eq where 'in-text)) +;; (nxhtml-insert-tag)) +;; (progn +;; (cond ((memq where '(in-start-tag in-closed-start-tag in-end-tag)) +;; (re-search-forward "\\=/?[a-z]*" nil t)) +;; ((memq where '(in-attr)) +;; (re-search-forward "\\=[a-z]*=" nil t)) +;; ((memq where '(in-attr-val in-xml-attr-val)) +;; (re-search-forward "\\=[^<>\" \t\r\n]*" nil t)) +;; ) +;; (when (run-hook-with-args-until-success 'nxml-completion-hook) +;; (when (re-search-backward "[^=]\"\\=" nil t) +;; (forward-char) (delete-char 1) +;; ;;(undo-start) (undo-more 1) +;; ) +;; t)) +;; (when (and (not where) +;; (char-before) +;; (= ?\" (char-before))) +;; nil) +;; (when (or (when (char-before) (= ?> (char-before))) +;; (eq where 'in-text)) +;; (setq res t) +;; (nxhtml-insert-tag)) +;; ;; Eventually we will complete on entity names here. +;; res +;; (progn +;; (ding) +;; (message "Cannot complete in this context"))))) + +(defvar nxhtml-in-proc-instr-back-regex "<\\?[^<>]*\\=") +(defvar nxhtml-in-proc-instr-forw-regex "\\=[^<>]*\\?>") + +(defconst rngalt-in-pre-attribute-value-regex + (replace-regexp-in-string + "w" + xmltok-ncname-regexp + "<w\\(?::w\\)?\ +\\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\ +\[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\ +\[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\ +\\=" + t + t)) + +(defun nxhtml-check-where () + "Get a state for `nxhtml-complete-last-try'." + (let ((p (point)) + (lt-pos (save-excursion (search-backward "<" nil t))) + res) + (cond ((= 0 (buffer-size)) + (setq res 'in-empty-page)) + ((looking-back "<!--[^<>]*\\=" 1 t) + (setq res 'in-comment)) + ((let ((face (get-char-property (point) 'face))) + (when (memq face '(nxml-comment-content-face + nxml-comment-delimiter-face)) + (setq res 'in-comment))) + t) + ((looking-back nxhtml-in-xml-attribute-value-regex lt-pos t) + (setq res 'in-xml-attr-val)) + ((looking-back nxhtml-in-proc-instr-back-regex 1 t) + (setq res 'in-proc-instr)) + ((looking-back "<!D[^>]*\\=" 1 t) + (setq res 'in-doctype)) + ((looking-back ">[^<]*" 1 t) + (setq res 'in-text)) + ((looking-back rng-in-start-tag-name-regex 1 t) + (setq res 'in-tag-start) + (when (looking-at "\\=[^<]*>") + (setq res 'in-closed-start-tag))) + ((looking-back rng-in-end-tag-name-regex 1 t) + (setq res 'in-tag-end)) + ((looking-back rng-in-attribute-regex 1 t) + (setq res 'in-attr)) + ((looking-back rng-in-attribute-value-regex 1 t) + (setq res 'in-attr-val)) + ((looking-back rngalt-in-pre-attribute-value-regex 1 t) + (setq res 'in-pre-attr-val)) + ((looking-back "\"") + (setq res 'after-attr-val)) + ((and rngalt-validation-header + (looking-back "\\`[^<]*")) + ;; FIX-ME: This is treated the same as in text currently, + ;; but this should be checked. Maybe it is best to test + ;; this here and return the relevant value? + (setq res 'after-validation-header)) + ) + ;;(message "res=%s" res)(sit-for 1) + (unless res + (error "Could not find a state for completion")) + res)) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Make the completions additions cleaner: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst nxhtml-tag-sets + '(("logical" + "del" + "ins" + "abbr" + "acronym" + "fieldset" + "blockquote" + "q" + "code" + "samp" + "cite" + "kbd" + "var" + "dfn" + "address" + "em" + "strong" + "pre" + ) + ("physical" + "hr" + "sup" + "sub" + "font" + "basefont" + "br" + "big" + "small" + "strike" + "u" + "i" + "b" + "s" + "tt" + "center" + "bdo" + ) + ("scripting" + "script" + "noscript" + "object" + "applet" + ) + ("structure" + "iframe" + "p" + "div" + "span" + "h6" + "h5" + "h4" + "h3" + "h2" + "h1" + ) + + ("form" + "isindex" + "label" + "button" + "option" + "select" + "input" + "textarea" + "form" + ) + + ("list" + "dt" + "dd" + "li" + "dir" + "menu" + "ol" + "dl" + "ul" + ) + + ("link" + "a" + ) + + ("image" + "img" + "map" + ) + + ("table" + "table" + "tr" + "th" + "td" + "caption" + "col" + "colgroup" + "thead" + "tbody" + "tfoot" + ) + + ("document" + "base" + "style" + "link" + "head" + "body" + "frame" + "frameset" + "noframes" + "isindex" + "nextid" + "meta" + "title" + ) + )) + +(defvar nxhtml-attr-sets + '(("scripting" + "onblur" + "onchange" + "onclick" + "ondblclick" + "onfocus" + "onkeydown" + "onkeypress" + "onkeyup" + "onload" + "onunload" + "onmousedown" + "onmousemove" + "onmouseout" + "onmouseover" + "onmouseup" + "onreset" + "onselect" + "onsubmit" + ) + ("form" + "method" + "accept" + "accept-charset" + "enctype" + ) + ("access" + "id" + "name" + "disabled" + "readonly") + ("layout" + "accesskey" + "class" + "coords" + "shape" + "style" + "tabindex" + "title" + "align" + "valign" + "alink" + "background" + "bgcolor" + "link" + "text" + "vlink" + "compact" + ) + ("target" + "charset" + "href" + "hreflang" + "rel" + "rev" + "target" + "type" + ) + ("language" + "dir" + "lang" + "xml:lang" + ) + ;; id + ;; name + ;; xml:lang + )) + +(defun nxhtml-complete-last-try () + (when rng-current-schema-file-name + (let ((where (nxhtml-check-where))) + (cond + ;;((eq where 'after-attr-val) + ;;(insert " ") + ;;) + ((eq where 'in-pre-attr-val) + (insert ?\")) + ((eq where 'in-comment) + (if (not (looking-at "[^>]*<")) + nil + (insert " -->") + t)) + ((eq where 'in-xml-attr-val) + (let (attr + delimiter + val) + (save-excursion + (save-match-data + (re-search-forward "\\=[^<> \t\r\n\"]*" nil t))) + (let* ((name-start (match-beginning 1)) + (name-end (match-end 1)) + (colon (match-beginning 2)) + (attr (buffer-substring-no-properties name-start + (or colon name-end))) + (value-start (1+ (match-beginning 3))) + (tag (save-excursion + (when (search-backward-regexp "<[[:alpha:]]+" nil t) + (match-string 0)))) + (init (buffer-substring-no-properties value-start (point)))) + (setq delimiter (char-before value-start)) + (cond ((string= "encoding" attr) + ;; Give a default that works in browsers today + (setq val (nxhtml-coding-systems-complete + init + (symbol-name nxhtml-default-encoding)))) + ((string= "version" attr) + (setq val "1.0"))) + (when val + (insert val) + t) + ))) + ((or (memq where '(in-text + after-validation-header + in-empty-page))) + (rngalt-complete-tag-region-prepare) + (insert "<") + (condition-case err + (nxhtml-redisplay-complete) + (quit + (message "%s" (error-message-string err)) + (undo-start) + (undo-more 1) + (rngalt-complete-tag-region-cleanup))) + t) + (t + ;;(message "LAST TRY where=%s" (nxhtml-check-where))(sit-for 1) + nil) + )))) + +(defun nxhtml-img-tag-do-also () + (insert "alt=\"") + (rngalt-validate) + (insert (read-string "Alt attribute: ") + "\" ") + (insert "src=\"") + (rngalt-validate) + (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image"))) + (insert src) + (insert "\"") + (when (file-exists-p src) + (let ((sizes (image-size (create-image (expand-file-name src)) t))) + (insert + " width=\"" (format "%d" (car sizes)) "\"" + " height=\"" (format "%d" (cdr sizes)) "\"") + ))) + (unless (save-match-data (looking-at "[^<]\\{,200\\}>")) + (insert " />"))) + +(defun nxhtml-redisplay-complete () + (rngalt-validate) + (rng-cancel-timers) + (message "") + (redisplay t) + (nxml-complete) + (rng-activate-timers)) + +(defun nxhtml-read-from-minibuffer (prompt &optional + initial-contents keymap + read hist default-value + inherit-input-method) + (rng-cancel-timers) + (message "") + (let ((res (read-from-minibuffer prompt initial-contents keymap + read hist default-value inherit-input-method))) + (rng-activate-timers) + res)) + +(defun nxhtml-meta-tag-do-also () + (let ((type (popcmp-completing-read + "Type: " + '( + ;;"Refresh/Redirect" + "HTTP Message Headers" + "Robot Rules" + "Description for Search Engines" + )))) + (cond + ((string= type "Description for Search Engines") + (insert " name=\"Description\"") + (insert " content=\"") + (insert (nxhtml-read-from-minibuffer "Description: ")) + (insert "\" />")) + ((string= type "Robot Rules") + (insert " name=\"Robots\"") + (insert " content=\"") + (nxhtml-redisplay-complete) + (insert " />")) + ((string= type "HTTP Message Headers") + (insert " http-equiv=\"") + (nxhtml-redisplay-complete) + (insert " content=\"") + (insert (nxhtml-read-from-minibuffer "Content: ")) + (insert "\" />"))))) + +(defun nxhtml-style-tag-do-also () + (insert "type=\"text/css\"") + (insert " media=\"") + (nxhtml-redisplay-complete) + (insert ">") + (indent-according-to-mode) + (insert "\n/* <![CDATA[ */") + (indent-according-to-mode) + (insert "\n") + (indent-according-to-mode) + (insert "\n/* ]]> */") + (indent-according-to-mode) + (insert "\n</style>") + (indent-according-to-mode) + (insert "\n") + (end-of-line -2)) + +(defun nxhtml-script-tag-do-also () + (let ((type (popcmp-completing-read + "Type: " + '("Inlined" + "Linked")))) + (cond + ((string= type "Inlined") + (insert "type=\"text/javascript\">") + (indent-according-to-mode) + (insert "\n// <![CDATA[") + (indent-according-to-mode) + (insert "\n") + (indent-according-to-mode) + (insert "\n// ]]>") + (indent-according-to-mode) + (insert "\n</script>") + (indent-according-to-mode) + (end-of-line -1)) + ((string= type "Linked") + (insert "type=\"text/javascript\"") + (insert " src=\"") + (nxhtml-redisplay-complete) + (insert "></script>"))))) + +(defun nxhtml-link-tag-do-also () + (let ((type (popcmp-completing-read "Type: " + '( + "Other" + "Shortcut icon" + "Style sheet" + )))) + (cond + ((string= type "Style sheet") + (insert " rel=\"Stylesheet\" ") + (insert "type=\"text/css\" ") + (insert "href=\"") + (nxhtml-redisplay-complete) + (insert " media=\"") + (nxhtml-redisplay-complete) + (insert " />")) + ((string= type "Shortcut icon") + (insert " rel=\"Shortcut Icon\" ") + (insert "href=\"") + (nxhtml-redisplay-complete) + (insert " />")) + (t + (insert " ") + (nxhtml-redisplay-complete) + )))) + +(defun nxhtml-input-tag-do-also () + (insert " ") + (rngalt-validate) + ;; type= + (insert "type=\"") + (nxhtml-redisplay-complete) + (insert " ") + + (let* ((choice (save-match-data + (when (looking-back "type=\"\\(.*\\)\" ") + (match-string 1))))) + ;;(insert "type=\"" choice "\" ") + (rngalt-validate) + ;;(message "choice=%s" choice)(sit-for 2) + ;; name= + (when (member choice '("button" "checkbox" "file" "hidden" "image" + "password" "radio" "text")) + (insert "name=\"" + (read-string "Name (name): ") + "\" ") + (rngalt-validate)) + ;; checked= + (when (member choice '("checkbox" "radio")) + (when (y-or-n-p "Checked? (checked): ") + (insert "checked=\"checked\" ") + (rngalt-validate))) + ;; disabled= + (unless (string= choice "hidden") + (unless (y-or-n-p "Enabled? : ") + (insert "disabled=\"disabled\" ") + (rngalt-validate))) + ;; readonly= + (when (string= choice "text") + (when (y-or-n-p "Readonly? (readonly): ") + (insert "readonly=\"readonly\" ")) + (rngalt-validate)) + (when (string= choice "file") + ;; accept= + (require 'mailcap) + (condition-case err + (let ((prompt (concat + "Accept mime type, RET to stop (" + "C-g to skip" + "): ")) + (mime " ") + mimes + (types (when (boundp 'mailcap-mime-extensions) + (mapcar (lambda (elt) + (cdr elt)) + mailcap-mime-extensions)))) + (while (< 0 (length mime)) + (setq mime + (if types + (completing-read prompt types) + (read-string prompt))) + (when (< 0 (length mime)) + (if mimes + (setq mimes (concat mimes "," mime)) + (setq mimes mime)))) + (when (and mimes + (< 0 (length mimes))) + (insert "accept=\"" mimes "\" "))) + (quit (message "Skipped accept attribute"))) + (rngalt-validate)) + (when (string= choice "image") + ;; alt= + (insert "alt=\"") + (rngalt-validate) + (insert (read-string "Alt attribute: ") + "\" ") + (rngalt-validate) + ;; src= + (insert "src=\"") + (rngalt-validate) + (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image"))) + (insert src) + (insert "\" ")) + (rngalt-validate)) + ;; value= + (cond + ((member choice '("button" "reset" "submit")) + (nxhtml-do-also-value "Label")) + ((member choice '("checkbox" "radio")) + (nxhtml-do-also-value "Result")) + ((member choice '("hidden" "password" "text")) + (nxhtml-do-also-value "Value")) + ) + (insert "/>") + ;;(message "type=%s" choice)(sit-for 2) + )) + +(defun nxhtml-do-also-value (label) + (let ((v (read-string (concat label " (value): ")))) + (when (and v + (< 0 (length v))) + (insert " value=\"" v "\" ")))) + +(defun nxhtml-form-tag-do-also () + (insert "action=\"") + (rngalt-validate) + (let ((src (nxhtml-read-url nil nil nil "Action"))) + (insert src "\" ")) + ) + +(defun nxhtml-a-tag-do-also () + (insert " href=\"") + (rngalt-validate) + (insert (nxhtml-read-url t)) + (insert "\"") + (let* ((pre-choices '("_blank" "_parent" "_self" "_top")) + (all-choices (reverse (cons "None" (cons "Frame name" pre-choices)))) + choice + (prompt "Target: ")) + (setq choice (popcmp-completing-read prompt all-choices nil t + "" nil nil t)) + (unless (string= choice "None") + (insert " target=\"") + (cond ((member choice pre-choices) + (insert choice "\"")) + ((string= choice "Frame name") + (rngalt-validate) + (insert (read-string "Frame name: ") "\"")) + (t (error "Uh?"))))) + (insert ">") + (rngalt-validate) + (insert (read-string "Link title: ") + "</a>")) + +(defconst nxhtml-complete-tag-do-also + '(("a" nxhtml-a-tag-do-also) + ;; (lambda () + ;; (insert " href=\"") + ;; (rngalt-validate) + ;; (insert (nxhtml-read-url t)) + ;; (insert "\""))) + ("form" nxhtml-form-tag-do-also) + ("img" nxhtml-img-tag-do-also) + ("input" nxhtml-input-tag-do-also) + ("link" nxhtml-link-tag-do-also) + ("script" nxhtml-script-tag-do-also) + ("style" nxhtml-style-tag-do-also) + ("meta" nxhtml-meta-tag-do-also) + ) + "List of functions to call at tag completion. +Each element of the list have the form + + \(TAG-NAME TAG-FUN) + +If `nxhtml-tag-do-also' is non-nil then TAG-FUN is called after +by `nxml-complete' (with the special setup of this function for +`nxhtml-mode') when completing a tag with the name TAG-NAME. + +The list is handled as an association list, ie only the first +occurence of a tag name is used.") + +(defun nxhtml-complete-tag-do-also-for-state-completion (dummy-completed) + "Add this to state completion functions completed hook." + (when (and nxhtml-tag-do-also + (derived-mode-p 'nxhtml-mode)) + ;; Find out tag + (let ((tag nil)) + (save-match-data + ;;(when (looking-back "<\\([a-z]+\\)[[:blank:]]+") + (when (looking-back "<\\([a-z]+\\)") + (setq tag (match-string 1)))) + (when tag + (insert " ") + (nxhtml-complete-tag-do-also tag))))) + +(defun nxhtml-complete-tag-do-also (tag) + ;; First required attributes: + (let ((tagrec (assoc tag nxhtml-complete-tag-do-also))) + (when tagrec + (funcall (cadr tagrec)))) + ) + + +;;;###autoload +(define-minor-mode nxhtml-validation-header-mode + "If on use a Fictive XHTML Validation Header for the buffer. +See `nxhtml-set-validation-header' for information about Fictive XHTML Validation Headers. + +This mode may be turned on automatically in two ways: +- If you try to do completion of a XHTML tag or attribute then + `nxthml-mode' may ask you if you want to turn this mode on if + needed. +- You can also choose to have it turned on automatically whenever + a mumamo multi major mode is used, see + `nxhtml-validation-header-if-mumamo' for further information." + :global nil + :lighter " VH" + :group 'nxhtml + (if nxhtml-validation-header-mode + (progn + (unless nxhtml-current-validation-header + (setq nxhtml-current-validation-header + (nxhtml-get-default-validation-header))) + ;;(message "nxhtml-current-validation-header=%s" nxhtml-current-validation-header) + (if nxhtml-current-validation-header + (progn + (nxhtml-apply-validation-header) + (add-hook 'change-major-mode-hook 'nxhtml-vhm-change-major nil t) + (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + (add-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major nil t) + (add-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major nil t))) + (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer)))) + (rngalt-set-validation-header nil) + (setq nxhtml-current-validation-header nil) + (remove-hook 'after-change-major-mode-hook 'nxhtml-vhm-after-change-major t) + (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + (remove-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major t) + (remove-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major t)))) + +(defun nxhtml-can-insert-page-here () + (and (not nxhtml-validation-header-mode) + (= 1 (point)) + (or (= 0 (buffer-size)) + (save-restriction + (widen) + (save-match-data + (looking-at (rx buffer-start + (0+ space) + buffer-end))))))) + +(defun nxhtml-complete-first-try () + (when (nxhtml-can-insert-page-here) + (nxhtml-empty-page-completion))) + +(defun nxhtml-completing-read-tag (prompt + table + &optional predicate require-match + initial-input hist def inherit-input-method) + (let ((popcmp-in-buffer-allowed t)) + (popcmp-completing-read prompt + table + predicate require-match + initial-input hist def inherit-input-method + nxhtml-help-tag + nxhtml-tag-sets))) + +(defun nxhtml-add-required-to-attr-set (tag) + (let ((missing (when tag + (rngalt-get-missing-required-attr + (nxthml-is-single-tag tag))))) + (if (not missing) + nxhtml-attr-sets + (cons (cons "Required" missing) + nxhtml-attr-sets)))) + +(defun nxhtml-get-tag-specific-attr-help (tag) + (append (cdr (assoc tag nxhtml-help-attribute-name-tag)) nxhtml-help-attribute-name) + ) + +(defconst nxhtml-in-start-tag-regex + ;;(defconst rng-in-start-tag-name-regex + (replace-regexp-in-string + "w" + xmltok-ncname-regexp + ;; Not entirely correct since < could be part of attribute value: + "<\\(w\\(?::w?\\)?\\)+ [^<]*" + t + t)) + +(defun nxhtml-completing-read-attribute-name (prompt + table + &optional predicate require-match + initial-input hist def inherit-input-method) + (let* ((tag (save-match-data + ;;(when (looking-back "<\\([a-z1-6]+\\) [^<]*") + (when (looking-back nxhtml-in-start-tag-regex) + (match-string 1)))) + (attr-sets (nxhtml-add-required-to-attr-set tag)) + (help-attr (nxhtml-get-tag-specific-attr-help tag)) + (popcmp-in-buffer-allowed t) + ) + (popcmp-completing-read prompt + table + predicate require-match + initial-input hist def inherit-input-method + help-attr + attr-sets))) + +(defun nxhtml-completing-read-attribute-value (prompt + table + &optional predicate require-match + initial-input hist def inherit-input-method) + (let (val) + (if table + (let ((popcmp-in-buffer-allowed t)) + (setq val (popcmp-completing-read prompt table + predicate require-match + initial-input hist def inherit-input-method))) + (let* (init + delimiter + (lt-pos (save-excursion (search-backward "<" nil t))) + (in-attr-val + (save-excursion + (re-search-backward rng-in-attribute-value-regex lt-pos t))) + (in-xml-attr-val + (unless in-attr-val + (save-excursion + (re-search-backward nxhtml-in-xml-attribute-value-regex lt-pos t)))) + ) + (when (or in-attr-val in-xml-attr-val) + ;;(save-match-data (save-excursion (re-search-forward "\\=[^<> \t\r\n\"]*" nil t))) + (let* ((name-start (match-beginning 1)) + (name-end (match-end 1)) + (colon (match-beginning 2)) + (attr (buffer-substring-no-properties name-start + (or colon name-end))) + (value-start (1+ (match-beginning 3))) + tag-start-end + (tag (save-excursion + (when (search-backward-regexp "<[[:alpha:]]+" nil t) + (setq tag-start-end (match-end 0)) + (match-string-no-properties 0))))) + (setq init (buffer-substring-no-properties value-start (point))) + (setq delimiter (char-before value-start)) + (if in-xml-attr-val + (error "in-xml-attr-val should not be true here!") + ;; (cond ((string= "encoding" attr) + ;; ;; Give a default that works in browsers today + ;; (setq val (nxhtml-coding-systems-complete + ;; init + ;; (symbol-name nxhtml-default-encoding)))) + ;; ((string= "version" attr) + ;; (setq val "1.0"))) + (cond ((string= "rel" attr) + (cond ((string= "<link" tag) + (setq val (nxhtml-read-link-rel)) + ))) + ((string= "media" attr) + (cond ((string= "<link" tag) + (setq val (nxhtml-read-link-media))) + ((string= "<style" tag) + (setq val (nxhtml-read-link-media))) + )) + ((string= "type" attr) + (cond ((string= "<link" tag) + (setq val (nxhtml-read-link-type)) + ))) + ((string= "http-equiv" attr) + (cond ((string= "<meta" tag) + (setq val (nxhtml-read-meta-http-equiv))))) + ((string= "content" attr) + (cond ((string= "<meta" tag) + (setq val (nxhtml-read-meta-content))))) + ((string= "scheme" attr) + (cond ((string= "<meta" tag) + (setq val (nxhtml-read-meta-scheme))))) + ((string= "name" attr) + (cond ((string= "<meta" tag) + (setq val (nxhtml-read-meta-name))))) + ((string= "href" attr) + (cond ((string= "<a" tag) + (setq val (nxhtml-read-url t init))) + ((string= "<base" tag) + (setq val (nxhtml-read-url nil init nil "Base"))) + ((string= "<area" tag) + (setq val (nxhtml-read-url nil init))) + ((string= "<link" tag) + (let (predicate + (here (point))) + (save-excursion + (goto-char tag-start-end) + (cond + ((search-forward "text/css" here nil) + (setq predicate 'nxhtml-css-url-predicate)) + )) + (setq val (nxhtml-read-url nil init predicate)))) + (t + (setq val (nxhtml-read-url nil init))))) + ((string= "src" attr) + (cond ((string= "<img" tag) + (setq val (nxhtml-read-url nil init 'nxhtml-image-url-predicate "Image"))) + ((string= "<script" tag) + (setq val (nxhtml-read-url nil init 'nxhtml-script-url-predicate "Script"))) + ((string= "<input" tag) + (setq val (nxhtml-read-url nil init 'nxhtml-image-url-predicate "Image"))) + ((string= "<frame" tag) + (setq val (nxhtml-read-url nil init nil "Frame Source"))) + ((string= "<iframe" tag) + (setq val (nxhtml-read-url nil init nil "Frame Source"))) + (t + (setq val (nxhtml-read-url nil init))))))))))) + ;;(unless val (setq val (read-from-minibuffer prompt init))) + (if (not val) + (progn + (message "No completion of attribute value available here") + nil) + val))) + +(defun nxhtml-read-link-type () + (require 'mailcap) + (let ((types (when (boundp 'mailcap-mime-extensions) + (mapcar (lambda (elt) + (cdr elt)) + mailcap-mime-extensions)))) + (completing-read "Link type: " types nil t))) + +(defun nxhtml-read-link-media () + (let ((types '( + "screen" + "tty" + "tv" + "projection" + "handheld" + "print" + "braille" + "aural" + "all" + ))) + (popcmp-completing-read "For media type: " types nil t))) + +(defun nxhtml-read-link-rel () + (let ((predefined-linktypes '( + "Alternate" + "Appendix" + "Bookmark" + "Chapter" + "Contents" + "Copyright" + "Glossary" + "Help" + "Index" + "Next" + "Prev" + "Section" + "Shortcut Icon" + "Start" + "Stylesheet" + "Subsection" + ))) + (popcmp-completing-read "Predefined LinkTypes: " predefined-linktypes nil t))) + +(defun nxhtml-read-meta-name () + (let ((types '( + "author" + "description" + "keywords" + "generator" + "revised" + ;;"others" + ))) + (popcmp-completing-read "Meta name: " types nil t))) + +(defun nxhtml-read-meta-content () + (nxhtml-read-from-minibuffer "Meta content: ")) + +(defun nxhtml-read-meta-scheme () + (nxhtml-read-from-minibuffer "Meta scheme: ")) + +(defun nxhtml-read-meta-http-equiv () + (let ((types '( + "content-type" + "expires" + "refresh" + "set-cookie" + ))) + (popcmp-completing-read "Meta http-equiv: " types nil t))) + +(when nil + (setq rngalt-completing-read-tag nil) + (setq rngalt-complete-last-try nil) + ) + + +(when (featurep 'typesetter) + (defun typesetter-init-nxhtml-mode () + (typesetter-init-html-mode)) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Validation start state + +(defcustom nxhtml-validation-headers + '( + ("body-iso-8859-1" . + "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> + <title>Fictive XHTML Validation Header</title> + </head> + <body> +" + ) + ("head-iso-8859-1" . + "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> +" + ) + ("html-iso-8859-1" . + "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> +" + ) + ;; ("doctype-iso-8859-1" . + ;; "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> + ;; <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" + ;; \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> + ;; " + ;; ) + ;; ("xml-iso-8859-1" . + ;; "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> + ;; " + ;; ) + + ("body-utf-8" . + "<?xml version=\"1.0\" encoding=\"utf-8\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> + <title>Fictive XHTML Validation Header</title> + </head> + <body> +" + ) + ("head-utf-8" . + "<?xml version=\"1.0\" encoding=\"utf-8\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> +" + ) + ("head-closed-utf-8" . + "<?xml version=\"1.0\" encoding=\"utf-8\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> + <title></title> + </head> +" + ) + ("html-utf-8" . + "<?xml version=\"1.0\" encoding=\"utf-8\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> +" + ) + ;; ("doctype-utf-8" . + ;; "<?xml version=\"1.0\" encoding=\"utf-8\"?> + ;; <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" + ;; \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> + ;; " + ;; ) + ;; ("xml-utf-8" . + ;; "<?xml version=\"1.0\" encoding=\"utf-8\"?> + ;; " + ;; ) + ) + "Fictive XHTML validation headers. +Used by `nxhtml-set-validation-header'." + :type '(alist :key-type string :value-type string) + :group 'nxhtml) + +(defcustom nxhtml-default-validation-header nil + "Default Fictive XHTML validation header. +Must be nil or one of the key values in +`nxhtml-validation-headers'." + :type 'string + :set (lambda (sym val) + (if (or (null val) + (assoc val nxhtml-validation-headers)) + (set-default sym val) + (lwarn 'nxhtml-default-validation-header + :warning "There is no Fictive XHTML Validation Header named %s" val))) + :group 'nxhtml) + +(defun nxhtml-must-have-validation-headers () + (unless nxhtml-validation-headers + (error + "No XHTML validation headers. Please customize nxhtml-validation-headers."))) + +(defvar nxhtml-set-validation-header-hist nil) + +(defcustom nxhtml-guess-validation-header-alist + ;;(rx line-start (0+ blank) "<body") + '( + ("^[[:blank:]]*<body" . "body-utf-8") + ("^[[:blank:]]*</head>" . "head-closed-utf-8") + ("^[[:blank:]]*<head" . "head-utf-8") + ("^[[:blank:]]*<html" . "html-utf-8") + ) + "Alist used by `nxhtml-guess-validation-header'. +Alternatives are tried from top to bottom until one fits." + :type '(alist :key-type (regexp :tag "If NOT found in buffer") + :value-type (string :tag "Use Fictive XHTML Validation Header")) + :group 'nxhtml) + +(defun nxhtml-guess-validation-header () + "Return Fictive XHTML validation that could fit current buffer. +This guess is made by matching the entries in +`nxhtml-guess-validation-header-alist' against the buffer." + (nxhtml-must-have-validation-headers) + (save-excursion + (save-restriction + (save-match-data + (widen) + (let (rec + regexp + key + (guesses nxhtml-guess-validation-header-alist)) + (goto-char (point-min)) + (if (not (search-forward "</" 2000 t)) + (progn + (setq rec (car guesses)) + (setq key (cdr rec))) + (while (and guesses + (not key)) + (setq rec (car guesses)) + (setq guesses (cdr guesses)) + (setq regexp (car rec)) + (goto-char (point-min)) + ;; Fix-me: check for chunk and check if in string. + (let (found) + (while (and (not found) + (re-search-forward regexp nil t)) + ;; ensure fontified, but how? + (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + (let ((mumamo-just-changed-major nil)) + ;;(unless (and (mumamo-get-existing-chunk-at (point)) + (unless (and (mumamo-find-chunks (point) "guess-validation-header") + (eq t (get-text-property (point) 'fontified))) + (mumamo-fontify-region (point-min) (+ 1000 (point)))))) + (unless (memq (get-text-property (point) 'face) + '(font-lock-comment-face + font-lock-comment-delimiter-face + font-lock-doc-face + font-lock-string-face + )) + (setq found t))) + (unless found + (setq key (cdr rec)))))) + ;;(unless (re-search-forward regexp nil t) (setq key (cdr rec))))) + key))))) + +(defun nxhtml-open-dir-saved-validation-headers (must-exist) + "Open file with saved validation headers and return buffer." + ;;(lwarn 't :warning "must-exist=%s" must-exist) + (when (buffer-file-name) + (let* ((dir-name (file-name-directory (buffer-file-name))) + (file-name (expand-file-name "nxhtml-val-headers.el")) + emacs-lisp-mode-hook) + (when (or (not must-exist) + (file-exists-p file-name)) + (find-file-noselect file-name))))) + +(defun nxhtml-get-saved-validation-header () + (when (buffer-file-name) + (let* ((val-buf (nxhtml-open-dir-saved-validation-headers t)) + (file-name (file-name-nondirectory (buffer-file-name))) + validation-headers) + (when val-buf + (with-current-buffer val-buf + (eval-buffer)) + (cadr (assoc file-name validation-headers)))))) + +(defun nxhtml-remove-saved-validation-header () + "Removed the saved validation header. +Reverse the action done by `nxhtml-save-validation-header'." + (interactive) + (nxhtml-update-saved-validation-header nil)) + +(defun nxhtml-save-validation-header () + "Save the current validation header. +The current validation is saved for the next time you open the +current file. It is then used by `nxhtml-validation-header-mode' +and `nxhtml-set-validation-header'. This means that if you have +turned on `nxhtml-global-validation-header-mode' this validation +header will be set automatically. + +The saved validation header can be removed with +`nxhtml-remove-saved-validation-header'. + +* Note: There is normally no need to save the validation headers + since `nxhtml-global-validation-header-mode' will add + validation headers as needed most of the time." + (interactive) + (nxhtml-update-saved-validation-header t)) + +(defun nxhtml-update-saved-validation-header (save) + (unless (buffer-file-name) + (error "Validation Header can only be saved if buffer contains a file.")) + (let* ((val-buf (nxhtml-open-dir-saved-validation-headers nil)) + ;;(get-buffer-create "temp val head")) + validation-headers + (file-name (file-name-nondirectory (buffer-file-name))) + (entry (list file-name nxhtml-current-validation-header)) + ;;entry-list + removed + ) + ;; Get old headers + (with-current-buffer val-buf + (eval-buffer)) + ;; Remove old value + (setq validation-headers + (delq nil + (mapcar (lambda (elt) + (if (string= file-name (car elt)) + (progn + (setq removed t) + nil) + elt)) + validation-headers))) + ;; Add new value + (when save + (setq validation-headers (cons entry validation-headers))) + (with-current-buffer val-buf + (erase-buffer) + ;;(print file-name val-buf) + ;;(print nxhtml-current-validation-header val-buf) + ;;(print entry val-buf) + (insert "(setq validation-headers (quote") + (print validation-headers val-buf) + (insert "))") + (basic-save-buffer) + ) + (if save + (message "Current validation header for file saved") + (if removed + (message "Removed saved validation header") + (message "There was no saved validation header"))))) + +(defun nxhtml-get-default-validation-header () + "Return default Fictive XHTML validation header key for current buffer. +If `nxhtml-default-validation-header' is non-nil then return +this. Otherwise return saved validation header if there is one +or guess using `nxhtml-guess-validation-header'." + (or nxhtml-default-validation-header + (nxhtml-get-saved-validation-header) + (nxhtml-guess-validation-header))) + +(defun nxhtml-set-validation-header (&optional key) + "Set a Fictive XHTML validation header in the buffer. +Such a header is not inserted in the buffer, but is only used by +validation and XHTML completion by `nxhtml-mode'. + +The header is active for validation and completion if and only if +`nxhtml-validation-header-mode' is on. + +Note that Fictive XHTML Validation Headers are normally chosen +automatically, but you can use this function to override that choice. + +The header is chosen from `nxhtml-validation-headers'. If there +is more than one you will be prompted. To set the default fictive +XHTML validation header customize `nxhtml-validation-headers'. + +If called non-interactive then the header corresponding to key +KEY will be used. If KEY is nil then it is set to +`nxhtml-default-validation-header'. + +This header can be visible or invisible in the buffer, for more +information see `rngalt-show-validation-header'." + (interactive + (list + (let ((nh (length nxhtml-validation-headers)) + (default (nxhtml-get-default-validation-header))) + (if (> nh 1) + (completing-read "XHTML validation header: " + nxhtml-validation-headers + nil + t + default + nxhtml-set-validation-header-hist) + (if (not (y-or-n-p "Only one XHTML validation header is defined. Define more? ")) + default + (customize-option 'nxhtml-validation-headers) + 'adding))))) + ;;(lwarn 'svh2 :warning "key=%s" key) + (or key + (setq key (nxhtml-get-default-validation-header)) + (setq key (cons 'schema "XHTML"))) + (unless (eq key 'adding) + (setq nxhtml-current-validation-header key) + (nxhtml-validation-header-mode 1) + (nxhtml-apply-validation-header))) + +(defun nxhtml-apply-validation-header () + (when nxhtml-current-validation-header + (setq rngalt-major-mode + (if (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + (mumamo-main-major-mode) + major-mode)) + (let* ((key nxhtml-current-validation-header) + (rec (unless (listp key) + (assoc key nxhtml-validation-headers))) + (header (cdr rec))) + (if (listp key) + (let ((schema-file (rng-locate-schema-file (cdr key)))) + (unless schema-file + (error "Could not locate schema for type id `%s'" key)) ;type-id)) + (rng-set-schema-file-1 schema-file)) + (rngalt-set-validation-header header) + )))) + +(defun nxhtml-update-validation-header () + "Update the validation header in the buffer as needed." + (interactive) + (let ((mode-on nxhtml-validation-header-mode)) + (when mode-on (nxhtml-validation-header-mode 0)) + (setq nxhtml-current-validation-header nil) + (when mode-on (nxhtml-validation-header-mode 1)))) + +(defun nxhtml-vhm-change-major () + "Turn off `nxhtml-validation-header-mode' after change major." + ;;(message "nxhtml-vhm-change-major here") + (unless (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + (setq nxhtml-current-validation-header nil)) + (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer))) +(put 'nxhtml-vhm-change-mode 'permanent-local-hook t) + +(defun nxhtml-recheck-validation-header () + "Just turn off and on again `nxhtml-validation-header-mode'. +This will adjust the XHTML validation to the code currently in +the buffer." + (interactive) + (nxhtml-validation-header-mode -1) + (nxhtml-validation-header-mode 1)) + +(defun nxhtml-validation-header-empty (buffer) + "Turn off validation header mode. +This is called because there was no validation header." + (with-current-buffer buffer + (unless nxhtml-current-validation-header + ;;(message "nxhtml-validation-header-empty") + (save-match-data ;; runs in timer + (nxhtml-validation-header-mode -1)) + ;;(message "No validation header was needed") + ))) + +(defun nxhtml-turn-on-validation-header-mode () + "Turn on `nxhtml-validation-header-mode'." + (nxhtml-validation-header-mode 1)) + + +(defun nxhtml-vhm-mumamo-change-major () + (put 'rngalt-validation-header 'permanent-local t) + (put 'nxhtml-validation-header-mode 'permanent-local t) + (put 'nxhtml-current-validation-header 'permanent-local t) + ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local t) + ;;(setq nxhtml-validation-header-mode-major-mode mumamo-set-major-running) + ) + +(defun nxhtml-vhm-mumamo-after-change-major () + (put 'rngalt-validation-header 'permanent-local nil) + (put 'nxhtml-validation-header-mode 'permanent-local nil) + (put 'nxhtml-current-validation-header 'permanent-local nil) + ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local nil) + ) + +(defcustom nxhtml-validation-headers-check 'html + "Defines what check the function with the same name does. +The function returns true if the condition here is met." + :type '(choice :tag "Add Fictive XHTML Validation Header if:" + (const :tag "If buffer contains html" html) + (const :tag "If buffer contains html or is empty" html-empty)) + :group 'nxhtml) + +;; (defun nxhtml-validation-headers-check (buffer) +;; "Return non-nil if buffer contains a html tag or is empty. +;; This is for use with `nxhtml-validation-header-filenames'. + +;; The variable `nxhtml-validation-headers-check' determines how the +;; check is made." +;; (if (= 0 (buffer-size buffer)) +;; (eq 'html-empty nxhtml-validation-headers-check) +;; (save-match-data +;; (save-restriction +;; (let ((here (point)) +;; (html nil)) +;; (goto-char (point-min)) +;; (setq html (re-search-forward "</?[a-z]+>" nil t)) +;; (goto-char here) +;; html))))) + +;; (defcustom nxhtml-validation-header-filenames +;; '( +;; ("\.php\\'" nxhtml-validation-headers-check) +;; ("\.rhtml\\'" nxhtml-validation-headers-check) +;; ("\.jsp\\'" nxhtml-validation-headers-check) +;; ("\.gsp\\'" nxhtml-validation-headers-check) +;; ) +;; "Alist for turning on `nxhtml-validation-mode'. +;; The entries in the list should have the form + +;; \(FILE-REGEXP CHECK-FUNCION) + +;; If buffer file name matches the regexp FILE-REGEXP and the +;; function CHECK-FUNCTION returns non-nil when called with the +;; buffer as an argument \(or CHECK-FUNCTION is nil) then +;; `nxhtml-global-validation-header-mode' will turn on +;; `nxhtml-validation-header-mode' in buffer. + +;; The function `nxhtml-validation-headers-check' may be a useful +;; value for CHECK-FUNCTION. + +;; See also `nxhtml-maybe-turn-on-validation-header'." +;; :type '(alist :key-type regexp :tag "File name regexp" +;; :value-type (group (choice (const :tag "No more check" nil) +;; (function :tag "Check buffer with")))) +;; :group 'nxhtml) + + + +;; (defun nxhtml-maybe-turn-on-validation-header () +;; "Maybe turn on `nxhtml-validation-header-mode' in buffer. +;; This is called by `nxhtml-global-validation-header-mode'. + +;; See `nxhtml-validation-header-filenames' for how the check +;; is made." +;; (or (and (or (and mumamo-mode +;; (eq (mumamo-main-major-mode) 'nxhtml-mode)) +;; (eq major-mode 'nxhtml-mode)) +;; rngalt-validation-header +;; nxhtml-current-validation-header +;; nxhtml-validation-header-mode +;; (progn +;; ;;(lwarn 'maybe :warning "quick, buffer=%s" (current-buffer)) +;; (nxhtml-validation-header-mode 1) +;; t)) +;; (when (buffer-file-name) +;; (unless (or ;;nxhtml-validation-header-mode +;; (minibufferp (current-buffer)) +;; (string= " " (substring (buffer-name) 0 1)) +;; (string= "*" (substring (buffer-name) 0 1)) +;; ) +;; (when (catch 'turn-on +;; (save-match-data +;; (dolist (rec nxhtml-validation-header-filenames) +;; (when (string-match (car rec) (buffer-file-name)) +;; (let ((fun (nth 1 rec))) +;; (if (not fun) +;; (progn +;; ;;(lwarn 't :warning "matched %s to %s, nil" (car rec) (buffer-file-name)) +;; (throw 'turn-on t)) +;; (when (funcall fun (current-buffer)) +;; ;;(lwarn 't :warning "matched %s to %s" (car rec) (buffer-file-name)) +;; (throw 'turn-on t)))))))) +;; ;;(lwarn 't :warning "turn on %s, buffer=%s" major-mode (current-buffer)) +;; (nxhtml-validation-header-mode 1)))))) + + +;; ;; Fix-me: Is this really the way to do it? Would it not be better to +;; ;; tie this to mumamo-mode in the turn on hook there? After all +;; ;; validation headers are probably not used unless mumamo-mode is on. +;; (define-globalized-minor-mode nxhtml-global-validation-header-mode +;; nxhtml-validation-header-mode +;; nxhtml-maybe-turn-on-validation-header +;; :group 'nxhtml) +;; ;; The problem with global minor modes: +;; (when (and nxhtml-global-validation-header-mode +;; (not (boundp 'define-global-minor-mode-bug))) +;; (nxhtml-global-validation-header-mode 1)) + + +(defcustom nxhtml-validation-header-mumamo-modes + '(nxhtml-mode) + "Main major modes for which to turn on validation header. +Turn on Fictive XHTML Validation Header if main major mode for the +used mumamo multi major mode is any of those in this list. + +See `mumamo-defined-turn-on-functions' for information about +mumamo multi major modes." + :type '(repeat (function :tag "Main major mode in mumamo")) + :group 'nxhtml) + +(defun nxhtml-add-validation-header-if-mumamo () + "Maybe turn on validation header. +See `nxhtml-validation-header-if-mumamo' for more information." + ;;(nxhtml-validation-headers-check (current-buffer)) + (when (and (fboundp 'mumamo-main-major-mode) + (memq (mumamo-main-major-mode) nxhtml-validation-header-mumamo-modes)) + (nxhtml-validation-header-mode 1))) + +;;(define-toggle nxhtml-validation-header-if-mumamo nil +(define-minor-mode nxhtml-validation-header-if-mumamo + "Add a fictive validation header when mumamo is used. +If this variable is t then add a Fictive XHTML Validation Header +\(see `nxhtml-validation-header-mode') in buffer when mumamo is +used. However do this only if `mumamo-main-major-mode' is one of +those in `nxhtml-validation-header-mumamo-modes'. + +Changing this variable through custom adds/removes the function +`nxhtml-add-validation-header-if-mumamo' to +`mumamo-turn-on-hook'." + :global t + :group 'nxhtml + (if nxhtml-validation-header-if-mumamo + (add-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo) + (remove-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo))) + +(defun nxhtml-validation-header-if-mumamo-toggle () + "Toggle `nxhtml-validation-header-if-mumamo'." + (interactive) + (nxhtml-validation-header-if-mumamo (if nxhtml-validation-header-if-mumamo -1 1))) + +(defun nxhtml-warnings-are-visible () + (get 'rng-error 'face)) + +(defvar nxhtml-old-rng-error-face nil) +(defun nxhtml-toggle-visible-warnings () + "Toggle the red underline on validation errors. +Those can be quite disturbing when using mumamo multi major modes +because there will probably be many validation errors in for +example a php buffer, since unfortunately the validation routines +in `rng-validate-mode' from `nxml-mode' tries to validate the +whole buffer as XHTML. + +Also, because of a \(normally unimportant) bug in Emacs 22, +the red underline that marks an error will sometimes span several +lines instead of just marking a single character as it +should. \(This bug is a problem with overlays in Emacs 22.)" + (interactive) + (let ((face (get 'rng-error 'face))) + (if face + (progn + (setq nxhtml-old-rng-error-face (get 'rng-error 'face)) + (put 'rng-error 'face nil)) + (put 'rng-error 'face nxhtml-old-rng-error-face)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Bug corrections +;; (defun nxml-indent-line () +;; "Indent current line as XML." +;; (let ((indent (nxml-compute-indent)) +;; (from-end (- (point-max) (point)))) +;; (when indent +;; (beginning-of-line) +;; (let ((bol (point))) +;; (skip-chars-forward " \t") +;; ;; There is a problem with some lines, try a quick fix: +;; (when (and (= 0 indent) +;; (not (eq (char-after) ?<))) +;; (save-excursion +;; (save-match-data +;; (when (re-search-backward "^<" nil t) +;; (when (search-forward " ") +;; (setq indent (current-column)))))) +;; (when (= 0 indent) +;; (setq indent nxml-child-indent))) +;; ;; And sometimes nxml-compute-indent get very upset, check for +;; ;; that: +;; (let ((here (point))) +;; (beginning-of-line 0) +;; (back-to-indentation) +;; (when (and (= indent (current-column)) +;; (eq (char-after) ?\")) +;; (setq indent 0)) +;; (goto-char here)) +;; (unless (= (current-column) indent) +;; (delete-region bol (point)) +;; (indent-to indent))) +;; (when (> (- (point-max) from-end) (point)) +;; (goto-char (- (point-max) from-end)))))) + + +;; FIX-ME: untag should be in nxml-mode.el since it is in no way +;; specific to nxhtml-mode, but I do not want to change nxml-mode.el +;; at the moment. + +(defcustom nxml-untag-select 'yes + "Decide whether to select an element untagged by `nxml-untag-element'. +If this variable is 'yes the element is selected after untagging +the element. The mark is set at the end of the element and point +at the beginning of the element. + +If this variable is 'no then the element is not selected and +point is not moved. If it is 'ask the user is asked what to do." + :type '(choice (const :tag "Yes" yes) + (const :tag "No" no) + (const :tag "Ask" ask)) + :group 'nxml) + +(defun nxml-untag-element (arg) + "Remove start and end tag from current element. +The mark is by default set to the end of the former element and +point is moved to the beginning. Mark is also activated so that +it is easy to surround the former element with a new tag. + +Whether to select the old element is controlled by +`nxml-untag-select'. The meaning of the values 'yes and 'no for +this variable is flipped by using a universal argument. + +Note: If you want to `undo' the untag and you use +`transient-mark-mode' then you must first do something so that +the region is not highlighted (for example C-g)." + (interactive "*P") + (let ((here (point-marker)) + el-start + el-start-end + el-end + el-end-end + (select t)) + (nxml-backward-up-element) + (setq el-start (point)) + (nxml-forward-balanced-item) + (setq el-start-end (point)) + (goto-char el-start) + (nxml-forward-element) + (setq el-end-end (point-marker)) + (nxml-backward-single-balanced-item) + (setq el-end (point)) + (delete-region el-end el-end-end) + (delete-region el-start el-start-end) + ;; Select the element or not? + (if (eq nxml-untag-select 'ask) + (setq select (y-or-n-p "Select the old element? ")) + (when (eq nxml-untag-select 'no) + (setq select nil)) + (when arg + (setq select (not select)))) + (if (not select) + (goto-char here) + (goto-char el-end-end) + (push-mark nil t t) + (setq mark-active t) + (setq deactivate-mark nil) + (goto-char el-start)))) + +(defun nxhtml-rollover-insert-2v () + "Insert CSS rollover images. +The upper half of the image will be used when mouse is out and +the lower half when mouse is over the image. + +Only CSS is used for the rollover. The CSS code is written to the +header part of the file if possible, otherwise it is copied to +the kill ring/clipboard. + +The CSS code is built from a template file and the image size. + +This might be used for example for creating a menu with +alternatives vertically or horizontally. + +Usage example: + + If you want to make a small button style menu with images you + can start like this: + + <div id=\"mylinks\"> + <ul> + <li> + X <a href=\"news.html\">News and Notes</a> + </li> + <li> + <a href=\"doc.html\">Documentation</a> + </li> + <ul> + </div> + + Then put point at the X above (this is just a mark, should not + be in your code) and call this function. + + It will add some CSS code to in the header of your file. You + may want to tweak this a little bit, see below (or place it + somewhere else). It may look like this: + + #mylinks a { + /* Image */ + display: block; + background: transparent url(\"img/mybutton.png\") 0 0 no-repeat; + overflow: hidden; + width: 200px; + /* Text placement and size, etc */ + text-align: center; + /* You may need to change top and bottom padding depending + on font size. */ + padding-top: 11px; + font-size: 12px; + padding-bottom: 9px; + text-decoration: none; + white-space: nowrap; + border: none; + } + #mylinks a:hover { + background-position: 0 -35px; + } + #mylinks li { + display: inline; + padding: 0; + margin: 0; + float: none; + } + +For an example of usage see the file nxhtml.html that comes with +nXhtml and can be opened from the nXhtml menu under + + nXhtml / nXhtml Help and Setup / nXhtml version nn Overview" + (interactive) + ;; Fix-me: not quite ready yet, but should work OK." + (save-excursion + (let* ((tag (progn + (search-forward ">" nil t) + (unless (re-search-backward (rx "<" + (1+ (any "a-zA-Z:")) + (1+ (not (any ">"))) + " id=\"" + (submatch (+? anything)) + "\"") + nil t) + (error "Can't find tag with id backwards")) + (match-string-no-properties 0))) + (tagid (match-string-no-properties 1)) + (tagovl (let ((ovl (make-overlay + (match-beginning 0) (match-end 0)))) + (overlay-put ovl 'face 'highlight) + ovl)) + (head-end (save-excursion (search-backward "</head" nil t)))) + (unless head-end + (error "Can't find end of head tag. Need this to insert css.")) + (sit-for 1) + (unwind-protect + (condition-case err + (let* ((img-src (nxhtml-read-url + '(?f) nil 'nxhtml-image-url-predicate + (concat "Rollover image for \"" tag "\","))) + (img-sizes (when (file-exists-p img-src) + (image-size (create-image + (expand-file-name img-src)) + t))) + (class (read-string + (concat + "Class name for rollover (empty to use id=" + tagid "): "))) + (rollover-spec (if (< 0 (length class)) + (concat "." class) + (concat "#" tagid))) + img-width img-height + img-h2 + img-w2 + padding-top + padding-bottom + (font-size (read-number "Font size (px): " 12)) + (css-template-file (read-file-name + "CSS template file: " + (expand-file-name "etc/templates/" nxhtml-install-dir) + nil + t + "rollover-2v.css" + )) + (center-or-pad + (if (y-or-n-p "Do you want to center the text? ") + "text-align: center" + (format "padding: %spx" (/ font-size 2)))) + (hor-or-ver + (if (y-or-n-p "Do you want the alternatives shown in a vertical list? ") + "float: none" + "float: left")) + (css-template-buffer (find-file-noselect + css-template-file)) + (css-template (with-current-buffer css-template-buffer + ;; Do not widen, let user decide. + (buffer-substring-no-properties + (point-min) (point-max)))) + (css css-template)) + (unless (file-exists-p css-template-file) + (error "Can't find file %s" css-template-file)) + (if img-sizes + (progn + (setq img-width (car img-sizes)) + (setq img-height (cdr img-sizes))) + (setq img-width (read-number "Width: ")) + (setq img-height (read-number "Width: "))) + (setq img-h2 (/ img-height 2)) + (setq img-w2 (/ img-width 2)) + (setq padding-top (/ (- img-h2 font-size) 2)) + ;; Fix-me: I have no idea why I have to subtract 3 + ;; from bottom, but inspection with Firebug seems to + ;; say so: + (setq padding-bottom (- img-h2 padding-top font-size 3)) + (setq css (replace-regexp-in-string "ROLLOVER_SPEC" rollover-spec css t t)) + (setq css (replace-regexp-in-string "IMG_WIDTH_2" (number-to-string img-h2) css t t)) + (setq css (replace-regexp-in-string "IMG_HEIGHT_2" (number-to-string img-h2) css t t)) + (setq css (replace-regexp-in-string "IMG_WIDTH" (number-to-string img-width) css t t)) + (setq css (replace-regexp-in-string "IMG_HEIGHT" (number-to-string img-height) css t t)) + (setq css (replace-regexp-in-string "IMG_URL" img-src css t t)) + (setq css (replace-regexp-in-string "FONT_SIZE" (number-to-string font-size) css t t)) + (setq css (replace-regexp-in-string "PADDING_TOP" (number-to-string padding-top) css t t)) + (setq css (replace-regexp-in-string "PADDING_BOTTOM" (number-to-string padding-bottom) css t t)) + (setq css (replace-regexp-in-string "CENTER_OR_PAD" center-or-pad css t t)) + (setq css (replace-regexp-in-string "HOR_OR_VER" hor-or-ver css t t)) + (if head-end + (let ((this-window (selected-window))) + (find-file-other-window buffer-file-name) + (goto-char head-end) + (beginning-of-line) + (insert "<style type=\"text/css\">\n" + css + "\n</style>\n") + (select-window this-window)) + (kill-new css) + (message "No place to insert CSS, copied to clipboard instead")))) + (delete-overlay tagovl) + )))) + +;; Fix-me: image border 0 +;; Fix-me: SSI <!--#include file="file:///C|/EmacsW32/nxml/nxhtml/bug-tests/bug-080609.html" --> +;; Fix-me: Better a tag completion, target etc. +;; Fix-me: image map - is that possible now? +;; Fix-me: Special chars - completing on &? Or popup? Use nxml-insert-named-char +;; Fix-me: Quick table insert? A form? +;; Fix-me: Quick object insert? (applet is depreceated) +;; Fix-me: Better meta insert? Quick meta? +;; Fix-me: Quick div! Better div completion with position: static, +;; relative, absolute and fixed - with some explanations. +;; Fix-me: Quick hr? +;; Fix-me: Import CSS? Export CSS? +;; Fix-me: Use nxhtml-js.el? +;; Fix-me: Scroll bar colors etc? See 1stPage. +;; body { +;; scrollbar-arrow-color: #FF6699; +;; scrollbar-3dlight-color: #00FF33; +;; scrollbar-highlight-color: #66FFFF; +;; scrollbar-face-color: #6699FF; +;; scrollbar-shadow-color: #6633CC; +;; scrollbar-darkshadow-color: #660099; +;; scrollbar-track-color: #CC6633; +;; } +;; Fix-me: More quick menus: http://www.cssplay.co.uk/menus/ + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(provide 'nxhtml-mode) + +;;; nxhtml-mode.el ends here diff --git a/emacs/nxhtml/nxhtml/nxhtml-mumamo.el b/emacs/nxhtml/nxhtml/nxhtml-mumamo.el new file mode 100644 index 0000000..83dca7b --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtml-mumamo.el @@ -0,0 +1,365 @@ +;;; nxhtml-mumamo.el --- Multi major modes using nxhtml +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-03-10T19:04:20+0100 Mon +(defconst nxhtml-mumamo:version "0.5") +;; Last-Updated: 2009-01-06 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `backquote', `bytecomp', `mumamo', `mumamo-fun'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'nxhtml nil t)) +(eval-when-compile (require 'nxhtml-base)) +(eval-when-compile (require 'nxhtml-mode)) +(eval-when-compile (require 'mumamo)) +(eval-and-compile (require 'mumamo-fun)) +(eval-when-compile (require 'rng-valid nil t)) +;;(mumamo-fun-require) + +;; (defgroup nxhtml-auto-val-head nil +;; "Automatic turn on of XHTML validation headers." +;; :group 'nxhtml) + +;; (defmacro define-fictive-validation-header-toggle (fun-sym default-value) +;; (let* ((fun-name (symbol-name fun-sym)) +;; (custom-sym (intern (concat fun-name "-auto-val-head"))) +;; (hook-sym (intern-soft (concat fun-name "-hook"))) +;; (docstring +;; (concat "Automatic XHTML validation header for `" fun-name "'. +;; ´"))) +;; (assert hook-sym) +;; `(defcustom ,custom-sym ,default-value +;; ,docstring +;; :type 'boolean +;; :set (lambda (sym val) +;; (set-default sym val) +;; (if val +;; (add-hook ',hook-sym 'nxhtml-turn-on-validation-header-mode) +;; (remove-hook ',hook-sym 'nxhtml-turn-on-validation-header-mode))) +;; :group 'nxhtml-auto-val-head) +;; )) + +;; Fix-me: add chunk type attr string as last alternative. This will +;; allow things like myattr="<?php echo ?>". + +;;;###autoload +(define-mumamo-multi-major-mode nxhtml-mumamo-mode + "Turn on multiple major modes for (X)HTML with main mode `nxhtml-mode'. +This covers inlined style and javascript and PHP. + +See also `mumamo-alt-php-tags-mode'." + ("nXhtml Family" nxhtml-mode + (mumamo-chunk-xml-pi + mumamo-chunk-alt-php + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'nxhtml-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) +;;(define-fictive-validation-header-toggle nxhtml-mumamo-mode t) + +;;;###autoload +(define-mumamo-multi-major-mode embperl-nxhtml-mumamo-mode + "Turn on multiple major modes for Embperl files with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("Embperl nXhtml Family" nxhtml-mode + (mumamo-chunk-embperl-<- + mumamo-chunk-embperl-<+ + mumamo-chunk-embperl-<! + mumamo-chunk-embperl-<$ + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;###autoload +(define-mumamo-multi-major-mode django-nxhtml-mumamo-mode + "Turn on multiple major modes for Django with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("Django nXhtml Family" nxhtml-mode + (mumamo-chunk-django4 + mumamo-chunk-django + mumamo-chunk-django2 + mumamo-chunk-django3 + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;###autoload +(define-mumamo-multi-major-mode mason-nxhtml-mumamo-mode + "Turn on multiple major modes for Mason using main mode `nxhtml-mode'. +This covers inlined style and javascript." + ("Mason nxhtml Family" nxhtml-mode + ( + mumamo-chunk-mason-perl-line + mumamo-chunk-mason-perl-single + mumamo-chunk-mason-perl-block + mumamo-chunk-mason-perl-init + mumamo-chunk-mason-perl-once + mumamo-chunk-mason-perl-cleanup + mumamo-chunk-mason-perl-shared + mumamo-chunk-mason-simple-comp + mumamo-chunk-mason-compcont + mumamo-chunk-mason-args + mumamo-chunk-mason-doc + mumamo-chunk-mason-text + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'mason-nxhtml-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) +;;(mumamo-inherit-sub-chunk-family-locally 'mason-nxhtml-mumamo-mode 'mason-nxhtml-mumamo-mode) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Genshi / kid + +(define-derived-mode nxhtml-genshi-mode nxhtml-mode "gXhtml" + "Like `nxhtml-mode' but with Genshi rnc. +You should not use this! This is just a part of +`genshi-nxhtml-mumamo-mode', use that instead." + (let* ((schema-dir (expand-file-name "etc/schema/" nxhtml-install-dir)) + (genshi-rnc (expand-file-name "qtmstr-xhtml.rnc" schema-dir))) + ;;(message "nxhtml-src-dir =%s" nxhtml-src-dir) + (message "schema-dir =%s" schema-dir) + (when (or (not rng-current-schema-file-name) + (string= "xhtml.rnc" (file-name-nondirectory rng-current-schema-file-name))) + (condition-case err + (progn + (rng-set-schema-file-1 genshi-rnc) + (rng-what-schema) + ;;(rng-save-schema-location-1 t) + ) + (nxml-file-parse-error + (nxml-display-file-parse-error err))) + (when rng-validate-mode + (rng-validate-mode -1) + (rng-validate-mode 1))))) + +;;;###autoload +(define-mumamo-multi-major-mode genshi-nxhtml-mumamo-mode + "Turn on multiple major modes for Genshi with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("Genshi HTML Family" nxhtml-genshi-mode + (;;mumamo-chunk-genshi% + mumamo-chunk-genshi$ + mumamo-chunk-py:= + mumamo-chunk-py:match + mumamo-chunk-xml-pi + ;;mumamo-chunk-alt-php + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; MJT + +;; MJT is run in the browser. Some new tags and attributes are used. + +(define-derived-mode nxhtml-mjt-mode nxhtml-mode "mjtXhtml" + "Like `nxhtml-mode' but with genshi rnc. +You should not use this! This is just a part of +`mjt-nxhtml-mumamo-mode', use that instead." + (let* ((schema-dir (expand-file-name "etc/schema/" nxhtml-install-dir)) + (genshi-rnc (expand-file-name "mjt.rnc" schema-dir))) + ;;(message "nxhtml-src-dir =%s" nxhtml-src-dir) + (message "schema-dir =%s" schema-dir) + (when (or (not rng-current-schema-file-name) + (string= "xhtml.rnc" (file-name-nondirectory rng-current-schema-file-name))) + (condition-case err + (progn + (rng-set-schema-file-1 genshi-rnc) + (rng-what-schema) + ;;(rng-save-schema-location-1 t) + ) + (nxml-file-parse-error + (nxml-display-file-parse-error err))) + (when rng-validate-mode + (rng-validate-mode -1) + (rng-validate-mode 1))))) + +;;;###autoload +(define-mumamo-multi-major-mode mjt-nxhtml-mumamo-mode + "Turn on multiple major modes for MJT with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("MJT nXhtml Family" nxhtml-mjt-mode + ( + mumamo-chunk-mjt$ + mumamo-chunk-xml-pi + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Smarty + +;;;###autoload +(define-mumamo-multi-major-mode smarty-nxhtml-mumamo-mode + "Turn on multiple major modes for Smarty with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("Smarty nXhtml Family" nxhtml-mode + (mumamo-chunk-xml-pi + mumamo-chunk-style= + mumamo-chunk-onjs= + ;;mumamo-chunk-inlined-style + ;;mumamo-chunk-inlined-script + mumamo-chunk-smarty-literal + mumamo-chunk-smarty-t + mumamo-chunk-smarty-comment + mumamo-chunk-smarty + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; GSP + +;;;###autoload +(define-mumamo-multi-major-mode gsp-nxhtml-mumamo-mode + "Turn on multiple major modes for GSP with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("GSP nXhtml Family" nxhtml-mode + (mumamo-chunk-gsp + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; JSP + +;;;###autoload +(define-mumamo-multi-major-mode jsp-nxhtml-mumamo-mode + "Turn on multiple major modes for JSP with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("JSP nXhtml Family" nxhtml-mode + (mumamo-chunk-jsp + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; eRuby + +;;;###autoload +(define-mumamo-multi-major-mode eruby-nxhtml-mumamo-mode + "Turn on multiple major modes for eRuby with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("eRuby nXhtml Family" nxhtml-mode + (mumamo-chunk-eruby + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; ASP + +;;;###autoload +(define-mumamo-multi-major-mode asp-nxhtml-mumamo-mode + "Turn on multiple major modes for ASP with main mode `nxhtml-mode'. +This also covers inlined style and javascript." + ("ASP nXhtml Family" nxhtml-mode + (mumamo-chunk-asp% + mumamo-asp-chunk-inlined-script + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Mako + +;;;###autoload +(define-mumamo-multi-major-mode mako-nxhtml-mumamo-mode + "Turn on multiple major modes for Mako with main mode `nxhtml-mode'. +This also covers inlined style and javascript." +;; Fix-me: test case +;; +;; Fix-me: Add chunks for the tags, but make sure these are made +;; invisible to nxml-mode parser. +;; +;; Fix-me: Maybe finally add that indentation support for one-line chunks? + ("Mako nXhtml Family" nxhtml-mode + ( + mumamo-chunk-mako-one-line-comment + mumamo-chunk-mako-<%doc + mumamo-chunk-mako-<%include + mumamo-chunk-mako-<%inherit + mumamo-chunk-mako-<%namespace + mumamo-chunk-mako-<%page + + ;;mumamo-chunk-mako-<%def + ;;mumamo-chunk-mako-<%call + ;;mumamo-chunk-mako-<%text + + mumamo-chunk-mako-<% + mumamo-chunk-mako-% + mumamo-chunk-mako$ + + mumamo-chunk-xml-pi + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;; Fix-me: This caused mumamo to loop during fontification since +;; fmode-replace-default-mode was not defined. Mumamo tried to load +;; the function in mumamo-fetch-major-mode-setup in (funcall major) +;; where major mode is php-mode. + +;;(eval-after-load 'php-mode '(fmode-replace-default-mode 'php-mode 'nxhtml-mumamo-mode)) + + + +(provide 'nxhtml-mumamo) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-mumamo.el ends here diff --git a/emacs/nxhtml/nxhtml/nxhtml-strval.el b/emacs/nxhtml/nxhtml/nxhtml-strval.el new file mode 100644 index 0000000..88ed1d0 --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtml-strval.el @@ -0,0 +1,210 @@ +;;; nxhtml-strval.el --- +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed Jun 06 12:42:09 2007 +(defconst nxhtml-strval:version "0.3") ;;Version: +;; LXast-Updated: Sun Jun 10 14:52:50 2007 (7200 +0200) +;; URL: +;; Keywords: +;; Compatibility: +;; +;; FXeatures that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This is a workaround for a problem caused by that the parser from +;; `nxml-mode' parses the whole buffer. This workaround handles things +;; like +;; +;; <a href="<?php title(); ?>">...</a> +;; +;; where the string value is not valid XHTML (because of the <). When +;; the minor mode `nxhtml-strval-mode' is on this construct will be +;; replaced by text that are valid XHTML. When writing to file or +;; copying/yanking this will be replaced with the intended text. +;; +;; For a long term solution the parser should be broken up, see also +;; +;; http://sourceforge.net/mailarchive/forum.php?thread_name=4638A428.9010408%40pareto.nl&forum_name=cedet-devel +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(define-minor-mode nxhtml-strval-mode + "Handle some useful, but not XHTML compliant attribute values. +This is mainly for PHP and similar. + +Things like + + <a href=\"<?php title(); ?>\">...</a> + +may be very useful in PHP. However the string value is not valid +XHTML (because of the <). This makes it difficult to use XHTML +completion and validation. + +This minor mode tries to take care of that by substituting the +<?php and ?> in the buffer while editing with something else. +The screen still shows <?php and ?> and when writing the buffer +to a file the substitutes are reverted to <?php and ?>. + +Note that this is a workaround. See the comments in the source +file. There are several \(I hope minor) problems with it. For +example is the buffer marked as modified when turning on/off this +minor mode. + +IMPORTANT: Do not edit the replaced string <? or ?>." + :lighter nil + :gropu 'nxhtml + (if nxhtml-strval-mode + (nxhtml-strval-mode-turn-on) + (nxhtml-strval-mode-turn-off))) +(put 'nxhtml-strval-mode 'permanent-local t) + +(defcustom nxhtml-strval-replface 'nxhtml-strval-replface + "Face used to mark replaced characters in strings." + :type 'face + :group 'nxhtml) + +(defface nxhtml-strval-replface '((t :inherit font-lock-warning-face)) + "Default face used to mark replaced characters in strings." + :group 'nxhtml) + +(defun nxthml-strval-add-ovl (start end) + (let ((ovl (make-overlay start end nil t nil))) + (overlay-put ovl 'nxhtml-strval t) + (overlay-put ovl 'face font-lock-warning-face))) + ;;(overlay-put ovl 'face 'highlight))) + +(defun nxhtml-strval-remove-all-ovls () + (remove-overlays (point-min) (point-max) 'nxhtml-strval t)) + +(defun nxhtml-strval-replace-match () + (let ((s (compose-string "{" nil nil ?<))) + (replace-match s t t nil 1)) + (put-text-property (1- (point)) (point) 'font-lock-face 'font-lock-warning-face) + (put-text-property (1- (point)) (point) 'nxhtml-strval-> t) + (nxthml-strval-add-ovl (1- (point)) (point)) + (let ((s (compose-string "}" nil nil ?>))) + (replace-match s t t nil 2)) + (nxthml-strval-add-ovl (1- (point)) (point)) + (put-text-property (1- (point)) (point) 'font-lock-face 'font-lock-warning-face) + (put-text-property (1- (point)) (point) 'nxhtml-strval-> nil)) + +(defun nxhtml-strval-revert-match () + (replace-match "<" t t nil 1) + (put-text-property (1- (point)) (point) 'font-lock-face nil) + (put-text-property (1- (point)) (point) 'nxhtml-strval-> nil) + (replace-match ">" t t nil 2) + (put-text-property (1- (point)) (point) 'font-lock-face nil) + (put-text-property (1- (point)) (point) 'nxhtml-strval-> nil)) + +(defconst nxhtml-strval-on-re "\"\\(<\\)[^>]*\\(>\\)\"") +(defconst nxhtml-strval-off-re "\"\\({\\)[^>]*\\(}\\)\"") + +(defun nxhtml-strval-mode-turn-on () + (unless (derived-mode-p 'nxml-mode 'php-mode) + (error "%s is not derived from nxml-mode" major-mode)) + (add-hook 'write-contents-functions 'nxhtml-strval-write-contents nil t) + (make-local-variable 'buffer-substring-filters) + (add-to-list 'buffer-substring-filters 'nxhtml-strval-buffer-substring-filter) + (nxhtml-strval-replace-values) + (add-hook 'after-change-functions 'nxhtml-strval-after-change nil t)) + +(defun nxhtml-strval-replace-values () + (save-excursion + (save-match-data + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward nxhtml-strval-on-re nil t) + (nxhtml-strval-replace-match)))))) + +(defun nxhtml-strval-mode-turn-off () + (remove-hook 'after-change-functions 'nxhtml-strval-after-change t) + (nxhtml-strval-revert-values) + (remove-hook 'write-contents-functions 'nxhtml-strval-write-contents t) + (kill-local-variable 'buffer-substring-filters)) + +(defun nxhtml-strval-revert-values () + (save-excursion + (save-match-data + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward nxhtml-strval-off-re nil t) + (nxhtml-strval-revert-match)) + (nxhtml-strval-remove-all-ovls))))) + +(defun nxhtml-strval-write-contents () + (let ((nxhtml-strval-no-after-change t)) + ;;(setq write-contents-functions (delq 'nxhtml-strval-write-contents write-contents-functions)) + (remove-hook 'write-contents-functions 'nxhtml-strval-write-contents t) + (undo-boundary) + (nxhtml-strval-revert-values) + ;;(write-file (buffer-file-name)) + (save-buffer) + ;; Fix-me: undo + ;;(nxhtml-strval-replace-values) + (undo-start) + (undo-more 1) + (add-hook 'write-contents-functions 'nxhtml-strval-write-contents nil t) + (set-buffer-modified-p nil) + t)) + +;;; Clip board etc. +(defun nxhtml-strval-buffer-substring-filter (orig-str) + (let ((str (replace-regexp-in-string "\"{" "\"<" orig-str))) + (setq str (replace-regexp-in-string "}\"" ">\"" str)) + str + )) + +;;; Changes +; after-change-functions +(defun nxhtml-strval-after-change (beg end len) + (unless (and (boundp 'nxhtml-strval-no-after-change) + nxhtml-strval-no-after-change) + (let ((here (point)) + (new-beg beg) + (new-end end)) + (goto-char beg) + (setq new-beg (line-beginning-position)) + (goto-char end) + (setq new-end (line-end-position)) + ;; Fix-me: examine old replacements here + (remove-text-properties new-beg new-end '(nxhtml-strval-< nxhtml-strval->)) + (goto-char new-beg) + (while (re-search-forward nxhtml-strval-on-re new-end t) + (nxhtml-strval-replace-match)) + (goto-char here) + ))) + +(provide 'nxhtml-strval) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-strval.el ends here diff --git a/emacs/nxhtml/nxhtml/nxhtml.el b/emacs/nxhtml/nxhtml/nxhtml.el new file mode 100644 index 0000000..7c85766 --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtml.el @@ -0,0 +1,339 @@ +;;; nxhtml.el --- Keeping nXhtml together +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-01-01 Thu +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'loadhist)) +(eval-when-compile (require 'nxhtml-base)) +(eval-and-compile (require 'nxhtml-menu nil t)) + +;;;###autoload +(defgroup nxhtml nil + "Customization of `nxhtml-mode'." + :group 'nxml) + +;;;###autoload +(defun nxhtml-customize () + "Customize nXhtml." + (interactive) + (customize-group 'nxhtml)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Features + +;; Fix-me: add help links +(defvar nxhtml-req-features + (let ((req-features + '( + "XHTML/HTML" + (nxml-mode "XML Completion" "nxml-mode.el") + (nxhtml "Additional XHTML Completion" "nxhtml.el") + (mlinks "Live XHTML links" "mlinks.el" "0.28") + (tidy-xhtml "Run HTML tidy program" "tidy-xhtml.el" "2.24") + (xhtml-help "HTML+CSS help" "xhtml-help.el" "0.57") + (nxml-where "Shows XML path" "nxml-where.el" "0.52") + (html-imenu "Table of content in menus" "html-imenu.el" "0.9") + (html-pagetoc "Page TOC" "html-pagetoc.el" "0.85") + (html-site "Web sites you define" "html-site.el" "0.2") + (html-upl "Upload web sites" "html-upl.el" "0.2") + (html-chklnk "Checking links in site" "html-chklnk.el" "0.2") + (html-move "Moving files in web sites" "html-move.el" "0.31") + (html-toc "Web site TOC" "html-toc.el" "0.4") + (html-wtoc "Merge pages and web Site TOC" "html-wtoc.el" "0.2") + (html-write "Show <i> as italic etc" "html-write.el" "0.6") + "General" + (mumamo "Multiple major modes in buffer" "mumamo.el" "0.73") + (majmodpri "Major mode priorities" "majmodpri.el" "0.5") + (tabkey2 "Tab completion" "tabkey2.el" "1.12") + (fold-dwim "Folding on headers and tags" "fold-dwim.el" "1.3") + (appmenu "General popup menu" "appmenu.el" "0.53") + (appmenu-fold "Popup menu entries for folding" "appmenu-fold.el" "0.51" appmenu fold-dwim) + (winsize "Resizing and window handling" "winsize.el" "0.98") + (winsav "Save/restore for windows/frames" "winsav.el" "0.77") + (viper-tut "Viper try-out tutorial" "viper-tut.el" "0.2") + (ourcomments-util "Some minor utilities" "ourcomments-util.el" "0.25") + "External applications / Emacs as dito" + (as-external "Emacs as an external editor" "as-external.el" "0.5") + (sex-mode "Send to EXternal program" "sex-mode.el" "0.71") + (freemind "Export/import freemind maps" "freemind.el" "0.60") + (hfyview "Print with browser/copy to html" "hfyview.el" "0.63") + (mozadd "Mirroring in Firefox" "mozadd.el" "0.2") + "Images and Colors" + (gimpedit "Edit images with GIMP" "gimp.el" "0.3") + (inlimg "Inline images" "inlimg.el" "0.7") + (css-color "Css color help functions" "css-color.el" "0.02") + (chart "Easy google charts" "chart.el" "0.2") + "Fetching and using elisp from repositories" + (udev "Fetch and from elisp repostories" "udev.el" "0.5") + ;;(udev-cedet "CEDET fetcher and loader" "udev-cedet.el" "0.2") + (udev-ecb "ECB fetcher and loader" "udev-ecb.el" "0.2") + (udev-rinari "Rinari fetcher and loader" "udev-rinari.el" "0.2") + "Games and life" + (pause "Take a break! I wish you some fun!" "pause.el" "0.64") + (n-back "n-back game for fun and brain" "n-back.el" "0.5") + ) + )) + req-features)) + +(defun nxhtml-load-req-features () + (dolist (extf nxhtml-req-features) + (unless (or (stringp extf) + (eq (car extf) 'nxhtml)) + (require (car extf) nil t)))) + + + +(defun nxhtml-make-library-link (beg end) + (let ((library (buffer-substring-no-properties beg end))) + (make-text-button beg end + 'action (lambda (button) + (find-library + (button-get button 'lib-name))) + 'lib-name library + 'face 'button))) + +(defun nxhtml-feature-insert (ok msg) + (put-text-property 0 (length msg) + 'face (if ok font-lock-type-face font-lock-warning-face) + msg) + (insert msg)) + +(defun nxhtml-feature-check (feat-entry silent) + (require 'loadhist) + (let ((feature (nth 0 feat-entry)) + (description (nth 1 feat-entry)) + (file (nth 2 feat-entry)) + (need-ver (nth 3 feat-entry)) + (need-list (cddddr feat-entry)) + (ok)) + (if (featurep feature) + (let* ( + (feat-versym (read (format "%s:version" feature))) + (feat-ver (condition-case err + (symbol-value feat-versym) + (error nil))) + (feat-vok (or (not need-ver) + (and feat-ver + (version<= need-ver feat-ver)))) + (need-ok (or (not need-list) + (let ((has t)) + (dolist (n need-list) + (unless (featurep n) + (setq has nil))) + has)))) + (setq ok (and feat-vok need-ok)) + (unless silent + (nxhtml-feature-insert + ok + (concat (format "%34s -- " description) + (if ok + (format "supported by %s%s\n" + file + (if (not need-ver) + "" + (if (string= feat-ver need-ver) + (format " (%s)" feat-ver) + (format " (%s/%s)" feat-ver need-ver)))) + (concat "found " file + " but needs" + (if feat-vok "" + (format " version %s" need-ver)) + (if (or feat-vok need-ok) "" " and") + (if need-ok "" + (format " also %s" need-list)) + "\n")))) + (unless (string= (file-name-sans-extension file) + (file-name-sans-extension + (file-name-nondirectory (feature-file feature)))) + (insert (make-string (+ 34 4) ?\ ) "** Bad file name: " file "\n")))) + (unless silent + (nxhtml-feature-insert + nil (format "%34s -- support missing, can't find %s\n" + description file)))) + ok)) + +;; Fix-me: move help here from `nxhtml-mode'? + +;;;###autoload +(defun nxhtml-features-check () + "Check if external modules used by nXhtml are found." + (interactive) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'nxhtml-features-check) (interactive-p)) + (with-current-buffer (help-buffer) + (nxhtml-menu-mode 1) + (erase-buffer) + (let ((s (concat "Elisp modules used by nXhtml version " nxhtml-menu:version ":"))) + (put-text-property 0 (length s) + 'face '( :weight bold :height 1.4) + s) + (insert s "\n\n")) + (nxhtml-load-req-features) + (nxhtml-load-req-features) + (nxhtml-load-req-features) + (nxhtml-load-req-features) + (dolist (feat-entry nxhtml-req-features) + (if (stringp feat-entry) + (insert "==== " (propertize feat-entry 'face 'font-lock-comment-face 'face '(:weight bold)) "\n") + (nxhtml-feature-check feat-entry nil))) + (goto-char (point-min)) + (while (search-forward-regexp "[-a-zA-Z0-9]+\\.el" nil t) + (nxhtml-make-library-link + (match-beginning 0) + (match-end 0))) + (goto-char (point-min))) + (set-buffer-modified-p nil))) + +(defun nxhtml-all-features-found () + (let ((all t)) + (dolist (feat-entry nxhtml-req-features) + ;;(unless (featurep (car extf)) + (unless (stringp feat-entry) + (unless (nxhtml-feature-check feat-entry t) + (setq all nil)))) + all)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Link saving and pasting + +(defun nxhtml-find-base-href () + "Return base href found in the current file." + (let ((base-href)) + (save-excursion + (goto-char (point-min)) + (while (and (not base-href) + (search-forward-regexp "<!--[^!]*-->\\|<base[[:space:]]" nil t)) + (when (equal " " (char-to-string (char-before))) + (backward-char 6) + (when (looking-at "<base [^>]*href *= *\"\\(.*?\\)\"") + (setq base-href (match-string-no-properties 1)))))) + base-href)) + + +(defvar nxhtml-saved-link-file nil + "Saved buffer file name for use in `nxhtml-paste-link'.") +(defvar nxhtml-saved-link-anchor nil + "Saved anchor name for use in `nxhtml-paste-link'.") + +;; Fix-me: same line??? +(defun nxhtml-save-link-to-here () + "Save buffer file name+anchor for `nxhtml-paste-link'." + (interactive) + (if (not buffer-file-name) + (message "Current buffer has no file name") + (setq nxhtml-saved-link-file (buffer-file-name)) + (setq nxhtml-saved-link-anchor nil) + (save-excursion + (let ((here (point))) + (while (not (or (bolp) (looking-at "\\(?:id\\|name\\)[[:space:]]*=[[:space:]]*\".*?\""))) + (backward-char)) + (when (and (looking-at "\\(?:id\\|name\\)[[:space:]]*=[[:space:]]*\"\\(.*?\\)\"") + (<= (match-beginning 0) here) + (< here (match-end 0))) + (setq nxhtml-saved-link-anchor (match-string-no-properties 1))))) + (message "Saved link: %s%s" nxhtml-saved-link-file + (if nxhtml-saved-link-anchor + (concat "#" nxhtml-saved-link-anchor) + "")))) + +(defun nxhtml-paste-link-as-a-tag () + "Paste link saved by `nxhtml-save-link-to-here' as an <a> tag. +Takes into account the relative position of the saved link." + (interactive) + (let ((paste-text (nxhtml-get-saved-link))) + (when paste-text + (let ((link-text (read-string "Link text: "))) + (insert "<a href=\"" paste-text "\">" link-text "</a>"))))) + +(defun nxhtml-paste-link () + "Paste link saved by `nxhtml-save-link-to-here'. +Takes into account the relative position of the saved link." + (interactive) + (let ((paste-text (nxhtml-get-saved-link))) + (when paste-text + (insert paste-text)))) + +(defun nxhtml-get-saved-link () + (if nxhtml-saved-link-file + (let* ( + (base-href (nxhtml-find-base-href)) + (rel (file-relative-name nxhtml-saved-link-file + (if base-href + base-href + (file-name-directory (buffer-file-name))))) + (to-file (file-name-nondirectory (buffer-file-name))) + (anchor nxhtml-saved-link-anchor) + ) + (when (equal to-file rel) (setq rel "")) + (when anchor (setq rel (concat rel "#" anchor))) + rel) + (message "There is no saved link") + nil)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Misc + +(defun nxhtml-update-mark-today (date-str) + "Update marks for today's date. +The mark has this form + + <!-- today -->zzz<!-- end today -->" + (interactive (list (format-time-string "%Y-%m-%d"))) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward (rx + "<!-- today -->" + (submatch (0+ anything)) + "<!-- end today -->") + nil t) + (replace-match date-str nil nil nil 1)))) + + +(provide 'nxhtml) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml.el ends here diff --git a/emacs/nxhtml/nxhtml/nxhtmljs.el b/emacs/nxhtml/nxhtml/nxhtmljs.el new file mode 100644 index 0000000..5adb3de --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxhtmljs.el @@ -0,0 +1,240 @@ +;;; nxhtml-js.el --- Javascript support functions +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Apr 28 2007 +;; Version: 0.1 +;; Last-Updated: 2008-12-28 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Fxeatures that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'nxhtml nil t)) +(eval-when-compile (require 'nxhtml-mode nil t)) + +(defun nxhtml-add-link (type src silent) + ;;<script type="text/javascript" src="EmacsW32.js"></script> + (catch 'exit + (save-excursion + (save-restriction + (widen) + (let ((here (point)) + (link (cond + ((eq type 'js) + (concat "<script type=\"text/javascript\" src=\"" src "\"></script>\n")) + ((eq type 'css) + (concat "<link rel=\"stylesheet\" href=\"" src "\" type=\"text/css\" media=\"screen\"/>\n")) + (t + (error "Bad type=%s" type)) + ))) + (goto-char (point-min)) + (when (search-forward link nil t) + (unless silent + (let ((temp-ovl (make-overlay (match-beginning 0) + (match-end 0))) + (after-string " <-- It is already here ")) + (condition-case err + (progn + (put-text-property 0 (length after-string) + 'face '(:background "red") + after-string) + (overlay-put temp-ovl 'face '(:background "yellow")) + (overlay-put temp-ovl 'priority 100) + (overlay-put temp-ovl 'after-string after-string) + (redisplay t) + (sit-for 3)) + (quit nil) + (error (message "%s" (error-message-string err)))) + (delete-overlay temp-ovl)) + (throw 'exit t))) + (unless (search-forward "</head>" nil t) + (goto-char here) + (unless (y-or-n-p "Can't find </head>, insert link to script here? ") + (throw 'exit nil))) + (beginning-of-line) + (insert link) + (beginning-of-line 0) + (indent-according-to-mode)))))) + +(defun nxhtml-smoothgallery-add-base (silent) + "Add links to javascript and style sheets. +This command add links to the javascript and style sheets that +comes with SmoothGallery, see URL +`http://smoothgallery.jondesign.net/'. + +* NOTICE: The files are not added to your project. Instead the +files that comes with nXhtml are linked to directly." + (interactive (list nil)) + (unless (buffer-file-name) + (error "Can't add SmoothGallery if buffer has no filename")) + (unless (memq major-mode '(html-mode nxhtml-mode)) + (error "Wrong major mode")) + (let* ((libfile (locate-library "nxhtml")) + (jsdir-abs (expand-file-name "doc/js/smoothgallery/scripts/" + (file-name-directory libfile))) + (jsdir-rel (file-relative-name jsdir-abs (file-name-directory (buffer-file-name)))) + (cssdir-abs (expand-file-name "doc/js/smoothgallery/css/" + (file-name-directory libfile))) + (cssdir-rel (file-relative-name cssdir-abs (file-name-directory (buffer-file-name))))) + (nxhtml-add-link 'js (concat jsdir-rel "mootools.js") silent) + (nxhtml-add-link 'js (concat jsdir-rel "jd.gallery.js") silent) + (nxhtml-add-link 'css (concat cssdir-rel "jd.gallery.css") silent) + (nxhtml-add-link 'css (concat cssdir-rel "layout.css") silent) + )) + +(defconst nxhtml-smoothgallery-mark "<!-- SmoothGallery -->") +(defun nxhtml-smoothgallery-find () + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (when (search-forward nxhtml-smoothgallery-mark nil t) + (back-to-indentation) + (when (looking-at + ;; (rx + ;; "<div id=\"" + ;; (submatch + ;; (1+ (not (any ">"))) + ;; ) + ;; "\">" (eval nxhtml-smoothgallery-mark)) + ;;(concat "<div id=\"\\([^>]+\\)\">" nxhtml-smoothgallery-mark) + (rx-to-string + `(and + "<div id=\"" + (submatch + (1+ (not (any ">"))) + ) + "\">" + ,nxhtml-smoothgallery-mark)) + ) + (cons + (copy-marker (match-beginning 0)) + (buffer-substring-no-properties + (match-beginning 1) (match-end 1)))))))) + +(defun nxhtml-smoothgallery-mk-jsmark (name) + (concat "new gallery($('" name "'), {")) + +(defun nxhtml-smoothgallery-find-script (name) + (let ((jsmark (nxhtml-smoothgallery-mk-jsmark name))) + (goto-char (point-min)) + (search-forward jsmark nil t))) + +(defun nxhtml-smoothgallery-add (point-name) + (interactive "i") + (unless point-name + (setq point-name (nxhtml-smoothgallery-find)) + (unless point-name + (setq point-name "myGallery"))) + (let ((name (if (consp point-name) + (cdr point-name) + point-name)) + (where (when (consp point-name) + (car point-name)))) + (unless where + (goto-char (point-min)) + (search-forward "<body") + (search-forward ">") + (insert "\n") + (setq where (point-marker)) + (insert-and-indent "<div id=\"" name "\">" nxhtml-smoothgallery-mark + "\n</div>") + ) + (unless (nxhtml-smoothgallery-find-script name) + (goto-char where) + (beginning-of-line) + (insert-and-indent "<script type=\"text/javascript\"> + function startGallery() { + var myGallery = new gallery($('" name "'), { + timed: true, + delay: 9000, + embedLinks: false, + showArrows: true, + showCarousel: false, + showInfopane: true, + }); + } + window.onDomReady(startGallery); + </script>") + (indent-according-to-mode)) + (goto-char where))) + +(defun nxhtml-smoothgallery-add-img (imgsrc thumbsrc title description) + (interactive (let ((gallery (nxhtml-smoothgallery-find))) + (when gallery + (goto-char (car gallery))) + (list + (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image") + (when (y-or-n-p "Include thumbnail? " ) + (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Thumbnail")) + (read-string "Title: ") + (read-string "Description: ") + ))) + (unless thumbsrc (setq thumbsrc imgsrc)) + (let ((gallery (nxhtml-smoothgallery-find))) + (unless gallery + (setq gallery (nxhtml-smoothgallery-add nil))) + (goto-char (car gallery)) + (end-of-line) + (insert-and-indent " + <div class=\"imageElement\"> + <h3>" title "</h3> + <p>" description "</p> + <a href=\"#\" title=\"open image\" class=\"open\"></a> + <img src=\"" imgsrc "\" class=\"full\" alt=\"" title "\" /> + <img src=\"" thumbsrc "\" class=\"thumbnail\" alt=\"" title " (thumbnail)\" /> + </div>") +;; (when (file-exists-p src) +;; (let ((sizes (image-size (create-image src) t))) +;; (insert +;; " width=\"" (format "%d" (car sizes)) "\"" +;; " height=\"" (format "%d" (cdr sizes)) "\"") +;; )) + )) + +(defun insert-and-indent (&rest lines) + (let ((lines (split-string (apply 'concat lines) "[\n\r]"))) + (dolist (line lines) + (insert "\n" line) + (indent-according-to-mode)))) + + +(provide 'nxhtml-js) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtml-js.el ends here diff --git a/emacs/nxhtml/nxhtml/nxml-where.el b/emacs/nxhtml/nxhtml/nxml-where.el new file mode 100644 index 0000000..8c171d4 --- /dev/null +++ b/emacs/nxhtml/nxhtml/nxml-where.el @@ -0,0 +1,734 @@ +;;; nxml-where.el --- Show XML path +;; +;; Author: Lennart Borgman +;; Maintainer: +;; Created: Tue Dec 19 14:59:01 2006 +(defconst nxml-where:version "0.52");; Version: +;; Lxast-Updated: Thu Mar 01 23:16:35 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `cl'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;; This buffer is for notes you don't want to save, and for Lisp evaluation. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'nxml-mode nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) +;; (eval-when-compile +;; (unless (featurep 'nxhtml-autostart) +;; (let ((efn (expand-file-name "../autostart.el"))) +;; (load efn)) +;; (require 'nxml-mode))) + +(defun nxml-where-error-message (format-string &rest args) + (with-current-buffer (get-buffer-create "*Messages*") + (let ((start (1+ (point-max)))) + (apply 'message format-string args) + (goto-char (point-max)) + (backward-char) + ;; fix-me: got some error here: + ;;(put-text-property start (point) 'face 'highlight) + ))) + +(defvar nxml-where-last-point nil + "Where point was last time marking finished. +Ie we should not restart marking if point is still there and no +changes have occured.") +(make-variable-buffer-local 'nxml-where-last-point) +(put 'nxml-where-last-point 'permanent-local t) + +(defvar nxml-where-last-finished nil + "Non-nil then marking is finished.") +(make-variable-buffer-local 'nxml-where-last-finished) +(put 'nxml-where-last-finished 'permanent-local t) + +(defvar nxml-where-last-added nil) +(make-variable-buffer-local 'nxml-where-last-added) +(put 'nxml-where-last-added 'permanent-local t) + +(defvar nxml-where-path nil + "The current where path. +This is a list where the records have the form + + \(START END TAG-STR OVERLAY)") +(make-variable-buffer-local 'nxml-where-path) +(put 'nxml-where-path 'permanent-local t) + +(defvar nxml-where-new-path nil + "The new where path. +This is a list where the records have the form + + \(START END TAG-STR OVERLAY)") +(make-variable-buffer-local 'nxml-where-new-path) +(put 'nxml-where-new-path 'permanent-local t) + +(defvar nxml-where-once-update-timer nil) +(make-variable-buffer-local 'nxml-where-once-update-timer) +(put 'nxml-where-once-update-timer 'permanent-local t) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Custom options + +;;;###autoload +(defgroup nxml-where nil + "Customization group for nxml-where." + :group 'nxhtml + :group 'nxml) + +;;(define-toggle nxml-where-only-inner nil +(define-minor-mode nxml-where-only-inner + "Mark only inner-most tag." + :global t + :group 'nxml-where + (when (fboundp 'nxml-where-update-buffers) + (nxml-where-update-buffers))) + +(defun nxml-where-only-inner-toggle () + "Toggle `nxml-where-only-inner'." + (interactive) + (nxml-where-only-inner (if nxml-where-only-inner -1 1))) + +;;(define-toggle nxml-where-header t +(define-minor-mode nxml-where-header + "Show header with XML-path if non-nil." + :global t + :init-value t + :group 'nxml-where + (when (fboundp 'nxml-where-update-buffers) + (nxml-where-update-buffers))) + +(defun nxml-where-header-toggle () + "Toggle `nxml-where-header'." + (interactive) + (nxml-where-header (if nxml-where-header -1 1))) + +;;(define-toggle nxml-where-tag+id t +(define-minor-mode nxml-where-tag+id + "Show tags + id in path if non-nil. +If nil show only tag names." + :global t + :init-value t + :group 'nxml-where + (when (fboundp 'nxml-where-update-buffers) + (nxml-where-update-buffers))) + +(defun nxml-where-tag+id-toggle () + "Toggle `nxml-where-tag+id'." + (interactive) + (nxml-where-tag+id (if nxml-where-tag+id -1 1))) + +;;(define-toggle nxml-where-marks t +(define-minor-mode nxml-where-marks + "Show marks in buffer for XML-path if non-nil." + :global t + :init-value t + :group 'nxml-where + (when (fboundp 'nxml-where-update-buffers) + (nxml-where-update-buffers))) + +(defun nxml-where-marks-toggle () + "Toggle `nxml-where-marks'." + (interactive) + (nxml-where-marks (if nxml-where-marks -1 1))) + +;; Fix-me: implement this? +;; (define-toggle nxml-where-only-tags-with-id t +;; "Show only tags with id in the header line." +;; :set (lambda (sym val) +;; (set-default sym val) +;; (when (fboundp 'nxml-where-update-buffers) +;; (nxml-where-update-buffers))) +;; :group 'nxml-where) + +(defface nxml-where-marking + '((t (:inherit secondary-selection))) + "The default face used for marking tags in path." + :group 'nxml-where) + +(defcustom nxml-where-marking 'nxml-where-marking + "Variable pointing to the face used for marking tags in path." + :type 'face + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'nxml-where-update-buffers) + (nxml-where-update-buffers))) + :group 'nxml-where) + +(defcustom nxml-where-header-attributes '("id" "name") + "List of attributes `nxml-where-header' should display." + :type '(repeat string) + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'nxml-where-update-buffers) + (nxml-where-update-buffers))) + :group 'nxml-where) + +(defcustom nxml-where-widen t + "If non-nil and narrowed widen before getting XML path." + :type 'boolean + :group 'nxml-where) + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Modes + +(defvar nxml-where-modes '(nxml-mode nxhtml-mode)) + +(defun nxml-where-is-nxml () + (or (derived-mode-p 'nxml-mode) + (and (featurep 'mumamo) + mumamo-multi-major-mode + (let ((major-mode (mumamo-main-major-mode))) + (derived-mode-p 'nxml-mode))))) + +(defun nxml-where-setup-updating () + (nxml-where-clear-old-path 0 "setup") + (setq nxml-where-last-added nil) + (setq nxml-where-last-point nil) + (when (and nxml-where-header + (not nxml-where-only-inner)) + (setq header-line-format "Started nxml-where-mode ...")) + ;;(nxml-where-restart-update) + (add-hook 'post-command-hook 'nxml-where-restart-update nil t)) + +(defun nxml-where-mode-start () + ;;(message "START") + (unless (nxml-where-is-nxml) + (error "Can't display XML path since major mode is not nxml-mode child.")) + (add-hook 'after-change-major-mode-hook 'nxml-where-turn-off-unless-nxml nil t) + (add-hook 'after-change-functions 'nxml-where-after-change nil t) + (nxml-where-save-header-line-format) + (nxml-where-setup-updating)) + +(defun nxml-where-mode-stop () + ;;(message "STOP") + (remove-hook 'after-change-major-mode-hook 'nxml-where-turn-off-unless-nxml t) + (remove-hook 'after-change-functions 'nxml-where-after-change t) + (nxml-where-stop-updating) + (nxml-where-unmark-forward-element) + (nxml-where-restore-header-line-format) + (nxml-where-clear-old-path 0 "stop")) + +(defun nxml-where-turn-off-unless-nxml () + (unless (nxml-where-is-nxml) + (nxml-where-mode-stop))) +(put 'nxml-where-turn-off-unless-nxml 'permanent-local-hook t) + +;;;###autoload +(define-minor-mode nxml-where-mode + "Shows path in mode line." + :global nil + :group 'nxml-where + (if nxml-where-mode + ;;Turn it on + (nxml-where-mode-start) + ;; Turn it off + (nxml-where-mode-stop) + )) +(put 'nxml-where-mode 'permanent-local t) + +(defun nxml-where-turn-on-in-nxml-child () + "Turn on `nxml-where-mode' if possible. +This is possible if `major-mode' in the buffer is derived from +`nxml-mode'." + (when (or (derived-mode-p 'nxml-mode) + (and mumamo-multi-major-mode + (let ((major-mode (mumamo-main-major-mode))) + (derived-mode-p 'nxml-mode)))) + (unless nxml-where-mode + (nxml-where-mode 1)))) + +;;;###autoload +(define-globalized-minor-mode nxml-where-global-mode nxml-where-mode + nxml-where-turn-on-in-nxml-child + :group 'nxml-where) +;; The problem with global minor modes: +(when (and nxml-where-global-mode + (not (boundp 'define-global-minor-mode-bug))) + (nxml-where-global-mode 1)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Auto updating + +(defvar nxhtml-where-hook nil + "Normal hook run when marking has changed.") + +(defun nxml-where-start-update-in-timer (buffer) + "First checks post command." + ;;(message "nxml-where-start-update buffer=%s (bufferp buffer)=%s" buffer (bufferp buffer)) + (when (and (bufferp buffer) + (buffer-live-p buffer)) + (with-current-buffer buffer + (let ((here (point))) + (save-match-data + (condition-case err + (progn + ;;(unless nxml-where-marks (nxml-where-clear-old-path)) + (unless (and nxml-where-header + (not nxml-where-only-inner)) + (setq header-line-format nil)) + (when (and nxml-where-mode + (or nxml-where-header nxml-where-marks)) + (nxml-where-do-marking nil buffer))) + (error + (nxml-where-error-message + "nxml-where-start-update-in-timer error: %s" err))) + (goto-char here)))))) + +(defun nxml-where-continue-marking-in-timer (this-point buffer) + "Continue unfinished marking after last restart. +Ie we have run at least once post command." + ;;(message "continue-marking-in-timer %s %s" this-point buffer) + (with-current-buffer buffer + (let ((here (point))) + (condition-case err + (save-match-data ;; runs in timer + (nxml-where-do-marking this-point buffer)) + (error + (nxml-where-error-message + "nxml-where-do-marking error: %s" + err))) + (goto-char here)))) + +(defun nxml-where-start-continue-in-timer (next-point buffer) + ;;(message "start second") + (condition-case err + (setq nxml-where-once-update-timer + (run-with-idle-timer idle-update-delay + nil + 'nxml-where-continue-marking-in-timer + next-point + buffer)) + (error + (nxml-where-error-message + "nxml-where-start-second error %s" err)))) + +(defun nxml-where-restart-update () + "Restart update, runs in `post-command-hook'." + ;;(message "restart-update") + (condition-case err + (save-match-data ;; runs in timer + (unless (and nxml-where-last-point + (= nxml-where-last-point (point))) + (setq nxml-where-last-point nil) + (setq nxml-where-last-finished nil) + (nxml-where-cancel-once) + (setq nxml-where-once-update-timer + (run-with-idle-timer + (* 0.2 idle-update-delay) + nil + 'nxml-where-start-update-in-timer + (current-buffer))))) + (error + (nxml-where-error-message + "%s" (error-message-string err))))) +(put 'nxml-where-restart-update 'permanent-local-hook t) + +(defvar nxml-where-first-change-pos nil) +(make-variable-buffer-local 'nxml-where-first-change-pos) +(put 'nxml-where-first-change-pos 'permanent-local t) + +(defun nxml-where-after-change (beg end len) + (setq nxml-where-last-point nil) + (setq nxml-where-first-change-pos + (min beg + (or nxml-where-first-change-pos + beg)))) + +(defun nxml-where-cancel-once () + (when (timerp nxml-where-once-update-timer) + (cancel-timer nxml-where-once-update-timer) + (setq nxml-where-once-update-timer nil))) + +(defun nxml-where-update-buffers () + (when (boundp 'nxml-where-mode) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when nxml-where-mode + (nxml-where-mode -1) + (nxml-where-mode 1)))))) + +(defun nxml-where-stop-updating () + (remove-hook 'post-command-hook 'nxml-where-restart-update t)) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Marking + +(defconst nxml-where-get-id-pattern + (rx-to-string + `(and + space + ,(cons 'or nxml-where-header-attributes) + (0+ space) + ?= + (0+ space) + ?\" + (0+ (not (any ?\"))) + ?\") + t)) + +(defvar nxml-where-tag+id-pattern + (rx ?< + (submatch + (1+ (char "-a-z0-9:")) + ) + (0+ (1+ space) + (1+ (any "a-z")) + (0+ space) + ?= + (0+ space) + ?\" + (0+ (not (any ?\"))) + ?\" + ) + (0+ space) + (opt ?/) + ?>)) + + +(defvar nxml-where-forward-element nil) +(make-variable-buffer-local 'nxml-where-forward-element) +(put 'nxml-where-forward-element 'permanent-local t) + +(defun nxml-where-unmark-forward-element () + "Unmark currently marked end tag." + (when nxml-where-forward-element + (let* ((ovl (nth 1 nxml-where-forward-element)) + (str (when ovl (buffer-substring-no-properties (overlay-start ovl) (overlay-end ovl))))) + (when (overlayp ovl) + ;;(message "unmark-forward-element:delete-overlay %s %s" str ovl) + (delete-overlay ovl))) + (setq nxml-where-forward-element nil))) + +(defun nxml-where-mark-forward-element (start-tag) + "Mark the end tag matching START-TAG." + ;;(message "nxml-where-forward-element=%s" nxml-where-forward-element) + (unless (and start-tag + nxml-where-forward-element + (nth 1 nxml-where-forward-element) + (= (nth 0 nxml-where-forward-element) + start-tag)) + ;;(message "before unmark") + (nxml-where-unmark-forward-element) + ;;(message "after unmark") + (when start-tag + (let ((here (point)) + (end-of-narrow + (progn + (goto-char start-tag) + (line-end-position 4))) + start end ovl) + ;; Fix-me: Narrow how much? + (setq end-of-narrow (max (+ 4000 (window-end)) + end-of-narrow)) + (setq end-of-narrow (min (point-max) + end-of-narrow)) + (save-restriction + (narrow-to-region start-tag end-of-narrow) + (condition-case err + (progn + (goto-char start-tag) + (nxml-forward-element) + (when (looking-back "</[a-z0-9]+>") + (setq start (match-beginning 0)) + (setq end (point)) + (setq ovl (make-overlay start end)) + (overlay-put ovl 'nxml-where t) + (overlay-put ovl 'face nxml-where-marking))) + (error + (let ((msg (error-message-string err))) + (unless (string= msg "Start-tag has no end-tag") + (message "nxml-where-mark-forw: %s" msg)))))) + (goto-char here) + ;;(message "point 2 = %s" (point)) + (setq nxml-where-forward-element (list start-tag ovl)))))) + + +(defun nxml-where-make-rec (tag-start tag-end tag-str buf) + ;;(message "nxml-where-make-rec %s %s %s %s" tag-start tag-end tag-str buf) + (let ((ovls (overlays-at tag-start)) + str) + (dolist (ovl ovls) + (when (overlay-get ovl 'nxml-where) + (setq str (buffer-substring-no-properties (overlay-start ovl) (overlay-end ovl))) + (message "==================================================") + (nxml-where-error-message "old ovl=%s %S" ovl str) + (message "old: nxml-where-path=%s" nxml-where-path) + (message "old: nxml-where-new-path=%s" nxml-where-new-path) + ))) + (let ((ovl (when buf (make-overlay tag-start tag-end)))) + (when ovl + (overlay-put ovl 'nxml-where t) + (overlay-put ovl 'face nxml-where-marking)) + (list tag-start tag-end tag-str ovl))) + +(defun nxml-where-delete-rec (rec from) + (let* ((ovl (nth 3 rec)) + (str (when ovl + (buffer-substring-no-properties (overlay-start ovl) (overlay-end ovl))))) + (when (and ovl (overlay-buffer ovl)) + (assert (overlayp ovl) t) + ;;(message "delete-rec:delete-overlay %s %s (%s)" str ovl from) + (delete-overlay ovl) + ;;(message "after delete=%s" ovl) + ))) + + +(defun nxml-where-clear-old-path (end-of-interest from) + "Clear all marking below END-OF-INTEREST. +Update `nxml-where-path accordingly." + (setq nxml-where-last-added nil) + ;;(message "++++++ clear A: %s (%s)" end-of-interest from) + (setq nxml-where-path (cons 'dummy nxml-where-path)) + (let ((path nxml-where-path)) + ;;(message "path 1=%s" path) + (while (cdr path) + ;;(message "path 2=%s" path) + (when (> (nth 1 (cadr path)) end-of-interest) + (dolist (p (cdr path)) + (nxml-where-delete-rec p "clear")) + (setcdr path nil)) + (setq path (cdr path)))) + (setq nxml-where-path (cdr nxml-where-path))) + +(defun nxml-where-clear-new-path () + (dolist (new nxml-where-new-path) + (nxml-where-delete-rec new "clear new")) + (setq nxml-where-new-path nil) + ;;(message "clear B:nxml-where-path=%s" nxml-where-path) + ) + + +(defun nxml-where-update-where-path (tag-start tag-end tag-str buffer) + "Update where path with given tag. +The tag is between TAG-START and TAG-END and the string to +display for it in the header-line is TAG-STR. This is in buffer +BUFFER." + ;; Delete old marks below tag-start: + (nxml-where-clear-old-path (+ tag-end 0) (format "update-where-path, tag-start=%s" tag-start)) + ;; Is this now the same as the old value? + (let ((last-old (last nxml-where-path)) + new-rec + result) + ;;(message "update: %s %s %s %s, last-old=%s" tag-start tag-end tag-str buffer last-old) + (if (and last-old + (= tag-start (nth 0 (car last-old))) + (= tag-end (nth 1 (car last-old)))) + (progn + (setq result 'ready)) + (when nxml-where-only-inner + ;;(message "last-old=%S, nwp=%S, nwnp=%S" last-old nxml-where-path nxml-where-new-path) + (setq last-old (car (last nxml-where-path))) + (when last-old + (setq nxml-where-path nil) + (nxml-where-delete-rec last-old "only-inner"))) + (setq new-rec (nxml-where-make-rec tag-start tag-end tag-str buffer)) + (setq nxml-where-last-added new-rec) + (setq nxml-where-new-path (cons new-rec nxml-where-new-path)) + (setq result 'continue)) + result)) + +(defun nxml-where-do-marking (this-point buffer) + "Do marking. +If THIS-POINT is nil then it is the first marking post command in +buffer BUFFER. In that case start from current point, otherwise +from THIS-POINT. + +Go up to previous tag. Then check if this is the same tag where +we started last time and ran to completion. If so just finish. + +Otherwise check this tag. If not ready after that then restart +this command with arg THIS-POINT set to right before this tag." + ;;(message "****************nxml-where-do-marking %s %s, point=%s" this-point buffer (point)) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (save-restriction + (when nxml-where-widen (widen)) + (let ((here (point)) + next-point + (is-first (not this-point)) + (end-of-interest (if nxml-where-first-change-pos + (min (point) nxml-where-first-change-pos) + ;; Check for tag at point + (catch 'eoi + (let (ovl) + (dolist (ovl (overlays-at (point))) + (when (overlay-get ovl 'nxml-where) + (throw 'eoi (overlay-end ovl))))) + (point))))) + ;; If on beginning of tag step forward one char. + (unless (or (eobp) + this-point + (not (eq ?< (char-after)))) + (forward-char)) + (when this-point (goto-char this-point)) + (setq next-point + (catch 'cnext-point + (progn + (condition-case err + (nxml-backward-up-element) + (error + (if (equal err '(error "No parent element")) + (let (rec) + ;;(message "------------ No parent element") + (dolist (rec nxml-where-path) + (nxml-where-delete-rec rec "no parent")) + (setq nxml-where-path nil) + (throw 'cnext-point nil)) ;; <---- remember... + (nxml-where-error-message "nxml-where error: %S" err) + (throw 'cnext-point "uh?")))) + ;; Is this the first call + ;;(message ";; Is this the first call, %s" is-first) + (when is-first + (when (and nxml-where-path + nxml-where-last-finished + (= (point) (caar (last nxml-where-path)))) + (throw 'cnext-point 'same-as-last)) + ;;(setq nxml-where-new-path nil) + (setq nxml-where-last-added nil) + ;; Delete those parts we can't trust or don't + ;; need any more. Fix-me, Note: this is different + ;; dependent on if some buffer changes occured. + (nxml-where-clear-old-path end-of-interest (format "is-first,p=%s" (point))) + (nxml-where-clear-new-path)) + ;;(message "looking-at") + (when (looking-at nxml-where-tag+id-pattern) + (let ((start (point)) + (end (match-end 0)) + (tag (match-string-no-properties 1)) + (all (match-string-no-properties 0))) + (when nxml-where-tag+id + (when (string-match nxml-where-get-id-pattern all) + (setq tag (concat tag (match-string 0 all))))) + (setq tag (concat "<" tag ">")) + (when (or (eq 'ready + (nxml-where-update-where-path start end tag t)) + nxml-where-only-inner) + ;;(message "throw 'cp nil") + (throw 'cnext-point nil)))) + (throw 'cnext-point (max (1- (point)) (point-min)))))) + (goto-char here) + (if next-point + (cond + ((stringp next-point) (message "%s" next-point) ;; Some error + (when nxml-where-header (setq header-line-format next-point))) + ((eq 'same-as-last next-point) + nil) + (t + (unless nxml-where-only-inner + (setq nxml-where-once-update-timer + (run-with-timer (* 0.2 idle-update-delay) + nil + 'nxml-where-start-continue-in-timer + next-point (current-buffer)))))) + (if nxml-where-path + (setcdr (last nxml-where-path) nxml-where-new-path) + (setq nxml-where-path nxml-where-new-path)) + (setq nxml-where-new-path nil) + ;;(message "nxml-where-path=%s" nxml-where-path) + (nxml-where-mark-forward-element (caar (last nxml-where-path))) + (setq nxml-where-last-finished t) + (setq nxml-where-first-change-pos nil) + (run-hooks 'nxhtml-where-hook) + (setq nxml-where-last-point (point)) + (when (and nxml-where-header + (not nxml-where-only-inner)) + (nxml-where-insert-header)))))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Header path + +(defun nxml-where-insert-header () + (let ((path (mapcar (lambda (elt) + (nth 2 elt)) + nxml-where-path))) + (unless path + (setq path (list (if (looking-at "[[:space:]]*\\'") + "(After last tag)" + "(Before first tag)")))) + (if (null path) + (setq path " *Error* ") + ;; Throw away <html> + (let* ((first (car path)) + (html "<html") + (hlen (length html))) + (when (and (> (length first) hlen) + (string= html (substring first 0 hlen))) + (setq path (cdr path)))) + (unless path + (setq path (list "(At html start)")))) + (let* ((sp (substring (format "%s" path) 1 -1)) + (label " Path: ") + (totlen (+ (length sp) (length label))) + header) + (when (> totlen (window-width)) + (setq sp (concat "... " + (substring sp (+ (- totlen (window-width)) + 4))))) + (setq header (concat label sp)) + (when nxml-where-header + (setq header-line-format header))))) + +(defvar nxml-where-saved-header-line-format nil) +(make-variable-buffer-local 'nxml-where-saved-header-line-format) +(put 'nxml-where-saved-header-line-format 'permanent-local t) + +(defun nxml-where-save-header-line-format () + (unless nxml-where-saved-header-line-format + (setq nxml-where-saved-header-line-format header-line-format))) + +(defun nxml-where-restore-header-line-format () + (setq header-line-format nxml-where-saved-header-line-format)) + + + +(provide 'nxml-where) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxml-where.el ends here diff --git a/emacs/nxhtml/nxhtml/outline-magic.el b/emacs/nxhtml/nxhtml/outline-magic.el new file mode 100644 index 0000000..5b800ed --- /dev/null +++ b/emacs/nxhtml/nxhtml/outline-magic.el @@ -0,0 +1,588 @@ +;;; outline-magic.el --- outline mode extensions for Emacs + +;; Copyright (C) 2002 Carsten Dominik <dominik@science.uva.nl> + +;; Maintainer: Carsten Dominik <dominik@science.uva.nl> +;; Version: 0.9 +;; Keywords: outlines + +;; This file is not 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: + +;; This file implements extensions for outline(-minor)-mode. +;; +;; - VISIBILITY CYCLING: A *single* command to replace the many +;; outline commands for showing and hiding parts of a document. +;; +;; - STRUCTURE EDITING: Promotion, demotion and transposition of subtrees. +;; +;; Installation +;; ============ +;; +;; Byte-compile outline-magic.el, put it on the load path and copy the +;; following into .emacs (adapting keybindings to your own preferences) +;; +;; (add-hook 'outline-mode-hook +;; (lambda () +;; (require 'outline-cycle))) +;; +;; (add-hook 'outline-minor-mode-hook +;; (lambda () +;; (require 'outline-magic) +;; (define-key outline-minor-mode-map [(f10)] 'outline-cycle))) +;; +;; Usage +;; ===== +;; +;; Visibility cycling +;; ------------------ +;; +;; The command `outline-cycle' changes the visibility of text and headings +;; in the buffer. Instead of using many different commands to show and +;; hide buffer parts, `outline-cycle' cycles through the most important +;; states of an outline buffer. In the major `outline-mode', it will be +;; bound to the TAB key. In `outline-minor-mode', the user can choose a +;; different keybinding. The action of the command depends on the current +;; cursor location: +;; +;; 1. When point is at the beginning of the buffer, `outline-cycle' +;; cycles the entire buffer through 3 different states: +;; - OVERVIEW: Only top-level headlines are shown. +;; - CONTENTS: All headlines are shown, but no body text. +;; - SHOW ALL: Everything is shown. +;; +;; 2. When point in a headline, `outline-cycle' cycles the subtree started +;; by this line through the following states: +;; - FOLDED: Only the headline is shown. +;; - CHILDREN: The headline and its direct children are shown. From +;; this state, you can move to one of the children and +;; zoom in further. +;; - SUBTREE: The entire subtree under the heading is shown. +;; +;; 3. At other positions, `outline-cycle' jumps back to the current heading. +;; It can also be configured to emulate TAB at those positions, see +;; the option `outline-cycle-emulate-tab'. +;; +;; Structure editing +;; ----------------- +;; +;; Four commands are provided for structure editing. The commands work on +;; the current subtree (the current headline plus all inferior ones). In +;; addition to menu access, the commands are assigned to the four arrow +;; keys pressed with a modifier (META by default) in the following way: +;; +;; move up +;; ^ +;; promote <- | -> demote +;; v +;; move down +;; +;; Thus, M-left will promote a subtree, M-up will move it up +;; vertically throught the structure. Configure the variable +;; `outline-structedit-modifiers' to use different modifier keys. +;; +;; Moving subtrees +;; - - - - - - - - +;; The commands `outline-move-subtree-up' and `outline-move-subtree-down' +;; move the entire current subtree (folded or not) past the next same-level +;; heading in the given direction. The cursor moves with the subtree, so +;; these commands can be used to "drag" a subtree to the wanted position. +;; For example, `outline-move-subtree-down' applied with the cursor at the +;; beginning of the "* Level 1b" line will change the tree like this: +;; +;; * Level 1a * Level 1a +;; * Level 1b ===\ * Level 1c +;; ** Level 2b ===/ * Level 1b +;; * Level 1c ** Level 2b +;; +;; Promotion/Demotion +;; - - - - - - - - - - +;; The commands `outline-promote' and `outline-demote' change the current +;; subtree to a different outline level - i.e. the level of all headings in +;; the tree is decreased or increased. For example, `outline-demote' +;; applied with the cursor at the beginning of the "* Level 1b" line will +;; change the tree like this: +;; +;; * Level 1a * Level 1a +;; * Level 1b ===\ ** Level 1b +;; ** Level 2b ===/ *** Level 2 +;; * Level 1c * Level 1c +;; +;; The reverse operation is `outline-promote'. Note that the scope of +;; "current subtree" may be changed after a promotion. To change all +;; headlines in a region, use transient-mark-mode and apply the command to +;; the region. +;; +;; NOTE: Promotion/Demotion in complex outline setups +;; - - - - - - - - - - - - - - - - - - - - - - - - - - +;; Promotion/demotion works easily in a simple outline setup where the +;; indicator of headings is just a polymer of a single character (e.g. "*" +;; in the default outline mode). It can also work in more complicated +;; setups. For example, in LaTeX-mode, sections can be promoted to +;; chapters and vice versa. However, the outline setup for the mode must +;; meet two requirements: +;; +;; 1. `outline-regexp' must match the full text which has to be changed +;; during promotion/demotion. E.g. for LaTeX, it must match "\chapter" +;; and not just "\chap". Major modes like latex-mode, AUCTeX's +;; latex-mode and texinfo-mode do this correctly. +;; +;; 2. The variable `outline-promotion-headings' must contain a sorted list +;; of headings as matched by `outline-regexp'. Each of the headings in +;; `outline-promotion-headings' must be matched by `outline-regexp'. +;; `outline-regexp' may match additional things - those matches will be +;; ignored by the promotion commands. If a mode has multiple sets of +;; sectioning commands (for example the texinfo-mode with +;; chapter...subsubsection and unnumbered...unnumberedsubsubsec), the +;; different sets can all be listed in the same list, but must be +;; separated by nil elements to avoid "promotion" accross sets. +;; Examples: +;; +;; (add-hook 'latex-mode-hook ; or 'LaTeX-mode-hook for AUCTeX +;; (lambda () +;; (setq outline-promotion-headings +;; '("\\chapter" "\\section" "\\subsection" +;; "\\subsubsection" "\\paragraph" "\\subparagraph")))) +;; +;; (add-hook 'texinfo-mode-hook +;; (lambda () +;; (setq outline-promotion-headings +;; '("@chapter" "@section" "@subsection" "@subsubsection" nil +;; "@unnumbered" "@unnumberedsec" "@unnumberedsubsec" +;; "@unnumberedsubsubsec" nil +;; "@appendix" "@appendixsec" "@appendixsubsec" +;; "@appendixsubsubsec" nil +;; "@chapheading" "@heading" "@subheading" "@subsubheading")))) +;; +;; If people find this useful enough, maybe the maintainers of the +;; modes can be persuaded to set `outline-promotion-headings' +;; already as part of the mode setup. +;; +;; Compatibility: +;; -------------- +;; outline-magic was developed to work with the new outline.el +;; implementation which uses text properties instead of selective display. +;; If you are using XEmacs which still has the old implementation, most +;; commands will work fine. However, structure editing commands will +;; require all relevant headlines to be visible. +;; +;; History +;; ------- +;; - Before first header now works as at beginning of file +;; - Two levels are shown for contents. +;; +;;; Code: + +(require 'outline) + +;;; Visibility cycling + +(defcustom outline-cycle-emulate-tab nil + "Where should `outline-cycle' emulate TAB. +nil Never +white Only in completely white lines +t Everywhere except in headlines" + :group 'outlines + :type '(choice (const :tag "Never" nil) + (const :tag "Only in completely white lines" white) + (const :tag "Everywhere except in headlines" t) + )) + +(defvar outline-promotion-headings nil + "A sorted list of headings used for promotion/demotion commands. +Set this to a list of headings as they are matched by `outline-regexp', +top-level heading first. If a mode or document needs several sets of +outline headings (for example numbered and unnumbered sections), list +them set by set, separated by a nil element. See the example for +`texinfo-mode' in the file commentary.") +(make-variable-buffer-local 'outline-promotion-headings) + +(defun outline-cycle (&optional arg) + "Visibility cycling for outline(-minor)-mode. + +- When point is at the beginning of the buffer, or when called with a + C-u prefix argument, rotate the entire buffer through 3 states: + 1. OVERVIEW: Show only top-level headlines. + 2. CONTENTS: Show all headlines of all levels, but no body text. + 3. SHOW ALL: Show everything. + +- When point is at the beginning of a headline, rotate the subtree started + by this line through 3 different states: + 1. FOLDED: Only the main headline is shown. + 2. CHILDREN: The main headline and the direct children are shown. From + this state, you can move to one of the children and + zoom in further. + 3. SUBTREE: Show the entire subtree, including body text. + +- When point is not at the beginning of a headline, execute + `indent-relative', like TAB normally does." + (interactive "P") + (setq deactivate-mark t) + (cond + + ((equal arg '(4)) + ; Run `outline-cycle' as if at the top of the buffer. + (save-excursion + (goto-char (point-min)) + (outline-cycle nil))) + + (t + (cond + ((or (bobp) ;; Beginning of buffer: Global cycling + (let ((here (point)) + (atbobp t)) + (condition-case err + (progn + (outline-back-to-heading) + (setq atbobp nil)) + (error nil)) + atbobp)) + + (cond + ((eq last-command 'outline-cycle-overview) + ;; We just created the overview - now do table of contents + ;; This can be slow in very large buffers, so indicate action + (message "CONTENTS...") + (save-excursion + ;; Visit all headings and show their offspring + (goto-char (point-max)) + (catch 'exit + (while (and (progn (condition-case nil + (outline-previous-visible-heading 1) + (error (goto-char (point-min)))) + t) + (looking-at outline-regexp)) + (show-branches) + (if (bobp) (throw 'exit nil)))) + (message "CONTENTS...done")) + (setq this-command 'outline-cycle-toc)) + ((eq last-command 'outline-cycle-toc) + ;; We just showed the table of contents - now show everything + (show-all) + (message "SHOW ALL") + (setq this-command 'outline-cycle-showall)) + (t + ;; Default action: go to overview + ;; FIX-ME: variable sublevel here (for wikipedia for example): + (hide-sublevels 2) + (message "OVERVIEW") + (setq this-command 'outline-cycle-overview)))) + + ((save-excursion (beginning-of-line 1) (looking-at outline-regexp)) + ;; At a heading: rotate between three different views + (outline-back-to-heading) + (let ((goal-column 0) beg eoh eol eos) + ;; First, some boundaries + (save-excursion + (outline-back-to-heading) (setq beg (point)) + (save-excursion (outline-next-line) (setq eol (point))) + (outline-end-of-heading) (setq eoh (point)) + (outline-end-of-subtree) (setq eos (point))) + ;; Find out what to do next and set `this-command' + (cond + ((= eos eoh) + ;; Nothing is hidden behind this heading + (message "EMPTY ENTRY")) + ((>= eol eos) + ;; Entire subtree is hidden in one line: open it + (show-entry) + (show-children) + (message "CHILDREN") + (setq this-command 'outline-cycle-children)) + ((eq last-command 'outline-cycle-children) + ;; We just showed the children, now show everything. + (show-subtree) + (message "SUBTREE")) + (t + ;; Default action: hide the subtree. + (hide-subtree) + (message "FOLDED"))))) + + ;; TAB emulation + ((outline-cycle-emulate-tab) + (indent-relative)) + + (t + ;; Not at a headline: Do indent-relative + (outline-back-to-heading)))))) + +(defun outline-cycle-emulate-tab () + "Check if TAB should be emulated at the current position." + ;; This is called after the check for point in a headline, + ;; so we can assume we are not in a headline + (if (and (eq outline-cycle-emulate-tab 'white) + (save-excursion + (beginning-of-line 1) (looking-at "[ \t]+$"))) + t + outline-cycle-emulate-tab)) + +(defun outline-next-line () + "Forward line, but mover over invisible line ends. +Essentially a much simplified version of `next-line'." + (interactive) + (beginning-of-line 2) + (while (and (not (eobp)) + (get-char-property (1- (point)) 'invisible)) + (beginning-of-line 2))) + +;;; Vertical tree motion + +(defun outline-move-subtree-up (&optional arg) + "Move the currrent subtree up past ARG headlines of the same level." + (interactive "p") + (outline-move-subtree-down (- arg))) + +(defun outline-move-subtree-down (&optional arg) + "Move the currrent subtree down past ARG headlines of the same level." + (interactive "p") + (let ((re (concat "^" outline-regexp)) + (movfunc (if (> arg 0) 'outline-get-next-sibling + 'outline-get-last-sibling)) + (ins-point (make-marker)) + (cnt (abs arg)) + beg end txt) + ;; Select the tree + (outline-back-to-heading) + (setq beg (point)) + (outline-end-of-subtree) + (if (= (char-after) ?\n) (forward-char 1)) + (setq end (point)) + ;; Find insertion point, with error handling + (goto-char beg) + (while (> cnt 0) + (or (funcall movfunc) + (progn (goto-char beg) + (error "Cannot move past superior level"))) + (setq cnt (1- cnt))) + (if (> arg 0) + ;; Moving forward - still need to move over subtree + (progn (outline-end-of-subtree) + (if (= (char-after) ?\n) (forward-char 1)))) + (move-marker ins-point (point)) + (setq txt (buffer-substring beg end)) + (delete-region beg end) + (insert txt) + (goto-char ins-point) + (move-marker ins-point nil))) + +;;; Promotion and Demotion + +(defun outline-promote (&optional arg) + "Decrease the level of an outline-structure by ARG levels. +When the region is active in transient-mark-mode, all headlines in the +region are changed. Otherwise the current subtree is targeted. Note that +after each application of the command the scope of \"current subtree\" +may have changed." + (interactive "p") + (outline-change-level (- arg))) + + +(defun outline-demote (&optional arg) + "Increase the level of an outline-structure by ARG levels. +When the region is active in transient-mark-mode, all headlines in the +region are changed. Otherwise the current subtree is targeted. Note that +after each application of the command the scope of \"current subtree\" +may have changed." + (interactive "p") + (outline-change-level arg)) + +(defun outline-change-level (delta) + "Workhorse for `outline-demote' and `outline-promote'." + (let* ((headlist (outline-headings-list)) + (atom (outline-headings-atom headlist)) + (re (concat "^" outline-regexp)) + (transmode (and transient-mark-mode mark-active)) + beg end) + + ;; Find the boundaries for this operation + (save-excursion + (if transmode + (setq beg (min (point) (mark)) + end (max (point) (mark))) + (outline-back-to-heading) + (setq beg (point)) + (outline-end-of-heading) + (outline-end-of-subtree) + (setq end (point))) + (setq beg (move-marker (make-marker) beg) + end (move-marker (make-marker) end)) + + (let (head newhead level newlevel static) + + ;; First a dry run to test if there is any trouble ahead. + (goto-char beg) + (while (re-search-forward re end t) + (outline-change-heading headlist delta atom 'test)) + + ;; Now really do replace the headings + (goto-char beg) + (while (re-search-forward re end t) + (outline-change-heading headlist delta atom)))))) + +(defun outline-headings-list () + "Return a list of relevant headings, either a user/mode defined +list, or an alist derived from scanning the buffer." + (let (headlist) + (cond + (outline-promotion-headings + ;; configured by the user or the mode + (setq headlist outline-promotion-headings)) + + ((and (eq major-mode 'outline-mode) (string= outline-regexp "[*\^L]+")) + ;; default outline mode with original regexp + ;; this need special treatment because of the \f in the regexp + (setq headlist '(("*" . 1) ("**" . 2)))) ; will be extrapolated + + (t ;; Check if the buffer contains a complete set of headings + (let ((re (concat "^" outline-regexp)) head level) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward re nil t) + (save-excursion + (beginning-of-line 1) + (setq head (outline-cleanup-match (match-string 0)) + level (funcall outline-level)) + (add-to-list 'headlist (cons head level)))))) + ;; Check for uniqueness of levels in the list + (let* ((hl headlist) entry level seen nonunique) + (while (setq entry (car hl)) + (setq hl (cdr hl) + level (cdr entry)) + (if (and (not (outline-static-level-p level)) + (member level seen)) + ;; We have two entries for the same level. + (add-to-list 'nonunique level)) + (add-to-list 'seen level)) + (if nonunique + (error "Cannot promote/demote: non-unique headings at level %s\nYou may want to configure `outline-promotion-headings'." + (mapconcat 'int-to-string nonunique ",")))))) + ;; OK, return the list + headlist)) + +(defun outline-change-heading (headlist delta atom &optional test) + "Change heading just matched by `outline-regexp' by DELTA levels. +HEADLIST can be either an alist ((\"outline-match\" . level)...) or a +straight list like `outline-promotion-headings'. ATOM is a character +if all headlines are composed of a single character. +If TEST is non-nil, just prepare the change and error if there are problems. +TEST nil means, really replace old heading with new one." + (let* ((head (outline-cleanup-match (match-string 0))) + (level (save-excursion + (beginning-of-line 1) + (funcall outline-level))) + (newhead ; compute the new head + (cond + ((= delta 0) t) + ((outline-static-level-p level) t) + ((null headlist) nil) + ((consp (car headlist)) + ;; The headlist is an association list + (or (car (rassoc (+ delta level) headlist)) + (and atom + (> (+ delta level) 0) + (make-string (+ delta level) atom)))) + (t + ;; The headlist is a straight list - grab the correct element. + (let* ((l (length headlist)) + (n1 (- l (length (member head headlist)))) ; index old + (n2 (+ delta n1))) ; index new + ;; Careful checking + (cond + ((= n1 l) nil) ; head not found + ((< n2 0) nil) ; newlevel too low + ((>= n2 l) nil) ; newlevel too high + ((let* ((tail (nthcdr (min n1 n2) headlist)) + (nilpos (- (length tail) (length (memq nil tail))))) + (< nilpos delta)) ; nil element between old and new + nil) + (t (nth n2 headlist)))))))) ; OK, we have a match! + (if (not newhead) + (error "Cannot shift level %d heading \"%s\" to level %d" + level head (+ level delta))) + (if (and (not test) (stringp newhead)) + (save-excursion + (beginning-of-line 1) + (or (looking-at (concat "[ \t]*\\(" (regexp-quote head) "\\)")) + (error "Please contact maintainer")) + (replace-match newhead t t nil 1))))) + +(defun outline-headings-atom (headlist) + "Use the list created by `outline-headings-list' and check if all +headings are polymers of a single character, e.g. \"*\". +If yes, return this character." + (if (consp (car headlist)) + ;; this is an alist - it makes sense to check for atomic structure + (let ((re (concat "\\`" + (regexp-quote (substring (car (car headlist)) 0 1)) + "+\\'"))) + (if (not (delq nil (mapcar (lambda (x) (not (string-match re (car x)))) + headlist))) + (string-to-char (car (car headlist))))))) + +(defun outline-cleanup-match (s) + "Remove text properties and start/end whitespace from a string." + (set-text-properties 1 (length s) nil s) + (save-match-data + (if (string-match "^[ \t]+" s) (setq s (replace-match "" t t s))) + (if (string-match "[ \t]+$" s) (setq s (replace-match "" t t s)))) + s) + +(defun outline-static-level-p (level) + "Test if a level should not be changed by level promotion/demotion." + (>= level 1000)) + +;;; Key bindings + +(defcustom outline-structedit-modifiers '(meta) + "List of modifiers for outline structure editing with the arrow keys." + :group 'outlines + :type '(repeat symbol)) + +(define-key outline-mode-map [(tab)] 'outline-cycle) +(let ((keys '((left . outline-promote) + (right . outline-demote) + (up . outline-move-subtree-up) + (down . outline-move-subtree-down))) + key) + (while (setq key (pop keys)) + (apply 'define-key outline-mode-map + (list + (vector (append outline-structedit-modifiers (list (car key)))) + (cdr key))))) + +;;; Menu entries + +(define-key outline-mode-menu-bar-map [headings outline-move-subtree-down] + '("Move subtree down" . outline-move-subtree-down)) +(define-key outline-mode-menu-bar-map [headings outline-move-subtree-up] + '("Move subtree up" . outline-move-subtree-up)) +(define-key outline-mode-menu-bar-map [headings outline-demote] + '("Demote by 1 level" . outline-demote)) +(define-key outline-mode-menu-bar-map [headings outline-promote] + '("Promote by 1 level" . outline-promote)) +(define-key outline-mode-menu-bar-map [show outline-cycle] + '("Rotate visibility" . outline-cycle)) +(define-key outline-mode-menu-bar-map [hide outline-cycle] + '("Rotate visibility" . outline-cycle)) + +;;; Finish up + +(provide 'outline-magic) + +;;; outline-magic.el ends here diff --git a/emacs/nxhtml/nxhtml/rngalt.el b/emacs/nxhtml/nxhtml/rngalt.el new file mode 100644 index 0000000..788128a --- /dev/null +++ b/emacs/nxhtml/nxhtml/rngalt.el @@ -0,0 +1,828 @@ +;;; rngalt.el --- Tools for making completion addition to nxml mode +;; +;; Author: Lennart Borgman +;; Created: Wed Jan 10 17:17:18 2007 +(defconst rngalt:version "0.51") ;;Version: +;; Last-Updated: 2008-03-08T03:33:56+0100 Sat +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `nxml-enc', `nxml-ns', `nxml-parse', `nxml-util', +;; `ourcomments-util', `rng-dt', `rng-loc', `rng-match', +;; `rng-parse', `rng-pttrn', `rng-uri', `rng-util', `rng-valid', +;; `xmltok'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-and-compile (require 'rng-valid)) +(eval-when-compile (require 'rng-nxml)) +(eval-when-compile (unless load-file-name (require 'nxhtml-mode nil t))) + +(eval-when-compile + (let* ((this-file (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + (this-dir (file-name-directory this-file)) + (util-dir (expand-file-name "../util/" this-dir)) + (load-path (cons util-dir load-path))) + (require 'ourcomments-util))) +;;(require 'ourcomments-util) + +;; (setq x (macroexpand '(defcustom my-temp-opt t "doc" :type 'boolean))) +;; (setq x (macroexpand '(define-minor-mode my-temp-mode "doc"))) +;; (setq x (macroexpand '(define-toggle my-temp-toggle t "doc"))) +;;(define-toggle rngalt-display-validation-header t +(define-minor-mode rngalt-display-validation-header + "Display XML validation headers at the top of buffer when t. +The validation header is only displayed in buffers where the main +major mode is derived from `nxml-mode'." + :global t + :init-value t + :group 'relax-ng + :group 'nxhtml + (when (fboundp 'rngalt-update-validation-header-overlay-everywhere) + (rngalt-update-validation-header-overlay-everywhere))) + +(defun rngalt-display-validation-header-toggle () + "Toggle `rngalt-display-validation-header'." + (interactive) + (rngalt-display-validation-header (if rngalt-display-validation-header -1 1))) + +;;(define-toggle rngalt-minimal-validation-header t +(define-minor-mode rngalt-minimal-validation-header + "If non-nil display only a short informaion about the XML validation header. +See also `rngalt-display-validation-header'." + :global t + :init-value t + :group 'relax-ng + :group 'nxhtml + (when (fboundp 'rngalt-update-validation-header-overlay-everywhere) + (rngalt-update-validation-header-overlay-everywhere))) + +(defun rngalt-minimal-validation-header-toggle () + "Toggle `rngalt-minimal-validation-header'." + (interactive) + (rngalt-minimal-validation-header (if rngalt-minimal-validation-header -1 1))) + +(defface rngalt-validation-header-top + '((t (:foreground "RGB:87/CE/FA" :background "white"))) + "Face first line of validation header." + :group 'nxhtml) + +(defface rngalt-validation-header-bottom + '((t (:foreground "white" :background "RGB:87/CE/FA"))) + "Face first line of validation header." + :group 'nxhtml) + +;; FIX-ME: remember to clear these variable, but where? +(defvar rngalt-validation-header nil) +(make-variable-buffer-local 'rngalt-validation-header) +(put 'rngalt-validation-header 'permanent-local t) + +(defvar rngalt-current-schema-file-name nil) +(make-variable-buffer-local 'rngalt-current-schema-file-name) +(put 'rngalt-current-schema-file-name 'permanent-local t) + +(defvar rngalt-validation-header-overlay nil) +(make-variable-buffer-local 'rngalt-validation-header-overlay) +(put 'rngalt-validation-header-overlay 'permanent-local t) + +(defvar rngalt-major-mode nil) +(make-variable-buffer-local 'rngalt-major-mode) +(put 'rngalt-major-mode 'permanent-local t) + +(defvar rngalt-complete-first-try nil + "First function to try for completion. +If non-nil should be a function with no parameters. Used by +`rngalt-complete'.") + +(defvar rngalt-complete-last-try nil + "Last function to try for completion. +If non-nil should be a function with no parameters. Used by +`rngalt-complete'.") + +(defvar rngalt-completing-read-tag nil + "Alternate function for completing tag name. +If non-nil should be a function with the same parameters as +`completing-read'. Used by `rngalt-complete'.") + +(defvar rngalt-completing-read-attribute-name nil + "Alternate function for completing attribute name. +If non-nil should be a function with the same parameters as +`completing-read'. Used by `rngalt-complete'.") + +(defvar rngalt-completing-read-attribute-value nil + "Alternate function for completing attribute value. +If non-nil should be a function with the same parameters as +`completing-read'. Used by `rngalt-complete'.") + + +(defun rngalt-finish-element () + "Finish the current element by inserting an end-tag. +Like `nxml-finish-element' but takes `rngalt-validation-header' +into account." + (interactive "*") + (rngalt-finish-element-1 nil)) + +;; Fix-me: Check the other uses of `nxml-finish-element-1'. But this +;; is maybe not necessary since the only other use is in +;; `nxml-split-element' and that will anyway work - I believe ... +(defun rngalt-finish-element-1 (startp) + "Insert an end-tag for the current element and optionally a start-tag. +The start-tag is inserted if STARTP is non-nil. Return the position +of the inserted start-tag or nil if none was inserted. + +This is like `nxml-finish-element-1' but takes +`rngalt-validation-header' into account." + (interactive "*") + (let (token-end + start-tag-end + starts-line + ends-line + start-tag-indent + qname + inserted-start-tag-pos) + ;; Temporary insert the fictive validation header if any. + (let ((buffer-undo-list nil) + (here (point-marker))) + (when rngalt-validation-header + (let ((vh (nth 2 rngalt-validation-header))) + (set-marker-insertion-type here t) + (save-restriction + (widen) + (goto-char (point-min)) + (insert vh))) + (goto-char here)) + (setq token-end (nxml-token-before)) + (setq start-tag-end + (save-excursion + (when (and (< (point) token-end) + (memq xmltok-type + '(cdata-section + processing-instruction + comment + start-tag + end-tag + empty-element))) + (error "Point is inside a %s" + (nxml-token-type-friendly-name xmltok-type))) + (nxml-scan-element-backward token-end t))) + (when start-tag-end + (setq starts-line + (save-excursion + (unless (eq xmltok-type 'start-tag) + (error "No matching start-tag")) + (goto-char xmltok-start) + (back-to-indentation) + (eq (point) xmltok-start))) + (setq ends-line + (save-excursion + (goto-char start-tag-end) + (looking-at "[ \t\r\n]*$"))) + (setq start-tag-indent (save-excursion + (goto-char xmltok-start) + (current-column))) + (setq qname (xmltok-start-tag-qname))) + + ;; Undo the insertion of the fictive header: + (undo-start) + (while (and (not (eq t pending-undo-list)) + pending-undo-list) + (undo-more 1)) + (goto-char here)) + + (unless start-tag-end (error "No more start tags")) + + (when (and starts-line ends-line) + ;; start-tag is on a line by itself + ;; => put the end-tag on a line by itself + (unless (<= (point) + (save-excursion + (back-to-indentation) + (point))) + (insert "\n")) + (indent-line-to start-tag-indent)) + (insert "</" qname ">") + (when startp + (when starts-line + (insert "\n") + (indent-line-to start-tag-indent)) + (setq inserted-start-tag-pos (point)) + (insert "<" qname ">") + (when (and starts-line ends-line) + (insert "\n") + (indent-line-to (save-excursion + (goto-char xmltok-start) + (forward-line 1) + (back-to-indentation) + (if (= (current-column) + (+ start-tag-indent nxml-child-indent)) + (+ start-tag-indent nxml-child-indent) + start-tag-indent))))) + inserted-start-tag-pos)) + +(defun rngalt-complete () + "Complete the string before point using the current schema. +Return non-nil if in a context it understands. + +This function should be added to `nxml-completion-hook' before +`rng-complete'. By default it works just like this function, but +you can add your own completion by setting the variables +`rngalt-complete-first-try', `rngalt-completing-read-tag', +`rngalt-completing-read-attribute-name', +`rngalt-completing-read-attribute-value' and +`rngalt-complete-last-try'." + (interactive) + (unless rng-validate-mode + (when (y-or-n-p + "XML Validation is not on. Do you want to turn it on? ") + (rng-validate-mode 1))) + (when rng-validate-mode + ;; schema file may mismatch if user sets it explicitly: + (rngalt-reapply-validation-header) + (when rng-current-schema-file-name + (rngalt-validate)) + (or (when rngalt-complete-first-try + (funcall rngalt-complete-first-try)) + (progn + (unless rng-current-schema-file-name + (when (eq major-mode 'nxhtml-mode) + (when (y-or-n-p + "There is currently no DTD specified for the buffer. +This makes XHTML completion impossible. You can add a fictive +XHTML validation header that sets the DTD to XHTML. This will +not be inserted in the buffer but completion and XHTML validation +will assume it is there so both error checking and completion +will work. + +Do you want to add a fictive XHTML validation header? ") + (message "") ;; Get rid of the large minibuffer message window + (nxhtml-validation-header-mode) + ))) + (let ((lt-pos (save-excursion (search-backward "<" nil t))) + xmltok-dtd) + (or (and lt-pos + (= (rng-set-state-after lt-pos) lt-pos) + (or (rngalt-complete-tag lt-pos) + (rng-complete-end-tag lt-pos) + (rngalt-complete-attribute-name lt-pos) + (rngalt-complete-attribute-value lt-pos))) + (when rngalt-complete-last-try + (funcall rngalt-complete-last-try)))))))) + +(defun rngalt-validate () + (unless (= (buffer-size) 0) + (let ((while-n1 0) + (maxn1 20)) + (condition-case err + (while (and (> maxn1 (setq while-n1 (1+ while-n1))) + (rng-do-some-validation)) + nil) + (error + ;; FIX-ME: for debugging: + ;;(lwarn 'rngalt-validate :error "%s" (error-message-string err)) + (message "rngalt-validate: %s" (error-message-string err)) + nil)) + (when (>= while-n1 maxn1) + (error "rngalt-validate: Could not validate"))) + (rng-validate-done))) + +(defvar rngalt-region-ovl nil) +(defvar rngalt-region-prepared nil) +(defun rngalt-complete-tag-region-prepare () + (unless rngalt-region-prepared + (when rngalt-region-ovl + (when (overlayp rngalt-region-ovl) + (delete-overlay rngalt-region-ovl)) + (setq rngalt-region-ovl nil)) + (when (and mark-active + transient-mark-mode) + (let ((beginning (region-beginning)) + (end (region-end))) + (unless (= (point) (region-beginning)) + (goto-char beginning)) + (when (save-excursion + (when (re-search-forward "\\=[^<]*\\(?:<[^<]*>\\)*[^>]*" end t) + (= end (point)))) + (setq rngalt-region-ovl (make-overlay beginning end)) + (overlay-put rngalt-region-ovl 'face 'region) + ))) + (setq rngalt-region-prepared t))) + +(defun rngalt-complete-tag-region-cleanup () + (when rngalt-region-prepared + (when (overlayp rngalt-region-ovl) + (delete-overlay rngalt-region-ovl)) + (deactivate-mark) + (setq rngalt-region-prepared nil))) + +(defun rngalt-complete-tag-region-finish () + (when (and rngalt-region-prepared + (overlayp rngalt-region-ovl)) + (let ((here (point))) + (insert ">") + (goto-char (overlay-end rngalt-region-ovl)) + (nxml-finish-element) + (rngalt-validate) + (goto-char here))) + (rngalt-complete-tag-region-cleanup)) + +(defun rngalt-complete-tag (lt-pos) + "Like `rng-complete-tag' but with some additions. +The additions are: +- Alternate completion. +- Complete around highlighted region. + +See also the variable `rngalt-completing-read-tag'." + (let (rng-complete-extra-strings) + (when (and (= lt-pos (1- (point))) + rng-complete-end-tags-after-< + rng-open-elements + (not (eq (car rng-open-elements) t)) + (or rng-collecting-text + (rng-match-save + (rng-match-end-tag)))) + (setq rng-complete-extra-strings + (cons (concat "/" + (if (caar rng-open-elements) + (concat (caar rng-open-elements) + ":" + (cdar rng-open-elements)) + (cdar rng-open-elements))) + rng-complete-extra-strings))) + (when (save-excursion + (re-search-backward rng-in-start-tag-name-regex + lt-pos + t)) + (and rng-collecting-text (rng-flush-text)) + (rngalt-complete-tag-region-prepare) + (let ((completion + (let ((rng-complete-target-names + (rng-match-possible-start-tag-names)) + (rng-complete-name-attribute-flag nil)) + (rngalt-complete-before-point (1+ lt-pos) + 'rng-complete-qname-function + "Insert tag: " + nil + 'rng-tag-history + rngalt-completing-read-tag))) + name) + (when completion + (cond ((rng-qname-p completion) + (setq name (rng-expand-qname completion + t + 'rng-start-tag-expand-recover)) + (when (and name + (rng-match-start-tag-open name) + (or (not (rng-match-start-tag-close)) + ;; need a namespace decl on the root element + (and (car name) + (not rng-open-elements)))) + ;; attributes are required + (insert " ")) + (rngalt-complete-tag-region-finish) + (run-hook-with-args 'rngalt-complete-tag-hooks completion) + ) + ((member completion rng-complete-extra-strings) + (insert ">"))))) + (rngalt-complete-tag-region-finish) + t))) + +(defvar rngalt-complete-tag-hooks nil + "Hook run after completing a tag. +Each function is called with the last name of the last tag +completed.") + +(defun rngalt-complete-attribute-name (lt-pos) + "Like `rng-complete-attribute-name' but with alternate completion. +See the variable `rngalt-completing-read-attribute-name'." + (when (save-excursion + (re-search-backward rng-in-attribute-regex lt-pos t)) + (let ((attribute-start (match-beginning 1)) + rng-undeclared-prefixes) + (and (rng-adjust-state-for-attribute lt-pos + attribute-start) + (let ((rng-complete-target-names + (rng-match-possible-attribute-names)) + (rng-complete-extra-strings + (mapcar (lambda (prefix) + (if prefix + (concat "xmlns:" prefix) + "xmlns")) + rng-undeclared-prefixes)) + (rng-complete-name-attribute-flag t) + completion) + (setq completion + (rngalt-complete-before-point attribute-start + 'rng-complete-qname-function + "Attribute: " + nil + 'rng-attribute-name-history + rngalt-completing-read-attribute-name)) + (when (and completion + (< 0 (length completion))) + (insert "=\""))))) + t)) + +(defun rngalt-complete-attribute-value (lt-pos) + "Like `rng-complete-attribute-value' but with alternate completion. +See the variable `rngalt-completing-read-attribute-value'." + (when (save-excursion + (re-search-backward rng-in-attribute-value-regex lt-pos t)) + (let ((name-start (match-beginning 1)) + (name-end (match-end 1)) + (colon (match-beginning 2)) + (value-start (1+ (match-beginning 3)))) + (and (rng-adjust-state-for-attribute lt-pos + name-start) + (if (string= (buffer-substring-no-properties name-start + (or colon name-end)) + "xmlns") + (rngalt-complete-before-point + value-start + (rng-strings-to-completion-alist + (rng-possible-namespace-uris + (and colon + (buffer-substring-no-properties (1+ colon) name-end)))) + "Namespace URI: " + nil + 'rng-namespace-uri-history + rngalt-completing-read-attribute-value) ;; fix-me + (rng-adjust-state-for-attribute-value name-start + colon + name-end) + (rngalt-complete-before-point + value-start + (rng-strings-to-completion-alist + (rng-match-possible-value-strings)) + "Value: " + nil + 'rng-attribute-value-history + rngalt-completing-read-attribute-value)) + (unless (eq (char-after) (char-before value-start)) + (insert (char-before value-start))))) + t)) + +(defun rngalt-complete-before-point (start table prompt &optional predicate hist altcompl) + "Complete text between START and point. +Works like `rng-complete-before-point' if ALTCOMPL is nil. When +ALTCOMPL is a function symbol and no completion alternative is +available from table then this is called instead of +`compleating-read' with the same parameters." + (let* ((orig (buffer-substring-no-properties start (point))) + (completion (try-completion orig table predicate)) + (completing-fun (if altcompl altcompl 'completing-read)) + (completion-ignore-case t)) + (cond ((not (or completion completing-fun)) + (if (string= orig "") + (message "No completions available") + (message "No completion for %s" (rng-quote-string orig))) + (ding) + nil) + ((eq completion t) orig) + ((and completion + (not (string= completion orig))) + (delete-region start (point)) + (insert completion) + (cond ((not (rng-completion-exact-p completion table predicate)) + (message "Incomplete") + nil) + ((eq (try-completion completion table predicate) t) + completion) + (t + (message "Complete but not unique") + nil))) + (t + (setq completion + (let ((saved-minibuffer-setup-hook + (default-value 'minibuffer-setup-hook))) + (add-hook 'minibuffer-setup-hook + 'minibuffer-completion-help + t) + (unwind-protect + (funcall completing-fun + prompt + table + predicate + nil + orig + hist) + (setq-default minibuffer-setup-hook + saved-minibuffer-setup-hook)))) + (when completion + (delete-region start (point)) + (insert completion)) + completion)))) + +(defun rngalt-get-missing-required-attr (single-tag) + "Get a list of missing required attributes. +This is to be used when completing attribute names. +SINGLE-TAG should be non-nil if the tag has no end tag. + +For a typical use see `nxhtml-completing-read-attribute-name' in +nxhtml.el. +" + ;; FIX-ME: This is a terrible cludge. One day I hope I will + ;; understand how to write this ;-) + ;; + ;; I currently fetch the missing tags from the error message in the + ;; error overlay set by rng validate. + (let ((here (point))) + (unless (save-match-data (looking-at "[^<]\\{,200\\}>")) + ;; We can probably add a >, so let us do it: + (when single-tag + (insert "/")) + (insert ">") + (rngalt-validate)) + (goto-char here)) + (let ((ovl (rng-error-overlay-message (or (rng-error-overlay-after (point)) + (rng-error-overlay-after (1- (point))))))) + ;;(message "ovl=%s" ovl)(sit-for 1) + ;;(message "prop ovl=%s" (overlay-properties ovl))(sit-for 1) + (when (and ovl + (eq (overlay-get ovl 'category) 'rng-error)) + ;;(message "rng-error")(sit-for 1) + (let ((msg (overlay-get ovl 'help-echo))) + ;;(message "msg=%s" msg);(sit-for 1) + (when (string-match "Missing attributes? \\(.*\\)" msg) + ;;(message "0=%s" (match-string 0 msg));(sit-for 1) + ;;(message "1=%s" (match-string 1 msg));(sit-for 1) + (let* ((matches (match-string 1 msg)) + (lst (split-string (substring matches 1 (- (length matches) 1)) "\", \""))) + ;;(message "matches=%s" matches);(sit-for 2) + ;;(message "lst=%s" lst);(sit-for 1) + lst)))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Validation start state + +(defun rngalt-after-change-major () + (unless (and (boundp 'mumamo-set-major-running) + mumamo-set-major-running) + (setq rngalt-major-mode major-mode) + (when (and (derived-mode-p 'nxml-mode) + rngalt-validation-header) + (rngalt-reapply-validation-header)) + (rngalt-update-validation-header-overlay))) + +(defvar rngalt-validation-header-keymap + (let ((map (make-sparse-keymap))) + (define-key map [mouse-1] 'rngalt-minimal-validation-header-toggle) + map)) + +(defun rngalt-update-validation-header-overlay () + (if (and (boundp 'rngalt-display-validation-header) + rngalt-display-validation-header + rngalt-validation-header + (or (derived-mode-p 'nxml-mode) + (let ((major-mode rngalt-major-mode)) + (and major-mode + (derived-mode-p 'nxml-mode)))) + ) + (progn + (if rngalt-validation-header-overlay + (move-overlay rngalt-validation-header-overlay 1 1) + (setq rngalt-validation-header-overlay (make-overlay 1 1))) + (overlay-put rngalt-validation-header-overlay + 'priority 1000) + ;; Other properties should go to the 'before-string + (let* ((validation-header (nth 2 rngalt-validation-header)) + (header + (if rngalt-minimal-validation-header + (propertize + (concat + "*** Fictive XHTML/XML Validation Header: ... " + (save-match-data + (if (string-match "\\(<[^[:space:]>]+\\)[^>]*>[^<>]*\\'" + validation-header) + (concat (match-string 1 validation-header) ">") + "Error")) + "\n") + 'face 'rngalt-validation-header-bottom) + (concat + (propertize "*** Fictive XHTML/XML Validation Header:\n" + 'face 'rngalt-validation-header-top) + (propertize (concat validation-header "\n") + 'face 'rngalt-validation-header-bottom))))) + (setq header + (propertize + header + 'help-echo + "Click to toggle full/minimal display of header" + 'keymap rngalt-validation-header-keymap)) + (overlay-put rngalt-validation-header-overlay + 'before-string header))) + (when rngalt-validation-header-overlay + (delete-overlay rngalt-validation-header-overlay)))) + +(defun rngalt-update-validation-header-overlay-everywhere () + (dolist (b (buffer-list)) + (when (buffer-live-p b) + (with-current-buffer b + (when rngalt-validation-header + (rngalt-update-validation-header-overlay)))))) + +;; This is exactly the same as the original `rng-set-initial-state' +;; except when `rngalt-validation-header' is non-nil." +(defadvice rng-set-initial-state (around + rngalt-set-initial-state + activate + compile + ) + (nxml-ns-init) + (rng-match-start-document) + (setq rng-open-elements nil) + (setq rng-pending-contents nil) + (when rngalt-validation-header + (let ((state (car rngalt-validation-header))) + (rng-restore-state state))) + (setq ad-return-value (goto-char (point-min)))) + +;; (defun rng-new-validate-prepare () +;; "Prepare to do some validation, initializing point and the state. +;; Return t if there is work to do, nil otherwise. + +;; This is exactly the same as the original-insert-directory +;; `rng-validate-prepare' with the difference that the state at +;; point 1 is set differently if `rngalt-validation-header' is +;; non-nil. + +;; See also `rng-set-initial-state'." +;; (cond ((= rng-validate-up-to-date-end 1) +;; (rng-set-initial-state) +;; t) +;; ((= rng-validate-up-to-date-end (point-max)) +;; nil) +;; (t (let ((state +;; (if (and rngalt-validation-header +;; (= rng-validate-up-to-date-end 1)) +;; (car rngalt-validation-header) +;; (get-text-property (1- rng-validate-up-to-date-end) +;; 'rng-state)))) +;; (cond (state +;; (rng-restore-state state) +;; (goto-char rng-validate-up-to-date-end)) +;; (t +;; (let ((pos (previous-single-property-change +;; rng-validate-up-to-date-end +;; 'rng-state))) +;; (cond (pos +;; (rng-restore-state +;; (or (get-text-property (1- pos) 'rng-state) +;; (error "Internal error: state null"))) +;; (goto-char pos)) +;; (t (rng-set-initial-state)))))))))) + + +;; For as-external.el +;;;###autoload +(defun rngalt-set-validation-header (start-of-doc) + (let ((old-rvm rng-validate-mode)) + (when old-rvm (rng-validate-mode -1)) + (if start-of-doc + (progn + (add-hook 'after-change-major-mode-hook 'rngalt-after-change-major nil t) + (setq rngalt-validation-header (rngalt-get-state-after start-of-doc)) + (rng-set-schema-file-1 (cadr rngalt-validation-header)) + (setq rngalt-current-schema-file-name rng-current-schema-file-name) + (setq rng-compile-table nil) + (setq rng-ipattern-table nil) + (setq rng-last-ipattern-index nil)) + (remove-hook 'after-change-major-mode-hook 'rngalt-after-change-major t) + (setq rngalt-validation-header nil) + (when old-rvm + (rng-set-vacuous-schema) + (rng-auto-set-schema))) + (when old-rvm + (rng-validate-mode 1) + (rngalt-update-validation-header-overlay) + (rngalt-update-validation-header-buffer)))) + +(defun rngalt-reapply-validation-header () + (when rngalt-validation-header + (when (or (not rng-current-schema-file-name) + (unless (string= rngalt-current-schema-file-name rng-current-schema-file-name) + (lwarn 'schema-mismatch :warning + "XHTML validation header schema %s reapplied (replaces %s)" + (file-name-nondirectory rngalt-current-schema-file-name) + (file-name-nondirectory rng-current-schema-file-name)) + t)) + (rngalt-set-validation-header (nth 2 rngalt-validation-header))))) + +;; (defun rngalt-clear-validation-header () +;; "Remove XML validation header from current buffer. +;; For more information see `rngalt-show-validation-header'." +;; (interactive) +;; (rngalt-set-validation-header nil) +;; (rng-auto-set-schema t)) + +;; FIX-ME: Add edit header? + +(defun rngalt-get-validation-header-buffer () + (let ((b (get-buffer " *XML Validation Header*"))) + (unless b + (setq b (get-buffer-create " *XML Validation Header*")) + (with-current-buffer b + ;;(fundamental-mode) + (nxml-mode))) + b)) + +(defun rngalt-get-state-after (start-of-doc) + ;; FIX-ME: better buffer name? + (let ((statebuf (rngalt-get-validation-header-buffer))) + (with-current-buffer statebuf + (when rng-validate-mode (rng-validate-mode -1)) + (erase-buffer) + (insert start-of-doc) + ;; From rng-get-state + (setq rng-match-state nil) + (setq nxml-ns-state nil) + (setq rng-open-elements nil) + ;; From rng-match-init-buffer + (setq rng-compile-table nil) + (setq rng-ipattern-table nil) + (setq rng-last-ipattern-index nil) + + (nxml-mode) + (rng-validate-mode 1) + (rngalt-validate) + (let* ((state (rng-get-state)) + (cp-state (copy-tree state))) + ;;(if (equal state cp-state) (message "(equal state cp-state)=t") (message "(equal state cp-state)=nil")) + ;; Fix-me: is the copy-tree necessary here? + (list + cp-state + (rng-locate-schema-file) + start-of-doc))))) + +(defun rngalt-show-validation-header () + "Show XML validation header used in current buffer. +The XML validation header is used in `nxhtml-mode' to set a state +for XML validation at the start of the buffer. + +The purpose is to make it possible to use `nxml-mode' completion +in buffers where you do not actually have a full XML file. This +could for example be a buffer with PHP code or a buffer with a +blog entry. + +More techhnical info: This can be used by any mode derived from +`nxml-mode'. To use it in other modes than `nxhtml-mode' replace +`rng-complete' by `rngalt-complete' in `nxml-completion-hook'." + (interactive) + (unless (derived-mode-p 'nxml-mode) + (error "Buffer mode is not an nXml type major mode: %s" major-mode)) + (rngalt-update-validation-header-buffer) + (display-buffer (rngalt-get-validation-header-buffer) t)) + +(defun rngalt-update-validation-header-buffer () + (let ((vh (nth 2 rngalt-validation-header)) + (cb (current-buffer))) + (with-current-buffer (rngalt-get-validation-header-buffer) + (erase-buffer) + (if (not vh) + (setq header-line-format (concat " No XML validation header in buffer " + (buffer-name cb))) + (insert vh) + (setq header-line-format (concat " XML validation header in buffer " + (buffer-name cb))))))) + +;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + +(provide 'rngalt) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; rngalt.el ends here diff --git a/emacs/nxhtml/nxhtml/tidy-xhtml.el b/emacs/nxhtml/nxhtml/tidy-xhtml.el new file mode 100644 index 0000000..1c2cdd4 --- /dev/null +++ b/emacs/nxhtml/nxhtml/tidy-xhtml.el @@ -0,0 +1,2921 @@ +;;; tidy-xhtml.el --- Interface to the HTML Tidy program + +;; Copyright (C) 2001, 2002, 2003, 2006, 2007 by Free Software +;; Foundation, Inc. + +;; Emacs Lisp Archive Entry +;; Ancestors filename: tidy.el +;; Author: Kahlil (Kal) HODGSON <dorge@tpg.com.au> +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Original X-URL: http://www.emacswiki.org/elisp/tidy.el +;; Last-Updated: 2008-03-09T13:10:06+0100 Sun +(defconst tidy-xhtml:version "2.25") +;; Keywords: languages + +;; This file is NOT part of GNU Emacs. + +;; 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;;; Commentary: + +;; Provides a simple interface to the HTML Tidy program -- a free +;; utility that can fix common errors in your mark-up and clean up +;; sloppy editing automatically. See +;; +;; <http://tidy.sourceforge.net/> +;; +;; for more details. This package provides the following functions: +;; +;; `tidy-buffer', +;; `tidy-region', +;; `tidy-tree', +;; `tidy-html-site', +;; `tidy-parse-config-file', +;; `tidy-save-settings', +;; `tidy-describe-options', +;; `tidy-show-xhtml-options', +;; `tidy-set-xhtml-options', +;; +;; These can be invoked interactively (using M-x) or via the menu-bar. +;; The function `tidy-buffer' sends the current buffer to HTML Tidy, +;; replacing the existing contents with a "tidied" version. If +;; `tidy-buffer' is given a prefix argument, tidy operates on the +;; current region, ignoring mark-up outside <BODY>...</BODY> tags +;; (useful for writhing cgi scripts in Pearl). Warnings and errors +;; are presented in a compilation buffer to facilitate tracking down +;; necessary changes (e.g. C-x ` is bound to `next-error'). +;; +;; This package also provides menu-bar support for setting Tidy's many +;; options, and includes support for Tidy configuration files. The +;; function `tidy-parse-config-file' will synchronise options +;; displayed in the menu-bar with the settings in `tidy-config-file'. +;; This is normally called by the load-hook for your HTML editing mode +;; (see installation instructions below). The function +;; `tidy-save-settings' will save the current option settings to your +;; `tidy-config-file'. Finally `tidy-describe-options' allows you to +;; browse the documentation strings associated with each option. + +;;; + +;;;; Installation: + +;; This package assumes you have and up-to-date HTML Tidy program +;; installed on your system. See the URL above for instructions on +;; how to do this. To set up this support package, first place the +;; "tidy.el" file somewhere in your `load-path' and open it in Emacs. +;; Byte-compile and load this package using the command +;; +;; M-x emacs-lisp-byte-compile-and-load <RET> +;; +;; Next customise the variables `tidy-config-file', `tidy-temp-dir' +;; `tidy-shell-program', `tidy-menu-lock' and `tidy-menu-x-position' +;; +;; M-x customize-group <RET> tidy <RET> +;; +;; Now add the following autoloads to your ".emacs.el" file: +;; +;; (autoload 'tidy-buffer "tidy" "Run Tidy HTML parser on current buffer" t) +;; (autoload 'tidy-parse-config-file "tidy" "Parse the `tidy-config-file'" t) +;; (autoload 'tidy-save-settings "tidy" "Save settings to `tidy-config-file'" t) +;; (autoload 'tidy-build-menu "tidy" "Install an options menu for HTML Tidy." t) +;; +;; If you use html-mode to edit HTML files then add something like +;; this as well + +;; (defun my-html-mode-hook () "Customize my html-mode." +;; (tidy-build-menu html-mode-map) +;; (local-set-key [(control c) (control c)] 'tidy-buffer) +;; (setq sgml-validate-command "tidy")) +;; +;; (add-hook 'html-mode-hook 'my-html-mode-hook) + +;; This will set up a "tidy" menu in the menu bar and bind the key +;; sequence "C-c C-c" to `tidy-buffer' in html-mode (normally bound to +;; `validate-buffer'). +;; +;; For other modes (like html-helper-mode) simple change the variables +;; `html-mode-hook' and `html-mode-map' to whatever is appropriate e.g. + +;; (defun my-html-mode-hook () "Customize my html-helper-mode." +;; (tidy-build-menu html-helper-mode-map) +;; (local-set-key [(control c) (control c)] 'tidy-buffer) +;; (setq sgml-validate-command "tidy")) +;; +;; (add-hook 'html-helper-mode-hook 'my-html-mode-hook) + +;; Finally, restart Emacs and open an HTML file to test-drive the tidy +;; package. For people new to HTML tidy check that the option "markup" +;; under the "Input/Output" sub menu is set. You can read the +;; documentation on this option via the menu item "Describe Options". +;; +;; Enjoy! + +;;;; New Features: +;; +;; 0. Now compatible with CVS version of Tidy as at 22 May 2003 +;; 1. Improved menu support to facillitate incorporting new options +;; 2. Menu lock option makes menu stick when toggling options. +;; 3. Now runs on XEmacs!! +;; 4. Uses error file rather than std-error to retrieve errors (this +;; fixes some odd pop up behaviour) +;; 5. minor bug fix (empty config files) +;; 6. handle buffer modified query in error buffer better +;; 7. make it impossible to mark the error buffer as modified +;; 8. Added the variable `tidy-temp-directory'. +;; 9. Bugfix in tidy-buffer: call find-file-noselect with NOWARN +;; 10. Removes ^M on w32. +;; 11. Changed defcustom types to 'file and 'directory. +;; 12. Added `tidy-set-xhtml-options'. +;; 13. Tried to handle encodings. +;; 14. Added the function `tidy-region'. +;; 15. Added ediff support. +;; 16. Added `tidy-tree'. +;; 17. Added `tidy-html-site'. + +;;;; ToDo: +;; +;; 1. Automatically set "char-encoding" according to the buffer encoding +;; 2. Should check value of HTML_TIDY environment variable. + + +;;;; Bugs: + +;; Requires a version of HTML Tidy that understands the "-f" +;; "-config" "--show-body-only" command line options e.g. source-forge +;; pre-release. +;; +;; There may be a bug with setting doctypes. I don't use this feature +;; yet and, well, don't really know how its supposed to work:-) +;; +;; Care with character encodings!! + + +;;; History: + +;; 2006-05-09: New features 10-17 above. +;; - Lennart Borgman +;; 2006-05-24: Fixed some errors spotted by Andreas Roethler. + + +;;;; Credits + +;; This code was inspired by an Emacs "tip" suggested by Pete Gelbman. +;; +;; Thanks to Hans-Michael Stahl for comments regarding XEmacs +;; compatibility. +;; +;; Thanks to Thomas Baumann for bugfix's in `tidy-parse-config-file' +;; and `tidy-buffer'. +;; +;; Thanks to Chris Lott for comments regarding installation and menu +;; display +;; +;; Thanks to Jeroen Baekelandt for noting a problem with ange-ftp and +;; inspiring `tidy-temp-directory'. + +;;;; Code: + +;;;;; Forward references (stuff which must come first) + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'ediff)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) +(eval-when-compile + (add-to-list 'load-path default-directory)) +(eval-when-compile (require 'html-site nil t)) +(require 'easymenu) ;; This makes menus so much easier! +(require 'compile) ;; To make the error buffer more sexy +(require 'cus-edit) ;; Just for face custom-button +(require 'help-mode) + +;; The following two are functions so that the same compiled code will +;; work in both situations (time cost is negligible) + +(defsubst tidy-xemacs-p () + "Return t iff we are running XEmacs this session." + (not (null (string-match "^XEmacs.*" (emacs-version))))) + +(defsubst tidy-windows-p () + "Return t iff we are running on a Windows system." + (memq system-type '(emx win32 w32 mswindows ms-dos windows-nt))) + +;; function definitions + +;; XEmacs +(defalias 'tidy-x-event-function 'event-function) +(defalias 'tidy-x-event-object 'event-object) +(defalias 'tidy-x-find-menu-item 'find-menu-item) +(defalias 'tidy-x-get-popup-menu-response 'get-popup-menu-response) +(defalias 'tidy-x-make-event 'make-event) +(defalias 'tidy-x-misc-user-event-p 'misc-user-event-p) + +;;;;; User Variables + +;;;###autoload +(defgroup tidy nil + "Provides a simple interface to the HTML Tidy program -- a free +utility that can fix common errors in your mark-up and clean up +sloppy editing automatically. See + + <http://tidy.sourceforge.net/> + +for more details. This package provides the following functions: + + `tidy-buffer', + `tidy-parse-config-file', + `tidy-save-settings', and + `tidy-describe-options', + +These can be invoked interactively (using M-x) or via the menu-bar. +The function `tidy-buffer' sends the current buffer to HTML Tidy, +replacing the existing contents with a \"tidied\" version. If +`tidy-buffer' is given a prefix argument, tidy operates on the +current region, ignoring mark-up outside <BODY>...</BODY> tags +\(useful for writhing cgi scripts in Pearl). Warnings and errors +are presented in a compilation buffer to facilitate tracking down +necessary changes (e.g. C-x ` is bound to `next-error'). + +This package also provides menu-bar support for setting Tidy's many +options, and includes support for Tidy configuration files. The +function `tidy-parse-config-file' will synchronise options +displayed in the menu-bar with the settings in `tidy-config-file'. +This is normally called by the load-hook for your HTML editing mode +\(see installation instructions below). The function +`tidy-save-settings' will save the current option settings to your +`tidy-config-file'. Finally `tidy-describe-options' allows you to +browse the documentation strings associated with each option. +" + :group 'nxhtml + :group 'hypermedia) + +;; (defcustom tidy-use-ediff nil +;; "If non-nil call ediff in `tidy-buffer' instead of replacing." +;; :group 'tidy +;; :type 'boolean) + +(defvar tidy-warnings 0) +(defvar tidy-errors 0) +(defvar tidy-message nil) + +;;(defvar tidy-batch-buffer nil) +(defvar tidy-batch-last-file nil) + +(defvar tidy-default-config-file "~/.tidyrc") + +(defvar tidy-config-file-parsed nil) + +(defcustom tidy-config-file tidy-default-config-file + "Path to your default tidy configuration file. + +This is used by `tidy-parse-config-file' to synchronise Tidy's behaviour +inside Emacs with its behaviour outside, and by `tidy-save-settings' to +set your configuration file from within Emacs. If you never want this to +happen, set `tidy-config-file' to \"\"." + :group 'tidy + :type 'file + :set (lambda (symbol value) + (set-default symbol value) + (if (file-readable-p value) + ;; Just set the default values here: + ;;(tidy-parse-config-file) + ;; Just tell we need to parse: + (setq tidy-config-file-parsed nil) + (if (file-exists-p value) + (lwarn '(tidy-config-file) + :warning "Tidy config file not readable: %s" value) + (unless (string= value tidy-default-config-file) + (lwarn '(tidy-config-file) + :warning "Tidy config file not found: %s" value)))))) + + +(defcustom tidy-shell-program "tidy" + "The HTML program." + :group 'tidy + :type '(choice (file :must-match t) + (string :tag "File name (searched for in path): ")) + :set (lambda (symbol value) + (set-default symbol value) + (unless (string= value "tidy") + (or (file-executable-p value) + (executable-find value) + (lwarn '(tidy-shell-program) + :error "Tidy program not found: %s" value))))) + +(defcustom tidy-temp-directory temporary-file-directory + "Directory where tidy places its temp files. The default is the +current directory which works fine unless you are operating on remote +files via `ange-ftp' and its ilk, in which case it will try to place +the temp files on the remote server (and will probably fail). If this +is the case try setting this variable to something like \"/tmp/\" or +\"/var/tmp/\"." + :group 'tidy + :type 'directory + :set-after '(temporary-file-directory)) + +(defcustom tidy-menu-lock t + " *Non-nil means menu is locked (i.e. doesn't pop down) when +selecting toggle and radio options. + +See also `tidy-menu-x-position'." + :type 'boolean + :group 'tidy) + +(defcustom tidy-menu-x-position 211 + "Specify menu position height in pixels. + +This variable is used to set the horizontal position of the locked +menu, so don't forget to adjust it if menu position is not ok. + +See also `tidy-menu-lock'." + :type 'integer + :group 'tidy) + +;;;;; Local Variables + +(defvar tidy-debug nil + "If t then we rebuild everything on reload. Useful for debugging.") + +;;(eval-when-compile (setq tidy-debug t)) + +(defun tidy-toggle-debug () + "Toggle value of tidy-debug." + (interactive) + (message "tidy-debug is %s" (setq tidy-debug (not tidy-debug)))) + +;; (defun tidy-boolean-option-value (symbol) +;; "Return t when the symbol's value is \"yes\"." +;; (let ((name (symbol-name symbol))) +;; (assert (string= "tidy-" (substring name 0 5))) +;; (setq name (substring name 5)) +;; (let ((entry (assoc name tidy-options-alist))) +;; (assert (string= "Boolean" (nth 2 entry))))) +;; (when (symbol-value symbol) +;; (string= (symbol-value symbol)))) + +(defvar tidy-options-alist nil + "An alist containing all valid tidy options. +Each element is a list of the form + (NAME, SUB-MENU, VALUE-TYPE, DEFAULT-VALUE, DOC-STRING). +This is used to automatically construct variables and a menu bar. +To add new or modify exiting options simply modify this list.") + +;; Fix-me: built the options list dynamically, point to +;; http://tidy.sourceforge.net/docs/quickref.html for help +(defun tidy-build-options-alist () + (when (and tidy-shell-program + (executable-find tidy-shell-program)) + (let ((outbuf (get-buffer-create "* Tidy options *"))) + (call-process tidy-shell-program + nil ;; No input + outbuf ;; Output here + nil ;; Do not display + "-help-config") + (switch-to-buffer outbuf)))) + +(when (or (null tidy-options-alist) tidy-debug) + (setq tidy-options-alist + '( + ("add-xml-decl" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should add the XML declaration when +outputting XML or XHTML. Note that if the input already includes an <?xml +... ?> declaration then this option will be ignored.") + +;; ("add-xml-pi" "Fix Markup" "Boolean" "no" +;; " +;; Type: Boolean +;; Default: no +;; Example: y/n, yes/no, t/f, true/false, 1/0 + +;; This option is the same as the add-xml-decl option.") + + ("add-xml-space" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should add xml:space=\"preserve\" to elements +such as <PRE>, <STYLE> and <SCRIPT> when generating XML. This is needed if +the whitespace in such elements is to be parsed appropriately without +having access to the DTD.") + + ("alt-text" "Fix Markup" "String" "" + " +Type: String +Default: -none- + +This option specifies the default \"alt=\" text Tidy uses for <IMG> +attributes. This feature is dangerous as it suppresses further +accessibility warnings. You are responsible for making your documents +accessible to people who can not see the images!") + + ("ascii-chars" "Fix Markup" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +Can be used to modify behavior of -c (--clean yes) option. +Defaults to \"yes\" when using -c. Set to \"no\" to prevent +converting &emdash;, ”, and other named character entities +to their ascii equivalents.") + + ("assume-xml-procins" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should change the parsing of processing +instructions to require ?> as the terminator rather than >. This option is +automatically set if the input is in XML.") + + ("bare" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should strip Microsoft specific HTML from +Word 2000 documents, and output spaces rather than non-breaking spaces +where they exist in the input.") + + ("break-before-br" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output a line break before each <BR> +element.") + + ("char-encoding" "Encoding" "Encoding" "ascii" + " +Type: Encoding +Default: ascii +Example: ascii, latin1, raw, utf8, iso2022, mac, win1252 + +This option specifies the character encoding Tidy uses for both the input +and output. Possible values are: ascii, latin1, raw, utf8, iso2022, mac, +win1252. For ascii, Tidy will accept Latin-1 (ISO-8859-1) character +values, but will use entities for all characters whose value > 127. For +raw, Tidy will output values above 127 without translating them into +entities. For latin1, characters above 255 will be written as +entities. For utf8, Tidy assumes that both input and output is encoded as +UTF-8. You can use iso2022 for files encoded using the ISO-2022 family of +encodings e.g. ISO-2022-JP. For mac and win1252, Tidy will accept vendor +specific character values, but will use entities for all characters whose +value > 127.") + + ("clean" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should strip out surplus presentational tags +and attributes replacing them by style rules and structural markup as +appropriate. It works well on the HTML saved by Microsoft Office products.") + + ("doctype" "Fix Markup" "DocType" "auto" + " +Type: DocType +Default: auto +Example: auto, omit, strict, loose, transitional, user specified fpi \(string\) + +This option specifies the DOCTYPE declaration generated by Tidy. If set to +\"omit\" the output won't contain a DOCTYPE declaration. If set to \"auto\" +\(the default\) Tidy will use an educated guess based upon the contents of +the document. If set to \"strict\", Tidy will set the DOCTYPE to the strict +DTD. If set to \"loose\", the DOCTYPE is set to the loose \(transitional\) +DTD. Alternatively, you can supply a string for the formal public +identifier \(FPI\). For example: + + doctype: \"-//ACME//DTD HTML 3.14159//EN\" + +If you specify the FPI for an XHTML document, Tidy will set +the system identifier to the empty string. Tidy leaves the DOCTYPE for +generic XML documents unchanged.") + + ("drop-empty-paras" "Fix Markup" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should discard empty paragraphs. If set to +no, empty paragraphs are replaced by a pair of <BR> elements as HTML4 +precludes empty paragraphs.") + + ("drop-font-tags" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should discard <FONT> and <CENTER> tags +rather than creating the corresponding style rules, but only if the clean +option is also set to yes.") + + ("drop-proprietary-attributes" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should strip out proprietary attributes, +such as MS data binding attributes.") + + ("enclose-block-text" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should insert a <P> element to enclose any +text it finds in any element that allows mixed content for HTML +transitional but not HTML strict.") + + ("enclose-text" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should enclose any text it finds in the body +element within a <P> element. This is useful when you want to take +existing HTML and use it with a style sheet.") + +;; ("error-file" "Omit" "String" "-none-" +;; " +;; Type: String +;; Default: -none- + +;; This option specifies the error file Tidy uses for errors and +;; warnings. Normally errors and warnings are output to \"stderr\". + +;; This is option is ignored in Emacs.") + + ("escape-cdata" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should convert <![CDATA[]]> sections to +normal text.") + + ("fix-backslash" "Fix Markup" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should replace backslash characters \"\\\" in +URLs by forward slashes \"/\".") + + ("fix-bad-comments" "Fix Markup" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should replace unexpected hyphens with \"=\" +characters when it comes across adjacent hyphens. The default is yes. This +option is provided for users of Cold Fusion which uses the comment syntax: +<!--- --->") + + ("fix-uri" "Fix Markup" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should check attribute values that carry +URIsfor illegal characters and if such are found, escape them as HTML 4 +recommends.") + + ("force-output" "Input/Output" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should produce output even if errors are +encountered. Use this option with care - if Tidy reports an error, +this means Tidy was not able to, or is not sure how to, fix the error, +so the resulting output may not reflect your intention.") + +;; ("gnu-emacs" "Omit" "Boolean" "no" +;; " +;; Type: Boolean +;; Default: no +;; Example: y/n, yes/no, t/f, true/false, 1/0 + +;; This option specifies if Tidy should change the format for reporting +;; errors and warnings to a format that is more easily parsed by GNU +;; Emacs. + +;; This option is automatically set in Emacs." ) + + ("hide-comments" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should print out comments.") + + ("hide-endtags" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should omit optional end-tags when +generating the pretty printed markup. This option is ignored if you are +outputting to XML.") + + ("indent" "Indentation" "AutoBool" "no" + " +Type: AutoBool +Default: no +Example: auto, y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should indent block-level tags. If set to +\"auto\", this option causes Tidy to decide whether or not to indent the +content of tags such as TITLE, H1-H6, LI, TD, TD, or P depending on whether +or not the content includes a block-level element. You are advised to avoid +setting indent to yes as this can expose layout bugs in some browsers.") + + ("indent-attributes" "Indentation" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should begin each attribute on a new line.") + + ("indent-cdata" "Indent" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should indent <![CDATA[]]> sections.") + + ("indent-spaces" "Indentation" "Integer" "2" + " +Type: Integer +Default: 2 +Example: 0, 1, 2, ... + +This option specifies the number of spaces Tidy uses to indent content, +when indentation is enabled.") + + ("input-encoding" "Encoding" "Encoding" "latin1" + " +Type: Encoding +Default: ascii +Example: ascii, latin1, raw, utf8, iso2022, mac, win1252 + +This option specifies the character encoding Tidy uses for the input. See +char-encoding for more info.") + + ("input-xml" "Input/Output" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should use the XML parser rather than the +error correcting HTML parser.") + + ("join-classes" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should combine class names to generate a +single new class name, if multiple class assignments are detected on an +element.") + + ("join-styles" "Fix Markup" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should combine styles to generate a single +new style, if multiple style values are detected on an element.") + + ("keep-time" "Preference" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should alter the last modified time for +files it writes back to. The default is no, which allows you to tidy files +without affecting which ones will be uploaded to a Web server when using a +tool such as 'SiteCopy'. Note that this feature may not work on some +platforms.") + + ("literal-attributes" "Preference" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should ensure that whitespace characters +within attribute values are passed through unchanged.") + + ("logical-emphasis" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should replace any occurrence of <I> by <EM> +and any occurrence of <B> by <STRONG>. In both cases, the attributes are +preserved unchanged. This option can be set independently of the clean and +drop-font-tags options.") + + ("lower-literals" "Preference" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should convert the value of an attribute +that takes a list of predefined values to lower case. This is required for +XHTML documents.") + + ("markup" "Input/Output" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should generate a pretty printed version of +the markup. Note that Tidy won't generate a pretty printed version if it +finds significant errors (see force-output).") + + ("ncr" "Preference" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should allow numeric character references.") + + ("newline" "Encoding" "Encoding" "LF" + " +Type: Encoding +Default: LF +Example: LF, CRLF, CR + +Line ending style. \(Only used in batch operations here.\)") + + ("new-blocklevel-tags" "Tags" "Tag names" "" + " +Type: Tag names +Default: -none- +Example: tagX, tagY, ... + +This option specifies new block-level tags. This option takes a space or +comma separated list of tag names. Unless you declare new tags, Tidy will +refuse to generate a tidied file if the input includes previously unknown +tags. Note you can't change the content model for elements such as +<TABLE>, <UL>, <OL> and <DL>.") + + ("new-empty-tags" "Tags" "Tag names" "" + " +Type: Tag names +Default: -none- +Example: tagX, tagY, ... + +This option specifies new empty inline tags. This option takes a space or +comma separated list of tag names. Unless you declare new tags, Tidy will +refuse to generate a tidied file if the input includes previously unknown +tags. Remember to also declare empty tags as either inline or blocklevel.") + + ("new-inline-tags" "Tags" "Tag names" "" + " +Type: Tag names +Default: -none- +Example: tagX, tagY, ... + +This option specifies new non-empty inline tags. This option takes a space +or comma separated list of tag names. Unless you declare new tags, Tidy +will refuse to generate a tidied file if the input includes previously +unknown tags.") + + ("new-pre-tags" "Tags" "Tag names" "" + " +Type: Tag names +Default: -none- +Example: tagX, tagY, ... + +This option specifies new tags that are to be processed in exactly the +same way as HTML's <PRE> element. This option takes a space or comma +separated list of tag names. Unless you declare new tags, Tidy will refuse +to generate a tidied file if the input includes previously unknown +tags. Note you can not as yet add new CDATA elements (similar to +<SCRIPT>).") + + ("numeric-entities" "Preference" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output entities other than the +built-in HTML entities \(&, <, > and "\) in the numeric +rather than the named entity form.") + + ("output-bom" "Encoding" "AutoBool" "auto" + " +Type: AutoBool +Default: auto +Example: auto, y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should write a Unicode Byte Order Mark +character (BOM; also known as Zero Width No-Break Space; has value of +U+FEFF) to the beginning of the output; only for UTF-8 and UTF-16 output +encodings. If set to \"auto\", this option causes Tidy to write a BOM to the +output only if a BOM was present at the beginning of the input. A BOM is +always written for XML/XHTML output using UTF-16 output encodings.") + + ("output-encoding" "Encoding" "Encoding" "ascii" + " +Type: Encoding +Default: ascii +Example: ascii, latin1, raw, utf8, iso2022, mac, win1252 + +This option specifies the character encoding Tidy uses for the output. See +char-encoding for more info. May only be different from input-encoding for +Latin encodings (ascii, latin1, mac, win1252).") + + ("output-xhtml" "Input/Output" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should generate pretty printed output, +writing it as extensible HTML. This option causes Tidy to set the DOCTYPE +and default namespace as appropriate to XHTML. If a DOCTYPE or namespace +is given they will checked for consistency with the content of the +document. In the case of an inconsistency, the corrected values will +appear in the output. For XHTML, entities can be written as named or +numeric entities according to the setting of the \"numeric-entities\" +option. The original case of tags and attributes will be preserved, +regardless of other options.") + + ("output-xml" "Input/Output" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should pretty print output, writing it as +well-formed XML. Any entities not defined in XML 1.0 will be written as +numeric entities to allow them to be parsed by a XML parser. The original +case of tags and attributes will be preserved, regardless of other +options.") + + ("quiet" "Input/Output" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output the summary of the numbers of +errors and warnings, or the welcome or informational messages.") + + ("quote-ampersand" "Preference" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output unadorned & characters as +&.") + + ("quote-marks" "Preference" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output \" characters as " as is +preferred by some editing environments. The apostrophe character \' is +written out as ' since many web browsers don't yet support '.") + + ("quote-nbsp" "Preference" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output non-breaking space characters +as entities, rather than as the Unicode character value 160 (decimal).") + + ("raw" "Omit" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 char-encoding + +Currently not used, but this option would be the same as the +char-encoding: raw option.") + + ("repeated-attributes" "Fix Markup" ("keep-first" "keep-last") "keep-last" + " +Type: - +Default: keep-last +Example: keep-first, keep-last + +This option specifies if Tidy should keep the first or last attribute, if +an attribute is repeated, e.g. has two align attributes.") + + + ("replace-color" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should replace numeric values in color +attributes by HTML/XHTML color names where defined, e.g. replace +\"#ffffff\" with \"white\"." ) + + ("slide-style" "Omit" "String" + " +Type: Name +Default: -none- +split Currently not used.") + +;; ("show-body-only" "Omit" "Boolean" "no" +;; " +;; Type: Boolean +;; Default: no +;; Example: y/n, yes/no, t/f, true/false, 1/0 + +;; This option specifies if Tidy should print only the contents of the body +;; tag as an HTML fragment. Useful for incorporating existing whole pages as +;; a portion of another page. + +;; Emacs overrides this option.") + + ("show-errors" "Input/Output" "Integer" "6" + " +Type: Integer +Default: 6 +Example: 0, 1, 2, ... + +This option specifies the number Tidy uses to determine if further errors +should be shown. If set to 0, then no errors are shown.") + + ("show-warnings" "Input/Output" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should suppress warnings. This can be useful +when a few errors are hidden in a flurry of warnings.") + + ("slide-style" "Omit" "String" "" + " +Type: Name +Default: -none- + +Currently not used.") + + ("split" "Omit" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should create a sequence of slides from +the input, splitting the markup prior to each successive <H2>. The +slides are written to \"slide001.html\", \"slide002.html\" etc. + +There is currently no Emacs support for this option.") + + ("tab-size" "Indentation" "Integer" "4" + " +Type: Integer +Default: 4 +Example: 0, 1, 2, ... + +This option specifies the number of columns that Tidy uses between +successive tab stops. It is used to map tabs to spaces when reading the +input. Tidy never outputs tabs.") + + ("tidy-mark" "Preference" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should add a meta element to the document +head to indicate that the document has been tidied. Tidy won't add a meta +element if one is already present.") + + ("uppercase-attributes" "Preference" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output attribute names in upper +case. The default is no, which results in lower case attribute names, +except for XML input, where the original case is preserved.") + + ("uppercase-tags" "Preference" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should output tag names in upper case. The +default is no, which results in lower case tag names, except for XML +input, where the original case is preserved.") + + ("word-2000" "Fix Markup" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should go to great pains to strip out all +the surplus stuff Microsoft Word 2000 inserts when you save Word documents +as \"Web pages\". Doesn't handle embedded images or VML.") + + ("wrap" "Line Wrapping" "Integer" "68" + " +Type: Integer +Default: 68 +Example: 0, 1, 2, ... + +This option specifies the right margin Tidy uses for line wrapping. Tidy +tries to wrap lines so that they do not exceed this length. Set wrap to +zero if you want to disable line wrapping.") + + ("wrap-asp" "Line Wrapping" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should line wrap text contained within ASP +pseudo elements, which look like: <% ... %>.") + + ("wrap-attributes" "Line Wrapping" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should line wrap attribute values, for +easier editing. This option can be set independently of +wrap-script-literals.") + + ("wrap-jste" "Line Wrapping" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should line wrap text contained within JSTE +pseudo elements, which look like: <# ... #>.") + + ("wrap-php" "Line Wrapping" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should line wrap text contained within PHP +pseudo elements, which look like: <?php ... ?>.") + + ("wrap-script-literals" "Line Wrapping" "Boolean" "no" + " +Type: Boolean +Default: no +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should line wrap string literals that appear +in script attributes. Tidy wraps long script string literals by inserting +a backslash character before the line break.") + + ("wrap-sections" "Line Wrapping" "Boolean" "yes" + " +Type: Boolean +Default: yes +Example: y/n, yes/no, t/f, true/false, 1/0 + +This option specifies if Tidy should line wrap text contained within +<![... ]> section tags.") + +;; ("write-back" "Omit" "Boolean" "no" +;; " +;; Type: Boolean +;; Default: no +;; Example: y/n, yes/no, t/f, true/false, 1/0 + +;; This option specifies if Tidy should write back the tidied markup to +;; the same file it read from. You are advised to keep copies of +;; important files before tidying them, as on rare occasions the result +;; may not be what you expect. + +;; This option is ignored by Emacs.") + )) + ) + +;;;;; Create a variable for each option in `tidy-options-alist'" + +;; these variables are made buffer local so that different buffers can +;; use a different set of options + +(let ((options-alist tidy-options-alist) + option name symbol docstring) + + (while (setq option (car options-alist)) + (setq name (nth 0 option) + docstring (nth 4 option) + symbol (intern (concat "tidy-" name))) + ;; create the variable on the fly + (put symbol 'variable-documentation docstring) + (make-variable-buffer-local symbol) + (set symbol nil) ;;default) + (setq options-alist (cdr options-alist)) + ) + ) + + +;;;;; Quick options setting + +(defvar tidy-xhtml-values + '( + (add-xml-decl "yes") + (add-xml-space "no") + (doctype "auto") + (escape-cdata "no") + (fix-backslash "yes") + (fix-bad-comments "yes") + (fix-uri "yes") + (indent "yes") + (indent-cdata "yes") + (indent-spaces "2") + (join-classes "yes") + (join-styles "yes") + (lower-literals "yes") + (newline "LF") + (output-xhtml "yes") + (output-xml "no") + (quote-ampersand "yes") + (quote-nbsp "yes") + (tidy-mark "no") + (uppercase-attributes "no") + (uppercase-tags "no"))) + +(defun tidy-xhtml-options-ok () + (let ((ok t)) + (dolist (optval tidy-xhtml-values) + (let* ((opt (car optval)) + (val (cadr optval)) + (nam (symbol-name opt)) + (ent (assoc nam tidy-options-alist)) + (def (nth 3 ent)) + (sym (intern (concat "tidy-" nam)))) + (when (equal val def) + (setq val nil)) + (unless (equal val (symbol-value sym)) + (setq ok nil)))) + ok)) + +(defun tidy-show-xhtml-options () + "List the settings set by `tidy-set-xhtml-options'." + (interactive) + (with-output-to-temp-buffer (help-buffer) + (with-current-buffer (help-buffer) + (help-setup-xref (list #'tidy-show-xhtml-settings) (interactive-p)) + (let ((inhibit-read-only t) + (point (point)) + s) + (insert "Values that will be set by `tidy-set-xhtml-options'. ") + (setq s "Green") + (put-text-property 0 (length s) + 'face '(:foreground "green") + s) + (insert s " indicates that the local value in the current buffer") + (insert " is the value that would be set, ") + (setq s "red") + (put-text-property 0 (length s) + 'face '(:foreground "red") + s) + (insert s " indicates it is not.\n\n") + (fill-region point (point)) + (dolist (optval tidy-xhtml-values) + (let* ((opt (car optval)) + (val (cadr optval)) + (nam (symbol-name opt)) + (ent (assoc nam tidy-options-alist)) + (def (nth 3 ent)) + (cur (symbol-value (intern (concat "tidy-" nam)))) + (show (copy-seq val)) + ) + (unless cur (setq cur def)) + (put-text-property 0 (length show) + 'face + (if (equal val cur) + '(:foreground "green") + 'face '(:foreground "red")) + show) + (insert (format "%25s => %s\n" opt show)))))) + (with-no-warnings (print-help-return-message)))) + +(defun tidy-set-xhtml-options (&optional only-current-buffer) + "Set option necessary to convert to XHTML. +To get a list of this settings use `tidy-show-xhtml-options'. + +Note that the option variables are buffer local. The default +variable values are always set. If ONLY-CURRENT-BUFFER is nil set +the buffer local variables in all buffers." + (interactive (list + (not (y-or-n-p "Set XHTML options in all buffers? ")))) + (let ((buffers (if (not only-current-buffer) + (buffer-list) + (list (current-buffer))))) + (dolist (buffer buffers) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (dolist (optval tidy-xhtml-values) + (let* ((opt (car optval)) + (val (cadr optval)) + (nam (symbol-name opt)) + (ent (assoc nam tidy-options-alist)) + (def (nth 3 ent)) + (symbol (intern (concat "tidy-" nam)))) + (when (equal val def) + (setq val nil)) + (set-default symbol val) ;; The least overhead I think + (unless (equal val (symbol-value symbol)) + (set symbol val))))))))) + + +;;;;; Menu Lock (adapted from printing.el) + +;; quite compiler +(eval-when-compile + (progn + (or (boundp 'current-menubar) + (defvar current-menubar nil)) + (or (fboundp 'tidy-menu-position) + (defun tidy-menu-position () "")) + (or (fboundp 'tidy-menu-lock) + (defun tidy-menu-lock (entry state path) "")) + (or (fboundp 'tidy-menu-lookup) + (defun tidy-menu-lookup (path) "")) + )) + +;; always define these +(defvar tidy-menu nil "Menu used by tidy.") +(defvar tidy-menu-position nil) +(defvar tidy-menu-state nil) + +(cond + ((tidy-xemacs-p) + ;; XEmacs + (defun tidy-menu-position () + (tidy-x-make-event + 'button-release + (list 'button 1 + 'x tidy-menu-x-position + 'y -5 + ))) + + ;; XEmacs + (defun tidy-menu-lock (entry state path) + (when (and (not (interactive-p)) tidy-menu-lock) + (or (and tidy-menu-position (eq state tidy-menu-state)) + (setq tidy-menu-position (tidy-menu-position) + tidy-menu-state state)) + (let* ((menu (tidy-menu-lookup path)) + (result (tidy-x-get-popup-menu-response menu tidy-menu-position))) + (and (tidy-x-misc-user-event-p result) + (funcall (tidy-x-event-function result) + (tidy-x-event-object result)))) + (setq tidy-menu-position nil))) + + ;; XEmacs + (defun tidy-menu-lookup (path) + (car (tidy-x-find-menu-item current-menubar (cons "Tidy" path))))) + + (t + ;; GNU Emacs + (defun tidy-menu-position () + (let () + (list (list tidy-menu-x-position '-5) + (selected-frame)))) ; frame + + ;; GNU Emacs +;; (defun tidy-menu-lock-old (entry state path) +;; (when (and (not (interactive-p)) tidy-menu-lock) +;; (or (and tidy-menu-position (eq state tidy-menu-state)) +;; (setq tidy-menu-position (tidy-menu-position ) +;; tidy-menu-state state)) +;; (let* ((menu (tidy-menu-lookup path)) +;; (result (x-popup-menu tidy-menu-position menu))) +;; (and result +;; (let ((command (lookup-key menu (vconcat result)))) +;; (if (fboundp command) +;; (funcall command) +;; (eval command))))) +;; (setq tidy-menu-position nil))) + (defun tidy-menu-lock (entry state path) + (when (and (not (interactive-p)) tidy-menu-lock) + (or (and tidy-menu-position (eq state tidy-menu-state)) + (setq tidy-menu-position (tidy-menu-position ) + tidy-menu-state state)) + ;;(popup-menu tidy-menu tidy-menu-position))) + (run-with-idle-timer 1 nil 'popup-menu tidy-menu tidy-menu-position))) + + ;; GNU Emacs + (defun tidy-menu-lookup (dummy) + (lookup-key (current-local-map) [menu-bar Tidy]))) + ) + +;;;;; Define classes of menu items + +(defun tidy-set (var-sym value mess entry state &optional path) + "Set the value of the symbol VAR-SYM to VALUE giving a message +derived from VALUE and MESS. Pass on menu data to `tidy-menu-lock'." + (set var-sym value) + (message "%s is %s" mess value) + (tidy-menu-lock entry state path)) + +(defun tidy-boolean-entry (symbol name type default menu) + "Returns a menu entry that allows us to toggle the value of SYMBOL. +SYMBOL refers to the option called NAME which has default value +DEFAULT. TYPE should always have the value \"Boolean\". MENU refers +to the sub-menu that this item belongs to and POSITION its position in +that list." + (cond ((equal default "no") + (list (vector name + (list 'tidy-set (list 'quote symbol) + (list 'if symbol 'nil "yes") + name + (list 'quote menu) + '(quote toggle) + ) + :style 'toggle + :selected (list 'if symbol 't 'nil)))) + + ((equal default "yes") + (list (vector name (list 'tidy-set (list 'quote symbol) + (list 'if symbol 'nil "no") + name + (list 'quote menu) + '(quote toggle) + ) + :style 'toggle + :selected (list 'if symbol 'nil 't)))))) + +(defun tidy-list-entry (symbol name type default menu) +"Returns a menu entry that allows us to set via a radio button the +value of SYMBOL. SYMBOL refers to the option called NAME which has +default value DEFAULT. TYPE should be a list of the possible +values. MENU refers to the sub-menu that this item belongs to and +POSITION its position in that list." + (let (value element) + (while (setq value (car type)) + (if (equal value default) + (setq element + (append element + (list + (vector + (concat name " is \"" value "\"") + (list 'tidy-set (list 'quote symbol) + (list 'if symbol 'nil value) + name + (list 'quote menu) + '(quote toggle) + ) + :style 'radio + :selected (list 'if symbol 'nil 't) + )))) + (setq element + (append element + (list + (vector + (concat name " is \"" value "\"") + + (list 'tidy-set (list 'quote symbol) + (list 'if symbol 'nil value) + name + (list 'quote menu) + '(quote toggle) + ) + + :style 'radio + :selected (list + 'if (list 'string-equal symbol value) + 't 'nil) + ))))) + (setq type (cdr type))) + element)) + +(defun tidy-set-string (symbol name default) + "Set the value of SYMBOL identified by name to VALUE, +unless VALUE equals DEFAULT, in which case we set it to nil." + (interactive) + (let* ((last-value (symbol-value symbol)) + (new-value + (if (tidy-xemacs-p) + (read-string (format "Set %s to: " name) + (or last-value default) nil) ;; no default arg + (read-string (format "Set %s to: " name) + (or last-value default) nil default)))) + (set symbol (if (equal new-value default) nil new-value)))) + +(defun tidy-set-integer (symbol name default) + "Set the value of SYMBOL identified by name to VALUE, +unless VALUE = DEFAULT, in which case we set it to nil." + (interactive) + (let* ((last-value (symbol-value symbol)) + ;; careful to interpret the string as a number + (new-value + (string-to-number + (if (tidy-xemacs-p) + (read-string (format "Set %s to: " name) + (or last-value default) nil) + (read-string (format "Set %s to: " name) + (or last-value default) nil default) + )))) + (set symbol (if (= new-value (string-to-number default)) nil + (number-to-string new-value))))) + + +(defun tidy-string-entry (symbol name type default menu) + "Returns a menu entry that allows us to set the value of SYMBOL. +SYMBOL refers to the option called NAME which has default value +DEFAULT. TYPE should always be one of \"String\" \"Tags\", or +\"DocType\". MENU and POSITION are not used in this case." + + (list (vector (concat "set " name) + (list 'tidy-set-string + (list 'quote symbol) + name default)))) + +(defun tidy-integer-entry (symbol name type default menu) +"Returns a menu entry that allows us to set the value of SYMBOL. +SYMBOL refers to the option called NAME which has default value +DEFAULT. TYPE should always have the value \"Integer\". MENU and +POSITION are not used in this case. " + (list (vector (concat "set " name) + (list 'tidy-set-integer + (list 'quote symbol) + name default)))) + +(defun tidy-exe-found () + (when tidy-shell-program + ;;(file-executable-p (car (split-string tidy-shell-program))))) + (or (file-executable-p tidy-shell-program) + (executable-find tidy-shell-program)))) + + +(defvar tidy-top-menu nil + "The first part of the menu.") +(when (or (null tidy-top-menu) tidy-debug) + (setq tidy-top-menu + '("Tidy" + ["Tidy Buffer" tidy-buffer + :active (tidy-exe-found)] + +;; ["Tidy Region" tidy-region +;; :active (and (mark) +;; (tidy-exe-found)) +;; :keys "C-u \\[tidy-buffer]"] + + ["Tidy Directory Tree" tidy-tree + :active (tidy-exe-found)] + + ["Tidy Site" tidy-tree + :active (and (featurep 'html-site) + (tidy-exe-found))] + + "----------------------------------------------" + + ["Customize Tidy" (customize-group-other-window 'tidy)] + +;; ["Use Ediff" (lambda () (interactive) +;; (setq tidy-use-ediff (not tidy-use-ediff))) +;; :style toggle +;; :selected tidy-use-ediff +;; ] + +;; ["Load Settings" tidy-parse-config-file +;; :active (and tidy-config-file (file-exists-p tidy-config-file))] + +;; ["Load Settings All Buffers" (lambda () (interactive) +;; (tidy-parse-config-file t)) +;; :active (and tidy-config-file (file-readable-p tidy-config-file))] + + ["Save Settings" tidy-save-settings + :active (and tidy-config-file (file-readable-p tidy-config-file))] + + "----------------------------------------------" + + ))) + +(defvar tidy-newline-menu + '("Set newline" + ["LF" (tidy-set 'tidy-newline + nil + "newline" + 'newline + 'toggle) + :style radio + :selected (if (null tidy-newline) t nil)] + + ["CRLF" (tidy-set 'tidy-newline + "CRLF" + "newline" + 'newline + 'toggle) + :style radio + :selected (if (equal tidy-newline "CRLF") t nil)] + + ["CR" (tidy-set 'tidy-newline + "CR" + "newline" + 'newline + 'toggle) + :style radio + :selected (if (equal tidy-newline "CRLF") t nil)] + )) + +(defvar tidy-doctype-menu nil "The second to last sub-menu.") +(when (or (null tidy-doctype-menu) tidy-debug) + (setq tidy-doctype-menu + '("Set doctype" ;; ==> + + ["auto" (tidy-set 'tidy-doctype + nil + "doctype" + 'doctype + 'toggle) + :style radio + :selected (if (null tidy-doctype) t nil)] + + ["omit" (tidy-set 'tidy-doctype + "omit" + "doctype" + 'doctype + 'toggle) + :style radio + :selected (if (equal tidy-doctype "omit") t nil)] + + ["strict" (tidy-set 'tidy-doctype + "strict" + "doctype" + 'doctype + 'toggle) + :style radio + :selected (if (equal tidy-doctype "strict") t nil)] + + ["loose" (tidy-set 'tidy-doctype + "loose" + "doctype" + 'doctype + 'toggle) + :style radio + :selected (if (equal tidy-doctype "loose") t nil)] + + ["transitional" (tidy-set 'tidy-doctype + "transitional" + "doctype" + 'doctype + 'toggle) + :style radio + :selected (if (equal tidy-doctype "transitional") t nil)] + + ["fpi" (null nil) ;; stub function + :style radio + :selected (if (or (null tidy-doctype) + (equal tidy-doctype "omit") + (equal tidy-doctype "strict") + (equal tidy-doctype "loose")) + nil t) ] + + ["reset fpi" (tidy-set-string 'tidy-doctype "doctype" "" "")] + ))) + +(defconst tidy-emacs-encoding-lbl "Use Emacs' encoding") + +(defun tidy-create-encoding-menu (label encoding-what msg-what) + (list label ;; ==> + (vector tidy-emacs-encoding-lbl (list 'tidy-set (list 'quote encoding-what) + tidy-emacs-encoding-lbl ;(list 'tidy-get-buffer-encoding) + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'equal encoding-what tidy-emacs-encoding-lbl) t nil) + ) + + "----------------------------------------------" + + (vector "ascii" (list 'tidy-set (list 'quote encoding-what) + nil + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'null encoding-what) t nil) ;; default + ) + + (vector "raw" (list 'tidy-set (list 'quote encoding-what) + "raw" + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'equal encoding-what "raw") t nil)) + + (vector "latin1" (list 'tidy-set (list 'quote encoding-what) + "latin1" + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'equal encoding-what "latin1") t nil)) + + (vector "utf8" (list 'tidy-set (list 'quote encoding-what) + "utf8" + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'equal encoding-what "utf8") t nil)) + + (vector "iso2022" (list 'tidy-set (list 'quote encoding-what) + "iso2022" + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'equal encoding-what "iso2022") t nil)) + + (vector "mac" (list 'tidy-set (list 'quote encoding-what) + "mac" + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'equal encoding-what "mac") t nil)) + + (vector "win1252" (list 'tidy-set (list 'quote encoding-what) + "win1252" + msg-what + ''encoding + ''toggle) + :style 'radio + :selected (list 'if (list 'equal encoding-what "win1252") t nil)) + + )) +;; (defvar tidy-char-encoding-menu nil "The last sub-menu.") +;; (when (or (null tidy-char-encoding-menu) tidy-debug) +;; (setq tidy-char-encoding-menu +;; (tidy-create-encoding-menu +;; "Set char-encoding" 'tidy-char-encoding "char-encoding"))) +;; (defvar tidy-input-encoding-menu nil "The last sub-menu.") +;; (when (or (null tidy-input-encoding-menu) tidy-debug) +;; (setq tidy-input-encoding-menu +;; (tidy-create-encoding-menu +;; "Set input-encoding" 'tidy-input-encoding "input-encoding"))) +(defvar tidy-output-encoding-menu nil "The last sub-menu.") +(when (or (null tidy-output-encoding-menu) tidy-debug) + (setq tidy-output-encoding-menu + (tidy-create-encoding-menu + "Set output-encoding" 'tidy-output-encoding "output-encoding"))) + +;;;;; Create a menu item for each option that has a valid sub-menu +;; field + +(when (or (null tidy-menu) tidy-debug) + (let ((options-alist tidy-options-alist) + + ;; sub menus are divided into two parts with list type options + ;; coming first, followed by the rest + + markup-menu-bool markup-menu-set + line-wrap-menu-bool line-wrap-menu-set + preference-menu-bool preference-menu-set + indent-menu-bool indent-menu-set + io-menu-bool io-menu-set + tags-menu-bool tags-menu-set + + name sub-menu type default symbol entry entry-function option) + + (while (setq option (car options-alist)) + (setq name (nth 0 option) + sub-menu (nth 1 option) + type (nth 2 option) + default (nth 3 option) + symbol (intern (concat "tidy-" name)) + entry nil) + + (cond ((equal type "Boolean") + (setq entry-function 'tidy-boolean-entry)) + + ((equal type "AutoBool") + (setq entry-function 'tidy-list-entry) + (setq type '("auto" "yes" "no"))) + + ((equal type "DocType") + (setq entry '())) ;; handled below + + ((equal type "Tag names") + (setq entry-function 'tidy-string-entry)) + + ((equal type "String") + (setq entry-function 'tidy-string-entry)) + + ((equal type "Integer") + (setq entry-function 'tidy-integer-entry)) + + ((equal type "Encoding") + (setq entry '()));; handled below + + ((listp type) + (setq entry-function 'tidy-list-entry)) + (t + (error (concat "Tidy: unhandled value type " type " for " name)))) + + (cond ((equal sub-menu "Fix Markup") + (setq entry (funcall + entry-function + symbol + name + type + default + 'markup)) + + (if (or (equal type "Boolean") (equal type "AutoBool") (listp type)) + (setq markup-menu-bool (append markup-menu-bool entry)) + (setq markup-menu-set (append markup-menu-set entry)))) + + ((equal sub-menu "Indentation") + (setq entry (funcall + entry-function + symbol + name + type + default + 'indent)) + + (if (or (equal type "Boolean") (equal type "AutoBool") (listp type)) + (setq indent-menu-bool (append indent-menu-bool entry)) + (setq indent-menu-set (append indent-menu-set entry)))) + + ((equal sub-menu "Line Wrapping") + (setq entry (funcall + entry-function + symbol + name + type + default + 'line-wrap)) + + (if (or (equal type "Boolean") (equal type "AutoBool") (listp type)) + (setq line-wrap-menu-bool (append line-wrap-menu-bool entry)) + (setq line-wrap-menu-set (append line-wrap-menu-set entry)))) + + ((equal sub-menu "Input/Output") + (setq entry (funcall + entry-function + symbol + name + type + default + 'io)) + + (if (or (equal type "Boolean") (equal type "AutoBool") (listp type)) + (setq io-menu-bool (append io-menu-bool entry)) + (setq io-menu-set (append io-menu-set entry)))) + + ((equal sub-menu "Preference") + (setq entry (funcall + entry-function + symbol + name + type + default + 'preference)) + + (if (or (equal type "Boolean") (equal type "AutoBool") (listp type)) + (setq preference-menu-bool (append preference-menu-bool entry)) + (setq preference-menu-set (append preference-menu-set entry)))) + + ((equal sub-menu "Tags") + (setq entry (funcall + entry-function + symbol + name + type + default + 'tags)) + + (if (or (equal type "Boolean") (equal type "AutoBool")) + (setq tags-menu-bool (append tags-menu-bool entry)) + (setq tags-menu-set (append tags-menu-set entry)))) + (t)) ;; we simple omit all other menus + + (setq options-alist (cdr options-alist))) + + (setq tidy-menu (append + tidy-top-menu + (list + (list "Quick Options Settings" + (vector "Set Options for XHTML" + 'tidy-set-xhtml-options + :style 'toggle + :selected '(tidy-xhtml-options-ok) + ) + (vector "Show Options for XHTML" + 'tidy-show-xhtml-options + ) + )) + (list (append (list "Advanced") + + +;; "----------------------------------------------" + +;; ["Menu Lock" (tidy-set 'tidy-menu-lock +;; (if tidy-menu-lock nil t) +;; "Menu Lock" +;; 'top +;; 'toggle) +;; :style toggle +;; :selected (if tidy-menu-lock t nil) +;; ] +;; (vector "Menu Lock" +;; 'tidy-menu-lock +;; :style 'toggle +;; :selected '(if tidy-menu-lock t nil) +;; ) + (list (vector "Menu Lock" + '(tidy-set 'tidy-menu-lock + (if tidy-menu-lock nil t) + "Menu Lock" + 'top + 'toggle + ) + :style 'toggle + :selected '(if tidy-menu-lock t nil) + )) + (list (list "-------")) + + (list (append (list "Fix Markup") + markup-menu-bool + markup-menu-set)) + (list (append (list "Line Wrapping") + line-wrap-menu-bool + line-wrap-menu-set)) + (list (append (list "Preference") + preference-menu-bool + preference-menu-set)) + (list (append (list "Indentation") + indent-menu-bool + indent-menu-set)) + (list (append (list "Input/Output") + io-menu-bool + io-menu-set)) + (list (append (list "Tags") + tags-menu-bool + tags-menu-set)) + (list tidy-doctype-menu) + (list tidy-output-encoding-menu) + (list tidy-newline-menu) + )) + '(["Describe Options" tidy-describe-options t]) + (list (list "-------")) + '(["Tidy Home Page" + (lambda () + "Open Tidy home page in your web browser." + (interactive) + (browse-url "http://tidy.sourceforge.net/")) + t]) + )) + ) +) + +(defvar tidy-menu-symbol nil) +;;(tidy-build-menu (&optional map) +;;;###autoload +(defun tidy-build-menu (&optional map) + "Set up the tidy menu in MAP. +Used to set up a Tidy menu in your favourite mode." + (interactive) ;; for debugging + (unless tidy-menu-symbol + (unless tidy-config-file-parsed + (tidy-parse-config-file) + (setq tidy-config-file-parsed t)) + ;;(or map (setq map (current-local-map))) + (easy-menu-remove tidy-menu) + (easy-menu-define tidy-menu-symbol map "Menu for Tidy" tidy-menu) + (setq tidy-menu-symbol (delete "Tidy" tidy-menu-symbol)) + (easy-menu-add tidy-menu map)) + t) + +;;;;; Option description support + +;; quiet FSF Emacs and XEmacs compilers +(eval-when-compile + (progn (or (fboundp 'event-point) (defun event-point (dummy) "")) + (or (fboundp 'posn-point) (defun posn-point (dummy) "")) + (or (fboundp 'event-start) (defun event-start (dummy) "")))) + +(defun tidy-describe-this-option-mouse (click) + (interactive "e") + (let ((p (if (tidy-xemacs-p) + (event-point click) + (posn-point (event-start click))))) + (tidy-describe-this-option p))) + +(defun tidy-describe-this-option (&optional point) + "Describe variable associated with the text at point." + (interactive (list (point))) + + (let* ((variable (get-text-property + point + 'tidy-variable)) + value + buffer) ;; reuse the help buffer + (when variable + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'tidy-describe-this-option point) (interactive-p)) + (with-current-buffer (help-buffer) + (setq value (symbol-value variable)) + (insert (substring (symbol-name variable) 5) ;; clip the `tidy-' prefix + " is set to ") + (if value (insert value) (insert "set to the default value")) + (insert "\n\n" (documentation-property variable 'variable-documentation)) + (local-set-key [(q)] 'tidy-quit-describe-options) + (with-no-warnings (print-help-return-message))))))) + +(defun tidy-quit-describe-options () + "Rid thyself of any display associated with Tidy's options." + (interactive) + (bury-buffer (get-buffer "*tidy-options*")) + (delete-windows-on (get-buffer "*tidy-options*")) + (bury-buffer (get-buffer "*Help*")) + (delete-windows-on (get-buffer "*Help*"))) + +;; nicked this from cal-desk-calendar.el:-) +(defun tidy-current-line () + "Get the current line number (in the buffer) of point." + ;;(interactive) + (save-restriction + (widen) + (save-excursion + (beginning-of-line) + (1+ (count-lines 1 (point)))))) + +(defun tidy-goto-line (line) + (save-restriction + (widen) + (goto-char (point-min)) + (forward-line (1- line)))) + +(defun tidy-describe-options () + "Interactively access documentation strings for `tidy-' variables." + (interactive) + (let ((buffer (get-buffer "*tidy-options*"))) + (if buffer (pop-to-buffer buffer) + ;; else build it from scratch + (setq buffer (get-buffer-create "*tidy-options*")) + (let* ((start 0) + (end 0) + name + (count 0) + (option-alist tidy-options-alist) + (column2a (+ (length "drop-proprietary-attributes") 3)) + (column2b (/ (window-width) 3)) + (column2 (if (> column2a column2b) column2a column2b)) + (column3 (* 2 column2)) + (start-line 0) + (third-length 0) + (two-third-length 0)) + + (set-buffer buffer) + + (setq buffer-read-only nil) + (delete-region (point-min) (point-max)) ;; empty the buffer + + ;; set up local bindings + (if (tidy-xemacs-p) + (local-set-key [(button2)] 'tidy-describe-this-option-mouse) + (local-set-key [(mouse-2)] 'tidy-describe-this-option-mouse)) + + (local-set-key "\r" 'tidy-describe-this-option) + (local-set-key [(q)] 'tidy-quit-describe-options) + + (insert "Press RET over option to see its description. " + "Type \"q\" to quit." "\n\n") + + (setq start-line (tidy-current-line)) + (setq third-length (1+ (/ (length option-alist) 3) )) + (setq two-third-length (1- (* 2 third-length))) + + (while (setq name (car (car-safe option-alist))) + (setq option-alist (cdr option-alist)) + (setq count (+ count 1)) + + (cond + ((< count third-length) ;; 0 <= count < third-length + (setq start (point)) + (insert name) + (setq end (point)) + (insert "\n")) + ((< count two-third-length) ;; third-length <= count < two-third-length + (if (= count third-length) + (tidy-goto-line start-line) + (forward-line 1)) + (end-of-line) + (setq start (point)) + (indent-to-column column2) + (setq end (point)) + (put-text-property start end 'mouse-face 'default) + (setq start (point)) + (insert name) + (setq end (point))) + (t ;; two-third-length <= count < length + (if (= count two-third-length) + (tidy-goto-line start-line) + (forward-line 1)) + (end-of-line) + (setq start (point)) + (indent-to-column column3) + (setq end (point)) + (put-text-property start end 'mouse-face 'default) + (setq start (point)) + (insert name) + (setq end (point)))) + + ;; make the strings funky + (put-text-property start end 'mouse-face 'highlight) + (put-text-property start end 'tidy-variable (intern (concat "tidy-" name))) + ) + (setq buffer-read-only t) + ;;(beginning-of-buffer) + (goto-char (point-min)) + (pop-to-buffer buffer) + )))) + +;;;;; Configuration file support + +(defun tidy-parse-config-file (&optional all-buffers) + "Parse `tidy-config-file' and set variables accordingly. +If `tidy-config-file' is nil or \"\" do nothing. If the file does +not exist just give a message. + +Note that the option variables are buffer local. The default +variable values are always set. If ALL-BUFFERS is non-nil set the +buffer local variables in all buffers." + (interactive (list + (y-or-n-p "Set Tidy config file values in all buffers? "))) + (tidy-set-xhtml-options all-buffers) + (when (and tidy-config-file + (not (string= "" tidy-config-file))) + (if (not (file-exists-p tidy-config-file)) + (unless (string= tidy-config-file tidy-default-config-file) + (message "Could not find Tidy config file \"%s\"." tidy-config-file)) + (message "Parsing config file...") + (let ((html-buffer (current-buffer)) + (config-buffer (find-file-noselect tidy-config-file t)) + config-variables) + (with-current-buffer config-buffer + (goto-char (point-min)) ;; unnecessary but pedantic + + ;; delete all comments + (while (re-search-forward "//.*\n" nil t) + (replace-match "" nil nil)) + + (goto-char (point-min)) + (while (re-search-forward "\\([a-z,-]+\\):\\s-*\\(.*\\)\\s-*" nil t) + ;; set the variable + ;; Thanks to Thomas Baumann for this bugfix + (let ((variable (concat "tidy-" (match-string 1))) + (value (match-string 2))) + ;;(set-default (intern variable value)) + (set-default (intern variable) value) + (setq config-variables + (cons (cons variable value) config-variables)) + (with-current-buffer html-buffer + (set (intern variable) value)) + )) + + (set-buffer-modified-p nil) ;; don't save changes + (kill-buffer config-buffer)) + (when all-buffers + (dolist (buffer (buffer-list)) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (dolist (optval config-variables) + (let* ((opt (car optval)) + (val (cdr optval)) + (sym (intern opt))) + (set sym val)))))))) + (message "Parsing config file...done") + ))) + +(defun tidy-save-settings (&optional config-file) + "Query saving the current settings to your `tidy-config-file'. +The local values in the current buffer will be saved." + (interactive) + (or config-file (setq config-file tidy-config-file)) + (when config-file + + ;; should check for locks! + (if (or (not (interactive-p)) + (y-or-n-p "Save settings to your tidy configuration file? ")) + + (let ((buffer (find-file-noselect config-file t)) + (option-alist tidy-options-alist) + (outer-buffer (current-buffer)) + option name symbol value) + (with-current-buffer buffer + (delete-region (point-min) (point-max)) ;; clear the buffer + + ;; need this line so that config file is always non empty + (insert "// HTML Tidy configuration file \n") + (while (setq option (car option-alist)) + (setq option-alist (cdr option-alist)) + (setq name (nth 0 option) + symbol (intern (concat "tidy-" name))) + (with-current-buffer outer-buffer + (setq value (symbol-value symbol))) + (when (string= value tidy-emacs-encoding-lbl) + (setq value (tidy-get-buffer-encoding))) + (when value ;; nil iff default + (insert (car option) ": " value "\n"))) + + (save-buffer) + ;;(basic-save-buffer) + (kill-buffer buffer) + ))))) + + +;;;;; Main user function + +(eval-when-compile (defvar tidy-markup nil "")) + +(defun tidy-set-buffer-unmodified (dummy1 dummy2 dumm3) + "Used to prevent error buffer form being marked as modified." + (set-buffer-modified-p nil)) + +;; See http://www.mhonarc.org/MHonArc/doc/resources/charsetaliases.html +(defconst tidy-encodings-mime-charset-list + '( + ;; ("raw") ;; Same as ascii?? + ("ascii" . "us-ascii") + ("latin0" . "iso-8859-15") + ("latin1" . "iso-8859-1") + ("iso2022" . "iso-2022-jp") ;; Correct? There are several iso-2022-.. + ("utf8" . "utf-8") + ("mac" . "macintosh") + ("win1252" . "windows-1252") + ("ibm858" . "cp850") + ("utf16le" . "utf-16-le") + ("utf16be" . "utf-16-be") + ("utf16" . "utf-16") + ("big5" . "big5") + ("shiftjis" . "shift_jis") + ) + "Encoding names used by Tidy and Emacs. +First column is Tidy's name, second Emacs' name." + ) + +(defun tidy-get-buffer-encoding () + "Get Tidy's name for value of `buffer-file-coding-system'." + (tidy-get-tidy-encoding buffer-file-coding-system)) + +(defun tidy-get-tidy-encoding (emacs-coding-system) + (let ((encoding (rassoc + (symbol-name + (coding-system-get emacs-coding-system 'mime-charset)) + tidy-encodings-mime-charset-list))) + (if encoding + (setq encoding (car encoding)) + (setq encoding "raw")) + encoding)) + +(defun tidy-temp-config-file () + (expand-file-name "temp-tidy-config" + tidy-temp-directory)) + +(defconst tidy-output-buf-name "Tidy (X)HTML Output") + +(defvar tidy-tidied-buffer nil) +(make-variable-buffer-local 'tidy-tidied-buffer) +(put 'tidy-tidied-buffer 'permanent-local t) + +(defun tidy-check-is-tidied (orig-buf tidy-buf) + (with-current-buffer tidy-buf + (unless tidy-tidied-buffer + (error "%s is not a tidy output buffer" tidy-buf)) + (unless (eq orig-buf tidy-tidied-buffer) + (error "Buffer does not contain tidied %s" orig-buf)))) + +(defconst tidy-control-buffer-name "Tidy Control Buffer") + +(defvar tidy-output-encoding) ;; dyn var + +(defun tidy-buffer () + "Run the HTML Tidy program on the current buffer. +Show the errors in a buffer with buttons to: + +- show the original buffer +- show the tidied output +- copy tidied to original +- run ediff + +This buffer also contains any error and warning messages and they +link to the original source code. + +If the buffer to tidy contains a fictive XHTML validation header +\(see `nxhtml-validation-header-mode') then the corresponding +header is added before running tidy. This header is removed again +after tidying, together with additions tidy might have done at +the end of the buffer. + +You may tidy part of the buffer, either by narrowing the buffer +or by selecting a region and having it visibly marked (`cua-mode' +etc). A fictive XHTML validation header will apply as +above. However if there is no such header then when you tidy part +of the buffer still a hopefully suitable header is added before +calling tidy." +;; Fix-me: copy back parts outside visible region + (interactive) + (message "starting tidy-buffer") + (let* ((is-narrowed (buffer-narrowed-p)) + (validation-header (when (boundp 'rngalt-validation-header) + (let ((header (nth 2 rngalt-validation-header))) + (when header (concat header "\n"))))) + (region-restricted (and mark-active + transient-mark-mode + (or (< (point-min) (region-beginning)) + (< (region-end) (point-max))))) + (partial (or validation-header + is-narrowed + region-restricted)) + (start (if region-restricted (region-beginning) (point-min))) + (end (if region-restricted (region-end) (point-max))) + (region-header (when region-restricted + (when (< (point-min) (region-beginning)) + (buffer-substring-no-properties + (point-min) (region-beginning))))) + (region-footer (when region-restricted + (when (< (region-end) (point-max)) + (buffer-substring-no-properties + (region-end) (point-max))))) + (tidy-beg-mark "<!-- TIDY BEGIN MARK 142505535 -->\n") + (tidy-end-mark "<!-- TIDY END MARK 143345187 -->") + ;;(whole-file t) ;(and (= start 1) (= end (1+ (buffer-size))))) + (filename buffer-file-name) + ;;(orig-dir (file-name-directory filename)) + (orig-buffer (current-buffer)) + (work-buffer (get-buffer-create "* Tidy Temporary Work Buffer *")) + (line-header-offset nil) + + ;; Gasp! We have to use temp files here because the command + ;; line would likely get too long! + + (error-buf-name tidy-control-buffer-name) + + (error-file (expand-file-name error-buf-name + tidy-temp-directory)) + + (error-buffer (get-buffer-create error-buf-name)) + + (output-buffer (get-buffer-create tidy-output-buf-name)) + + (config-file (tidy-temp-config-file)) + + ;;(eol (coding-system-eol-type buffer-file-coding-system)) + ;;(encoding (coding-system-get buffer-file-coding-system 'mime-charset)) + ;;(errors 0) + ;;(warnings 0) + (tidy-message "") + (seg-error nil) + ;;(use-ediff tidy-use-ediff) + + (want-mumamo nil) + ) + +;; (when (and use-ediff +;; (not tidy-show-warnings)) ;; default "yes" hence inverted logic +;; (setq use-ediff (y-or-n-p "Warning can not be shown when using ediff. Still use ediff? "))) + (unless buffer-file-name + (error "Can't tidy buffer with no file name")) + + (when (buffer-modified-p orig-buffer) + (error "Can't tidy buffer because it is modified")) + + (with-current-buffer error-buffer + (setq buffer-read-only nil) + (erase-buffer) + (setq tidy-tidied-buffer orig-buffer)) + + ;; OK do the tidy +;; (message "coding-system: %s, %s, %s" +;; (find-operation-coding-system +;; 'call-process-region start end command) +;; coding-system-for-write +;; buffer-file-coding-system) + (let* ((coding-system-for-write buffer-file-coding-system) + (tidy-input-encoding (tidy-get-tidy-encoding coding-system-for-write))) + + (let ((output-mode (if (not (featurep 'mumamo)) + major-mode + (if (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + mumamo-multi-major-mode + major-mode)))) + (with-current-buffer output-buffer + (erase-buffer) + ;;(when (and (fboundp 'mumamo-mode) mumamo-mode) (setq want-mumamo t) (mumamo-mode 0)) + (funcall output-mode) + (set (make-local-variable 'coding-system-for-read) coding-system-for-write))) + + (let ((tidy-output-encoding tidy-output-encoding)) + (unless tidy-output-encoding + (setq tidy-output-encoding tidy-input-encoding)) + ;;(message "tidy-input-enc=%s, tidy-output-enc=%s" tidy-input-encoding tidy-output-encoding) + (tidy-save-settings config-file) + ) + + ;; Tidy does not replace the xml declaration so it must be removed: + ;(setq tidy-add-xml-decl "no") + (let (;(orig-min (point-min)) (orig-max (point-max)) + ) +;; (when region-restricted +;; ;; We have a visible region +;; (setq orig-min (region-beginning)) +;; (setq orig-max (region-end))) + (with-current-buffer work-buffer + (erase-buffer) + (when validation-header + (insert validation-header)) + (when partial + ;; Have to insert things to make tidy insert at correctt + ;; position. A bit of guessing here to keep it simple. + (let ((p "\n<p>TIDY</p>\n") + (b "\n<body>\n") + (he "\n<head><title></title></head>\n") + (ht (concat + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n" + "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"))) + (goto-char (point-min)) + (if (re-search-forward "<body[^>]*>" nil t) + (insert p) + (if (search-forward "</head>" nil t) + (insert b p) + (if (re-search-forward "<html[^>]*>" nil t) + (insert he b p) + (insert ht he b p)))) + (goto-char (point-max)) + (insert "\n" tidy-beg-mark))) + (setq line-header-offset (line-number-at-pos)) + (insert-buffer-substring orig-buffer start end) ;orig-min orig-max) + (when partial (insert "\n" tidy-end-mark "\n")) + (let ((args + (list + ;;start end + (point-min) (point-max) + tidy-shell-program + nil + output-buffer + t + "-config" config-file + "--error-file" error-file + "--write-back" "no" + ;;(if (not whole-file) "--show-body-only" "--show-body-only") + ;;(if (not whole-file) "yes" "no") + "--show-body-only" "no" + "--gnu-emacs" "yes" + "--gnu-emacs-file" (file-name-nondirectory filename) + )) + (default-directory (file-name-directory filename)) + ) + (apply 'call-process-region args))) + )) + + + ;; Since XEmacs can't grab the std error stream we use an error file + ;;(setq error-buffer (find-file-noselect error-file t)) + (with-current-buffer error-buffer + (setq tidy-tidied-buffer orig-buffer) + (insert-file-contents error-file) + ;; Change the line numbers if a header was inserted + (when line-header-offset + (goto-char (point-min)) + (while (re-search-forward ":\\([0-9]+\\):[0-9]+" nil t) + (let ((line (1+ (- (string-to-number (match-string-no-properties 1)) + line-header-offset)))) + (replace-match (number-to-string line) nil nil nil 1)))) + ) + + ;; avoid leaving these guys lying around + (if (file-exists-p error-file) (delete-file error-file)) + ;;(if (file-exists-p config-file) (delete-file config-file)) + + ;; scan the buffer for error strings + (with-current-buffer error-buffer + ;;(local-set-key [tab] 'tidy-errbuf-forward) + (goto-char (point-min)) + (insert "\n") + (make-local-variable 'widget-button-face) + (setq widget-button-face custom-button) + (set (make-local-variable 'widget-push-button-prefix) "") + (set (make-local-variable 'widget-push-button-suffix) "") + (set (make-local-variable 'widget-link-prefix) "") + (set (make-local-variable 'widget-link-suffix) "") + (widget-create 'push-button + :tag " Show Source " + :keymap (make-sparse-keymap) + :arg-orig orig-buffer + :action (lambda (widget &optional event) + (let ((orig-buf (widget-get widget :arg-orig)) + (curr-win (selected-window))) + (switch-to-buffer-other-window orig-buf) + (select-window curr-win)))) + (insert " ") + (widget-create 'push-button + :tag " Show Tidied " + :keymap (make-sparse-keymap) + :arg-tidy output-buffer + :arg-orig orig-buffer + :action (lambda (widget &optional event) + (let ((tidy-buf (widget-get widget :arg-tidy)) + (orig-buf (widget-get widget :arg-orig)) + (curr-win (selected-window))) + (tidy-check-is-tidied orig-buf tidy-buf) + (switch-to-buffer-other-window tidy-buf) + (select-window curr-win)))) + + + (insert " ") + (widget-create 'push-button + :tag " Use Tidied " + :keymap (make-sparse-keymap) + :arg-tidy output-buffer + :arg-orig orig-buffer + :action (lambda (widget &optional event) + (message "Copying ...") + (let* ((orig-buf (widget-get widget :arg-orig)) + (tidy-buf (widget-get widget :arg-tidy)) + (orig-buf-str + (save-restriction + (with-current-buffer orig-buf + (widen) + (buffer-substring-no-properties (point-min) (point-max))))) + (tidy-buf-str + (save-restriction + (with-current-buffer tidy-buf + (widen) + (buffer-substring-no-properties (point-min) (point-max))))) + ) + (tidy-check-is-tidied orig-buf tidy-buf) + (kill-buffer (current-buffer)) + (kill-buffer tidy-buf) + (if (string= orig-buf-str tidy-buf-str) + (message "Original buffer's and tidied buffer's contents are equal") + (with-current-buffer orig-buf + (erase-buffer) + (insert tidy-buf-str) + (goto-char (point-min)) + (delete-window (selected-window)) + (switch-to-buffer orig-buf) + (message "Copied to %s" orig-buf)))))) + (insert " ") + (widget-create 'push-button + :tag " Ediff " + :keymap (make-sparse-keymap) + :arg-tidy output-buffer + :arg-orig orig-buffer + :action (lambda (widget &optional event) + (require 'ediff) + (let ((orig-buf (widget-get widget :arg-orig)) + (tidy-buf (widget-get widget :arg-tidy)) + ;; Fix-me: How should ediff-actual-options be set? + (old-ediff-actual-diff-options (default-value 'ediff-actual-diff-options)) + (new-ediff-actual-diff-options " -a -b -w ")) + (with-current-buffer orig-buf (setq ediff-actual-diff-options " -a -b -w ")) + (with-current-buffer tidy-buf (setq ediff-actual-diff-options " -a -b -w ")) + (tidy-check-is-tidied orig-buf tidy-buf) + (set-default 'ediff-actual-diff-options new-ediff-actual-diff-options) + (tidy-ediff-buffers orig-buf tidy-buf) + (set-default 'ediff-actual-diff-options old-ediff-actual-diff-options) + ))) + ;;(widget-setup) + + (insert "\n\n") + (when (re-search-forward (concat + "\\([0-9]+\\) warnings?, " + "\\([0-9]+\\) errors? were found!") + nil t) + (setq tidy-warnings (string-to-number (match-string 1))) + (setq tidy-errors (string-to-number (match-string 2))) + (setq tidy-message (match-string 0))) + + (goto-char (point-min)) + ;;(while (re-search-forward "stdin:" nil t) (replace-match (concat filename ":"))) + (wab-compilation-mode) + (set-buffer-modified-p nil) + (goto-char (point-min)) + ;; Fix-me: How should this be run? Some hook for compilation I + ;; guess, but what is the name of it? + ;; (wab-forward) + ) + + + (when (buffer-live-p output-buffer) + ;; Catch segmentation violations + ;; Sometimes get this when editing files from Macs + ;; See the function at the bottom of the file + (with-current-buffer output-buffer + (goto-char (point-min)) + (let ((case-fold-search t)) + (if (looking-at "Segmentation") ;; might work with XEmacs + (setq seg-error t)))) + ;; Fix-me: add parts outside region + (when partial + (with-current-buffer output-buffer + (goto-char (point-min)) + (when (search-forward tidy-beg-mark nil t) + (delete-region (point-min) (point))) + (when region-header (insert region-header)) + (when (search-forward tidy-end-mark nil t) + (backward-char (length tidy-end-mark)) + (delete-region (point) (point-max))) + (when region-footer (insert region-footer)))) + ) + + (unless (or (> tidy-errors 0) seg-error) + ;; Do not know if the window stuff is needed? + (let* ((window (get-buffer-window (current-buffer))) + (top (window-start window))) + + (unless tidy-markup ;; default is "yes" hence inverted logic + (when (eq system-type 'windows-nt) + (tidy-remove-ctrl-m output-buffer)) + (with-current-buffer output-buffer + (setq tidy-tidied-buffer orig-buffer) + (delete-trailing-whitespace) + (indent-region (point-min) (point-max)) + (goto-char (point-min)))) + + ;; Try not to move the window too much when we tidy the whole buffer + (set-window-start window top))) + + (switch-to-buffer-other-window error-buffer) + + (if seg-error + (message (concat "Tidy: Segmentation violation!!!" + " Check your character encoding.")) + (message "%s" tidy-message)))) + +(defun tidy-after-ediff () + (run-with-idle-timer 0 nil 'remove-hook 'ediff-quit-hook 'tidy-after-ediff) + ;;(lwarn 't :warning "cb=%s, %s, %s" (current-buffer) ediff-buffer-A ediff-buffer-B) + (let ((sw (selected-window)) + nw) + (select-window ediff-window-B) + (setq nw (split-window)) + (set-window-buffer nw (get-buffer-create tidy-control-buffer-name)) + (select-window sw)) + nil) + +(defun tidy-ediff-buffers (buffer-a buffer-b &optional startup-hooks job-name) + (add-hook 'ediff-quit-hook 'tidy-after-ediff) + (ediff-buffers buffer-a buffer-b startup-hooks job-name)) + +;; http://sf.net/tracker/index.php?func=detail&aid=1425219&group_id=27659&atid=390963 +(defun tidy-remove-ctrl-m (buffer) + (with-current-buffer buffer + (goto-char (point-min)) + (let ((control-m (char-to-string ?\r))) + (while (search-forward control-m nil t) + (replace-match "" nil t))))) + +(defvar tidy-html-files-re "\.x?html?$") +(defun tidy-is-html-file (filename) + (string-match tidy-html-files-re filename)) + +(defun tidy-contains (dir file) + (let ((d (file-name-as-directory dir))) + (when (< (length d) (length file)) + (string= d (substring file 0 (length d)))))) + + + +(defvar tidy-tree-files nil) +(defun tidy-tree-next () + (let ((next-file (car tidy-tree-files)) + file-buffer + ;;(tidy-use-ediff nil) + ) + (if (not next-file) + ;;(setq tidy-batch-buffer nil) + nil + (setq tidy-tree-files (cdr tidy-tree-files)) + (if (file-directory-p next-file) + (error "Uh?") + (tidy-batch next-file))))) + +(defun tidy-tree (root) + "Run Tidy on all files in the directory ROOT. +The files are first opened in Emacs and then `tidy-buffer' is +called." + (interactive "DDirectory tree: ") + (unless (file-directory-p root) + (error "tidy-tree called with non-directory arg: %s" root)) + (setq tidy-tree-files (html-site-get-sub-files root html-site-files-re)) + (dolist (f tidy-tree-files) + (let ((b (get-file-buffer f))) + (when (and b + (buffer-modified-p b)) + (unless + (y-or-n-p (format "Modified buffer %s must be saved. Save it and continue? " + (buffer-name b))) + (error "Modified buffers prevent run with Tidy")) + (with-current-buffer b + (basic-save-buffer))))) + (setq tidy-batch-last-file nil) + (tidy-tree-next)) + +(defun tidy-html-site () + "Tidy the whole tree in the current site." + ;; Fix-me: document html-site better. + (interactive) + (unless (featurep 'html-site) + (error "html-site is not loaded")) + (html-site-current-ensure-site-defined) + (tidy-tree (html-site-current-site-dir))) + +(defun tidy-batch-sentinel (process event) + (with-current-buffer (process-buffer process) + (let ((inhibit-read-only t)) + (insert "PROCESS-EVENT: " event "\n"))) + (when (eq (process-status process) 'exit) + (when tidy-batch-last-file + (let ((b (get-file-buffer tidy-batch-last-file))) + (when b + (with-current-buffer b + (save-excursion + (widen) + (let ((old (buffer-substring-no-properties (point-min) (point-max))) + (new (with-temp-buffer + ;;(insert-file tidy-batch-last-file) + (insert-file-contents tidy-batch-last-file) + (buffer-substring-no-properties (point-min) (point-max)))) + ) + (unless (string= old new) + (erase-buffer) + (insert new)))))))) + (tidy-tree-next))) + +(defun tidy-batch-output-filter (proc string) + (display-buffer (process-buffer proc)) + (with-current-buffer (process-buffer proc) + (let ((moving (= (point) (process-mark proc)))) + (save-excursion + ;; Insert the text, advancing the process marker. + (goto-char (process-mark proc)) + (let ((inhibit-read-only t)) + ;; http://sf.net/tracker/index.php?func=detail&aid=1425219&group_id=27659&atid=390963 + (setq string (replace-regexp-in-string "\r$" "" string)) + (insert string)) + (set-marker (process-mark proc) (point))) + (if moving (goto-char (process-mark proc)))))) + +(defun tidy-batch (filename) + (interactive (list buffer-file-name)) ;; For testing + (setq tidy-batch-last-file filename) + (let* (;;(filename buffer-file-name) + (config-file (tidy-temp-config-file)) + (command (list tidy-shell-program + ;; load configuration file first so that + ;; options are overridden by command line + + "-config" config-file + ;;"--error-file" error-file + "--write-back" "yes" + ;;"--show-body-only" "no" + "--gnu-emacs" "yes" + "--gnu-emacs-file" filename + filename + )) + (procbuf (noshell-procbuf-setup "subprocess for Tidy")) + (start (with-current-buffer procbuf (point))) + proc + ;; This does not work at the moment (2006-05-16): + (coding-system-for-read 'undecided-dos) + (coding-system-for-write 'undecided-dos) + ) + ;;(setq tidy-batch-buffer procbuf) + (tidy-save-settings config-file) + (unwind-protect + (setq proc (apply 'noshell-procbuf-run procbuf command)) + (with-current-buffer procbuf + (set-process-sentinel proc 'tidy-batch-sentinel) + ;;(set-process-coding-system 'dos) + (set-process-filter proc 'tidy-batch-output-filter) + (let ((win (get-buffer-window procbuf))) + (when win + (set-window-point win (point-max)) + )) + )))) + +;;;}}} + + +;;;}}} + +;; (with-temp-buffer +;; (tidy-parse-config-file)) + +(defun wab-compilation-button-at (pos) + (let ((old (point)) + ret) + (goto-char pos) + (setq ret (eq 'compilation-button-map + (get-char-property pos 'keymap))) + (goto-char old) + ret)) + +(defun wab-click (&optional event) + "Do the action that is tighed to the button." + (interactive (list last-input-event)) + (if event (posn-set-point (event-end event))) + (let ((button (get-char-property (point) 'button)) + done) + (condition-case nil + (progn + (compile-goto-error) + (setq done t)) + (error nil)) + (unless done + (when button + (if (widget-at) + ;;(widget-apply-action button event) + (widget-apply-action button) + (push-button)))))) + +(defvar wab-errors-supress + '("No more buttons" + "Moved past last error" + "No buttons or fields found" + "Moved back before first error" + )) + +(defun wab-fb-errmsg (err) + (let ((s (error-message-string err))) + (unless (member s wab-errors-supress) + (message "%s" err) + (signal (car err) (cdr err))))) + +(defun wab-fb-helper (forward function check-at args) + (let (ret + (len (1+ (- (point-max) (point-min)))) + (old (point))) + (condition-case err + (progn + (apply function args) + (when (funcall check-at (point)) + (setq ret (point)))) + (error (wab-fb-errmsg err))) + (unless ret + (if forward + (goto-char (point-min)) + (goto-char (point-max))) + (condition-case err + (progn + (apply function args) + (when (funcall check-at (point)) + (setq ret (point)))) + (error (message "%s" (error-message-string err))))) + (goto-char old) + (when (and ret (= ret old)) + (if forward + (setq ret (+ ret len)) + (setq ret (- ret len)))) + ;;(message "function=%s, ret=%s" function ret) + ret)) +(defvar wab-button-list + '( + (compilation-previous-error (1) compilation-next-error (1) wab-compilation-button-at) + (backward-button (1) forward-button (1) button-at) + (widget-backward (1) widget-forward (1) widget-at) + )) +(defun wab-fb (forward) + ;;(message "==================") + (let* ((pos-list (mapcar (lambda (p) + (let ((prev-fun (nth 0 p)) + (prev-arg (nth 1 p)) + (next-fun (nth 2 p)) + (next-arg (nth 3 p)) + (test-fun (nth 4 p))) + (if forward + (wab-fb-helper t next-fun test-fun next-arg) + (wab-fb-helper nil prev-fun test-fun prev-arg)))) + wab-button-list)) + (len (1+ (- (point-max) (point-min)))) + (defpos (if forward (* 2 len) (- len))) + (newpos defpos) + (here (point))) + ;;(message "pos-list=%s" pos-list) + (mapc (lambda (p) (when (and p + (if forward + (progn + (when (< p here) + (setq p (+ p len))) + (< p newpos)) + (when (> p here) + (setq p (- p len))) + (> p newpos))) + (setq newpos p))) + pos-list) + (if (= newpos defpos) + (setq newpos here) + (setq newpos (mod newpos len))) + (goto-char newpos))) + +(defun wab-backward () + "Go to next button or error link." + (interactive) + (wab-fb nil)) + +(defun wab-forward () + "Go to previous button or error link." + (interactive) + (wab-fb t)) + +(define-compilation-mode wab-compilation-mode "WAB Compilation" + "Mode for tidy control buffer." + ) +(define-key wab-compilation-mode-map [tab] 'wab-forward) +(define-key wab-compilation-mode-map [(shift tab)] 'wab-backward) +(define-key wab-compilation-mode-map [backtab] 'wab-backward) +(define-key wab-compilation-mode-map "\r" 'wab-click) +(define-key wab-compilation-mode-map [mouse-1] 'wab-click) +(define-key wab-compilation-mode-map [mouse-2] 'wab-click) + +(defvar tidy-menu-mode-map + (let ((map (make-sparse-keymap))) + ;; This did not work: + ;;(define-key map [menu-bar tidy-menu] (list 'menu-item "Tidy" '(lambda () (interactive) tidy-menu-symbol))) + map)) + +(define-minor-mode tidy-menu-mode + "This mode just adds Tidy to the menu bar." + nil + nil + nil + (when tidy-menu-mode + (define-key tidy-menu-mode-map [menu-bar tidy-menu] + (list 'menu-item "Tidy" tidy-menu-symbol)))) + +(provide 'tidy-xhtml) + +;;; tidy-xhtml.el ends here diff --git a/emacs/nxhtml/nxhtml/wtest.el b/emacs/nxhtml/nxhtml/wtest.el new file mode 100644 index 0000000..6cf1c39 --- /dev/null +++ b/emacs/nxhtml/nxhtml/wtest.el @@ -0,0 +1,56 @@ +(require 'wid-edit) +(require 'help-mode) + +(defun test-widget-formats () + (interactive) + (let ((widget-button-prefix "<<<<") + (widget-button-suffix "")) + (with-output-to-temp-buffer (help-buffer) + (with-current-buffer (help-buffer) + (set (make-local-variable 'widget-push-button-prefix) "") + (set (make-local-variable 'widget-push-button-suffix) "") + (set (make-local-variable 'widget-link-prefix) "") + (set (make-local-variable 'widget-link-suffix) "") + + (widget-create 'push-button + :action '(lambda (w &optional e) (message "1")) + :button-face 'emacsw32-link-face + :button-prefix "" + :button-suffix "" + "One" + ) + (widget-create 'push-button + :action '(lambda (w &optional e) (message "2")) + :format "%[%v%]" + :value "two" + ) + (widget-create 'push-button + :action '(lambda (w &optional e) (message "3")) + :format "%[%v%]" + :button-prefix "" + :button-suffix "" + "three" + ) + (widget-create 'push-button + :action '(lambda (w &optional e) (message "4")) + :format "%v" + :button-prefix "" + :button-suffix "" + "four" + ) + (widget-create 'push-button + :action '(lambda (w &optional e) (message "5")) + :format "%{%v%}" + :button-prefix "" + :button-suffix "" + "five" + ) + (widget-create 'push-button + :action '(lambda (w &optional e) (message "6")) + ;;:format "%[[%v]%]" + :value "Six" + ;;:value-create 'widget-browse-value-create + :value-create (lambda (widget) (insert (widget-get widget :value))) + ) + (widget-setup) + )))) diff --git a/emacs/nxhtml/nxhtml/xhtml-help.el b/emacs/nxhtml/nxhtml/xhtml-help.el new file mode 100644 index 0000000..f72c2fa --- /dev/null +++ b/emacs/nxhtml/nxhtml/xhtml-help.el @@ -0,0 +1,373 @@ +;;; xhtml-help.el --- Browse XHTML reference sites +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2005-08-16 +;; Last-Updated: Wed Aug 01 14:24:07 2007 (7200 +0200) +(defconst xhtml-help:version "0.57") ;; Version: +;; Keywords: languages + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Use when editing XHTML file to get tag references or CSS property +;; name references (like background-color) from web sources. +;; +;; Usage: +;; +;; (require 'fmode) +;; +;; Then call `xhtml-help-show-tag-ref' or `xhtml-help-show-css-ref'. + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; History: +;; +;; 2005-12-02: Corrected fetching margin-*. +;; 2006-01-08: Prompt for tag and property name before fetching help. + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This file is not part of 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 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. + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(defun xhtml-help-css-prop-at-point () + "Get possible css name property at point." + (save-excursion + (let ((ch (char-after)) + (in-word)) + (when (and (not (bolp)) + (or (not ch) + (member ch '(10 9 32 ?\:)))) + (backward-char) + (setq ch (char-after))) + (while (string-match "[a-z-]" (char-to-string ch)) + (setq in-word t) + (backward-char) + (setq ch (char-after))) + (when in-word + (forward-char) + (when (looking-at "[a-z-]+") + (match-string-no-properties 0)))))) + +;;;###autoload +(defun xhtml-help-show-css-ref () + "Show CSS reference for CSS property name at point." + (interactive) + (let ((css-prop (xhtml-help-css-prop-at-point))) + (setq css-prop (read-from-minibuffer "Get help for CSS property: " css-prop)) + (when css-prop + (xhtml-help-browse-css css-prop)))) + +;;;###autoload +(defun xhtml-help-tag-at-point () + "Get xhtml tag name at or before point." + (save-excursion + (when (eq (following-char) ?<) + (forward-char)) + (when (and (search-backward "<" nil t) + (looking-at "</?\\([[:alnum:]]+\\)")) + (match-string-no-properties 1)))) + +;;;###autoload +(defun xhtml-help-show-tag-ref () + "Show xhtml reference for tag name at or before point." + (interactive) + (let ((tag (xhtml-help-tag-at-point))) + (setq tag (read-from-minibuffer "Get help for tag name: " tag)) + (when (< 0 (length tag)) + (xhtml-help-browse-tag tag)))) + +;;;###autoload +(defgroup xhtml-help nil + "Customization group for xhtml-help." + :group 'nxhtml + :group 'hypermedia) + +(defcustom xhtml-help-refurl "http://www.w3.org/" + "Web url to get references from." + :type '(choice + (const "http://www.w3.org/") + (const "http://xhtml.com/") + (const "http://www.w3schools.com/") + ;;(const "http://learningforlife.fsu.edu/") + ) + :group 'xhtml-help) + +(defcustom xhtml-help-query-refurl t + "Query for reference url. +This is used in `xhtml-help-browse-tag' and `xhtml-help-browse-css'." + :type 'boolean + :group 'xhtml-help) + +(defun xhtml-help-query-refurl (prompt &optional notvalid) + (let ((choices (get 'xhtml-help-refurl 'custom-type)) + (default xhtml-help-refurl)) + (unless (eq 'choice (car choices)) + (error "Custom type of xhtml-help-refurl is not choices")) + (setq choices (cdr choices)) + (setq choices (mapcar (lambda (elt) + (car (cdr elt))) + choices)) + (mapc (lambda (elt) + (setq choices (delete elt choices))) + notvalid) + (when (member default notvalid) + (setq default (car choices))) + (completing-read (concat "Fetch " prompt " reference from: ") + choices + nil + t + default + '(choices . 1)))) + +(defun xhtml-match (target str) + (let ((len (length target))) + (when (<= len (length str)) + (equal target (substring str 0 len))))) + +(defun xhtml-match-member (target str-list) + (let (m) + (mapc (lambda (elt) + (when (xhtml-match elt target) + (setq m t))) + str-list) + m)) + +(defun xhtml-help-browse-css (css-prop) + (let* ((refurl (if xhtml-help-query-refurl + (xhtml-help-query-refurl (concat "CSS property '" css-prop "'") + (list "http://xhtml.com/")) + xhtml-help-refurl)) + (url + (cond + ( (equal refurl "http://www.w3schools.com/") + (concat + refurl "css/pr_" + (cond + ( (member css-prop '("clear" "cursor" "display" "float" "position" "visibility")) + "class_") + ( (member css-prop '("height" "line-height" "max-width" "min-height" "min-width" "width")) + "dim_") + ( (xhtml-match "font-weight" css-prop) + (setq css-prop "") "font_weight") + ( (xhtml-match "font" css-prop) + "font_") + ( (member css-prop '("content" "counter-increment" "counter-reset" "quotes")) + "gen_") + ( (xhtml-match "list" css-prop) + "list_") + ( (xhtml-match "margin" css-prop) + "") + ( (xhtml-match "outline" css-prop) + "outline_") + ( (equal "padding" css-prop) + "") + ( (xhtml-match "padding" css-prop) + "padding_") + ( (member css-prop '("bottom" "clip" "left" "overflow" "right" "top" + "vertical-align" "z-index")) + "pos_") + ( (member css-prop '("border-collapse")) + "tab_") + ( (member css-prop '("color" "direction" "letter-spacing" "text-align" + "text-decoration" "text-indent" "text-transform" + "white-space" "word-spacing")) + "text_") + ( t "")) + css-prop ".asp")) + ;; ( (equal refurl "http://learningforlife.fsu.edu/") + ;; (let ((css-prop2 css-prop) + ;; (cc) + ;; (ii 0)) + ;; (while (< ii (length css-prop)) + ;; (setq cc (substring css-prop2 ii (1+ ii))) + ;; (when (equal cc "-") + ;; (store-substring css-prop2 ii "_")) + ;; (setq ii (1+ ii))) + ;; (concat + ;; refurl "webmaster/references/css/" css-prop2 ".cfm"))) + ( (equal refurl "http://www.w3.org/") + (let ((properties "") + (prop-def "")) + (concat + refurl "TR/REC-CSS2/" + (cond + ( (xhtml-match-member css-prop '("margin" "padding" "border")) + "box.html#propdef-") + ( (member css-prop '("display" "position" + "top" "right" "bottom" "left" + "float" "clear" + "z-index" + "direction" "unicode-bidi")) + "visuren.html#propdef-") + ( (member css-prop '("width" "min-width" "max-width" + "height" "min-height" "max-height" + "line-height" "vertical-align")) + "visudet.html#propdef-") + ( (member css-prop '("overflow" "clip" "visibility")) + "visufx.html#propdef-") + ( (member css-prop '("content" "quotes")) + "generate.html#propdef-") + ( (or (xhtml-match css-prop "counter") + (member css-prop '("marker-offset"))) + (setq css-prop "") + "generate.html#counters") + ( (xhtml-match-member css-prop '("list")) + "generate.html#propdef-") + ( (member css-prop '("size" "marks" + "page-break-before" "page-break-after" "page-break-inside" + "page" + "orphans" "widows" + )) + "page.html#propdef-") + ( (member css-prop '("color" + "background-color" "background-image" "background-repeat" + "background-attachment" "background-position" "background" + )) + "colors.html#propdef-") + ( (xhtml-match "font" css-prop) + "fonts.html#propdef-") + ( (xhtml-match "text" css-prop) + "text.html#") + ( (member css-prop '("letter-spacing" "word-spacing")) + "text.html#") + ;; Fix-me: tables??? + ( (member css-prop '("cursor")) + "ui.html#propdef-") + ( (xhtml-match "outline" css-prop) + "ui.html#dynamic-outlines") + ( (or (xhtml-match "speak" css-prop) + (xhtml-match "pause" css-prop) + (xhtml-match "cue" css-prop) + (xhtml-match "pitch" css-prop) + (member css-prop '("volume" "play-during" "azimuth" "elevation" + "speech-rate" "voice-family" "richness"))) + "aural.html#propdef-") + ) + css-prop + ))) + ( t (error "Bad value for xhtml-help-refurl: %s" refurl))))) + (browse-url url))) + + + + + +(defun xhtml-help-browse-tag (tag) + (let* ((refurl (if xhtml-help-query-refurl + (xhtml-help-query-refurl (concat "XHTML tag '" tag "'") + (list "http://www.w3.org/")) + xhtml-help-refurl)) + (url + (cond + ( (equal refurl "http://xhtml.com/") + (concat + refurl "en/xhtml/reference/" + tag + "/") + ) + ( (equal refurl "http://www.w3schools.com/") + (concat + refurl "tags/" + (cond + ( (member tag '("tt" "i" "b" "big" "small")) + "tag_font_style.asp") + ( (member tag '("em" "strong" "dfn" "code" "samp" "kbd" "var" "cite")) + "tag_phrase_elements.asp") + ( (member tag '("h1" "h2" "h3" "h4" "h5" "h6")) + "tag_hn.asp") + ( (member tag '("sub" "sup")) + "tag_sup.asp") + ( t + (concat "tag_" tag ".asp") + )))) + ;; ( (equal refurl "http://learningforlife.fsu.edu/") + ;; (concat + ;; refurl "webmaster/references/xhtml/tags/" + ;; (cond + ;; ( (member tag '("body" "head" "html" "title")) + ;; "structure/") + ;; ( (member tag '("abbr" "acronym" "address" "blockquote" "br" "cite" + ;; "code" "dfn" "div" "em" "h1" "h2" "h3" "h4" "h5" "h6" + ;; "kbd" "p" "pre" "q" "samp" "span" "strong" "var")) + ;; "text/") + ;; ( (member tag '("a")) + ;; "hypertext/") + ;; ( (member tag '("dl" "dd" "dt" "ol" "ul" "li")) + ;; "list/") + ;; ( (member tag '("object" "param")) + ;; "object/") + ;; ( (member tag '("b" "big" "hr" "i" "small" "sub" "sup" "tt")) + ;; "presentation/") + ;; ( (member tag '("del" "ins")) + ;; "edit/") + ;; ( (member tag '("bdo")) + ;; "bidirectional/") + ;; ( (member tag '("button" "fieldset" "form" "input" "label" "legend" + ;; "select" "optgroup" "option" "textarea")) + ;; "forms/") + ;; ( (member tag '("caption" "col" "colgroup" "table" "tbody" "td" + ;; "tfoot" "th" "thead" "tr")) + ;; "table/") + ;; ( (member tag '("img")) + ;; "image/") + ;; ( (member tag '("area" "map")) + ;; "client/") + ;; ( (member tag '("area" "map")) + ;; "client/") + ;; ( (member tag '("meta")) + ;; "meta/") + ;; ( (member tag '("noscript" "script")) + ;; "scripting/") + ;; ( (member tag '("style")) + ;; "stylesheet/") + ;; ( (member tag '("link")) + ;; "link/") + ;; ( (member tag '("base")) + ;; "base/") + ;; ( (member tag '("base")) + ;; "base/") + ;; ( (member tag '("ruby" "rbc" "rtc" "rb" "rt" "rp")) + ;; "ruby/") + ;; ) + ;; tag ".cfm")) + ( t (error "Bad value for xhtml-help-refurl: %s" refurl)) + ))) + (browse-url url))) + +(defconst xhtml-help-mode-keymap + (let ((map (make-sparse-keymap "XHTML Help"))) + (define-key map [menu-bar xh-help] (cons "XHTML Help" (make-sparse-keymap "second"))) + (define-key map [menu-bar xh-help css-help] '("CSS Help" . xhtml-help-show-css-ref)) + (define-key map [menu-bar xh-help tag-help] '("XHTML Tag Help" . xhtml-help-show-tag-ref)) + map)) + +(define-minor-mode xhtml-help-mode + "Minor mode that adds keys for accessing xhtml and css help." + :keymap xhtml-help-mode-keymap) + +(provide 'xhtml-help) + +;;; xhtml-help.el ends here diff --git a/emacs/nxhtml/nxhtmlmaint.el b/emacs/nxhtml/nxhtmlmaint.el new file mode 100644 index 0000000..68c03b7 --- /dev/null +++ b/emacs/nxhtml/nxhtmlmaint.el @@ -0,0 +1,439 @@ +;;; nxhtmlmaint.el --- Some maintenance helpers +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-09-27T15:29:35+0200 Sat +;; Version: 0.6 +;; Last-Updated: 2010-01-18 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This module contains maintenance functions: +;; +;; `nxhtmlmaint-get-all-autoloads' (nxhtmlmaint-get-all-autoloads) +;; +;; `nxhtmlmaint-start-byte-compilation' +;; `nxhtmlmaint-byte-uncompile-all' +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'advice)) +(eval-when-compile (require 'nxhtml-base)) +(eval-when-compile (require 'nxhtml-web-vcs nil t)) +(eval-when-compile (require 'web-vcs nil t)) +(eval-when-compile (require 'ourcomments-util)) + +(defvar nxhtmlmaint-dir + ;;(file-name-directory (if load-file-name load-file-name buffer-file-name)) + (file-name-directory (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + "Maintenance directory for nXhtml.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Autoload helpers + +(defun nxhtmlmaint-autoloads-file () + "Return autoload file name for nXhtml." + (file-truename (expand-file-name "nxhtml-loaddefs.el" nxhtmlmaint-dir))) + +(defun nxhtmlmaint-util-dir () + "Return nXhtml util directory." + (file-truename (file-name-as-directory + (expand-file-name "util" nxhtmlmaint-dir)))) + +(defvar nxhtmlmaint-autoload-default-directory (nxhtmlmaint-util-dir)) + +(defvar generated-autoload-file) + +(defun nxhtmlmaint-initialize-autoloads-file () + "Initialize nXhtml autoload file." + (with-current-buffer (find-file-noselect generated-autoload-file) + (when (= 0 (buffer-size)) + (insert ";; Autoloads for nXthml +;; +;; This file should be updated by `nxhtmlmaint-get-file-autoloads', +;; `nxhtmlmaint-get-dir-autoloads' or `nxhtmlmaint-get-all-autoloads'. +\(eval-when-compile (require 'nxhtml-base)) +\(eval-when-compile (require 'web-vcs))") + (basic-save-buffer)))) + +(defun nxmtmlmaint-advice-autoload (on) + "Activate advices if ON, otherwise turn them off." + (if on + (progn + (ad-activate 'autoload-file-load-name) + (ad-activate 'make-autoload)) + (ad-deactivate 'autoload-file-load-name) + (ad-deactivate 'make-autoload))) + +(defun nxhtmlmaint-get-file-autoloads (file) + "Get autoloads for file FILE. +Update nXhtml autoload file with them." + (interactive (list (buffer-file-name))) + (let* ((generated-autoload-file (nxhtmlmaint-autoloads-file)) + (emacs-lisp-mode-hook nil) + (default-directory (nxhtmlmaint-util-dir))) + (nxhtmlmaint-initialize-autoloads-file) + ;; Get the autoloads using advice + (nxmtmlmaint-advice-autoload t) + (update-file-autoloads file nil) + (nxmtmlmaint-advice-autoload nil) + ;; Display + (display-buffer (find-file-noselect generated-autoload-file)))) + +(defun nxhtmlmaint-get-dir-autoloads (dir) + "Get autoloads for directory DIR. +Update nXhtml autoload file with them." + (interactive (list (or (when (buffer-file-name) + (file-name-directory (buffer-file-name))) + default-directory))) + (let* ((generated-autoload-file (nxhtmlmaint-autoloads-file)) + (emacs-lisp-mode-hook nil) + (auto-buf (find-file-noselect generated-autoload-file))) + (nxhtmlmaint-initialize-autoloads-file) + ;; Get the autoloads using advice + (nxmtmlmaint-advice-autoload t) + ;; Fix-me: Loop instead, some files must be avoided. + (update-directory-autoloads dir) + (nxmtmlmaint-advice-autoload nil) + ;; Display + (display-buffer (find-file-noselect generated-autoload-file)))) + +(defun nxhtmlmaint-get-tree-autoloads (root) + "Get autoloads for directory tree ROOT. +Update nXhtml autoload file with them." + (interactive (list (or (when (buffer-file-name) + (file-name-directory (buffer-file-name))) + default-directory))) + (message "Getting autoloads in %s" root) + (nxhtmlmaint-get-dir-autoloads root) + (let* ((files (directory-files root)) + (sub-dirs (mapcar (lambda (file) + (when (and (not (member file '("." ".."))) + (not (member file '("nxml-mode-20041004" "old"))) + (not (member file '("nxhtml-company-mode"))) + (not (member file '("in"))) + (file-directory-p (expand-file-name file root))) + file)) + files))) + (setq sub-dirs (delq nil sub-dirs)) + ;;(message "sub-dirs=%s" sub-dirs) + (dolist (dir sub-dirs) + (let ((full-dir (expand-file-name dir root))) + (unless (or (string= full-dir nxhtmlmaint-dir) + (string= dir "alts")) + (nxhtmlmaint-get-tree-autoloads full-dir)))))) + +;;(nxhtmlmaint-get-all-autoloads) +(defun nxhtmlmaint-get-all-autoloads () + "Get all autoloads for nXhtml. +Update nXhtml autoload file with them." + ;;(interactive) + (if nxhtml-autoload-web + (message "Skipping rebuilding autoloads, not possible when autoloading from web") + (let ((auto-buf (find-file-noselect (nxhtmlmaint-autoloads-file)))) + (with-current-buffer auto-buf + (erase-buffer) + (basic-save-buffer)) + (nxhtmlmaint-get-tree-autoloads nxhtmlmaint-dir) + ;; `nxhtml-mode' and `nxhtml-validation-header-mode' should only be + ;; autoloaded if nxml-mode if available. + (with-current-buffer auto-buf + (message "Fixing nxml autoloads") + (let ((frmt (if (= emacs-major-version 22) + "^(autoload (quote %s) " + "^(autoload '%s "))) + (dolist (nxmode '(nxhtml-mode nxhtml-validation-header-mode)) + (goto-char (point-min)) + (when (re-search-forward (format frmt nxmode) nil t) + (forward-line 0) + (insert "(when (fboundp 'nxml-mode)\n") + (forward-sexp) + (insert ")")))) + ;; Fix defcustom autoloads + (goto-char (point-min)) + (let ((cus-auto "(\\(custom-autoload\\) +'.* +\\(\".*?\"\\)")) + (while (re-search-forward cus-auto nil t) + ;;(backward-char (1- (length cus-auto))) + ;;(insert "nxhtml-") + (let ((lib (match-string 2))) + ;; Change to symbol to fix autoloading. This works because + ;; custom-load-symbol does require on symbols. + (setq lib (concat "'" (substring lib 1 -1))) + (replace-match "nxhtml-custom-autoload" t t nil 1) + (replace-match lib t t nil 2)))) + ;; Fix autoload calls + (goto-char (point-min)) + (let ((auto "(autoload ")) + (while (search-forward auto nil t) + (backward-char (1- (length auto))) + (insert "nxhtml-"))) + ;; Fix autoload source + (goto-char (point-min)) + (let* ((patt-src "^;;; Generated autoloads from \\(.*\\)$") + (patt-auto "^(nxhtml-autoload '[^ ]+ \\(\"[^\"]+\"\\)") + (patt-cust "^(nxhtml-custom-autoload '[^ ]+ \\(\"[^\"]+\"\\)") + (patt (concat "\\(?:" patt-src "\\)\\|\\(?:" patt-auto "\\)\\|\\(?:" patt-cust "\\)")) + curr-src) + (while (re-search-forward patt nil t) + (cond + ( (match-string 1) + (setq curr-src (match-string-no-properties 1)) + ;; Remove .el + (setq curr-src (substring curr-src 0 -3)) + ;; Setup up for web autoload + (let* ((src-name (file-name-nondirectory curr-src)) + (feature (make-symbol src-name)) + ) + (end-of-line) + (insert "\n" + "(web-autoload-require '" + (symbol-name feature) + " 'lp" + " '(nxhtml-download-root-url nil)" + " \"" curr-src "\"" + " nxhtml-install-dir" + " 'nxhtml-byte-compile-file" + ")\n")) + ) + ( (match-string 3) + ;; (custom-autoload 'sym "lib" nil) is will give a + ;; (require 'lib) so everything is ok here. + nil) + ( (or (match-string 2) + (match-string 3) + ) + (let* ((subexp (if (match-string 2) 2 3)) + (file (match-string-no-properties subexp))) + (replace-match (concat "`(lp '(nxhtml-download-root-url nil)" + " \"" curr-src "\"" + " nxhtml-install-dir)") + nil ;; fixedcase + nil ;; literal + nil ;; string + subexp ;; subexp + )) + ) + (t (error "No match???"))))) + ;; Save + (basic-save-buffer))))) + + +(defun nxhtmlmaint-autoload-file-load-name (file) + "Return relative file name for FILE to autoload file directory." + (let ((name (if (and nxhtmlmaint-autoload-default-directory + (file-name-absolute-p file)) + (file-relative-name + file nxhtmlmaint-autoload-default-directory) + (file-name-nondirectory file)))) + (if (string-match "\\.elc?\\(\\.\\|\\'\\)" name) + (substring name 0 (match-beginning 0)) + name))) + +(defadvice autoload-file-load-name (around + nxhtmlmaint-advice-autoload-file-load-name + ;;activate + compile) + "Advice to return relative file name." + (setq ad-return-value (nxhtmlmaint-autoload-file-load-name (ad-get-arg 0)))) + +(defun nxhtmlmaint-make-autoload (form file) + "Make autoload for multi major modes." + ;;(message "form=%S" form) + (if (or (not (listp form)) + (not (eq 'define-mumamo-multi-major-mode (car form)))) + ad-return-value + (if ad-return-value + ad-return-value + ;; Fix-me: Maybe expand?? + (let ((name (nth 1 form)) + (doc (nth 2 form))) + `(autoload ',name ,file ,doc t) + )))) + +(defadvice make-autoload (after + nxhtmlmaint-advice-make-autoload + ;;activate + compile) + "Make autoload for multi major modes." + (setq ad-return-value + (nxhtmlmaint-make-autoload (ad-get-arg 0) + (ad-get-arg 1)))) + +;; (defun nxhtmlmaint-generate-library-autoloads (library) +;; "Insert at point autoloads for Emacs library LIBRARY. +;; Works like `generate-file-autoloads', but for a library." +;; (interactive +;; (list (completing-read "Generate autoloads for library: " +;; 'locate-file-completion +;; (cons load-path (get-load-suffixes))))) +;; (let ((file (locate-library library))) +;; ;; Fix-me: wasn't this defined??? +;; (generate-file-autoloads file))) + +;;;###autoload +(defun nxhtmlmaint-start-byte-compilation () + "Start byte compilation of nXhtml in new Emacs instance. +Byte compiling in general makes elisp code run 5-10 times faster +which is quite noticeable when you use nXhtml. + +This will also update the file nxhtml-loaddefs.el. + +You must restart Emacs to use the byte compiled files. + +If for some reason the byte compiled files does not work you can +remove then with `nxhtmlmaint-byte-uncompile-all'." + (interactive) + ;; Fix-me: This message and redisplay seems only necessary sometimes. + (message "Preparing byte compilation of nXhtml ...") (redisplay t) + (let* ((this-file (expand-file-name "nxhtmlmaint.el" nxhtmlmaint-dir)) + (auto-file (expand-file-name "autostart.el" nxhtmlmaint-dir)) + (web-vcs-file (expand-file-name "nxhtml-web-vcs.el" nxhtmlmaint-dir)) + (this-emacs (locate-file invocation-name + (list invocation-directory) + exec-suffixes)) + (process-args `(,this-emacs nil 0 nil "-Q"))) + (nxhtmlmaint-byte-uncompile-all) + (if (or noninteractive + (not window-system)) + (nxhtmlmaint-byte-compile-all) + ;;(when noninteractive (setq process-args (append process-args '("-batch")))) + (setq process-args (append process-args + (list "-l" auto-file + "-l" web-vcs-file + "-l" this-file + "-f" "nxhtmlmaint-byte-compile-all"))) + (message "process-args=%S" process-args) + (message "Starting new Emacs instance for byte compiling ...") + (apply 'call-process process-args)))) + +;;(nxhtmlmaint-byte-compile-all) +(defun nxhtmlmaint-byte-compile-all () + "Byte recompile all files in nXhtml that needs it." + (message "nxhtmlmaint-byte-compile-all: nxhtmlmaint-dir=%S, exists=%s" nxhtmlmaint-dir (file-directory-p nxhtmlmaint-dir)) + (let* ((load-path load-path) + (nxhtml-dir (file-name-as-directory + (expand-file-name "nxhtml" + nxhtmlmaint-dir))) + (util-dir (file-name-as-directory + (expand-file-name "util" + nxhtmlmaint-dir))) + ;; (nxhtml-company-dir (file-name-as-directory + ;; (expand-file-name "nxhtml-company-mode" + ;; util-dir))) + (related-dir (file-name-as-directory + (expand-file-name "related" + nxhtmlmaint-dir))) + (tests-dir (file-name-as-directory + (expand-file-name "tests" + nxhtmlmaint-dir))) + (emacsw32-dir (file-name-as-directory + (expand-file-name "../lisp" + nxhtmlmaint-dir))) + (default-dir nxhtml-dir) + ) + (message "nxhtmlmaint-byte-compile-all: nxhtml-dir=%S, exists=%s" nxhtml-dir (file-directory-p nxhtml-dir)) + (message "nxhtmlmaint-byte-compile-all: util-dir=%S, exists=%s" util-dir (file-directory-p util-dir)) + (message "nxhtmlmaint-byte-compile-all: related-dir=%S, exists=%s" related-dir (file-directory-p related-dir)) + (message "nxhtmlmaint-byte-compile-all: tests-dir=%S, exists=%s" tests-dir (file-directory-p tests-dir)) + (add-to-list 'load-path nxhtml-dir) + (add-to-list 'load-path util-dir) + ;;(add-to-list 'load-path nxhtml-company-dir) + (add-to-list 'load-path related-dir) + (add-to-list 'load-path tests-dir) + (when (file-directory-p emacsw32-dir) + (add-to-list 'load-path emacsw32-dir)) + (require 'cl) ;; This is run in a new Emacs. Fix-me: This might not be true any more. + (message "load-path=%s" load-path) + (let ((dummy-debug-on-error t)) + (nxhtmlmaint-byte-compile-dir nxhtmlmaint-dir nil nil nil)) + (web-vcs-message-with-face 'web-vcs-gold "Byte compiling nXhtml is ready, restart Emacs to use the compiled files"))) + +;;;###autoload +(defun nxhtmlmaint-byte-recompile () + "Recompile or compile all nXhtml files in current Emacs." + (interactive) + (nxhtmlmaint-byte-compile-dir nxhtmlmaint-dir nil nil t) + (web-vcs-message-with-face 'web-vcs-gold "Byte recompiling nXhtml ready")) + +;;;###autoload +(defun nxhtmlmaint-byte-uncompile-all () + "Delete byte compiled files in nXhtml. +This will also update the file nxhtml-loaddefs.el. + +See `nxhtmlmaint-start-byte-compilation' for byte compiling." + (interactive) + (nxhtmlmaint-get-all-autoloads) + (let ((dummy-debug-on-error t)) + (nxhtmlmaint-byte-compile-dir nxhtmlmaint-dir t t nil)) + (message "Byte uncompiling is ready, restart Emacs to use the elisp files")) + +(defconst nxhtmlmaint-nonbyte-compile-dirs + '("." ".." "alts" "nxml-mode-20041004" "old" "tests" "nxhtml-company-mode")) + +;; Fix-me: simplify this now that nxml is not included +(defun nxhtmlmaint-byte-compile-dir (dir force del-elc load) + "Byte compile or uncompile directory tree DIR. +If FORCE is non-nil byte recompile the elisp file even if the +compiled file is newer. + +If DEL-ELC is nil then byte compile files. If DEL-ELC is non-nil +then instead delete the compiled files." + ;;(directory-files (file-name-directory buffer-file-name) t "\.el\\'") + (dolist (el-src (directory-files dir t "\.el\\'")) + (let ((elc-dst (concat el-src "c"))) + (if del-elc + (when (file-exists-p elc-dst) + (delete-file elc-dst) + (message "Deleted %s" elc-dst)) + (setq debug-on-error t) + (when (or force (file-newer-than-file-p el-src elc-dst)) + ;;(message "fn=%s" (file-name-nondirectory el-src)) + (when t ;;(string= "nxhtml-menu.el" (file-name-nondirectory el-src)) + ;;(message "(nxhtml-byte-compile-file %s)" el-src) + (unless (nxhtml-byte-compile-file el-src load) + (message "Couldn't compile %s" el-src))))))) + (dolist (f (directory-files dir t)) + (when (file-directory-p f) + ;; Fix-me: Avoid some dirs + (let ((name (file-name-nondirectory f))) + (unless (member name nxhtmlmaint-nonbyte-compile-dirs) + (nxhtmlmaint-byte-compile-dir f force del-elc load)))))) + +(provide 'nxhtmlmaint) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtmlmaint.el ends here diff --git a/emacs/nxhtml/related/blank.html b/emacs/nxhtml/related/blank.html new file mode 100644 index 0000000..f8b6c17 --- /dev/null +++ b/emacs/nxhtml/related/blank.html @@ -0,0 +1,6 @@ +<html> + <head> + </head> + <body> + </body> +</html> diff --git a/emacs/nxhtml/related/csharp-mode.el b/emacs/nxhtml/related/csharp-mode.el new file mode 100644 index 0000000..9cd7914 --- /dev/null +++ b/emacs/nxhtml/related/csharp-mode.el @@ -0,0 +1,1977 @@ +;;; csharp-mode.el --- C# mode derived mode + +;; Author: Dylan R. E. Moonfire +;; Maintainer: Dylan R. E. Moonfire <contact@mfgames.com> +;; Created: Feburary 2005 +;; Modified: February 2010 +;; Version: 0.7.4 - Dino Chiesa <dpchiesa@hotmail.com> +;; Keywords: c# languages oop mode + +;; 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; 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 a separate mode to implement the C# constructs and +;; font-locking. It is based on the java-mode example from cc-mode. +;; +;; csharp-mode requires CC Mode 5.30 or later. It works with +;; cc-mode 5.31.3, which is current at this time. +;; +;; Features: +;; +;; - font-lock and indent of C# syntax including: +;; all c# keywords and major syntax +;; attributes that decorate methods, classes, fields, properties +;; enum types +;; #if/#endif #region/#endregion +;; instance initializers +;; anonymous functions and methods +;; verbatim literal strings (those that begin with @) +;; generics +;; +;; - automagic code-doc generation when you type three slashes. +;; +;; - intelligent inserttion of matched pairs of curly braces. +;; +;; - sets the compiler regex for next-error, for csc.exe output. +;; +;; + + +;;; To use: +;; +;; put this in your .emacs: +;; +;; (autoload 'csharp-mode "csharp-mode" "Major mode for editing C# code." t) +;; +;; or: +;; +;; (require 'csharp-mode) +;; +;; +;; AND: +;; +;; (setq auto-mode-alist +;; (append '(("\\.cs$" . csharp-mode)) auto-mode-alist)) +;; (defun my-csharp-mode-fn () +;; "function that runs when csharp-mode is initialized for a buffer." +;; ...insert your code here... +;; ...most commonly, your custom key bindings ... +;; ) +;; (add-hook 'csharp-mode-hook 'my-csharp-mode-fn t) +;; +;; + + +;;; Bugs: +;; +;; Namespaces in the using statements are not fontified. Should do in +;; c-basic-matchers-before or c-basic-matchers-after. +;; +;; Method names with a preceding attribute are not fontified. +;; +;; Field/Prop names inside object initializers are fontified only +;; if the null constructor is used, with no parens. +;; +;; This code doesn't seem to work when you compile it, then +;; load/require in the emacs file. You will get an error (error +;; "`c-lang-defconst' must be used in a file") which happens because +;; cc-mode doesn't think it is in a buffer while loading directly +;; from the init. However, if you call it based on a file extension, +;; it works properly. Interestingly enough, this doesn't happen if +;; you don't byte-compile cc-mode. +;; +;; +;; +;; Todo: +;; +;; Get csharp-mode.el accepted as part of the emacs standard distribution. +;; Must contact monnier at iro.umontreal.ca to make this happen. +;; +;; +;; +;; Acknowledgements: +;; +;; Thanks to Alan Mackenzie and Stefan Monnier for answering questions +;; and making suggestions. +;; +;; + +;;; Versions: +;; +;; 0.1.0 - Initial release. +;; 0.2.0 - Fixed the identification on the "enum" keyword. +;; - Fixed the font-lock on the "base" keyword +;; 0.3.0 - Added a regex to fontify attributes. It isn't the +;; the best method, but it handles single-like attributes +;; well. +;; - Got "super" not to fontify as a keyword. +;; - Got extending classes and interfaces to fontify as something. +;; 0.4.0 - Removed the attribute matching because it broke more than +;; it fixed. +;; - Corrected a bug with namespace not being properly identified +;; and treating the class level as an inner object, which screwed +;; up formatting. +;; - Added "partial" to the keywords. +;; 0.5.0 - Found bugs with compiled cc-mode and loading from init files. +;; - Updated the eval-when-compile to code to let the mode be +;; compiled. +;; 0.6.0 - Added the c-filter-ops patch for 5.31.1 which made that +;; function in cc-langs.el unavailable. +;; - Added a csharp-lineup-region for indention #region and +;; #endregion block differently. +;; 0.7.0 - Added autoload so update-directory-autoloads works +;; (Thank you, Nikolaj Schumacher) +;; - Fontified the entire #region and #endregion lines. +;; - Initial work to get get, set, add, remove font-locked. +;; 0.7.1 - Added option to indent #if/endif with code +;; - Fixed c-opt-cpp-prefix defn (it must not include the BOL +;; char (^). +;; - proper fontification and indent of classes that inherit +;; (previously the colon was confusing the parser) +;; - reclassified namespace as a block beginner +;; - removed $ as a legal symbol char - not legal in C#. +;; - added struct to c-class-decl-kwds so indent is correct +;; within a struct. +;; 0.7.2 - Added automatic codedoc insertion. +;; 0.7.3 - Instance initializers (new Type { ... } ) and +;; (new Type() { ...} ) are now indented properly. +;; - proper fontification and indent of enums as brace-list-*, +;; including special treatment for enums that explicitly +;; inherit from an int type. Previously the colon was +;; confusing the parser. +;; - proper fontification of verbatim literal strings, +;; including those that end in slash. This edge case was not +;; handled at all before; it is now handled correctly. +;; - code cleanup and organization; removed the linefeed. +;; - intelligent curly-brace insertion +;; 0.7.4 - added a C# style +;; - using is now a keyword and gets fontified +;; - fixed a bug that had crept into the codedoc insertion +;; + + +(require 'cc-mode) + +(message (concat "Loading " load-file-name)) + + +;; ================================================================== +;; c# upfront stuff +;; ================================================================== + +;; This is a copy of the function in cc-mode which is used to handle +;; the eval-when-compile which is needed during other times. +(defun c-filter-ops (ops opgroup-filter op-filter &optional xlate) + ;; See cc-langs.el, a direct copy. + (unless (listp (car-safe ops)) + (setq ops (list ops))) + (cond ((eq opgroup-filter t) + (setq opgroup-filter (lambda (opgroup) t))) + ((not (functionp opgroup-filter)) + (setq opgroup-filter `(lambda (opgroup) + (memq opgroup ',opgroup-filter))))) + (cond ((eq op-filter t) + (setq op-filter (lambda (op) t))) + ((stringp op-filter) + (setq op-filter `(lambda (op) + (string-match ,op-filter op))))) + (unless xlate + (setq xlate 'identity)) + (c-with-syntax-table (c-lang-const c-mode-syntax-table) + (delete-duplicates + (mapcan (lambda (opgroup) + (when (if (symbolp (car opgroup)) + (when (funcall opgroup-filter (car opgroup)) + (setq opgroup (cdr opgroup)) + t) + t) + (mapcan (lambda (op) + (when (funcall op-filter op) + (let ((res (funcall xlate op))) + (if (listp res) res (list res))))) + opgroup))) + ops) + :test 'equal))) + + + +;; These are only required at compile time to get the sources for the +;; language constants. (The cc-fonts require and the font-lock +;; related constants could additionally be put inside an +;; (eval-after-load "font-lock" ...) but then some trickery is +;; necessary to get them compiled.) +(eval-when-compile + (let ((load-path + (if (and (boundp 'byte-compile-dest-file) + (stringp byte-compile-dest-file)) + (cons (file-name-directory byte-compile-dest-file) load-path) + load-path))) + (load "cc-mode" nil t) + (load "cc-fonts" nil t) + (load "cc-langs" nil t))) + +(eval-and-compile + ;; Make our mode known to the language constant system. Use Java + ;; mode as the fallback for the constants we don't change here. + ;; This needs to be done also at compile time since the language + ;; constants are evaluated then. + (c-add-language 'csharp-mode 'java-mode)) + +;; ================================================================== +;; end of c# upfront stuff +;; ================================================================== + + + + + +;; ================================================================== +;; csharp-mode utility and feature defuns +;; ================================================================== + +;; Indention: csharp-mode follows normal indention rules except for +;; when indenting the #region and #endregion blocks. This function +;; defines a custom indention to indent the #region blocks properly +;; + +(defun csharp-lineup-region (langelem) + "Indent all #region and #endregion blocks inline with code while +retaining normal column-zero indention for #if and the other +processing blocks. + +To use this indenting just put the following in your emacs file: + (c-set-offset 'cpp-macro 'csharp-lineup-region) + +An alternative is to use `csharp-lineup-if-and-region'. +" + + (save-excursion + (back-to-indentation) + (if (re-search-forward "#\\(end\\)?region" (c-point 'eol) [0]) 0 [0]))) + + + +(defun csharp-lineup-if-and-region (langelem) + +"Indent all #region/endregion blocks and #if/endif blocks inline +with code while retaining normal column-zero indention for any +other processing blocks. + +To use this indenting just put the following in your emacs file: + (c-set-offset 'cpp-macro 'csharp-lineup-if-and-region) + +Another option is to use `csharp-lineup-region'. + +" + (save-excursion + (back-to-indentation) + (if (re-search-forward "#\\(\\(end\\)?\\(if\\|region\\)\\|else\\)" (c-point 'eol) [0]) 0 [0]))) + + + + + +(defun csharp-insert-open-brace () + "Intelligently insert a pair of curly braces. This fn is most +often bound to the open-curly brace, with + + (local-set-key (kbd \"{\") 'csharp-insert-open-brace) + +The default binding for an open curly brace in cc-modes is often +`c-electric-brace' or `skeleton-pair-insert-maybe'. The former +can be configured to insert newlines around braces in various +syntactic positions. The latter inserts a pair of braces and +then does not insert a newline, and does not indent. + +This fn provides another option, with some additional +intelligence for csharp-mode. When you type an open curly, the +appropriate pair of braces appears, with spacing and indent set +in a context-sensitive manner. + +Within a string literal, you just get a pair of braces, and point +is set between them. Following an equals sign, you get a pair of +braces, with a semincolon appended. Otherwise, you +get the open brace on a new line, with the closing brace on the +line following. + +There may be another way to get this to happen appropriately just within emacs, +but I could not figure out how to do it. So I wrote this alternative. +" + (interactive) + (let + (tpoint + (in-string (string= (csharp-in-literal) "string")) + (preceding3 + (save-excursion + (and + (skip-chars-backward " ") + (> (- (point) 2) (point-min)) + (buffer-substring-no-properties (point) (- (point) 3))))) + (one-word-back + (save-excursion + (backward-word 2) + (thing-at-point 'word)))) + + (cond + + ;; Case 1: inside a string literal? + ;; -------------------------------------------- + ;; If so, then just insert a pair of braces and put the point + ;; between them. The most common case is a format string for + ;; String.Format() or Console.WriteLine(). + (in-string + (self-insert-command 1) + (insert "}") + (backward-char)) + + ;; Case 2: the open brace starts an array initializer. + ;; -------------------------------------------- + ;; When the last non-space was an equals sign or square brackets, + ;; then it's an initializer. + ((save-excursion + (backward-sexp) + (looking-at "\\(\\w+\\b *=\\|[[]]+\\)")) + (self-insert-command 1) + (insert " };") + (backward-char 3)) + + ;; Case 3: the open brace starts an instance initializer + ;; -------------------------------------------- + ;; If one-word-back was "new", then it's an object initializer. + ((string= one-word-back "new") + (save-excursion + (message "object initializer") + (setq tpoint (point)) ;; prepare to indent-region later + (newline) + (self-insert-command 1) + (newline-and-indent) + (newline) + (insert "};") + (c-indent-region tpoint (point)) + (previous-line) + (indent-according-to-mode) + (end-of-line) + (setq tpoint (point))) + (goto-char tpoint)) + + ;; Case 4: a lambda initialier. + ;; -------------------------------------------- + ;; If the open curly follows =>, then it's a lambda initializer. + ((string= (substring preceding3 -2) "=>") + (message "lambda init") + (self-insert-command 1) + (insert " }") + (backward-char 2)) + + ;; else, it's a new scope. (if, while, class, etc) + (t + (save-excursion + (message "new scope") + (set-mark (point)) ;; prepare to indent-region later + ;; check if the prior sexp is on the same line + (if (save-excursion + (let ((curline (line-number-at-pos)) + (aftline (progn + (backward-sexp) + (line-number-at-pos)))) + (= curline aftline))) + (newline-and-indent)) + (self-insert-command 1) + (c-indent-line-or-region) + (end-of-line) + (newline) + (insert "}") + ;;(c-indent-command) ;; not sure of the difference here + (c-indent-line-or-region) + (previous-line) + (end-of-line) + (newline-and-indent) + ;; point ends up on an empty line, within the braces, properly indented + (setq tpoint (point))) + + (goto-char tpoint))))) + + + + +;; ================================================================== +;; end of csharp-mode utility and feature defuns +;; ================================================================== + + + + + + +;; ================================================================== +;; c# values for "language constants" defined in cc-langs.el +;; ================================================================== + + +;; Java uses a series of regexes to change the font-lock for class +;; references. The problem comes in because Java uses Pascal (leading +;; space in names, SomeClass) for class and package names, but +;; Camel-casing (initial lowercase, upper case in words, +;; i.e. someVariable) for variables. The notation suggested by EMCA for C# is +;; to use Pascal notation for everything, except inner variables. So, +;; the Java regex and formatting produces very wrong results in C#. +;;(error (byte-compile-dest-file)) +;;(error (c-get-current-file)) +(c-lang-defconst c-opt-after-id-concat-key + csharp (if (c-lang-const c-opt-identifier-concat-key) + (c-lang-const c-symbol-start))) + +(c-lang-defconst c-basic-matchers-before + csharp `( + ;;;; Font-lock the attributes by searching for the + ;;;; appropriate regex and marking it as TODO. + ;;,`(,(concat "\\(" csharp-attribute-regex "\\)") + ;; 0 font-lock-function-name-face) + + ;; Put a warning face on the opener of unclosed strings that + ;; can't span lines. Later font + ;; lock packages have a `font-lock-syntactic-face-function' for + ;; this, but it doesn't give the control we want since any + ;; fontification done inside the function will be + ;; unconditionally overridden. + ,(c-make-font-lock-search-function + ;; Match a char before the string starter to make + ;; `c-skip-comments-and-strings' work correctly. + (concat ".\\(" c-string-limit-regexp "\\)") + '((c-font-lock-invalid-string))) + + ;; Fontify keyword constants. + ,@(when (c-lang-const c-constant-kwds) + (let ((re (c-make-keywords-re nil + (c-lang-const c-constant-kwds)))) + `((eval . (list ,(concat "\\<\\(" re "\\)\\>") + 1 c-constant-face-name))))) + + ;; Fontify all keywords except the primitive types. + ,`(,(concat "\\<" (c-lang-const c-regular-keywords-regexp)) + 1 font-lock-keyword-face) + + ;; Fontify leading identifiers in fully qualified names like + ;; "Foo.Bar". + ,@(when (c-lang-const c-opt-identifier-concat-key) + `((,(byte-compile + `(lambda (limit) + (while (re-search-forward + ,(concat "\\(\\<" ; 1 + "\\(" (c-lang-const c-symbol-key) + "\\)" ; 2 + "[ \t\n\r\f\v]*" + (c-lang-const + c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + "\\)" + "\\(" + (c-lang-const + c-opt-after-id-concat-key) + "\\)") + limit t) + (unless (progn + (goto-char (match-beginning 0)) + (c-skip-comments-and-strings limit)) + (or (get-text-property (match-beginning 2) 'face) + (c-put-font-lock-face (match-beginning 2) + (match-end 2) + c-reference-face-name)) + (goto-char (match-end 1))))))))) + )) + + + +;; C# does not allow a leading qualifier operator. It also doesn't +;; allow the ".*" construct of Java. So, we redo this regex without +;; the "\\|\\*" regex. +(c-lang-defconst c-identifier-key + csharp (concat "\\(" (c-lang-const c-symbol-key) "\\)" ; 1 + (concat "\\(" + "[ \t\n\r\f\v]*" + (c-lang-const c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + (concat "\\(" + "\\(" (c-lang-const c-symbol-key) "\\)" + "\\)") + "\\)*"))) + +;; C# has a few rules that are slightly different than Java for +;; operators. This also removed the Java's "super" and replaces it +;; with the C#'s "base". +(c-lang-defconst c-operators + csharp `((prefix "base"))) + + +;; C# uses CPP-like prefixes to mark #define, #region/endregion, +;; #if/else/endif, and #pragma. This regexp matches the prefix, +;; not including the beginning-of-line (BOL), and not including +;; the term after the prefix (define, pragma, etc). This regexp says +;; whitespace, followed by the prefix, followed by maybe more whitespace. + +(c-lang-defconst c-opt-cpp-prefix + csharp "\\s *#\\s *") + + +;; there are no message directives in C# +(c-lang-defconst c-cpp-message-directives + csharp nil) + +(c-lang-defconst c-cpp-expr-directives + csharp '("if")) + +(c-lang-defconst c-opt-cpp-macro-define + csharp "define") + +;; $ is not a legal char in an identifier in C#. So we need to +;; create a csharp-specific definition of this constant. +(c-lang-defconst c-symbol-chars + csharp (concat c-alnum "_")) + + +(c-lang-defconst c-colon-type-list-kwds + csharp '("class")) + +(c-lang-defconst c-block-prefix-disallowed-chars + + ;; Allow ':' for inherit list starters. + csharp (set-difference (c-lang-const c-block-prefix-disallowed-chars) + '(?: ?,))) + + +(c-lang-defconst c-assignment-operators + csharp '("=" "*=" "/=" "%=" "+=" "-=" ">>=" "<<=" "&=" "^=" "|=")) + +(c-lang-defconst c-primitive-type-kwds + ;; ECMA-344, S8 + csharp '("object" "string" "sbyte" "short" "int" "long" "byte" + "ushort" "uint" "ulong" "float" "double" "bool" "char" + "decimal" "void")) + +;; The keywords that define that the following is a type, such as a +;; class definition. +(c-lang-defconst c-type-prefix-kwds + ;; ECMA-344, S? + csharp '("class" "interface" "struct")) ;; no enum here. + ;; we want enum to be a brace list. + + +;; Type modifier keywords. They appear anywhere in types, but modify +;; instead of create one. +(c-lang-defconst c-type-modifier-kwds + ;; EMCA-344, S? + csharp '("readonly" "const")) + + +;; Tue, 20 Apr 2010 16:02 +;; need to vverify that this works for lambdas... +(c-lang-defconst c-special-brace-lists + csharp '((?{ . ?}) )) + + + +;; dinoch +;; Thu, 22 Apr 2010 18:54 +;; +;; No idea why this isn't getting set properly in the first place. +;; In cc-langs.el, it is set to the union of a bunch of things, none +;; of which include "new", or "enum". +;; +;; But somehow both of those show up in the resulting derived regexp. +;; This breaks indentation of instance initializers, such as +;; +;; var x = new Foo { ... }; +;; +;; Based on my inspection, the existing c-lang-defconst should work! +;; I don't know how to fix this c-lang-defconst, so I am re-setting this +;; variable here, to provide the regex explicitly. +;; +(c-lang-defconst c-decl-block-key + + csharp '"\\(namespace\\)\\([^[:alnum:]_]\\|$\\)\\|\\(class\\|interface\\|struct\\)\\([^[:alnum:]_]\\|$\\)" + ) + + + +;; Thu, 22 Apr 2010 14:29 +;; I want this to handle var x = new Foo[] { ... }; +;; not sure if necessary. +(c-lang-defconst c-inexpr-brace-list-kwds + csharp '("new")) + + +;; ;;(c-lang-defconst c-inexpr-class-kwds +;; ;; csharp '("new")) + + + +(c-lang-defconst c-class-decl-kwds + ;; EMCA-344, S? + csharp '("class" "interface" "struct" )) ;; no "enum"!! + + +;; The various modifiers used for class and method descriptions. +(c-lang-defconst c-modifier-kwds + csharp '("public" "partial" "private" "const" "abstract" + "protected" "ref" "out" "static" "virtual" + "override" "params" "internal")) + + +;; Thu, 22 Apr 2010 23:02 +;; Based on inspection of the cc-mode code, the c-protection-kwds +;; c-lang-const is used only for objective-c. So the value is +;; irrelevant for csharp. +(c-lang-defconst c-protection-kwds + csharp nil + ;; csharp '("private" "protected" "public" "internal") +) + + +;; Define the keywords that can have something following after them. +(c-lang-defconst c-type-list-kwds + csharp '("struct" "class" "interface" "is" "as" + "delegate" "event" "set" "get" "add" "remove")) + + +;; This allows the classes after the : in the class declartion to be +;; fontified. +(c-lang-defconst c-typeless-decl-kwds + csharp '(":")) + +;; Sets up the enum to handle the list properly, and also the new +;; keyword to handle object initializers. This requires a modified +;; c-basic-matchers-after (see above) in order to correctly fontify C# +;; 3.0 object initializers. +(c-lang-defconst c-brace-list-decl-kwds + csharp '("enum" "new")) + + +;; Statement keywords followed directly by a substatement. +;; catch is not one of them. +(c-lang-defconst c-block-stmt-1-kwds + csharp '("do" "try" "finally")) + + +;; Statement keywords followed by a paren sexp and then by a substatement. +(c-lang-defconst c-block-stmt-2-kwds + csharp '("for" "if" "switch" "while" "catch" "foreach" "using" + "checked" "unchecked" "lock")) + + +;; Statements that break out of braces +(c-lang-defconst c-simple-stmt-kwds + csharp '("return" "continue" "break" "throw" "goto" )) + +;; Statements that allow a label +;; TODO? +(c-lang-defconst c-before-label-kwds + csharp nil) + +;; Constant keywords +(c-lang-defconst c-constant-kwds + csharp '("true" "false" "null")) + +;; Keywords that start "primary expressions." +(c-lang-defconst c-primary-expr-kwds + csharp '("this" "base")) + +;; Treat namespace as an outer block so class indenting +;; works properly. +(c-lang-defconst c-other-block-decl-kwds + csharp '("namespace")) + +(c-lang-defconst c-other-kwds + csharp '("in" "sizeof" "typeof" "is" "as" "yield" + "where" "select" "from")) + +(c-lang-defconst c-overloadable-operators + ;; EMCA-344, S14.2.1 + csharp '("+" "-" "*" "/" "%" "&" "|" "^" + "<<" ">>" "==" "!=" ">" "<" ">=" "<=")) + + +;; This c-cpp-matchers stuff is used for fontification. +;; see cc-font.el +;; + +;; There's no preprocessor in C#, but there are still compiler +;; directives to fontify: "#pragma", #region/endregion, #define, #undef, +;; #if/else/endif. (The definitions for the extra keywords above are +;; enough to incorporate them into the fontification regexps for types +;; and keywords, so no additional font-lock patterns are required for +;; keywords.) + +(c-lang-defconst c-cpp-matchers + csharp (cons + ;; Use the eval form for `font-lock-keywords' to be able to use + ;; the `c-preprocessor-face-name' variable that maps to a + ;; suitable face depending on the (X)Emacs version. + '(eval . (list "^\\s *\\(#pragma\\|undef\\|define\\)\\>\\(.*\\)" + (list 1 c-preprocessor-face-name) + '(2 font-lock-string-face))) + ;; There are some other things in `c-cpp-matchers' besides the + ;; preprocessor support, so include it. + (c-lang-const c-cpp-matchers))) + +(defcustom csharp-font-lock-extra-types nil + "*List of extra types (aside from the type keywords) to recognize in C# mode. +Each list item should be a regexp matching a single identifier." + :type 'list :group 'csharp) + +(defconst csharp-font-lock-keywords-1 (c-lang-const c-matchers-1 csharp) + "Minimal highlighting for C# mode.") + +(defconst csharp-font-lock-keywords-2 (c-lang-const c-matchers-2 csharp) + "Fast normal highlighting for C# mode.") + +(defconst csharp-font-lock-keywords-3 (c-lang-const c-matchers-3 csharp) + "Accurate normal highlighting for C# mode.") + +(defvar csharp-font-lock-keywords csharp-font-lock-keywords-3 + "Default expressions to highlight in C# mode.") + +(defvar csharp-mode-syntax-table nil + "Syntax table used in csharp-mode buffers.") +(or csharp-mode-syntax-table + (setq csharp-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table csharp)))) + +(defvar csharp-mode-abbrev-table nil + "Abbreviation table used in csharp-mode buffers.") +(c-define-abbrev-table 'csharp-mode-abbrev-table + ;; Keywords that if they occur first on a line might alter the + ;; syntactic context, and which therefore should trig reindentation + ;; when they are completed. + '(("else" "else" c-electric-continued-statement 0) + ("while" "while" c-electric-continued-statement 0) + ("catch" "catch" c-electric-continued-statement 0) + ("finally" "finally" c-electric-continued-statement 0))) + +(defvar csharp-mode-map (let ((map (c-make-inherited-keymap))) + ;; Add bindings which are only useful for C# + map) + "Keymap used in csharp-mode buffers.") + + +;; TODO +;; Defines our constant for finding attributes. +;;(defconst csharp-attribute-regex "\\[\\([XmlType]+\\)(") +;;(defconst csharp-attribute-regex "\\[\\(.\\)") +;; This doesn't work because the string regex happens before this point +;; and getting the font-locking to work before and after is fairly difficult +;;(defconst csharp-attribute-regex +;; (concat +;; "\\[[a-zA-Z][ \ta-zA-Z0-9.]+" +;; "\\((.*\\)?" +;;)) + + +;; ================================================================== +;; end of c# values for "language constants" defined in cc-langs.el +;; ================================================================== + + + + +;; ================================================================== +;; C# code-doc insertion magic +;; ================================================================== +;; +;; In Visual Studio, if you type three slashes, it immediately expands into +;; an inline code-documentation fragment. The following method does the +;; same thing. +;; +;; This is the kind of thing that could be handled by YASnippet or +;; another similarly flexible snippet framework. But I don't want to +;; introduce a dependency on yasnippet to csharp-mode. So the capability +;; must live within csharp-mode itself. + +(defun csharp-maybe-insert-codedoc (arg) + + "Insert an xml code documentation template as appropriate, when +typing slashes. This fn gets bound to / (the slash key), in +csharp-mode. If the slash being inserted is not the third +consecutive slash, the slash is inserted as normal. If it is the +third consecutive slash, then a xml code documentation template +may be inserted in some cases. For example, + + a <summary> template is inserted if the prior line is empty, + or contains only an open curly brace; + a <remarks> template is inserted if the prior word + closes the <summary> element; + a <returns> template is inserted if the prior word + closes the <remarks> element; + an <example> template is inserted if the prior word closes + the <returns> element; + a <para> template is inserted if the prior word closes + a <para> element. + +In all other cases the slash is inserted as normal. + +If you want the default cc-mode behavior, which implies no automatic +insertion of xml code documentation templates, then use this in +your `csharp-mode-hook' function: + + (local-set-key (kbd \"/\") 'c-electric-slash) + + " + (interactive "*p") + ;;(message "csharp-maybe-insert-codedoc") + (let ( + (cur-point (point)) + (char last-command-char) + (cb0 (char-before (- (point) 0))) + (cb1 (char-before (- (point) 1))) + is-first-non-whitespace + did-auto-insert + ) + + ;; check if two prior chars were slash + (if (and + (= char ?/) + cb0 (= ?/ cb0) + cb1 (= ?/ cb1) + ) + + (progn + ;;(message "yes - this is the third consecutive slash") + (setq is-first-non-whitespace + (save-excursion + (back-to-indentation) + (= cur-point (+ (point) 2)))) + + (if is-first-non-whitespace + ;; This is a 3-slash sequence. It is the first non-whitespace text + ;; on the line. Now we need to examine the surrounding context + ;; in order to determine which xml cod doc template to insert. + (let (word-back char0 char1 + word-fore char-0 char-1 + text-to-insert ;; text to insert in lieu of slash + fn-to-call ;; func to call after inserting text + (preceding-line-is-empty (or + (= (line-number-at-pos) 1) + (save-excursion + (previous-line) + (beginning-of-line) + (looking-at "[ \t]*$\\|[ \t]*{[ \t]*$")))) + (flavor 0) ;; used only for diagnostic purposes + ) + + ;;(message "starting a 3-slash comment") + ;; get the prior word, and the 2 chars preceding it. + (backward-word) + + (setq word-back (thing-at-point 'word) + char0 (char-before (- (point) 0)) + char1 (char-before (- (point) 1))) + + ;; restore prior position + (goto-char cur-point) + + ;; get the following word, and the 2 chars preceding it. + (forward-word) + (backward-word) + (setq word-fore (thing-at-point 'word) + char-0 (char-before (- (point) 0)) + char-1 (char-before (- (point) 1))) + + ;; restore prior position again + (goto-char cur-point) + + (cond + ;; The preceding line is empty, or all whitespace, or + ;; contains only an open-curly. In this case, insert a + ;; summary element pair. + (preceding-line-is-empty + (setq text-to-insert "/ <summary>\n/// \n/// </summary>" + flavor 1) ) + + ;; The preceding word closed a summary element. In this case, + ;; if the forward word does not open a remarks element, then + ;; insert a remarks element. + ((and (string-equal word-back "summary") (eq char0 ?/) (eq char1 ?<)) + (if (not (and (string-equal word-fore "remarks") (eq char-0 ?<))) + (setq text-to-insert "/ <remarks>\n/// <para>\n/// \n/// </para>\n/// </remarks>" + flavor 2))) + + ;; The preceding word closed the remarks section. In this case, + ;; insert an example element. + ((and (string-equal word-back "remarks") (eq char0 ?/) (eq char1 ?<)) + (setq text-to-insert "/ <example>\n/// \n/// </example>" + flavor 3)) + + ;; The preceding word closed the example section. In this + ;; case, insert an returns element. This isn't always + ;; correct, because sometimes the xml code doc is attached to + ;; a class or a property, neither of which has a return + ;; value. A more intelligent implementation would inspect the + ;; syntax state and only inject a returns element if + ;; appropriate. + ((and (string-equal word-back "example") (eq char0 ?/) (eq char1 ?<)) + (setq text-to-insert "/ <returns></returns>" + fn-to-call (lambda () + (backward-word) + (backward-char) + (backward-char) + (c-indent-line-or-region) + ) + flavor 4)) + + ;; The preceding word opened the remarks section, or it + ;; closed a para section. In this case, insert a para + ;; element, using appropriate indentation with respect to the + ;; prior tag. + ((or + (and (string-equal word-back "remarks") (eq char0 ?<) (or (eq char1 32) (eq char1 9))) + (and (string-equal word-back "para") (eq char0 ?/) (eq char1 ?<))) + + (let (prior-point spacer) + (save-excursion + (backward-word) + (backward-char) + (backward-char) + (setq prior-point (point)) + (skip-chars-backward "\t ") + (setq spacer (buffer-substring (point) prior-point)) + ;;(message (format "pt(%d) prior(%d) spacer(%s)" (point) prior-point spacer)) + ) + + (if (string-equal word-back "remarks") + (setq spacer (concat spacer " "))) + + (setq text-to-insert (format "/%s<para>\n///%s \n///%s</para>" + spacer spacer spacer) + flavor 6))) + + ;; The preceding word opened a para element. In this case, if + ;; the forward word does not close the para element, then + ;; close the para element. + ;; -- + ;; This is a nice idea but flawed. Suppose I have a para element with some + ;; text in it. If I position the cursor at the first line, then type 3 slashes, + ;; I get a close-element, and that would be inappropriate. Not sure I can + ;; easily solve that problem, so the best thing might be to simply punt, and + ;; require people to close their own elements. + ;; + ;; ( (and (string-equal word-back "para") (eq char0 60) (or (eq char1 32) (eq char1 9))) + ;; (if (not (and (string-equal word-fore "para") (eq char-0 47) (eq char-1 60) )) + ;; (setq text-to-insert "/ \n/// </para>\n///" + ;; fn-to-call (lambda () + ;; (previous-line) + ;; (end-of-line) + ;; ) + ;; flavor 7) ) + ;; ) + + ;; the default case - do nothing + (t nil)) + + (if text-to-insert + (progn + ;;(message (format "inserting special text (f(%d))" flavor)) + + ;; set the flag, that we actually inserted text + (setq did-auto-insert t) + + ;; save point of beginning of insertion + (setq cur-point (point)) + + ;; actually insert the text + (insert text-to-insert) + + ;; indent the inserted string, and re-position point, either through + ;; the case-specific fn, or via the default progn. + (if fn-to-call + (funcall fn-to-call) + + (let ((newline-count 0) (pos 0) ix) + + ;; count the number of newlines in the inserted string + (while (string-match "\n" text-to-insert pos) + (setq pos (match-end 0) + newline-count (+ newline-count 1) ) + ) + + ;; indent what we just inserted + (c-indent-region cur-point (point) t) + + ;; move up n/2 lines. This assumes that the + ;; inserted text is ~symmetric about the halfway point. + ;; The assumption holds if the xml code doc uses a + ;; begin-elt and end-elt on a new line all by themselves, + ;; and a blank line in between them where the point should be. + ;; A more intelligent implementation would use a specific + ;; marker string, like @@DOT, to note the desired point. + (previous-line (/ newline-count 2)) + (end-of-line))))))))) + + (if (not did-auto-insert) + (self-insert-command (prefix-numeric-value arg))))) + +;; ================================================================== +;; end of c# code-doc insertion magic +;; ================================================================== + + + + +;; ================================================================== +;; c# fontification extensions +;; ================================================================== +;; Commentary: +;; +;; The purpose of the following code is to fix font-lock for C#, +;; specifically for the verbatim-literal strings. C# is a cc-mode +;; language and strings are handled mostly like other c-based +;; languages. The one exception is the verbatim-literal string, which +;; uses the syntax @"...". +;; +;; `parse-partial-sexp' treats those strings as just regular strings, +;; with the @ a non-string character. This is fine, except when the +;; verblit string ends in a slash, in which case, font-lock breaks from +;; that point onward in the buffer. +;; +;; This is an attempt to fix that. +;; +;; The idea is to scan the buffer in full for verblit strings, and apply the +;; appropriate syntax-table text properties for verblit strings. Also setting +;; `parse-sexp-lookup-properties' to t tells `parse-partial-sexp' +;; to use the syntax-table text properties set up by the scan as it does +;; its parse. +;; +;; Also need to re-scan after any changes in the buffer, but on a more +;; limited region. +;; + + +;; ;; I don't remember what this is supposed to do, +;; ;; or how I figured out the value. +;; ;; +;; (defconst csharp-font-lock-syntactic-keywords +;; '(("\\(@\\)\\(\"\\)[^\"]*\\(\"\\)\\(\"\\)[^\"]*\\(\"\\)[^\"]" +;; (1 '(6)) (2 '(7)) (3 '(1)) (4 '(1)) (5 '(7)) +;; )) +;; "Highlighting of verbatim literal strings. See also the variable +;; `font-lock-keywords'.") + + + +;; Allow this: +;; (csharp-log 3 "csharp: scan...'%s'" state) + +(defvar csharp-log-level 0 + "The current log level for CSharp-specific operations. +This is used in particular by the verbatim-literal +string scanning. + +Most other csharp functions are not instrumented. +0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG, 4 = SHUTUP ALREADY. ") + +(defun csharp-log (level text &rest args) + "Log a message at level LEVEL. +If LEVEL is higher than `csharp-log-level', the message is +ignored. Otherwise, it is printed using `message'. +TEXT is a format control string, and the remaining arguments ARGS +are the string substitutions (see `format')." + (if (<= level csharp-log-level) + (let* ((msg (apply 'format text args))) + (message "%s" msg) + ))) + + + +(defun csharp-max-beginning-of-stmt () + "Return the greater of `c-beginning-of-statement-1' and +`c-beginning-of-statement' . I don't understand why both of +these methods are necessary or why they differ. But they do." + + (let (dash + nodash + (curpos (point))) + + ;; I think this may need a save-excursion... + ;; Calling c-beginning-of-statement-1 resets the point! + + (setq dash (progn (c-beginning-of-statement-1) (point))) + (csharp-log 3 "C#: max-bostmt dash(%d)" dash) + (goto-char curpos) + + (setq nodash (progn (c-beginning-of-statement 1) (point))) + (csharp-log 3 "C#: max-bostmt nodash(%d)" nodash) + (goto-char curpos) + + (max dash nodash))) + + +(defun csharp-in-literal (&optional lim detect-cpp) + "Return the type of literal point is in, if any. +Basically this works like `c-in-literal' except it doesn't +use or fill the cache (`c-in-literal-cache'). + +The return value is `c' if in a C-style comment, `c++' if in a C++ +style comment, `string' if in a string literal, `pound' if DETECT-CPP +is non-nil and in a preprocessor line, or nil if somewhere else. +Optional LIM is used as the backward limit of the search. If omitted, +or nil, `c-beginning-of-syntax' is used. + +Note that this function might do hidden buffer changes. See the +comment at the start of cc-engine.el for more info." + + (let ((rtn + (save-excursion + (let* ((pos (point)) + (lim (or lim (progn + (c-beginning-of-syntax) + (point)))) + (state (parse-partial-sexp lim pos))) + (csharp-log 4 "C#: parse lim(%d) state: %s" lim (prin1-to-string state)) + (cond + ((elt state 3) + (csharp-log 4 "C#: in literal string (%d)" pos) + 'string) + ((elt state 4) + (csharp-log 4 "C#: in literal comment (%d)" pos) + (if (elt state 7) 'c++ 'c)) + ((and detect-cpp (c-beginning-of-macro lim)) 'pound) + (t nil)))))) + rtn)) + + +(defun csharp-set-vliteral-syntax-table-properties (beg end) + "Scan the buffer text between BEG and END, a verbatim literal +string, setting and clearing syntax-table text properties where +necessary. + +We need to modify the default syntax-table text property in these cases: + (backslash) - is not an escape inside a verbatim literal string. + (double-quote) - can be a literal quote, when doubled. + +BEG is the @ delimiter. END is the 'old' position of the ending quote. + +see http://www.sunsite.ualberta.ca/Documentation/Gnu/emacs-lisp-ref-21-2.7/html_node/elisp_592.html +for the list of syntax table numeric codes. + +" + + (csharp-log 3 "C#: set-vlit-syntax-table: beg(%d) end(%d)" beg end) + + (if (and (> beg 0) (> end 0)) + + (let ((curpos beg) + (state 0)) + + (c-clear-char-properties beg end 'syntax-table) + + (while (<= curpos end) + + (cond + ((= state 0) + (if (= (char-after curpos) ?@) + (progn + (c-put-char-property curpos 'syntax-table '(3)) ; (6) = expression prefix, (3) = symbol + ;;(message (format "C#: set-s-t: prefix pos(%d) chr(%c)" beg (char-after beg))) + ) + ) + (setq state (+ 1 state))) + + ((= state 1) + (if (= (char-after curpos) ?\") + (progn + (c-put-char-property curpos 'syntax-table '(7)) ; (7) = string quote + ;;(message (format "C#: set-s-t: open quote pos(%d) chr(%c)" + ;; curpos (char-after curpos))) + )) + (setq state (+ 1 state))) + + ((= state 2) + (cond + ;; handle backslash + ((= (char-after curpos) ?\\) + (c-put-char-property curpos 'syntax-table '(2)) ; (1) = punctuation, (2) = word + ;;(message (format "C#: set-s-t: backslash word pos(%d) chr(%c)" curpos (char-after curpos))) + ) + + ;; doubled double-quote + ((and + (= (char-after curpos) ?\") + (= (char-after (+ 1 curpos)) ?\")) + (c-put-char-property curpos 'syntax-table '(2)) ; (1) = punctuation, (2) = word + (c-put-char-property (+ 1 curpos) 'syntax-table '(2)) ; (1) = punctuation + ;;(message (format "C#: set-s-t: double doublequote pos(%d) chr(%c)" curpos (char-after curpos))) + (setq curpos (+ curpos 1)) + ) + + ;; a single double-quote, which should be a string terminator + ((= (char-after curpos) ?\") + (c-put-char-property curpos 'syntax-table '(7)) ; (7) = string quote + ;;(message (format "C#: set-s-t: close quote pos(%d) chr(%c)" curpos (char-after curpos))) + ;;go no further + (setq state (+ 1 state))) + + ;; everything else + (t + ;;(message (format "C#: set-s-t: none pos(%d) chr(%c)" curpos (char-after curpos))) + nil)))) + ;; next char + (setq curpos (+ curpos 1)))))) + + + +(defun csharp-end-of-verbatim-literal-string (&optional lim) + "Moves to and returns the position of the end quote of the verbatim literal +string. When calling, point should be on the @ of the verblit string. +If it is not, then no movement is performed and `point' is returned. + +This function ignores text properties. In fact it is the +underlying scanner used to set the text properties in a C# buffer. +" + + (csharp-log 3 "C#: end-of-vlit-string: point(%d) c(%c)" (point) (char-after)) + + (let (curpos + (max (or lim (point-max)))) + + (if (not (looking-at "@\"")) + (point) + (forward-char 2) ;; pass up the @ sign and first quote + (setq curpos (point)) + + ;; Within a verbatim literal string, a doubled double-quote + ;; escapes the double-quote." + (while (and ;; process characters... + (or ;; while... + (not (eq (char-after curpos) ?\")) ;; it's not a quote + (eq (char-after (+ curpos 1)) ?\")) ;; or, its a double (double) quote + (< curpos max)) ;; and we're not done yet + + (cond + ((and (eq (char-after curpos) ?\") ;; it's a double-quote. + (eq (char-after (+ curpos 1)) ?\")) + (setq curpos (+ 2 curpos))) ;; Skip 2 + (t ;; anything else + (setq curpos (+ 1 curpos))))) ;; skip fwd 1 + curpos))) + + + + +(defun csharp-scan-for-verbatim-literals-and-set-props (&optional beg end) + +"Scans the buffer, between BEG and END, for verbatim literal +strings, and sets override text properties on each string to +allow proper syntax highlighting, indenting, and cursor movement. + +BEG and END define the limits of the scan. When nil, they +default to `point-min' and `point-max' respectively. + +Setting text properties generally causes the buffer to be marked +as modified, but this fn suppresses that via the +`c-buffer-save-state' macro, for any changes in text properties +that it makes. This fn also ignores the read-only setting on a +buffer, using the same macro. + +This fn is called when a csharp-mode buffer is loaded, with BEG +and END set to nil, to do a full scan. It is also called on +every buffer change, with the BEG and END set to the values for +the change. + +The return value is nil if the buffer was not a csharp-mode +buffer. Otherwise it is the last cursor position examined by the +scan. +" + + (if (not (c-major-mode-is 'csharp-mode)) ;; don't scan if not csharp mode + nil + (save-excursion + (c-save-buffer-state + ((curpos (or beg (point-min))) + (lastpos (or end (point-max))) + (state 0) (start 0) (cycle 0) + literal eos limits) + + (csharp-log 3 "C#: scan") + (goto-char curpos) + + (while (and (< curpos lastpos) (< cycle 10000)) + (cond + + ;; Case 1: current char is a @ sign + ;; -------------------------------------------- + ;; Check to see if it demarks the beginning of a verblit + ;; string. + ((= ?@ (char-after curpos)) + + ;; are we in a comment? a string? Maybe the @ is a prefix + ;; to allow the use of a reserved word as a symbol. Let's find out. + + ;; not sure why I need both of the following. + (syntax-ppss-flush-cache 1) + (parse-partial-sexp 1 curpos) + (goto-char curpos) + (setq literal (csharp-in-literal)) + (cond + + ;; Case 1.A: it's a @ within a string. + ;; -------------------------------------------- + ;; This should never happen, because this scanner hops over strings. + ;; But it might happen if the scan starts at an odd place. + ((eq literal 'string) nil) + + ;; Case 1.B: The @ is within a comment. Hop over it. + ((and (memq literal '(c c++)) + ;; This is a kludge for XEmacs where we use + ;; `buffer-syntactic-context', which doesn't correctly + ;; recognize "\*/" to end a block comment. + ;; `parse-partial-sexp' which is used by + ;; `c-literal-limits' will however do that in most + ;; versions, which results in that we get nil from + ;; `c-literal-limits' even when `c-in-literal' claims + ;; we're inside a comment. + ;;(setq limits (c-literal-limits start))) + (setq limits (c-literal-limits))) + + ;; advance to the end of the comment + (if limits + (progn + (csharp-log 4 "C#: scan: jump end comment A (%d)" (cdr limits)) + (setq curpos (cdr limits))))) + + + ;; Case 1.B: curpos is at least 2 chars before the last + ;; position to examine, and, the following char is a + ;; double-quote (ASCII 34). + ;; -------------------------------------------- + ;; This looks like the beginning of a verbatim string + ;; literal. + ((and (< (+ 2 curpos) lastpos) + (= ?\" (char-after (+ 1 curpos)))) + + (setq eos (csharp-end-of-verbatim-literal-string)) + ;; set override syntax properties on the verblit string + (csharp-set-vliteral-syntax-table-properties curpos eos) + + (csharp-log 4 "C#: scan: jump end verblit string (%d)" eos) + (setq curpos eos)))) + + + ;; Case 2: current char is a double-quote. + ;; -------------------------------------------- + ;; If this is a string, we hop over it, on the assumption that + ;; this scanner need not bother with regular literal strings, which + ;; get the proper syntax with the generic approach. + ;; If in a comment, hop over the comment. + ((= ?\" (char-after curpos)) + (goto-char curpos) + (setq literal (c-in-literal)) + (cond + + ;; Case 2.A: a quote within a string + ;; -------------------------------------------- + ;; This shouldn't happen, because we hop over strings. + ;; But it might. + ((eq literal 'string) nil) + + ;; Case 2.B: a quote within a comment + ;; -------------------------------------------- + ((and (memq literal '(c c++)) + ;; This is a kludge for XEmacs where we use + ;; `buffer-syntactic-context', which doesn't correctly + ;; recognize "\*/" to end a block comment. + ;; `parse-partial-sexp' which is used by + ;; `c-literal-limits' will however do that in most + ;; versions, which results in that we get nil from + ;; `c-literal-limits' even when `c-in-literal' claims + ;; we're inside a comment. + ;;(setq limits (c-literal-limits start))) + (setq limits (c-literal-limits))) + + ;; advance to the end of the comment + (if limits + (progn + (setq curpos (cdr limits)) + (csharp-log 3 "C#: scan: jump end comment B (%s)" curpos)))) + + + ;; Case 2.C: Not in a comment, and not in a string. + ;; -------------------------------------------- + ;; This is the beginning of a literal (but not verbatim) string. + (t + (forward-char 1) ;; pass up the quote + (if (consp (setq limits (c-literal-limits))) + (progn + (csharp-log 4 "C#: scan: jump end literal (%d)" (cdr limits)) + (setq curpos (cdr limits)))))))) + + (setq cycle (+ 1 cycle)) + (setq curpos (+ 1 curpos)) + (c-safe (goto-char curpos))))))) + + +(defun csharp-before-font-lock (beg end old-len) + "Adjust`syntax-table' properties on the region affected by the change +in a csharp-mode buffer. + +This function is the C# value for `c-before-font-lock-function'. +It intended to be called only by the cc-mode runtime. + +It prepares the buffer for font locking, hence must get called +before `font-lock-after-change-function'. + +It does hidden buffer changes. + +BEG, END and OLD-LEN have the same meaning here as for any +after-change function. + +Point is undefined both before and after this function call. +The return value is meaningless, and is ignored by cc-mode. +" + (let ((start-scan (progn + (c-beginning-of-statement 1) + (point)))) + (csharp-scan-for-verbatim-literals-and-set-props start-scan end))) + + + +(c-lang-defconst c-before-font-lock-function + csharp 'csharp-before-font-lock) + +;; ================================================================== +;; end of c# fontification extensions +;; ================================================================== + + + + + +;; ================================================================== +;; C#-specific optimizations of cc-mode funcs +;; ================================================================== + + +;; There's never a need to check for C-style macro definitions in +;; a C# buffer. +(defadvice c-beginning-of-macro (around + csharp-mode-advice-1 + compile activate) + (if (c-major-mode-is 'csharp-mode) + nil + ad-do-it) + ) + + +;; There's never a need to move over an Obj-C directive in csharp mode +(defadvice c-forward-objc-directive (around + csharp-mode-advice-2 + compile activate) + (if (c-major-mode-is 'csharp-mode) + nil + ad-do-it) + ) + +;; ================================================================== +;; end of C#-specific optimizations of cc-mode funcs +;; ================================================================== + + + + + + + + +;; ================================================================== +;; c# - monkey-patching of basic parsing logic +;; ================================================================== +;; +;; Here, the model redefines two defuns to add special cases for csharp +;; mode. These primarily deal with indentation of instance +;; initializers, which are somewhat unique to C#. I couldn't figure out +;; how to get cc-mode to do what C# needs, without modifying these +;; defuns. +;; + +(defun c-looking-at-inexpr-block (lim containing-sexp &optional check-at-end) + ;; Return non-nil if we're looking at the beginning of a block + ;; inside an expression. The value returned is actually a cons of + ;; either 'inlambda, 'inexpr-statement or 'inexpr-class and the + ;; position of the beginning of the construct. + ;; + ;; LIM limits the backward search. CONTAINING-SEXP is the start + ;; position of the closest containing list. If it's nil, the + ;; containing paren isn't used to decide whether we're inside an + ;; expression or not. If both LIM and CONTAINING-SEXP are used, LIM + ;; needs to be farther back. + ;; + ;; If CHECK-AT-END is non-nil then extra checks at the end of the + ;; brace block might be done. It should only be used when the + ;; construct can be assumed to be complete, i.e. when the original + ;; starting position was further down than that. + ;; + ;; This function might do hidden buffer changes. + + (save-excursion + (let ((res 'maybe) passed-paren + (closest-lim (or containing-sexp lim (point-min))) + ;; Look at the character after point only as a last resort + ;; when we can't disambiguate. + (block-follows (and (eq (char-after) ?{) (point)))) + + (while (and (eq res 'maybe) + (progn (c-backward-syntactic-ws) + (> (point) closest-lim)) + (not (bobp)) + (progn (backward-char) + (looking-at "[\]\).]\\|\\w\\|\\s_")) + (c-safe (forward-char) + (goto-char (scan-sexps (point) -1)))) + + (setq res + (if (looking-at c-keywords-regexp) + (let ((kw-sym (c-keyword-sym (match-string 1)))) + (cond + ((and block-follows + (c-keyword-member kw-sym 'c-inexpr-class-kwds)) + (and (not (eq passed-paren ?\[)) + + ;; dinoch Thu, 22 Apr 2010 18:20 + ;; ============================================ + ;; looking at new MyType() { ... } + ;; means this is a brace list, so, return nil, + ;; implying NOT looking-at-inexpr-block + (not + (and (c-major-mode-is 'csharp-mode) + (looking-at "new\s+\\([[:alnum:]_]+\\)\\b"))) + + (or (not (looking-at c-class-key)) + ;; If the class instantiation is at the start of + ;; a statement, we don't consider it an + ;; in-expression class. + (let ((prev (point))) + (while (and + (= (c-backward-token-2 1 nil closest-lim) 0) + (eq (char-syntax (char-after)) ?w)) + (setq prev (point))) + (goto-char prev) + (not (c-at-statement-start-p))) + ;; Also, in Pike we treat it as an + ;; in-expression class if it's used in an + ;; object clone expression. + (save-excursion + (and check-at-end + (c-major-mode-is 'pike-mode) + (progn (goto-char block-follows) + (zerop (c-forward-token-2 1 t))) + (eq (char-after) ?\()))) + (cons 'inexpr-class (point)))) + ((c-keyword-member kw-sym 'c-inexpr-block-kwds) + (when (not passed-paren) + (cons 'inexpr-statement (point)))) + ((c-keyword-member kw-sym 'c-lambda-kwds) + (when (or (not passed-paren) + (eq passed-paren ?\()) + (cons 'inlambda (point)))) + ((c-keyword-member kw-sym 'c-block-stmt-kwds) + nil) + (t + 'maybe))) + + (if (looking-at "\\s(") + (if passed-paren + (if (and (eq passed-paren ?\[) + (eq (char-after) ?\[)) + ;; Accept several square bracket sexps for + ;; Java array initializations. + 'maybe) + (setq passed-paren (char-after)) + 'maybe) + 'maybe)))) + + (if (eq res 'maybe) + (when (and c-recognize-paren-inexpr-blocks + block-follows + containing-sexp + (eq (char-after containing-sexp) ?\()) + (goto-char containing-sexp) + (if (or (save-excursion + (c-backward-syntactic-ws lim) + (and (> (point) (or lim (point-min))) + (c-on-identifier))) + (and c-special-brace-lists + (c-looking-at-special-brace-list))) + nil + (cons 'inexpr-statement (point)))) + + res)))) + + + + +(defconst csharp-enum-decl-re + (concat + "\\<enum\\>\s+\\([[:alnum:]_]+\\)\s*:\s*" + "\\(" + (c-make-keywords-re nil + (list "sbyte" "byte" "short" "ushort" "int" "uint" "long" "ulong")) + "\\)") + "Regex that captures an enum declaration in C#" + ) + + + +(defun c-inside-bracelist-p (containing-sexp paren-state) + ;; return the buffer position of the beginning of the brace list + ;; statement if we're inside a brace list, otherwise return nil. + ;; CONTAINING-SEXP is the buffer pos of the innermost containing + ;; paren. PAREN-STATE is the remainder of the state of enclosing + ;; braces + ;; + ;; N.B.: This algorithm can potentially get confused by cpp macros + ;; placed in inconvenient locations. It's a trade-off we make for + ;; speed. + ;; + ;; This function might do hidden buffer changes. + (or + ;; This will pick up brace list declarations. + (c-safe + (save-excursion + (goto-char containing-sexp) + (c-forward-sexp -1) + (let (bracepos) + (if (and (or (looking-at c-brace-list-key) + + (progn (c-forward-sexp -1) + (looking-at c-brace-list-key)) + + ;; dinoch Thu, 22 Apr 2010 18:20 + ;; ============================================ + ;; looking enum Foo : int + ;; means this is a brace list, so, return nil, + ;; implying NOT looking-at-inexpr-block + + (and (c-major-mode-is 'csharp-mode) + (progn + (c-forward-sexp -1) + (looking-at csharp-enum-decl-re)))) + + (setq bracepos (c-down-list-forward (point))) + (not (c-crosses-statement-barrier-p (point) + (- bracepos 2)))) + (point))))) + ;; this will pick up array/aggregate init lists, even if they are nested. + (save-excursion + (let ((class-key + ;; Pike can have class definitions anywhere, so we must + ;; check for the class key here. + (and (c-major-mode-is 'pike-mode) + c-decl-block-key)) + bufpos braceassignp lim next-containing) + (while (and (not bufpos) + containing-sexp) + (when paren-state + (if (consp (car paren-state)) + (setq lim (cdr (car paren-state)) + paren-state (cdr paren-state)) + (setq lim (car paren-state))) + (when paren-state + (setq next-containing (car paren-state) + paren-state (cdr paren-state)))) + (goto-char containing-sexp) + (if (c-looking-at-inexpr-block next-containing next-containing) + ;; We're in an in-expression block of some kind. Do not + ;; check nesting. We deliberately set the limit to the + ;; containing sexp, so that c-looking-at-inexpr-block + ;; doesn't check for an identifier before it. + (setq containing-sexp nil) + ;; see if the open brace is preceded by = or [...] in + ;; this statement, but watch out for operator= + (setq braceassignp 'dontknow) + (c-backward-token-2 1 t lim) + ;; Checks to do only on the first sexp before the brace. + (when (and c-opt-inexpr-brace-list-key + (eq (char-after) ?\[)) + ;; In Java, an initialization brace list may follow + ;; directly after "new Foo[]", so check for a "new" + ;; earlier. + (while (eq braceassignp 'dontknow) + (setq braceassignp + (cond ((/= (c-backward-token-2 1 t lim) 0) nil) + ((looking-at c-opt-inexpr-brace-list-key) t) + ((looking-at "\\sw\\|\\s_\\|[.[]") + ;; Carry on looking if this is an + ;; identifier (may contain "." in Java) + ;; or another "[]" sexp. + 'dontknow) + (t nil))))) + ;; Checks to do on all sexps before the brace, up to the + ;; beginning of the statement. + (while (eq braceassignp 'dontknow) + (cond ((eq (char-after) ?\;) + (setq braceassignp nil)) + ((and class-key + (looking-at class-key)) + (setq braceassignp nil)) + ((eq (char-after) ?=) + ;; We've seen a =, but must check earlier tokens so + ;; that it isn't something that should be ignored. + (setq braceassignp 'maybe) + (while (and (eq braceassignp 'maybe) + (zerop (c-backward-token-2 1 t lim))) + (setq braceassignp + (cond + ;; Check for operator = + ((and c-opt-op-identifier-prefix + (looking-at c-opt-op-identifier-prefix)) + nil) + ;; Check for `<opchar>= in Pike. + ((and (c-major-mode-is 'pike-mode) + (or (eq (char-after) ?`) + ;; Special case for Pikes + ;; `[]=, since '[' is not in + ;; the punctuation class. + (and (eq (char-after) ?\[) + (eq (char-before) ?`)))) + nil) + ((looking-at "\\s.") 'maybe) + ;; make sure we're not in a C++ template + ;; argument assignment + ((and + (c-major-mode-is 'c++-mode) + (save-excursion + (let ((here (point)) + (pos< (progn + (skip-chars-backward "^<>") + (point)))) + (and (eq (char-before) ?<) + (not (c-crosses-statement-barrier-p + pos< here)) + (not (c-in-literal)) + )))) + nil) + (t t)))))) + (if (and (eq braceassignp 'dontknow) + (/= (c-backward-token-2 1 t lim) 0)) + (setq braceassignp nil))) + (if (not braceassignp) + (if (eq (char-after) ?\;) + ;; Brace lists can't contain a semicolon, so we're done. + (setq containing-sexp nil) + ;; Go up one level. + (setq containing-sexp next-containing + lim nil + next-containing nil)) + ;; we've hit the beginning of the aggregate list + (c-beginning-of-statement-1 + (c-most-enclosing-brace paren-state)) + (setq bufpos (point)))) + ) + bufpos)) + )) + +;; ================================================================== +;; end of monkey-patching of basic parsing logic +;; ================================================================== + + + + +;;(easy-menu-define csharp-menu csharp-mode-map "C# Mode Commands" +;; ;; Can use `csharp' as the language for `c-mode-menu' +;; ;; since its definition covers any language. In +;; ;; this case the language is used to adapt to the +;; ;; nonexistence of a cpp pass and thus removing some +;; ;; irrelevant menu alternatives. +;; (cons "C#" (c-lang-const c-mode-menu csharp))) + +;;; Autoload mode trigger +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.cs$" . csharp-mode)) + + + +(c-add-style "C#" + '("Java" + (c-basic-offset . 4) + (c-comment-only-line-offset . (0 . 0)) + (c-offsets-alist . ( + (access-label . -) + (arglist-close . c-lineup-arglist) + (arglist-cont . 0) + (arglist-cont-nonempty . c-lineup-arglist) + (arglist-intro . c-lineup-arglist-intro-after-paren) + (block-close . 0) + (block-open . 0) + (brace-entry-open . 0) + (brace-list-close . 0) + (brace-list-entry . 0) + (brace-list-intro . +) + (brace-list-open . +) + (c . c-lineup-C-comments) + (case-label . +) + (catch-clause . 0) + (class-close . 0) + (class-open . 0) + (comment-intro . c-lineup-comment) + (cpp-macro . 0) + (cpp-macro-cont . c-lineup-dont-change) + (defun-block-intro . +) + (defun-close . 0) + (defun-open . 0) + (do-while-closure . 0) + (else-clause . 0) + (extern-lang-close . 0) + (extern-lang-open . 0) + (friend . 0) + (func-decl-cont . +) + (inclass . +) + (inexpr-class . +) + (inexpr-statement . 0) + (inextern-lang . +) + (inher-cont . c-lineup-multi-inher) + (inher-intro . +) + (inlambda . c-lineup-inexpr-block) + (inline-close . 0) + (inline-open . 0) + (innamespace . +) + (knr-argdecl . 0) + (knr-argdecl-intro . 5) + (label . 0) + (lambda-intro-cont . +) + (member-init-cont . c-lineup-multi-inher) + (member-init-intro . +) + (namespace-close . 0) + (namespace-open . 0) + (statement . 0) + (statement-block-intro . +) + (statement-case-intro . +) + (statement-case-open . +) + (statement-cont . +) + (stream-op . c-lineup-streamop) + (string . c-lineup-dont-change) + (substatement . +) + (substatement-open . 0) + (template-args-cont c-lineup-template-args +) + (topmost-intro . 0) + (topmost-intro-cont . 0) + )) + )) + + + + +;; Custom variables +;;;###autoload +(defcustom csharp-mode-hook nil + "*Hook called by `csharp-mode'." + :type 'hook + :group 'c) + + + +;;; The entry point into the mode +;;;###autoload +(defun csharp-mode () + "Major mode for editing C# code. This mode is derived from CC Mode to +support C#. + +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `csharp-mode-hook'. + +This mode will automatically add a regexp for Csc.exe error and warning +messages to the `compilation-error-regexp-alist'. + +Key bindings: +\\{csharp-mode-map}" + (interactive) + (kill-all-local-variables) + (make-local-variable 'beginning-of-defun-function) + (make-local-variable 'end-of-defun-function) + (c-initialize-cc-mode t) + (set-syntax-table csharp-mode-syntax-table) + + ;; define underscore as part of a word in the Csharp syntax table + (modify-syntax-entry ?_ "w" csharp-mode-syntax-table) + + ;; define @ as an expression prefix in Csharp syntax table + (modify-syntax-entry ?@ "'" csharp-mode-syntax-table) + + (setq major-mode 'csharp-mode + mode-name "C#" + local-abbrev-table csharp-mode-abbrev-table + abbrev-mode t) + (use-local-map csharp-mode-map) + + ;; `c-init-language-vars' is a macro that is expanded at compile + ;; time to a large `setq' with all the language variables and their + ;; customized values for our language. + (c-init-language-vars csharp-mode) + + + ;; `c-common-init' initializes most of the components of a CC Mode + ;; buffer, including setup of the mode menu, font-lock, etc. + ;; There's also a lower level routine `c-basic-common-init' that + ;; only makes the necessary initialization to get the syntactic + ;; analysis and similar things working. + (c-common-init 'csharp-mode) + + + ;; csc.exe, the C# Compiler, produces errors like this: + ;; file.cs(6,18): error SC1006: Name of constructor must match name of class + + (add-hook 'compilation-mode-hook + (lambda () + (setq compilation-error-regexp-alist + (cons ' ("^[ \t]*\\([A-Za-z0-9][^(]+\\.cs\\)(\\([0-9]+\\)[,]\\([0-9]+\\)) ?: \\(error\\|warning\\) CS[0-9]+:" 1 2 3) + compilation-error-regexp-alist)))) + + ;; to allow next-error to work with csc.exe: + (setq compilation-scroll-output t) + + ;; allow fill-paragraph to work on xml code doc + (set (make-local-variable 'paragraph-separate) + "[ \t]*\\(//+\\|\\**\\)\\([ \t]+\\|[ \t]+<.+?>\\)$\\|^\f") + + + (c-run-mode-hooks 'c-mode-common-hook 'csharp-mode-hook) + + + ;; Need the following for parse-partial-sexp to work properly with + ;; verbatim literal strings Setting this var to non-nil tells + ;; `parse-partial-sexp' to pay attention to the syntax text + ;; properties on the text in the buffer. If csharp-mode attaches + ;; text syntax to @"..." then, `parse-partial-sexp' will treat those + ;; strings accordingly. + (set (make-local-variable 'parse-sexp-lookup-properties) + t) + + ;; scan the entire buffer for verblit strings + (csharp-scan-for-verbatim-literals-and-set-props nil nil) + + + (local-set-key (kbd "/") 'csharp-maybe-insert-codedoc) + (local-set-key (kbd "{") 'csharp-insert-open-brace) + + (c-update-modeline)) + + + +(message (concat "Done loading " load-file-name)) + + +(provide 'csharp-mode) + +;;; csharp-mode.el ends here +;;MD5: 4EDCB2ECE38841F407C7ED3DA8354E15 diff --git a/emacs/nxhtml/related/django.el b/emacs/nxhtml/related/django.el new file mode 100644 index 0000000..f592550 --- /dev/null +++ b/emacs/nxhtml/related/django.el @@ -0,0 +1,203 @@ +;;; django.el --- +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sun Nov 18 18:29:41 2007 +;; Version: 0.3 +;; Last-Updated: 2008-08-08T13:22:19+0200 Fri +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Simple highlighting for Django for use with mumamo. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +;; Maybe there are something to get here? +;; http://github.com/cosmin/emacs-utils/tree/85cc1d2bd447cb9b2fc98e27b5f8780453e5b978/django-html-mode.el + +(defconst django-indenting-keywords + '("block" "comment" "else" + "filter" "for" "if" "ifchanged" "ifequal" + "ifnotequal" "spaceless" "with")) + +;; (append '(or) django-indenting-keywords) +(defconst django-font-lock-keywords + (list + (cons (rx-to-string + `(and + word-start + (or "as" "autoescape" "csrf_token" "cycle" "debug" "extends" + "firstof" "in" "include" "load" "now" "regroup" "ssi" + "templatetag" "url" "widthratio" + (seq + (opt "end") + ;; (or "autoescape" "block" "comment" "cycle" "debug" "else" + ;; "extends" "filter" "firstof" "for" "if" "ifchanged" "ifequal" + ;; "ifnotequal" "include" "load" "now" "regroup" + ;; "spaceless" "ssi" "templatetag" "url" "widthratio" + ;; "with") + ,(append '(or) django-indenting-keywords) + )) + word-end)) + font-lock-keyword-face) + ) + "Minimal highlighting expressions for Django mode") + +(defcustom django-indent-width 2 + "Indentation width for Django." + :type 'integer + :group 'django) + +(defun django-indent-line () + "Indent current line as Django code. +Indent like the examples on URL +`http://docs.djangoproject.com/en/1.1/ref/templates/builtins/'." + (save-match-data + (let* ((indent-re (rx-to-string `(and word-start + ,(append '(or "else") django-indenting-keywords)))) + (deindent-re (rx-to-string `(and word-start + (or "else" + (seq + "end" + ,(append '(or) django-indenting-keywords)))))) + (here (point-marker)) + (this-indentation (current-indentation)) + (this-line-start (progn (beginning-of-line) (point))) + (prev-line-start (progn (skip-chars-backward " \t\n\r\f") + (beginning-of-line) + (when (< (point) this-line-start) + (point)))) + (prev-indentation (if prev-line-start (current-indentation) 0)) + (shift-in (if (and prev-line-start + (re-search-forward indent-re (point-at-eol) t)) + django-indent-width 0)) + (shift-out (progn + (goto-char this-line-start) + (if (re-search-forward deindent-re (point-at-eol) t) + (- django-indent-width) 0))) + (new-indentation (max 0 (+ prev-indentation shift-in shift-out))) + ) + (goto-char this-line-start) + (cond + ((> new-indentation this-indentation) + (skip-chars-forward " \t") + (indent-to new-indentation)) + ((< new-indentation this-indentation) + (back-to-indentation) + (delete-region this-line-start (point)) + (indent-to new-indentation))) + (goto-char here)))) + +;;;###autoload +(define-derived-mode django-mode nil "Django" + "Simple Django mode for use with mumamo. +This mode only provides syntax highlighting." + (set (make-local-variable 'indent-line-function) 'django-indent-line) + (setq font-lock-defaults '(django-font-lock-keywords))) + +;;; Comments mode +;; (defconst django-comment-font-lock-keywords +;; (list +;; (cons "\\(.*\\)" (list 1 font-lock-comment-face)) +;; )) + +;; (defvar django-comment-font-lock-defaults +;; '(django-comment-font-lock-keywords t t)) + +;; (define-derived-mode django-comment-mode nil "Django comment" +;; "For django comment blocks." +;; (set (make-local-variable 'font-lock-defaults) django-comment-font-lock-defaults)) + +;;; Variables mode + +(defconst django-variable-font-lock-keywords + (list + ;; Built in filters: + (cons (rx + "|" + (submatch + (or "add" "addslashes" "capfirst" "center" "cut" + "date" "default" "default_if_none" + "dictsort" "dictsortreversed" + "divisibleby" + "escape" + "filesizeformat" + "first" + "fixampersands" + "floatformat" + "force_escape" + "iriencode" + "join" + "length" "length_is" + "linebreaks" "linebreaksbr" "linenumbers" + "ljust" + "lower" + "make_list" + "phone2numeric" + "pluralize" + "pprint" + "random" + "removetags" + "rjust" + "safe" "slice" "slugify" "stringformat" "striptags" + "time" "timesince" "timeuntil" + "title" "truncatewords" "truncatewords_html" + "unordered_list" + "upper" "urlencode" "urlize" "urlizetrunc" + "wordcount" "wordwrap" "yesno"))) + (list 1 font-lock-builtin-face)) + (cons (rx + "|" + (submatch + (0+ (any "a-z")))) + (list 1 font-lock-function-name-face)) + (cons "\\([^|]*\\)" (list 1 font-lock-variable-name-face)) + )) + +(defvar django-variable-font-lock-defaults + '(django-variable-font-lock-keywords + t t + ;; This still gives teh syntax symbol to |, why? + ((?| . ". ")) + )) + +(define-derived-mode django-variable-mode nil "Django variable" + "For django comment blocks." + ;;(modify-syntax-entry ?| ?.) + (set (make-local-variable 'font-lock-defaults) django-variable-font-lock-defaults)) + +(provide 'django) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; django.el ends here diff --git a/emacs/nxhtml/related/env.js b/emacs/nxhtml/related/env.js new file mode 100644 index 0000000..53551e7 --- /dev/null +++ b/emacs/nxhtml/related/env.js @@ -0,0 +1,695 @@ +/* + * Simulated browser environment for Rhino + * By John Resig <http://ejohn.org/> + * Copyright 2007 John Resig, under the MIT License + */ + +// The window Object +var window = this; + +(function(){ + + // Browser Navigator + + window.navigator = { + get userAgent(){ + return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3"; + } + }; + + var curLocation = (new java.io.File("./")).toURL(); + + window.__defineSetter__("location", function(url){ + var xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onreadystatechange = function(){ + curLocation = new java.net.URL( curLocation, url ); + window.document = xhr.responseXML; + + var event = document.createEvent(); + event.initEvent("load"); + window.dispatchEvent( event ); + }; + xhr.send(); + }); + + window.__defineGetter__("location", function(url){ + return { + get protocol(){ + return curLocation.getProtocol() + ":"; + }, + get href(){ + return curLocation.toString(); + }, + toString: function(){ + return this.href; + } + }; + }); + + // Timers + + var timers = []; + + window.setTimeout = function(fn, time){ + var num; + return num = setInterval(function(){ + fn(); + clearInterval(num); + }, time); + }; + + window.setInterval = function(fn, time){ + var num = timers.length; + + timers[num] = new java.lang.Thread(new java.lang.Runnable({ + run: function(){ + while (true){ + java.lang.Thread.currentThread().sleep(time); + fn(); + } + } + })); + + timers[num].start(); + + return num; + }; + + window.clearInterval = function(num){ + if ( timers[num] ) { + timers[num].stop(); + delete timers[num]; + } + }; + + // Window Events + + var events = [{}]; + + window.addEventListener = function(type, fn){ + if ( !this.uuid || this == window ) { + this.uuid = events.length; + events[this.uuid] = {}; + } + + if ( !events[this.uuid][type] ) + events[this.uuid][type] = []; + + if ( events[this.uuid][type].indexOf( fn ) < 0 ) + events[this.uuid][type].push( fn ); + }; + + window.removeEventListener = function(type, fn){ + if ( !this.uuid || this == window ) { + this.uuid = events.length; + events[this.uuid] = {}; + } + + if ( !events[this.uuid][type] ) + events[this.uuid][type] = []; + + events[this.uuid][type] = + events[this.uuid][type].filter(function(f){ + return f != fn; + }); + }; + + window.dispatchEvent = function(event){ + if ( event.type ) { + if ( this.uuid && events[this.uuid][event.type] ) { + var self = this; + + events[this.uuid][event.type].forEach(function(fn){ + fn.call( self, event ); + }); + } + + if ( this["on" + event.type] ) + this["on" + event.type].call( self, event ); + } + }; + + // DOM Document + + window.DOMDocument = function(file){ + this._file = file; + this._dom = Packages.javax.xml.parsers. + DocumentBuilderFactory.newInstance() + .newDocumentBuilder().parse(file); + + if ( !obj_nodes.containsKey( this._dom ) ) + obj_nodes.put( this._dom, this ); + }; + + DOMDocument.prototype = { + createTextNode: function(text){ + return makeNode( this._dom.createTextNode( + text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")) ); + }, + createElement: function(name){ + return makeNode( this._dom.createElement(name.toLowerCase()) ); + }, + getElementsByTagName: function(name){ + return new DOMNodeList( this._dom.getElementsByTagName( + name.toLowerCase()) ); + }, + getElementById: function(id){ + var elems = this._dom.getElementsByTagName("*"); + + for ( var i = 0; i < elems.length; i++ ) { + var elem = elems.item(i); + if ( elem.getAttribute("id") == id ) + return makeNode(elem); + } + + return null; + }, + get body(){ + return this.getElementsByTagName("body")[0]; + }, + get documentElement(){ + return makeNode( this._dom.getDocumentElement() ); + }, + get ownerDocument(){ + return null; + }, + addEventListener: window.addEventListener, + removeEventListener: window.removeEventListener, + dispatchEvent: window.dispatchEvent, + get nodeName() { + return "#document"; + }, + importNode: function(node, deep){ + return makeNode( this._dom.importNode(node._dom, deep) ); + }, + toString: function(){ + return "Document" + (typeof this._file == "string" ? + ": " + this._file : ""); + }, + get innerHTML(){ + return this.documentElement.outerHTML; + }, + + get defaultView(){ + return { + getComputedStyle: function(elem){ + return { + getPropertyValue: function(prop){ + prop = prop.replace(/\-(\w)/g,function(m,c){ + return c.toUpperCase(); + }); + var val = elem.style[prop]; + + if ( prop == "opacity" && val == "" ) + val = "1"; + + return val; + } + }; + } + }; + }, + + createEvent: function(){ + return { + type: "", + initEvent: function(type){ + this.type = type; + } + }; + } + }; + + function getDocument(node){ + return obj_nodes.get(node); + } + + // DOM NodeList + + window.DOMNodeList = function(list){ + this._dom = list; + this.length = list.getLength(); + + for ( var i = 0; i < this.length; i++ ) { + var node = list.item(i); + this[i] = makeNode( node ); + } + }; + + DOMNodeList.prototype = { + toString: function(){ + return "[ " + + Array.prototype.join.call( this, ", " ) + " ]"; + }, + get outerHTML(){ + return Array.prototype.map.call( + this, function(node){return node.outerHTML;}).join(''); + } + }; + + // DOM Node + + window.DOMNode = function(node){ + this._dom = node; + }; + + DOMNode.prototype = { + get nodeType(){ + return this._dom.getNodeType(); + }, + get nodeValue(){ + return this._dom.getNodeValue(); + }, + get nodeName() { + return this._dom.getNodeName(); + }, + cloneNode: function(deep){ + return makeNode( this._dom.cloneNode(deep) ); + }, + get ownerDocument(){ + return getDocument( this._dom.ownerDocument ); + }, + get documentElement(){ + return makeNode( this._dom.documentElement ); + }, + get parentNode() { + return makeNode( this._dom.getParentNode() ); + }, + get nextSibling() { + return makeNode( this._dom.getNextSibling() ); + }, + get previousSibling() { + return makeNode( this._dom.getPreviousSibling() ); + }, + toString: function(){ + return '"' + this.nodeValue + '"'; + }, + get outerHTML(){ + return this.nodeValue; + } + }; + + // DOM Element + + window.DOMElement = function(elem){ + this._dom = elem; + this.style = { + get opacity(){ return this._opacity; }, + set opacity(val){ this._opacity = val + ""; } + }; + + // Load CSS info + var styles = (this.getAttribute("style") || "").split(/\s*;\s*/); + + for ( var i = 0; i < styles.length; i++ ) { + var style = styles[i].split(/\s*:\s*/); + if ( style.length == 2 ) + this.style[ style[0] ] = style[1]; + } + }; + + DOMElement.prototype = extend( new DOMNode(), { + get nodeName(){ + return this.tagName.toUpperCase(); + }, + get tagName(){ + return this._dom.getTagName(); + }, + toString: function(){ + return "<" + this.tagName + (this.id ? "#" + this.id : "" ) + ">"; + }, + get outerHTML(){ + var ret = "<" + this.tagName, attr = this.attributes; + + for ( var i in attr ) + ret += " " + i + "='" + attr[i] + "'"; + + if ( this.childNodes.length || this.nodeName == "SCRIPT" ) + ret += ">" + this.childNodes.outerHTML + + "</" + this.tagName + ">"; + else + ret += "/>"; + + return ret; + }, + + get attributes(){ + var attr = {}, attrs = this._dom.getAttributes(); + + for ( var i = 0; i < attrs.getLength(); i++ ) + attr[ attrs.item(i).nodeName ] = attrs.item(i).nodeValue; + + return attr; + }, + + get innerHTML(){ + return this.childNodes.outerHTML; + }, + set innerHTML(html){ + html = html.replace(/<\/?([A-Z]+)/g, function(m){ + return m.toLowerCase(); + }); + + var nodes = this.ownerDocument.importNode( + new DOMDocument( new java.io.ByteArrayInputStream( + (new java.lang.String("<wrap>" + html + "</wrap>")) + .getBytes("UTF8"))).documentElement, true).childNodes; + + while (this.firstChild) + this.removeChild( this.firstChild ); + + for ( var i = 0; i < nodes.length; i++ ) + this.appendChild( nodes[i] ); + }, + + get textContent(){ + return nav(this.childNodes); + + function nav(nodes){ + var str = ""; + for ( var i = 0; i < nodes.length; i++ ) + if ( nodes[i].nodeType == 3 ) + str += nodes[i].nodeValue; + else if ( nodes[i].nodeType == 1 ) + str += nav(nodes[i].childNodes); + return str; + } + }, + set textContent(text){ + while (this.firstChild) + this.removeChild( this.firstChild ); + this.appendChild( this.ownerDocument.createTextNode(text)); + }, + + style: {}, + clientHeight: 0, + clientWidth: 0, + offsetHeight: 0, + offsetWidth: 0, + + get disabled() { + var val = this.getAttribute("disabled"); + return val != "false" && !!val; + }, + set disabled(val) { return this.setAttribute("disabled",val); }, + + get checked() { + var val = this.getAttribute("checked"); + return val != "false" && !!val; + }, + set checked(val) { return this.setAttribute("checked",val); }, + + get selected() { + if ( !this._selectDone ) { + this._selectDone = true; + + if ( this.nodeName == "OPTION" && !this.parentNode.getAttribute("multiple") ) { + var opt = this.parentNode.getElementsByTagName("option"); + + if ( this == opt[0] ) { + var select = true; + + for ( var i = 1; i < opt.length; i++ ) + if ( opt[i].selected ) { + select = false; + break; + } + + if ( select ) + this.selected = true; + } + } + } + + var val = this.getAttribute("selected"); + return val != "false" && !!val; + }, + set selected(val) { return this.setAttribute("selected",val); }, + + get className() { return this.getAttribute("class") || ""; }, + set className(val) { + return this.setAttribute("class", + val.replace(/(^\s*|\s*$)/g,"")); + }, + + get type() { return this.getAttribute("type") || ""; }, + set type(val) { return this.setAttribute("type",val); }, + + get value() { return this.getAttribute("value") || ""; }, + set value(val) { return this.setAttribute("value",val); }, + + get src() { return this.getAttribute("src") || ""; }, + set src(val) { return this.setAttribute("src",val); }, + + get id() { return this.getAttribute("id") || ""; }, + set id(val) { return this.setAttribute("id",val); }, + + getAttribute: function(name){ + return this._dom.hasAttribute(name) ? + new String( this._dom.getAttribute(name) ) : + null; + }, + setAttribute: function(name,value){ + this._dom.setAttribute(name,value); + }, + removeAttribute: function(name){ + this._dom.removeAttribute(name); + }, + + get childNodes(){ + return new DOMNodeList( this._dom.getChildNodes() ); + }, + get firstChild(){ + return makeNode( this._dom.getFirstChild() ); + }, + get lastChild(){ + return makeNode( this._dom.getLastChild() ); + }, + appendChild: function(node){ + this._dom.appendChild( node._dom ); + }, + insertBefore: function(node,before){ + this._dom.insertBefore( node._dom, before ? before._dom : before ); + }, + removeChild: function(node){ + this._dom.removeChild( node._dom ); + }, + + getElementsByTagName: DOMDocument.prototype.getElementsByTagName, + + addEventListener: window.addEventListener, + removeEventListener: window.removeEventListener, + dispatchEvent: window.dispatchEvent, + + click: function(){ + var event = document.createEvent(); + event.initEvent("click"); + this.dispatchEvent(event); + }, + submit: function(){ + var event = document.createEvent(); + event.initEvent("submit"); + this.dispatchEvent(event); + }, + focus: function(){ + var event = document.createEvent(); + event.initEvent("focus"); + this.dispatchEvent(event); + }, + blur: function(){ + var event = document.createEvent(); + event.initEvent("blur"); + this.dispatchEvent(event); + }, + get elements(){ + return this.getElementsByTagName("*"); + }, + get contentWindow(){ + return this.nodeName == "IFRAME" ? { + document: this.contentDocument + } : null; + }, + get contentDocument(){ + if ( this.nodeName == "IFRAME" ) { + if ( !this._doc ) + this._doc = new DOMDocument( + new java.io.ByteArrayInputStream((new java.lang.String( + "<html><head><title></title></head><body></body></html>")) + .getBytes("UTF8"))); + return this._doc; + } else + return null; + } + }); + + // Helper method for extending one object with another + + function extend(a,b) { + for ( var i in b ) { + var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i); + + if ( g || s ) { + if ( g ) + a.__defineGetter__(i, g); + if ( s ) + a.__defineSetter__(i, s); + } else + a[i] = b[i]; + } + return a; + } + + // Helper method for generating the right + // DOM objects based upon the type + + var obj_nodes = new java.util.HashMap(); + + function makeNode(node){ + if ( node ) { + if ( !obj_nodes.containsKey( node ) ) + obj_nodes.put( node, node.getNodeType() == + Packages.org.w3c.dom.Node.ELEMENT_NODE ? + new DOMElement( node ) : new DOMNode( node ) ); + + return obj_nodes.get(node); + } else + return null; + } + + // XMLHttpRequest + // Originally implemented by Yehuda Katz + + window.XMLHttpRequest = function(){ + this.headers = {}; + this.responseHeaders = {}; + }; + + XMLHttpRequest.prototype = { + open: function(method, url, async, user, password){ + this.readyState = 1; + if (async) + this.async = true; + this.method = method || "GET"; + this.url = url; + this.onreadystatechange(); + }, + setRequestHeader: function(header, value){ + this.headers[header] = value; + }, + getResponseHeader: function(header){ }, + send: function(data){ + var self = this; + + function makeRequest(){ + var url = new java.net.URL(curLocation, self.url); + + if ( url.getProtocol() == "file" ) { + if ( self.method == "PUT" ) { + var out = new java.io.FileWriter( + new java.io.File( new java.net.URI( url.toString() ) ) ), + text = new java.lang.String( data || "" ); + + out.write( text, 0, text.length() ); + out.flush(); + out.close(); + } else if ( self.method == "DELETE" ) { + var file = new java.io.File( new java.net.URI( url.toString() ) ); + file["delete"](); + } else { + var connection = url.openConnection(); + connection.connect(); + handleResponse(); + } + } else { + var connection = url.openConnection(); + + connection.setRequestMethod( self.method ); + + // Add headers to Java connection + for (var header in self.headers) + connection.addRequestProperty(header, self.headers[header]); + + connection.connect(); + + // Stick the response headers into responseHeaders + for (var i = 0; ; i++) { + var headerName = connection.getHeaderFieldKey(i); + var headerValue = connection.getHeaderField(i); + if (!headerName && !headerValue) break; + if (headerName) + self.responseHeaders[headerName] = headerValue; + } + + handleResponse(); + } + + function handleResponse(){ + self.readyState = 4; + self.status = parseInt(connection.responseCode) || undefined; + self.statusText = connection.responseMessage || ""; + + var stream = new java.io.InputStreamReader(connection.getInputStream()), + buffer = new java.io.BufferedReader(stream), line; + + while ((line = buffer.readLine()) != null) + self.responseText += line; + + self.responseXML = null; + + if ( self.responseText.match(/^\s*</) ) { + try { + self.responseXML = new DOMDocument( + new java.io.ByteArrayInputStream( + (new java.lang.String( + self.responseText)).getBytes("UTF8"))); + } catch(e) {} + } + } + + self.onreadystatechange(); + } + + if (this.async) + (new java.lang.Thread(new java.lang.Runnable({ + run: makeRequest + }))).start(); + else + makeRequest(); + }, + abort: function(){}, + onreadystatechange: function(){}, + getResponseHeader: function(header){ + if (this.readyState < 3) + throw new Error("INVALID_STATE_ERR"); + else { + var returnedHeaders = []; + for (var rHeader in this.responseHeaders) { + if (rHeader.match(new Regexp(header, "i"))) + returnedHeaders.push(this.responseHeaders[rHeader]); + } + + if (returnedHeaders.length) + return returnedHeaders.join(", "); + } + + return null; + }, + getAllResponseHeaders: function(header){ + if (this.readyState < 3) + throw new Error("INVALID_STATE_ERR"); + else { + var returnedHeaders = []; + + for (var header in this.responseHeaders) + returnedHeaders.push( header + ": " + this.responseHeaders[header] ); + + return returnedHeaders.join("\r\n"); + } + }, + async: true, + readyState: 0, + responseText: "", + status: 0 + }; +})(); diff --git a/emacs/nxhtml/related/flymake-css.el b/emacs/nxhtml/related/flymake-css.el new file mode 100644 index 0000000..d80abe3 --- /dev/null +++ b/emacs/nxhtml/related/flymake-css.el @@ -0,0 +1,161 @@ +;;; flymake-css.el --- Flymake setup for css files +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-11-21 Sat +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; See variable `flymake-css-validator-jar' for instructions for how +;; to set this up. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + + +(require 'flymake) +(require 'xml) + + +(defcustom flymake-allowed-css-file-name-masks '(("\\.css\\'" flymake-css-init)) + "Filename extensions that switch on js syntax checks." + :type '(repeat (list (regexp :tag "File name regexp") + (function :tag "Init function") + (choice (const :tag "No cleanup function" nil) + (function :tag "Cleanup function")))) + :group 'flymake) + + +(defvar flymake-css-err-line-pattern-re '(("^file:\\([^:]+\\):\\([^:]+\\):\\(.*\\)" 1 2 nil 3)) + "Regexp matching CSS error messages") + +(defcustom flymake-css-validator-jar "~/bin/css-validator.jar" + "Full path to css-validor.jar file. +You need the css-validator.jar and some other files for flymake +for CSS to work. The instructions below tell you how to get and +install it. The instructions are copied from + + http://www.emacswiki.org/emacs/FlymakeCSS + +Get http://www.w3.org/QA/Tools/css-validator/css-validator.jar +create a directory named âlibâ in the same directory. Copy to the +âlibâ dir the following jars: + + * commons-collections-3.2.1.jar + * jigsaw.jar + * velocity-1.6.1.jar + * xml-apis.jar + * commons-lang-2.4.jar + * tagsoup-1.2.jar + * xercesImpl.jar + +From: + + URL `http://jigsaw.w3.org/Distrib/jigsaw_2.2.6.tar.gz' + URL `http://www.apache.org/dist/commons/collections/binaries/commons-collections-3.2.1-bin.tar.gz' + URL `http://www.apache.org/dist/commons/lang/binaries/commons-lang-2.4-bin.tar.gz' + URL `http://www.apache.org/dist/velocity/engine/1.6.1/velocity-1.6.1.tar.gz' + URL `http://www.apache.org/dist/xerces/j/Xerces-J-bin.2.9.1.tar.gz' + URL `http://home.ccil.org/~cowan/XML/tagsoup/tagsoup-1.2.jar' + +Test validating some CSS file by running: + + java -jar css-validator.jar file:somecssfile.css" + :type 'file + :group 'flymake) +;;(setq flymake-css-validator-jar "c:/dl/programs/css-valid/css-validator.jar") + +(defun flymake-css-init () + (let* ((temp-file (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-inplace)) + (local-file (file-relative-name + temp-file + (file-name-directory buffer-file-name)))) + (unless (file-exists-p flymake-css-validator-jar) + (error "Can't find css-validator.jar: %s\n\nPlease customize option flymake-css-validator-jar\n" + flymake-css-validator-jar)) + (list "java" + (list "-jar" flymake-css-validator-jar + "-output" "gnu" + (concat "file:" local-file))))) + +;;;###autoload +(defun flymake-css-load () + (dolist (rec flymake-allowed-css-file-name-masks) + (add-to-list 'flymake-allowed-file-name-masks rec)) + (dolist (rec flymake-css-err-line-pattern-re) + (add-to-list 'flymake-err-line-patterns rec))) + + +;;(defun flymake-make-overlay (beg end tooltip-text face mouse-face) +(defadvice flymake-make-overlay (before + flymake-css-ad-flymake-make-overlay + activate + compile) + (ad-set-arg 2 (xml-substitute-numeric-entities (ad-get-arg 2)))) + +;; Fix-me: remove when this has been giving its proper place in Emacs. +(eval-when-compile + (unless (fboundp 'xml-substitute-numeric-entities) + (message "Use Emacs 22 workaround for newsticker--decode-numeric-entities") + (defun xml-substitute-numeric-entities (string) + "Decode SGML numeric entities by their respective utf characters. +This is just a copy of the function in newst-backen.el for Emacs +22 users. + +This function replaces numeric entities in the input STRING and +returns the modified string. For example \"*\" gets replaced +by \"*\"." + (if (and string (stringp string)) + (let ((start 0)) + (while (string-match "&#\\([0-9]+\\);" string start) + (condition-case nil + (setq string (replace-match + (string (read (substring string + (match-beginning 1) + (match-end 1)))) + nil nil string)) + (error nil)) + (setq start (1+ (match-beginning 0)))) + string) + nil)) + )) + +;;(eval-after-load 'css-mode (flymake-css-load)) + +(provide 'flymake-css) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; flymake-css.el ends here diff --git a/emacs/nxhtml/related/flymake-helpers.el b/emacs/nxhtml/related/flymake-helpers.el new file mode 100644 index 0000000..34468d5 --- /dev/null +++ b/emacs/nxhtml/related/flymake-helpers.el @@ -0,0 +1,78 @@ +;;; flymake-helpers.el --- Helper functions for flymake +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-07-21T14:30:20+0200 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'flymake)) + +;; (flymake-create-temp-intemp buffer-file-name nil) +(defun flymake-create-temp-intemp (file-name prefix) + "Return file name in temporary directory for checking FILE-NAME. +This is a replacement for `flymake-create-temp-inplace'. The +only difference is that it gives a file name in +`temporary-file-directory' instead of the same directory as +FILE-NAME. + +For the use of PREFIX see that function. + +Note that not making the temporary file in another directory +\(like here) will not work if the file you are checking depends +on relative paths to other files \(for the type of checks flymake +makes)." + (unless (stringp file-name) + (error "Invalid file-name")) + (or prefix + (setq prefix "flymake")) + (let* ((prefix (concat + (file-name-nondirectory (file-name-sans-extension file-name)) + "_" prefix)) + (suffix (concat "." (file-name-extension file-name))) + (temp-name (make-temp-file prefix nil suffix))) + (flymake-log 3 "create-temp-intemp: file=%s temp=%s" file-name temp-name) + temp-name)) + + +(provide 'flymake-helpers) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; flymake-helpers.el ends here diff --git a/emacs/nxhtml/related/flymake-java-1.el b/emacs/nxhtml/related/flymake-java-1.el new file mode 100644 index 0000000..deb1e86 --- /dev/null +++ b/emacs/nxhtml/related/flymake-java-1.el @@ -0,0 +1,109 @@ +;;; flymake-java-1.el --- Flymake for single java files +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-12-02 Wed +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(eval-and-compile (require 'flymake)) + +(defun flymake-init-maybe-find-buildfile-dir (source-file-name buildfile-name) + "Find buildfile, store its dir in buffer data and return its dir, if found." + (let* ((buildfile-dir + (flymake-find-buildfile buildfile-name + (file-name-directory source-file-name)))) + (if buildfile-dir + (setq flymake-base-dir buildfile-dir) + (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name) + nil))) + +(defun flymake-complex-make-init-impl-1 (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f) + "Create syntax check command line for a directly checked source file. +Use CREATE-TEMP-F for creating temp copy." + (let* ((args nil) + (source-file-name buffer-file-name) + (buildfile-dir (flymake-init-maybe-find-buildfile-dir source-file-name build-file-name))) + (if buildfile-dir + (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))) + (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir + use-relative-base-dir use-relative-source + get-cmdline-f)))) + args)) + +(defun flymake-complex-java-init () + (or (flymake-complex-make-init-impl-1 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline) + (flymake-complex-make-init-impl-1 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-make-cmdline) + (flymake-java-1-init))) + +(defcustom flymake-java-1-javac "c:/Sun/SDK/jdk/bin/javac.exe" + "Path to javac." + :group 'flymake) + +(defun flymake-java-1-init () + (if (not (executable-find flymake-java-1-javac)) + (message "Can't find javac. Please customize flymake-java-1-javac") + (list flymake-java-1-javac + (list (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-with-folder-structure))))) + +;; (defun flymake-java-1-turn-on () +;; (interactive) +;; (if (not (executable-find flymake-java-1-javac)) +;; (message "Can't find javac. Please customize flymake-java-1-javac") +;; (let ((flymake-allowed-file-name-masks +;; '(("\\.java\\'" flymake-java-1-init flymake-simple-cleanup)))) +;; (when flymake-mode (flymake-mode -1)) +;; (flymake-mode 1)))) + +;;;###autoload +(defun flymake-java-1-load () + (let ((jrec (assoc "\\.java\\'" flymake-allowed-file-name-masks))) + (setq flymake-allowed-file-name-masks + (delete jrec flymake-allowed-file-name-masks)) + (setq flymake-allowed-file-name-masks + (cons + '("\\.java\\'" flymake-complex-java-init flymake-simple-java-cleanup) + flymake-allowed-file-name-masks)))) + +(provide 'flymake-java-1) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; flymake-java-1.el ends here diff --git a/emacs/nxhtml/related/flymake-js.el b/emacs/nxhtml/related/flymake-js.el new file mode 100644 index 0000000..256eee5 --- /dev/null +++ b/emacs/nxhtml/related/flymake-js.el @@ -0,0 +1,234 @@ +;;; flymake-js.el --- Flymake setup for javascript files +;; +;; Author: Lennart Borgman +;; Created: Sun Dec 02 07:52:52 2007 +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This library provides basic setup for using `flymake-mode' with +;; javascript files. To use this you must have a javascript +;; installed. There are (at least) two free javascript engines (both +;; from Mozill) you can use, Rhino (implemented in Java) or +;; SpiderMonkey (implemented in C). Both are supported in this +;; library. +;; +;; I have not been able to find binaries for SpiderMonkeys to +;; download. However the Rhino engine seems fast enough and is easy to +;; install. You find them at +;; +;; http://www.mozilla.org/rhino/ +;; http://www.mozilla.org/js/spidermonkey/ +;; +;; Put this file in your Emacs `load-path' and then in .emacs +;; +;; (require 'flymake-js) +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +;; Flymake JS mode + +(require 'flymake) + +(defconst flymake-js-dir + (file-name-directory (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + "Installation directory for flymake-js.") + +;;;###autoload +(defgroup flymake-js nil + "Customization group for flymake for javascript." + :group 'flymake) + +(defcustom flymake-allowed-js-file-name-masks '(("\\.json\\'" flymake-js-init) + ("\\.js\\'" flymake-js-init)) + "Filename extensions that switch on js syntax checks." + :type '(repeat (list (regexp :tag "File name regexp") + (function :tag "Init function") + (choice (const :tag "No cleanup function" nil) + (function :tag "Cleanup function")))) + :group 'flymake-js) + + +(defvar flymake-js-err-line-pattern-re + '(;; These pattern are probably for Rhino: + ("^js: \"\\(.+\\)\", line \\([0-9]+\\): \\(.+\\)$" 1 2 nil 3) + ("^js: uncaught JavaScript \\(.+\\)$" nil nil nil 1) + ;; For Rhino with jslint.js + ("^Lint at line \\([[:digit:]]+\\) character \\([[:digit:]]+\\): \\(.+\\)$" nil 1 2 3) + ;; These pattern are probably for SpiderMonkey: + ("^\\(.+\\)\:\\([0-9]+\\)\: \\(SyntaxError\:.+\\)\:$" 1 2 nil 3) + ("^\\(.+\\)\:\\([0-9]+\\)\: \\(strict warning: trailing comma.+\\)\:$" 1 2 nil 3)) + "Regexp matching JavaScript error messages") + +(defcustom flymake-js-rhino-jar "/path/to/js.jar" + "Path to Rihno jar file. +Download and install Rhino JavaScript engine from + + URL `http://www.mozilla.org/rhino/' + +This variable should point to the file js.jar that is in the top +directory of the Rhino dir tree. \(It was differently named +earlier and might perhaps be renamed again.)" + :type '(file :must-match t) + :group 'flymake-js) + +;;(setq flymake-log-level 3) +;;(setq flymake-js-rhino-use-jslint nil) +(defcustom flymake-js-rhino-use-jslint nil + "Use jslint.js if this is non-nil. +jslint.js will give you warnings about style things like indentation too." + :type 'boolean + :group 'flymake-js) + +(defcustom flymake-js-rhino-js (expand-file-name "rhino.js" flymake-js-dir) + "Path to rhino.js. +Only used if `flymake-js-rhino-use-jslint' is nil. + +This file and env.js must be placed in the same directory. Default +is this directory. + +Those files comes with Rhino, see `flymake-js-rhino-jar'." + :type '(file :must-match t) + :group 'flymake-js) + +(defcustom flymake-js-rhino-jslint (expand-file-name "jslint.js" flymake-js-dir) + "Path to jslint.js. +Only used if `flymake-js-rhino-use-jslint' is t. + +If you do not have this file you can download it from URL +`http://www.jslint.com/rhino/jslint.js'. I had to change quit(2) +to quit(0) in it \(which seems like a bug in `flymake-mode' to +me)." + :type '(file :must-match t) + :group 'flymake-js) + +;;(flymake-js-check-rhino-js) +(defun flymake-js-check-rhino-js () + "Checks that the path to env.js is ok." + (with-current-buffer (find-file-noselect flymake-js-rhino-js) + (let* ((proj-folder (file-name-as-directory (file-name-directory (buffer-file-name)))) + (proj-line (concat "var project_folder = 'file:///" proj-folder "';")) + (proj-line-re "^\\W*var\\W+project_folder\\W*=\\W*")) + (save-restriction + (widen) + (goto-char (point-max)) + (if (re-search-backward proj-line-re nil t) + (let ((beg (line-beginning-position)) + (end (line-end-position))) + (unless (string= (buffer-substring-no-properties beg end) + proj-line) + (delete-region beg end) + (insert proj-line) + (basic-save-buffer))) + (goto-char (point-min)) + (insert proj-line "\n") + (basic-save-buffer)))))) + +(defcustom flymake-js-engine 'rhino + "Javascript engine to use. +You may have to restart Emacs after changing this - if you can +not figure out what buffers and processes to kill. + +I have only been able to test Rhino since I do not have +SpiderMonkey." + :type '(choice (const :tag "Rhino" rhino) + (const :tag "SpiderMonkey" spidermonkey)) + :group 'flymake-js) + +(defun flymake-js-init () + (message "running flymake-js-init") + (let* ((temp-file (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-inplace)) + (local-file (file-relative-name + temp-file + (file-name-directory buffer-file-name)))) + (flymake-js-check-has-engine) + (cond + ((eq flymake-js-engine 'rhino) + (list "java" (list "-jar" flymake-js-rhino-jar + (if flymake-js-rhino-use-jslint + flymake-js-rhino-jslint + flymake-js-rhino-js) + local-file))) + ((eq flymake-js-engine 'spidermonkey) + (list "js" (list "-s" local-file))) + (t + (error "Bad value: %s" flymake-js-engine))))) + +(defvar flymake-js-has-engine nil) + +(defun flymake-js-check-has-engine () + "Check for the needed files." + (if flymake-js-has-engine + t + (cond + ;; Rhino + ((eq flymake-js-engine 'rhino) + (unless (executable-find "java") + (error "Could not find java executable")) + (unless (file-exists-p flymake-js-rhino-jar) + (error "Could not find file %s\n\nPlease customize flymake-js-rhino-jar\n" + flymake-js-rhino-jar)) + (if flymake-js-rhino-use-jslint + (unless (file-exists-p flymake-js-rhino-jslint) + (error "Could not find file %s" flymake-js-rhino-jslint)) + (unless (file-exists-p flymake-js-rhino-js) + (error "Could not find file %s" flymake-js-rhino-js)) + (flymake-js-check-rhino-js))) + ;; SpiderMonkey + ((eq flymake-js-engine 'spidermonkey) + (unless (executable-find "js") + (error "Could not find js program"))) + (t + (error "Bad value: %s" flymake-js-engine))) + (setq flymake-js-has-engine t))) + +;;;###autoload +(defun flymake-js-load () + (dolist (rec flymake-allowed-js-file-name-masks) + (add-to-list 'flymake-allowed-file-name-masks rec)) + (dolist (rec flymake-js-err-line-pattern-re) + (add-to-list 'flymake-err-line-patterns rec))) + +;;(eval-after-load 'javascript (flymake-js-load)) + +(provide 'flymake-js) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; flymake-js.el<2> ends here diff --git a/emacs/nxhtml/related/flymakemsg.el b/emacs/nxhtml/related/flymakemsg.el new file mode 100644 index 0000000..b704ba7 --- /dev/null +++ b/emacs/nxhtml/related/flymakemsg.el @@ -0,0 +1,144 @@ +;;; flymakemsg.el --- Show flymake compile errors in echo area +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-11-21 Sat +;; Version: 0.1 +;; Last-Updated: 2009-11-21 Sat +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `backquote', `bytecomp'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Show flymake error messages in minibuffer when point is on a +;; flymake error overlay. +;; +;; To use it just load this file. Put this in .emacs: +;; +;; (require 'flymakemsg) +;; +;; This file run `defadvice' on some functions in `flymake-mode'. +;; This code started from an idea in a paste. +;; +;; Note: This code breaks Emacs conventions since it does the +;; defadvising when you just loads this file. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(eval-when-compile (require 'flymake)) + +(defun flymakemsg-show-err-at-point () + "If point is on a flymake error, show it in echo area. +Protected to run in timers and hooks." + (condition-case err + (flymakemsg-show-err-at-point-1) + (error (message "%s" err)))) + +(defvar flymakemsg-last-errovl nil) + +(defun flymakemsg-show-err-at-point-1 () + "If point is on a flymake error, show it in echo area." + (interactive) + (when flymake-mode + (let ((flyovl (flymakemsg-get-errovl (point)))) + (unless (eq flyovl flymakemsg-last-errovl) + (setq flymakemsg-last-errovl flyovl) + (when flyovl + (message "%s" (propertize + (overlay-get flyovl 'help-echo) + 'face 'flymake-errline))))))) + +(defun flymakemsg-get-errovl (POS) + "Get flymake error overlay at POS." + (catch 'errovl + (dolist (ovl (overlays-at POS)) + (when (eq 'flymake-errline (overlay-get ovl 'face)) + (throw 'errovl ovl))))) + +(defadvice flymake-mode (after + flymakemsg-ad-flymake-mode + activate compile) + "Turn on showing of flymake errors then point is on them. +This shows the error in the echo area." + (if flymake-mode + nil ;;(add-hook 'post-command-hook 'flymakemsg-post-command t t) + (remove-hook 'post-command-hook 'flymakemsg-post-command t))) + +(defadvice flymake-log (after + flymakemsg-ad-flymake-log + activate compile) + "Display error on current line if any." + ;;(message "flymake-log defadvice called") + (if (not flymake-err-info) + (remove-hook 'post-command-hook 'flymakemsg-post-command t) + (add-hook 'post-command-hook 'flymakemsg-post-command t t) + ;; Wait, because there is another message first. + (flymakemsg-start-msg-timer 3.0))) + +(defun flymakemsg-post-command () + ;; Wait to not disturb to much. + (flymakemsg-start-msg-timer 0.2)) + +(defvar flymakemsg-msg-timer nil) + +(defun flymakemsg-cancel-msg-timer () + (when (timerp flymakemsg-msg-timer) + (cancel-timer flymakemsg-msg-timer))) + +(defun flymakemsg-start-msg-timer (delay) + (flymakemsg-cancel-msg-timer) + (run-with-idle-timer delay nil 'flymakemsg-show-err-at-point)) + +;;; I have no idea why it was done the way below. It was in the paste. +;;; It seems very unnecessary but I keep it for now. +;; +;; (defun fly-pyflake-determine-message (err) +;; "pyflake is flakey if it has compile problems, this adjusts the +;; message to display, so there is one ;)" +;; (cond ((not (or (eq major-mode 'Python) (eq major-mode 'python-mode) t))) +;; ((null (flymake-ler-file err)) +;; ;; normal message do your thing +;; (flymake-ler-text err)) +;; (t ;; could not compile err +;; (format "compile error, problem on line %s" (flymake-ler-line err))))) + +;; (let ((line-no (line-number-at-pos))) +;; (dolist (elem flymake-err-info) +;; (if (eq (car elem) line-no) +;; (let ((err (car (second elem)))) +;; (message "%s" (fly-pyflake-determine-message err)))))) + + +(provide 'flymakemsg) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; flymakemsg.el ends here diff --git a/emacs/nxhtml/related/flymu.el b/emacs/nxhtml/related/flymu.el new file mode 100644 index 0000000..6b3a552 --- /dev/null +++ b/emacs/nxhtml/related/flymu.el @@ -0,0 +1,157 @@ +;;; flymu.el --- Flymake for mumamo-mode +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sun Dec 02 14:52:32 2007 +;; Version: 0.1 +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Flymake syntax checks for mumamo chunks. +;; +;; Not ready yet!!! +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(require 'flymake) + +;;(flymu-make-major-mode-alist) +(defun flymu-make-major-mode-alist () + "Grab values from `flymake-allowed-file-name-masks'. +We need a list of major modes and the corresponding init and +cleanup functions for flymake. This functions creates such a list +from flymakes dito list for file names." + (let ((allowed nil)) + (save-match-data + (dolist (regexp-init flymake-allowed-file-name-masks) + (let* ((regexp (car regexp-init)) + (init (cdr regexp-init)) + ;; Make it as simple as possible. First see if the same + ;; regexp is used: + (mode (let ((m (cdr (assoc regexp auto-mode-alist)))) + ;; Don't use this if it is complicated: + (when (commandp m) m))) + (ext regexp)) + (unless mode + ;; Try to make a simple file name, this could be made + ;; better but I do not know if that would be meaningful: + (setq ext (replace-regexp-in-string "\\\\\\." "." ext)) + (setq ext (replace-regexp-in-string "\\\\'" "" ext)) + (setq ext (replace-regexp-in-string "[\\$?+*]" "" ext)) + ;; Next compare the filename against the entries in + ;; auto-mode-alist. The code is from `set-auto-mode'. + (let ((name ext) + (done nil)) + (while name + ;; Find first matching alist entry. + (setq mode + (if (memq system-type '(vax-vms windows-nt cygwin)) + ;; System is case-insensitive. + (let ((case-fold-search t)) + (assoc-default name auto-mode-alist + 'string-match)) + ;; System is case-sensitive. + (or + ;; First match case-sensitively. + (let ((case-fold-search nil)) + (assoc-default name auto-mode-alist + 'string-match)) + ;; Fallback to case-insensitive match. + (and auto-mode-case-fold + (let ((case-fold-search t)) + (assoc-default name auto-mode-alist + 'string-match)))))) + (if (and mode + (consp mode) + (cadr mode)) + (setq name (substring name 0 (match-beginning 0))) + (setq name))))) + (when (and mode + ;; nxml-mode's do not need flymake: + (let ((major-mode mode)) + (not (derived-mode-p 'nxml-mode)))) + (let ((rec (append (list mode) init))) + (when (= (length rec) 2) + (setq rec (append rec (list nil)))) + (add-to-list 'allowed rec)))))) + allowed)) + +(defcustom flymu-allowed-major-modes (flymu-make-major-mode-alist) + "Major modes syntax checking is allowed for." + :type '(repeat (list (function :tag "Major mode") + (function :tag "Init function") + (choice (const :tag "No cleanup function" nil) + (function :tag "Cleanup function")))) + :set-after '(flymake-allowed-file-name-masks) + :group 'flymu) + +(defvar flymu-mumamo-chunk nil) +(make-variable-buffer-local 'flymu-mumamo-chunk) + + +;; Fix-me: What to check? When? Make flymu-mumamo-chunk a function +;; instead? Mark chunks for checking - let mumamo do that? Flymake +;; should be able to mark a chunk to, even if it is not a whole +;; line. What about line numbers? + +;; Advice these functions: +(defadvice flymake-get-file-name-mode-and-masks (around + flymu-ad-flymake-get-file-name-mode-and-masks + (file-name)) + "Make flymake init file selection according to mode." + (if flymu-mumamo-chunk + (let ((major (overlay-get ovl 'mumamo-major-mode)) + (rec (assq major flymu-allowed-major-modes))) + (when rec + (setq ad-return-value (cdr rec)))) + ad-do-it)) +(ad-activate 'flymake-get-file-name-mode-and-masks) + +;;(defun flymake-save-buffer-in-file (file-name) +(defadvice flymake-save-buffer-in-file (around + flymu-ad-flymake-save-buffer-in-file + (file-name)) + (if flymu-mumamo-chunk + (let ((min (overlay-start flymu-mumamo-chunk)) + (max (overlay-end flymu-mumamo-chunk))) + (make-directory (file-name-directory file-name) 1) + (write-region min max file-name nil 566) + (flymake-log 3 "saved chunk %s:%s-%s in file %s" (buffer-name) min ma file-name)) + ad-do-it)) + +(provide 'flymu) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; flymu.el ends here diff --git a/emacs/nxhtml/related/iss-mode.el b/emacs/nxhtml/related/iss-mode.el new file mode 100644 index 0000000..7e498c0 --- /dev/null +++ b/emacs/nxhtml/related/iss-mode.el @@ -0,0 +1,205 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; iss-mode.el --- Mode for InnoSetup install scripts + +;; Copyright (C) 2000-2007 by Stefan Reichoer + +;; Emacs Lisp Archive Entry +;; Filename: iss-mode.el +;; Author: Stefan Reichoer, <stefan@xsteve.at> +;; Version: 1.1d + +;; iss-mode.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. + +;; iss-mode.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. + +;; 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 + +;; InnoSetup is an Application Installer for Windows +;; See: http://www.jrsoftware.org/isinfo.php +;; This version of iss-mode.el is tested with InnoSetup v5.0 + +;; iss-mode provides the following features: +;; * Syntax coloring for InnoSetup scripts +;; * Integration of the InnoSetup commandline compiler iscc.exe +;; - Compilation via M-x iss-compile +;; - Jump to compilation error via M-x next-error +;; * Start Innosetup help via M-x iss-compiler-help +;; * Test the installation via M-x iss-run-installer + +;; Of course you can bind this commands to keys (e.g. in the iss-mode-hook) + +;; My initialization for InnoSetup looks like this: +;; (autoload 'iss-mode "iss-mode" "Innosetup Script Mode" t) +;; (setq auto-mode-alist (append '(("\\.iss$" . iss-mode)) auto-mode-alist)) +;; (setq iss-compiler-path "c:/Programme/Inno Setup 5/") +;; (add-hook 'iss-mode-hook 'xsteve-iss-mode-init) +;; (defun xsteve-iss-mode-init () +;; (interactive) +;; (define-key iss-mode-map [f6] 'iss-compile) +;; (define-key iss-mode-map [(meta f6)] 'iss-run-installer))) + +;; The latest version of iss-mode.el can be found at: +;; http://www.xsteve.at/prg/emacs/iss-mode.el + +;; Comments / suggestions welcome! + +;;; Change log: +;; +;; Version 1.1e: +;; +;; - Add some new flags to keywords + +;;; Code: + +(eval-and-compile (require 'compile)) + +(defvar iss-compiler-path nil "Path to the iss compiler") + +;;; End of user settings + +(defvar iss-mode-syntax-table + (let ((table (make-syntax-table))) + ;; ";" starts a comment + ;;(modify-syntax-entry ?\; "<" iss-mode-syntax-table) + (modify-syntax-entry ?\; ". 12" table) + ;; and \n and \^M end a comment + (modify-syntax-entry ?\n ">" table) + (modify-syntax-entry ?\^M ">" table) + + (modify-syntax-entry ?\" "." table) + + (modify-syntax-entry ?_ "w" table) + table) + "Syntax table in use in iss-mode buffers.") + + +(defvar iss-font-lock-keywords + (list + (cons (concat "^;\.*") + 'font-lock-comment-face) + (cons (concat "\\sw+: ") + 'font-lock-keyword-face) + (cons "^[ \t]*\\[\.+\\]" 'font-lock-function-name-face) ;font-lock-constant-face) + (cons "^[ \t]*#include[ \t]*\".+\"" 'font-lock-preprocessor-face) + (cons (concat "^[ \t]*\\<\\(appname\\|appvername\\|appversion\\|appcopyright\\|appid\\|" + "appmutex\\|beveledlabel\\|defaultdirname\\|versioninfoversion" + "\\|defaultgroupname\\|minversion\\|outputdir\\|outputbasefilename\\|" + "allownoicons\\|uninstallfilesdir\\|" + "sourcedir\\|disableprogramgrouppage\\|alwayscreateuninstallicon\\)\\>") + 'font-lock-type-face) + (cons (concat "\\<\\(alwaysskipifsameorolder\\|uninsneveruninstall\\|" + "comparetimestampalso\\|restartreplace\\|isreadme\\|" + "unchecked\\|nowait\\|postinstall\\|skipifsilent\\|ignoreversion\\|" + "uninsdeletekeyifempty\\|uninsdeletekey\\|" + "runasoriginaluser\\|runascurrentuser" + "\\)\\>") + 'font-lock-variable-name-face) + (cons (concat "\\<\\(HKCU\\|HKLM\\|dirifempty\\|files\\|filesandordirs\\)\\>") + 'font-lock-constant-face) + (list 'iss-fontify-options '(1 'font-lock-variable-name-face) '(2 'font-lock-keyword-face)) + ) + "Expressions to highlight in iss mode.") + +(defun iss-fontify-options (bound) + (message "iss-fontify-options %s" bound) + (when (re-search-forward "^[ \t]*\\([^=]+\\)[ \t]*\\(=\\)" bound t) + (match-data))) + +(defvar iss-mode-map (make-sparse-keymap) + "Keymap used in iss-mode buffers.") + +(easy-menu-define + iss-menu + iss-mode-map + "InnoSetup script menu" + (list + "ISS" + ["Compile" (iss-compile) t] + ["Run Installer" (iss-run-installer) t] + ["InnoSetup Help" (iss-compiler-help) t] + )) +(easy-menu-add iss-menu) + +(defvar compilation-file-regexp-alist) ;; silence compiler, don't know the var. + +;;;###autoload +(defun iss-mode () + "Major mode for editing InnoSetup script files. Upon startup iss-mode-hook is run." + (interactive) + (kill-all-local-variables) + (use-local-map iss-mode-map) + (setq major-mode 'iss-mode) + (setq mode-name "iss") + (set-syntax-table iss-mode-syntax-table) + (set (make-local-variable 'comment-start) ";") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'comment-multi-line) nil) + + (set (make-local-variable 'compilation-error-regexp-alist) + '(("\\(Error on line\\) \\([0-9]+\\):" nil 2))) + (set (make-local-variable 'compilation-file-regexp-alist) + '(("iscc \\(.*\\)$" 1))) + + ;; Font lock support + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(iss-font-lock-keywords nil t)) + (run-hooks 'iss-mode-hook)) + +(defun iss-compiler-help () + "Start the online documentation for the InnoSetup compiler" + (interactive) + (let ((default-directory (or iss-compiler-path default-directory))) + (w32-shell-execute 1 "ISetup.chm"))) + +(defun iss-compile () + "Compile the actual file with the InnoSetup compiler" + (interactive) + (let ((default-directory (or iss-compiler-path default-directory)) + (compilation-process-setup-function 'iss-process-setup)) + (compile (concat "iscc " (buffer-file-name))))) + +(defun iss-process-setup () + "Set up `compilation-exit-message-function' for `iss-compile'." + (set (make-local-variable 'compilation-exit-message-function) + 'iss-compilation-exit-message-function)) + +(defun iss-compilation-exit-message-function (process-status exit-status msg) + (interactive) + (save-excursion + (let ((buffer-read-only nil)) + (goto-char (point-min)) + ;;scroll down one line, so that the compile command is parsed to: + ;; -> get the filename of the compiled file + (insert "\n"))) + (cons msg exit-status)) + +(defun iss-find-option (option) + (let ((search-regexp + (concat option "[ \t]*=[ \t]*\\(.*\\)$"))) + (save-excursion + (goto-char (point-min)) + (when (search-forward-regexp search-regexp nil t) + (buffer-substring-no-properties (match-beginning 1) (match-end 1)))))) + +(defun iss-run-installer () + (interactive) + (let ((executable + (concat (or (iss-find-option "outputdir") "Output\\") + (or (iss-find-option "outputbasefilename") "setup") + ".exe"))) + (w32-shell-execute 1 executable))) + +(provide 'iss-mode) + +;; arch-tag: b07b7119-d591-465e-927f-d0be0bcf7cab diff --git a/emacs/nxhtml/related/iss-mumamo.el b/emacs/nxhtml/related/iss-mumamo.el new file mode 100644 index 0000000..85e067c --- /dev/null +++ b/emacs/nxhtml/related/iss-mumamo.el @@ -0,0 +1,70 @@ +;;; iss-mumamo.el --- Defines multi major mode for Inno Setup files +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-09 +;; Version: 0.3 +;; Last-Updated: 2009-12-12 Sat +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `comint', `compile', `iss-mode', `ring', `tool-bar'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(require 'iss-mode) +(require 'mumamo) + +(defun mumamo-chunk-iss-code (pos min max) + "Find [code]..., return range and `pascal-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +Note that if this section is not the last" + (mumamo-quick-static-chunk pos min max "[code]" "{*** End of CODE **}" t 'pascal-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode iss-mumamo-mode + "Turn on multiple major modes Inno Setup .iss files. +The main major mode will be `iss-mode'. +The [code] section, if any, will be in `pascal-mode'." + ("Inno ISS Family" iss-mode + (mumamo-chunk-iss-code + ))) + +(add-to-list 'auto-mode-alist '("\\.iss\\'" . iss-mumamo-mode)) + +(provide 'iss-mumamo) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; iss-mumamo.el ends here diff --git a/emacs/nxhtml/related/js_temp.js b/emacs/nxhtml/related/js_temp.js new file mode 100644 index 0000000..a2c6748 --- /dev/null +++ b/emacs/nxhtml/related/js_temp.js @@ -0,0 +1,4 @@ + + // I am testing + + var x == 10; diff --git a/emacs/nxhtml/related/jslint.js b/emacs/nxhtml/related/jslint.js new file mode 100644 index 0000000..fb89c06 --- /dev/null +++ b/emacs/nxhtml/related/jslint.js @@ -0,0 +1,523 @@ +// (C)2002 Douglas Crockford +// www.JSLint.com +// Rhino Edition +"use strict";var JSLINT=(function(){var adsafe_id,adsafe_may,adsafe_went,anonname,approved,atrule={media:true,'font-face':true,page:true},bang={'<':true,'<=':true,'==':true,'===':true,'!==':true,'!=':true,'>':true,'>=':true,'+':true,'-':true,'*':true,'/':true,'%':true},banned={'arguments':true,callee:true,caller:true,constructor:true,'eval':true,prototype:true,unwatch:true,valueOf:true,watch:true},boolOptions={adsafe:true,bitwise:true,browser:true,cap:true,css:true,debug:true,eqeqeq:true,evil:true,forin:true,fragment:true,immed:true,laxbreak:true,newcap:true,nomen:true,on:true,onevar:true,passfail:true,plusplus:true,regexp:true,rhino:true,undef:true,safe:true,sidebar:true,strict:true,sub:true,white:true,widget:true},browser={addEventListener:false,alert:false,blur:false,clearInterval:false,clearTimeout:false,close:false,closed:false,confirm:false,console:false,Debug:false,defaultStatus:false,document:false,event:false,focus:false,frames:false,getComputedStyle:false,history:false,Image:false,length:false,location:false,moveBy:false,moveTo:false,name:false,navigator:false,onbeforeunload:true,onblur:true,onerror:true,onfocus:true,onload:true,onresize:true,onunload:true,open:false,opener:false,opera:false,Option:false,parent:false,print:false,prompt:false,removeEventListener:false,resizeBy:false,resizeTo:false,screen:false,scroll:false,scrollBy:false,scrollTo:false,setInterval:false,setTimeout:false,status:false,top:false,XMLHttpRequest:false},cssAttributeData,cssAny,cssColorData={"aliceblue":true,"antiquewhite":true,"aqua":true,"aquamarine":true,"azure":true,"beige":true,"bisque":true,"black":true,"blanchedalmond":true,"blue":true,"blueviolet":true,"brown":true,"burlywood":true,"cadetblue":true,"chartreuse":true,"chocolate":true,"coral":true,"cornflowerblue":true,"cornsilk":true,"crimson":true,"cyan":true,"darkblue":true,"darkcyan":true,"darkgoldenrod":true,"darkgray":true,"darkgreen":true,"darkkhaki":true,"darkmagenta":true,"darkolivegreen":true,"darkorange":true,"darkorchid":true,"darkred":true,"darksalmon":true,"darkseagreen":true,"darkslateblue":true,"darkslategray":true,"darkturquoise":true,"darkviolet":true,"deeppink":true,"deepskyblue":true,"dimgray":true,"dodgerblue":true,"firebrick":true,"floralwhite":true,"forestgreen":true,"fuchsia":true,"gainsboro":true,"ghostwhite":true,"gold":true,"goldenrod":true,"gray":true,"green":true,"greenyellow":true,"honeydew":true,"hotpink":true,"indianred":true,"indigo":true,"ivory":true,"khaki":true,"lavender":true,"lavenderblush":true,"lawngreen":true,"lemonchiffon":true,"lightblue":true,"lightcoral":true,"lightcyan":true,"lightgoldenrodyellow":true,"lightgreen":true,"lightpink":true,"lightsalmon":true,"lightseagreen":true,"lightskyblue":true,"lightslategray":true,"lightsteelblue":true,"lightyellow":true,"lime":true,"limegreen":true,"linen":true,"magenta":true,"maroon":true,"mediumaquamarine":true,"mediumblue":true,"mediumorchid":true,"mediumpurple":true,"mediumseagreen":true,"mediumslateblue":true,"mediumspringgreen":true,"mediumturquoise":true,"mediumvioletred":true,"midnightblue":true,"mintcream":true,"mistyrose":true,"moccasin":true,"navajowhite":true,"navy":true,"oldlace":true,"olive":true,"olivedrab":true,"orange":true,"orangered":true,"orchid":true,"palegoldenrod":true,"palegreen":true,"paleturquoise":true,"palevioletred":true,"papayawhip":true,"peachpuff":true,"peru":true,"pink":true,"plum":true,"powderblue":true,"purple":true,"red":true,"rosybrown":true,"royalblue":true,"saddlebrown":true,"salmon":true,"sandybrown":true,"seagreen":true,"seashell":true,"sienna":true,"silver":true,"skyblue":true,"slateblue":true,"slategray":true,"snow":true,"springgreen":true,"steelblue":true,"tan":true,"teal":true,"thistle":true,"tomato":true,"turquoise":true,"violet":true,"wheat":true,"white":true,"whitesmoke":true,"yellow":true,"yellowgreen":true},cssBorderStyle,cssBreak,cssLengthData={'%':true,'cm':true,'em':true,'ex':true,'in':true,'mm':true,'pc':true,'pt':true,'px':true},cssOverflow,escapes={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','/':'\\/','\\':'\\\\'},funct,functionicity=['closure','exception','global','label','outer','unused','var'],functions,global,htmltag={a:{},abbr:{},acronym:{},address:{},applet:{},area:{empty:true,parent:' map '},b:{},base:{empty:true,parent:' head '},bdo:{},big:{},blockquote:{},body:{parent:' html noframes '},br:{empty:true},button:{},canvas:{parent:' body p div th td '},caption:{parent:' table '},center:{},cite:{},code:{},col:{empty:true,parent:' table colgroup '},colgroup:{parent:' table '},dd:{parent:' dl '},del:{},dfn:{},dir:{},div:{},dl:{},dt:{parent:' dl '},em:{},embed:{},fieldset:{},font:{},form:{},frame:{empty:true,parent:' frameset '},frameset:{parent:' html frameset '},h1:{},h2:{},h3:{},h4:{},h5:{},h6:{},head:{parent:' html '},html:{parent:'*'},hr:{empty:true},i:{},iframe:{},img:{empty:true},input:{empty:true},ins:{},kbd:{},label:{},legend:{parent:' fieldset '},li:{parent:' dir menu ol ul '},link:{empty:true,parent:' head '},map:{},menu:{},meta:{empty:true,parent:' head noframes noscript '},noframes:{parent:' html body '},noscript:{parent:' body head noframes '},object:{},ol:{},optgroup:{parent:' select '},option:{parent:' optgroup select '},p:{},param:{empty:true,parent:' applet object '},pre:{},q:{},samp:{},script:{empty:true,parent:' body div frame head iframe p pre span '},select:{},small:{},span:{},strong:{},style:{parent:' head ',empty:true},sub:{},sup:{},table:{},tbody:{parent:' table '},td:{parent:' tr '},textarea:{},tfoot:{parent:' table '},th:{parent:' tr '},thead:{parent:' table '},title:{parent:' head '},tr:{parent:' table tbody thead tfoot '},tt:{},u:{},ul:{},'var':{}},ids,implied,inblock,indent,jsonmode,lines,lookahead,member,membersOnly,nexttoken,noreach,option,predefined,prereg,prevtoken,rhino={defineClass:false,deserialize:false,gc:false,help:false,load:false,loadClass:false,print:false,quit:false,readFile:false,readUrl:false,runCommand:false,seal:false,serialize:false,spawn:false,sync:false,toint32:false,version:false},scope,sidebar={System:false},src,stack,standard={Array:false,Boolean:false,Date:false,decodeURI:false,decodeURIComponent:false,encodeURI:false,encodeURIComponent:false,Error:false,'eval':false,EvalError:false,Function:false,hasOwnProperty:false,isFinite:false,isNaN:false,JSON:false,Math:false,Number:false,Object:false,parseInt:false,parseFloat:false,RangeError:false,ReferenceError:false,RegExp:false,String:false,SyntaxError:false,TypeError:false,URIError:false},standard_member={E:true,LN2:true,LN10:true,LOG2E:true,LOG10E:true,PI:true,SQRT1_2:true,SQRT2:true,MAX_VALUE:true,MIN_VALUE:true,NEGATIVE_INFINITY:true,POSITIVE_INFINITY:true},strict_mode,syntax={},tab,token,urls,warnings,widget={alert:true,animator:true,appleScript:true,beep:true,bytesToUIString:true,Canvas:true,chooseColor:true,chooseFile:true,chooseFolder:true,closeWidget:true,COM:true,convertPathToHFS:true,convertPathToPlatform:true,CustomAnimation:true,escape:true,FadeAnimation:true,filesystem:true,Flash:true,focusWidget:true,form:true,FormField:true,Frame:true,HotKey:true,Image:true,include:true,isApplicationRunning:true,iTunes:true,konfabulatorVersion:true,log:true,md5:true,MenuItem:true,MoveAnimation:true,openURL:true,play:true,Point:true,popupMenu:true,preferenceGroups:true,preferences:true,print:true,prompt:true,random:true,Rectangle:true,reloadWidget:true,ResizeAnimation:true,resolvePath:true,resumeUpdates:true,RotateAnimation:true,runCommand:true,runCommandInBg:true,saveAs:true,savePreferences:true,screen:true,ScrollBar:true,showWidgetPreferences:true,sleep:true,speak:true,Style:true,suppressUpdates:true,system:true,tellWidget:true,Text:true,TextArea:true,Timer:true,unescape:true,updateNow:true,URL:true,Web:true,widget:true,Window:true,XMLDOM:true,XMLHttpRequest:true,yahooCheckLogin:true,yahooLogin:true,yahooLogout:true},xmode,xquote,ax=/@cc|<\/?|script|\]*s\]|<\s*!|</i,cx=/[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,tx=/^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jslint|members?|global)?|=|\/)?|\*[\/=]?|\+[+=]?|-[\-=]?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,hx=/^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-]*|[0-9]+|--|.)/,nx=/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,nxg=/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,ox=/[>&]|<[\/!]?|--/,lx=/\*\/|\/\*/,ix=/^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,jx=/^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,ux=/&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i,sx=/^\s*([{:#%.=,>+\[\]@()"';]|\*=?|\$=|\|=|\^=|~=|[a-zA-Z_][a-zA-Z0-9_\-]*|[0-9]+|<\/|\/\*)/,ssx=/^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/,qx=/[^a-zA-Z0-9-_\/ ]/,dx=/[\[\]\/\\"'*<>.&:(){}+=#]/,rx={outer:hx,html:hx,style:sx,styleproperty:ssx};function F(){} +if(typeof Object.create!=='function'){Object.create=function(o){F.prototype=o;return new F();};} +function is_own(object,name){return Object.prototype.hasOwnProperty.call(object,name);} +function combine(t,o){var n;for(n in o){if(is_own(o,n)){t[n]=o[n];}}} +String.prototype.entityify=function(){return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');};String.prototype.isAlpha=function(){return(this>='a'&&this<='z\uffff')||(this>='A'&&this<='Z\uffff');};String.prototype.isDigit=function(){return(this>='0'&&this<='9');};String.prototype.supplant=function(o){return this.replace(/\{([^{}]*)\}/g,function(a,b){var r=o[b];return typeof r==='string'||typeof r==='number'?r:a;});};String.prototype.name=function(){if(ix.test(this)){return this;} +if(nx.test(this)){return'"'+this.replace(nxg,function(a){var c=escapes[a];if(c){return c;} +return'\\u'+('0000'+a.charCodeAt().toString(16)).slice(-4);})+'"';} +return'"'+this+'"';};function assume(){if(!option.safe){if(option.rhino){combine(predefined,rhino);} +if(option.browser||option.sidebar){combine(predefined,browser);} +if(option.sidebar){combine(predefined,sidebar);} +if(option.widget){combine(predefined,widget);}}} +function quit(m,l,ch){throw{name:'JSLintError',line:l,character:ch,message:m+" ("+Math.floor((l/lines.length)*100)+"% scanned)."};} +function warning(m,t,a,b,c,d){var ch,l,w;t=t||nexttoken;if(t.id==='(end)'){t=token;} +l=t.line||0;ch=t.from||0;w={id:'(error)',raw:m,evidence:lines[l-1]||'',line:l,character:ch,a:a,b:b,c:c,d:d};w.reason=m.supplant(w);JSLINT.errors.push(w);if(option.passfail){quit('Stopping. ',l,ch);} +warnings+=1;if(warnings>=option.maxerr){quit("Too many errors.",l,ch);} +return w;} +function warningAt(m,l,ch,a,b,c,d){return warning(m,{line:l,from:ch},a,b,c,d);} +function error(m,t,a,b,c,d){var w=warning(m,t,a,b,c,d);quit("Stopping, unable to continue.",w.line,w.character);} +function errorAt(m,l,ch,a,b,c,d){return error(m,{line:l,from:ch},a,b,c,d);} +var lex=(function lex(){var character,from,line,s;function nextLine(){var at;if(line>=lines.length){return false;} +character=1;s=lines[line];line+=1;at=s.search(/ \t/);if(at>=0){warningAt("Mixed spaces and tabs.",line,at+1);} +s=s.replace(/\t/g,tab);at=s.search(cx);if(at>=0){warningAt("Unsafe character.",line,at);} +if(option.maxlen&&option.maxlen<s.length){warningAt("Line too long.",line,s.length);} +return true;} +function it(type,value){var i,t;if(type==='(color)'){t={type:type};}else if(type==='(punctuator)'||(type==='(identifier)'&&is_own(syntax,value))){t=syntax[value]||syntax['(error)'];}else{t=syntax[type];} +t=Object.create(t);if(type==='(string)'||type==='(range)'){if(jx.test(value)){warningAt("Script URL.",line,from);}} +if(type==='(identifier)'){t.identifier=true;if(value==='__iterator__'||value==='__proto__'){errorAt("Reserved name '{a}'.",line,from,value);}else if(option.nomen&&(value.charAt(0)==='_'||value.charAt(value.length-1)==='_')){warningAt("Unexpected {a} in '{b}'.",line,from,"dangling '_'",value);}} +t.value=value;t.line=line;t.character=character;t.from=from;i=t.id;if(i!=='(endline)'){prereg=i&&(('(,=:[!&|?{};'.indexOf(i.charAt(i.length-1))>=0)||i==='return');} +return t;} +return{init:function(source){if(typeof source==='string'){lines=source.replace(/\r\n/g,'\n').replace(/\r/g,'\n').split('\n');}else{lines=source;} +line=0;nextLine();from=1;},range:function(begin,end){var c,value='';from=character;if(s.charAt(0)!==begin){errorAt("Expected '{a}' and instead saw '{b}'.",line,character,begin,s.charAt(0));} +for(;;){s=s.slice(1);character+=1;c=s.charAt(0);switch(c){case'':errorAt("Missing '{a}'.",line,character,c);break;case end:s=s.slice(1);character+=1;return it('(range)',value);case xquote:case'\\':warningAt("Unexpected '{a}'.",line,character,c);} +value+=c;}},token:function(){var b,c,captures,d,depth,high,i,l,low,q,t;function match(x){var r=x.exec(s),r1;if(r){l=r[0].length;r1=r[1];c=r1.charAt(0);s=s.substr(l);from=character+l-r1.length;character+=l;return r1;}} +function string(x){var c,j,r='';if(jsonmode&&x!=='"'){warningAt("Strings must use doublequote.",line,character);} +if(xquote===x||(xmode==='scriptstring'&&!xquote)){return it('(punctuator)',x);} +function esc(n){var i=parseInt(s.substr(j+1,n),16);j+=n;if(i>=32&&i<=126&&i!==34&&i!==92&&i!==39){warningAt("Unnecessary escapement.",line,character);} +character+=n;c=String.fromCharCode(i);} +j=0;for(;;){while(j>=s.length){j=0;if(xmode!=='html'||!nextLine()){errorAt("Unclosed string.",line,from);}} +c=s.charAt(j);if(c===x){character+=1;s=s.substr(j+1);return it('(string)',r,x);} +if(c<' '){if(c==='\n'||c==='\r'){break;} +warningAt("Control character in string: {a}.",line,character+j,s.slice(0,j));}else if(c===xquote){warningAt("Bad HTML string",line,character+j);}else if(c==='<'){if(option.safe&&xmode==='html'){warningAt("ADsafe string violation.",line,character+j);}else if(s.charAt(j+1)==='/'&&(xmode||option.safe)){warningAt("Expected '<\\/' and instead saw '</'.",line,character);}else if(s.charAt(j+1)==='!'&&(xmode||option.safe)){warningAt("Unexpected '<!' in a string.",line,character);}}else if(c==='\\'){if(xmode==='html'){if(option.safe){warningAt("ADsafe string violation.",line,character+j);}}else if(xmode==='styleproperty'){j+=1;character+=1;c=s.charAt(j);if(c!==x){warningAt("Escapement in style string.",line,character+j);}}else{j+=1;character+=1;c=s.charAt(j);switch(c){case xquote:warningAt("Bad HTML string",line,character+j);break;case'\\':case'\'':case'"':case'/':break;case'b':c='\b';break;case'f':c='\f';break;case'n':c='\n';break;case'r':c='\r';break;case't':c='\t';break;case'u':esc(4);break;case'v':c='\v';break;case'x':if(jsonmode){warningAt("Avoid \\x-.",line,character);} +esc(2);break;default:warningAt("Bad escapement.",line,character);}}} +r+=c;character+=1;j+=1;}} +for(;;){if(!s){return it(nextLine()?'(endline)':'(end)','');} +while(xmode==='outer'){i=s.search(ox);if(i===0){break;}else if(i>0){character+=1;s=s.slice(i);break;}else{if(!nextLine()){return it('(end)','');}}} +t=match(rx[xmode]||tx);if(!t){if(xmode==='html'){return it('(error)',s.charAt(0));}else{t='';c='';while(s&&s<'!'){s=s.substr(1);} +if(s){errorAt("Unexpected '{a}'.",line,character,s.substr(0,1));}}}else{if(c.isAlpha()||c==='_'||c==='$'){return it('(identifier)',t);} +if(c.isDigit()){if(xmode!=='style'&&!isFinite(Number(t))){warningAt("Bad number '{a}'.",line,character,t);} +if(xmode!=='style'&&xmode!=='styleproperty'&&s.substr(0,1).isAlpha()){warningAt("Missing space after '{a}'.",line,character,t);} +if(c==='0'){d=t.substr(1,1);if(d.isDigit()){if(token.id!=='.'&&xmode!=='styleproperty'){warningAt("Don't use extra leading zeros '{a}'.",line,character,t);}}else if(jsonmode&&(d==='x'||d==='X')){warningAt("Avoid 0x-. '{a}'.",line,character,t);}} +if(t.substr(t.length-1)==='.'){warningAt("A trailing decimal point can be confused with a dot '{a}'.",line,character,t);} +return it('(number)',t);} +switch(t){case'"':case"'":return string(t);case'//':if(src||(xmode&&xmode!=='script')){warningAt("Unexpected comment.",line,character);}else if(xmode==='script'&&/<\s*\//i.test(s)){warningAt("Unexpected <\/ in comment.",line,character);}else if((option.safe||xmode==='script')&&ax.test(s)){warningAt("Dangerous comment.",line,character);} +s='';token.comment=true;break;case'/*':if(src||(xmode&&xmode!=='script'&&xmode!=='style'&&xmode!=='styleproperty')){warningAt("Unexpected comment.",line,character);} +if(option.safe&&ax.test(s)){warningAt("ADsafe comment violation.",line,character);} +for(;;){i=s.search(lx);if(i>=0){break;} +if(!nextLine()){errorAt("Unclosed comment.",line,character);}else{if(option.safe&&ax.test(s)){warningAt("ADsafe comment violation.",line,character);}}} +character+=i+2;if(s.substr(i,1)==='/'){errorAt("Nested comment.",line,character);} +s=s.substr(i+2);token.comment=true;break;case'/*members':case'/*member':case'/*jslint':case'/*global':case'*/':return{value:t,type:'special',line:line,character:character,from:from};case'':break;case'/':if(prereg){depth=0;captures=0;l=0;for(;;){b=true;c=s.charAt(l);l+=1;switch(c){case'':errorAt("Unclosed regular expression.",line,from);return;case'/':if(depth>0){warningAt("Unescaped '{a}'.",line,from+l,'/');} +c=s.substr(0,l-1);q={g:true,i:true,m:true};while(q[s.charAt(l)]===true){q[s.charAt(l)]=false;l+=1;} +character+=l;s=s.substr(l);return it('(regexp)',c);case'\\':c=s.charAt(l);if(c<' '){warningAt("Unexpected control character in regular expression.",line,from+l);}else if(c==='<'){warningAt("Unexpected escaped character '{a}' in regular expression.",line,from+l,c);} +l+=1;break;case'(':depth+=1;b=false;if(s.charAt(l)==='?'){l+=1;switch(s.charAt(l)){case':':case'=':case'!':l+=1;break;default:warningAt("Expected '{a}' and instead saw '{b}'.",line,from+l,':',s.charAt(l));}}else{captures+=1;} +break;case'|':b=false;break;case')':if(depth===0){warningAt("Unescaped '{a}'.",line,from+l,')');}else{depth-=1;} +break;case' ':q=1;while(s.charAt(l)===' '){l+=1;q+=1;} +if(q>1){warningAt("Spaces are hard to count. Use {{a}}.",line,from+l,q);} +break;case'[':c=s.charAt(l);if(c==='^'){l+=1;if(option.regexp){warningAt("Insecure '{a}'.",line,from+l,c);}} +q=false;if(c===']'){warningAt("Empty class.",line,from+l-1);q=true;} +klass:do{c=s.charAt(l);l+=1;switch(c){case'[':case'^':warningAt("Unescaped '{a}'.",line,from+l,c);q=true;break;case'-':if(q){q=false;}else{warningAt("Unescaped '{a}'.",line,from+l,'-');q=true;} +break;case']':if(!q){warningAt("Unescaped '{a}'.",line,from+l-1,'-');} +break klass;case'\\':c=s.charAt(l);if(c<' '){warningAt("Unexpected control character in regular expression.",line,from+l);}else if(c==='<'){warningAt("Unexpected escaped character '{a}' in regular expression.",line,from+l,c);} +l+=1;q=true;break;case'/':warningAt("Unescaped '{a}'.",line,from+l-1,'/');q=true;break;case'<':if(xmode==='script'){c=s.charAt(l);if(c==='!'||c==='/'){warningAt("HTML confusion in regular expression '<{a}'.",line,from+l,c);}} +q=true;break;default:q=true;}}while(c);break;case'.':if(option.regexp){warningAt("Insecure '{a}'.",line,from+l,c);} +break;case']':case'?':case'{':case'}':case'+':case'*':warningAt("Unescaped '{a}'.",line,from+l,c);break;case'<':if(xmode==='script'){c=s.charAt(l);if(c==='!'||c==='/'){warningAt("HTML confusion in regular expression '<{a}'.",line,from+l,c);}}} +if(b){switch(s.charAt(l)){case'?':case'+':case'*':l+=1;if(s.charAt(l)==='?'){l+=1;} +break;case'{':l+=1;c=s.charAt(l);if(c<'0'||c>'9'){warningAt("Expected a number and instead saw '{a}'.",line,from+l,c);} +l+=1;low=+c;for(;;){c=s.charAt(l);if(c<'0'||c>'9'){break;} +l+=1;low=+c+(low*10);} +high=low;if(c===','){l+=1;high=Infinity;c=s.charAt(l);if(c>='0'&&c<='9'){l+=1;high=+c;for(;;){c=s.charAt(l);if(c<'0'||c>'9'){break;} +l+=1;high=+c+(high*10);}}} +if(s.charAt(l)!=='}'){warningAt("Expected '{a}' and instead saw '{b}'.",line,from+l,'}',c);}else{l+=1;} +if(s.charAt(l)==='?'){l+=1;} +if(low>high){warningAt("'{a}' should not be greater than '{b}'.",line,from+l,low,high);}}}} +c=s.substr(0,l-1);character+=l;s=s.substr(l);return it('(regexp)',c);} +return it('(punctuator)',t);case'<!--':l=line;c=character;for(;;){i=s.indexOf('--');if(i>=0){break;} +i=s.indexOf('<!');if(i>=0){errorAt("Nested HTML comment.",line,character+i);} +if(!nextLine()){errorAt("Unclosed HTML comment.",l,c);}} +l=s.indexOf('<!');if(l>=0&&l<i){errorAt("Nested HTML comment.",line,character+l);} +character+=i;if(s[i+2]!=='>'){errorAt("Expected -->.",line,character);} +character+=3;s=s.slice(i+3);break;case'#':if(xmode==='html'||xmode==='styleproperty'){for(;;){c=s.charAt(0);if((c<'0'||c>'9')&&(c<'a'||c>'f')&&(c<'A'||c>'F')){break;} +character+=1;s=s.substr(1);t+=c;} +if(t.length!==4&&t.length!==7){warningAt("Bad hex color '{a}'.",line,from+l,t);} +return it('(color)',t);} +return it('(punctuator)',t);default:if(xmode==='outer'&&c==='&'){character+=1;s=s.substr(1);for(;;){c=s.charAt(0);character+=1;s=s.substr(1);if(c===';'){break;} +if(!((c>='0'&&c<='9')||(c>='a'&&c<='z')||c==='#')){errorAt("Bad entity",line,from+l,character);}} +break;} +return it('(punctuator)',t);}}}}};}());function addlabel(t,type){if(option.safe&&funct['(global)']&&typeof predefined[t]!=='boolean'){warning('ADsafe global: '+t+'.',token);}else if(t==='hasOwnProperty'){warning("'hasOwnProperty' is a really bad name.");} +if(is_own(funct,t)&&!funct['(global)']){warning(funct[t]===true?"'{a}' was used before it was defined.":"'{a}' is already defined.",nexttoken,t);} +funct[t]=type;if(funct['(global)']){global[t]=funct;if(is_own(implied,t)){warning("'{a}' was used before it was defined.",nexttoken,t);delete implied[t];}}else{scope[t]=funct;}} +function doOption(){var b,obj,filter,o=nexttoken.value,t,v;switch(o){case'*/':error("Unbegun comment.");break;case'/*members':case'/*member':o='/*members';if(!membersOnly){membersOnly={};} +obj=membersOnly;break;case'/*jslint':if(option.safe){warning("ADsafe restriction.");} +obj=option;filter=boolOptions;break;case'/*global':if(option.safe){warning("ADsafe restriction.");} +obj=predefined;break;default:} +t=lex.token();loop:for(;;){for(;;){if(t.type==='special'&&t.value==='*/'){break loop;} +if(t.id!=='(endline)'&&t.id!==','){break;} +t=lex.token();} +if(t.type!=='(string)'&&t.type!=='(identifier)'&&o!=='/*members'){error("Bad option.",t);} +v=lex.token();if(v.id===':'){v=lex.token();if(obj===membersOnly){error("Expected '{a}' and instead saw '{b}'.",t,'*/',':');} +if(t.value==='indent'&&o==='/*jslint'){b=+v.value;if(typeof b!=='number'||!isFinite(b)||b<=0||Math.floor(b)!==b){error("Expected a small integer and instead saw '{a}'.",v,v.value);} +obj.white=true;obj.indent=b;}else if(t.value==='maxerr'&&o==='/*jslint'){b=+v.value;if(typeof b!=='number'||!isFinite(b)||b<=0||Math.floor(b)!==b){error("Expected a small integer and instead saw '{a}'.",v,v.value);} +obj.maxerr=b;}else if(v.value==='true'){obj[t.value]=true;}else if(v.value==='false'){obj[t.value]=false;}else{error("Bad option value.",v);} +t=lex.token();}else{if(o==='/*jslint'){error("Missing option value.",t);} +obj[t.value]=false;t=v;}} +if(filter){assume();}} +function peek(p){var i=p||0,j=0,t;while(j<=i){t=lookahead[j];if(!t){t=lookahead[j]=lex.token();} +j+=1;} +return t;} +function advance(id,t){switch(token.id){case'(number)':if(nexttoken.id==='.'){warning("A dot following a number can be confused with a decimal point.",token);} +break;case'-':if(nexttoken.id==='-'||nexttoken.id==='--'){warning("Confusing minusses.");} +break;case'+':if(nexttoken.id==='+'||nexttoken.id==='++'){warning("Confusing plusses.");} +break;} +if(token.type==='(string)'||token.identifier){anonname=token.value;} +if(id&&nexttoken.id!==id){if(t){if(nexttoken.id==='(end)'){warning("Unmatched '{a}'.",t,t.id);}else{warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",nexttoken,id,t.id,t.line,nexttoken.value);}}else if(nexttoken.type!=='(identifier)'||nexttoken.value!==id){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,id,nexttoken.value);}} +prevtoken=token;token=nexttoken;for(;;){nexttoken=lookahead.shift()||lex.token();if(nexttoken.id==='(end)'||nexttoken.id==='(error)'){return;} +if(nexttoken.type==='special'){doOption();}else{if(nexttoken.id!=='(endline)'){break;}}}} +function parse(rbp,initial){var left;if(nexttoken.id==='(end)'){error("Unexpected early end of program.",token);} +advance();if(option.safe&&typeof predefined[token.value]==='boolean'&&(nexttoken.id!=='('&&nexttoken.id!=='.')){warning('ADsafe violation.',token);} +if(initial){anonname='anonymous';funct['(verb)']=token.value;} +if(initial===true&&token.fud){left=token.fud();}else{if(token.nud){left=token.nud();}else{if(nexttoken.type==='(number)'&&token.id==='.'){warning("A leading decimal point can be confused with a dot: '.{a}'.",token,nexttoken.value);advance();return token;}else{error("Expected an identifier and instead saw '{a}'.",token,token.id);}} +while(rbp<nexttoken.lbp){advance();if(token.led){left=token.led(left);}else{error("Expected an operator and instead saw '{a}'.",token,token.id);}}} +return left;} +function adjacent(left,right){left=left||token;right=right||nexttoken;if(option.white||xmode==='styleproperty'||xmode==='style'){if(left.character!==right.from&&left.line===right.line){warning("Unexpected space after '{a}'.",right,left.value);}}} +function nospace(left,right){left=left||token;right=right||nexttoken;if(option.white&&!left.comment){if(left.line===right.line){adjacent(left,right);}}} +function nonadjacent(left,right){if(option.white){left=left||token;right=right||nexttoken;if(left.line===right.line&&left.character===right.from){warning("Missing space after '{a}'.",nexttoken,left.value);}}} +function nobreaknonadjacent(left,right){left=left||token;right=right||nexttoken;if(!option.laxbreak&&left.line!==right.line){warning("Bad line breaking before '{a}'.",right,right.id);}else if(option.white){left=left||token;right=right||nexttoken;if(left.character===right.from){warning("Missing space after '{a}'.",nexttoken,left.value);}}} +function indentation(bias){var i;if(option.white&&nexttoken.id!=='(end)'){i=indent+(bias||0);if(nexttoken.from!==i){warning("Expected '{a}' to have an indentation at {b} instead at {c}.",nexttoken,nexttoken.value,i,nexttoken.from);}}} +function nolinebreak(t){t=t||token;if(t.line!==nexttoken.line){warning("Line breaking error '{a}'.",t,t.value);}} +function comma(){if(token.line!==nexttoken.line){if(!option.laxbreak){warning("Bad line breaking before '{a}'.",token,nexttoken.id);}}else if(token.character!==nexttoken.from&&option.white){warning("Unexpected space after '{a}'.",nexttoken,token.value);} +advance(',');nonadjacent(token,nexttoken);} +function symbol(s,p){var x=syntax[s];if(!x||typeof x!=='object'){syntax[s]=x={id:s,lbp:p,value:s};} +return x;} +function delim(s){return symbol(s,0);} +function stmt(s,f){var x=delim(s);x.identifier=x.reserved=true;x.fud=f;return x;} +function blockstmt(s,f){var x=stmt(s,f);x.block=true;return x;} +function reserveName(x){var c=x.id.charAt(0);if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){x.identifier=x.reserved=true;} +return x;} +function prefix(s,f){var x=symbol(s,150);reserveName(x);x.nud=(typeof f==='function')?f:function(){this.right=parse(150);this.arity='unary';if(this.id==='++'||this.id==='--'){if(option.plusplus){warning("Unexpected use of '{a}'.",this,this.id);}else if((!this.right.identifier||this.right.reserved)&&this.right.id!=='.'&&this.right.id!=='['){warning("Bad operand.",this);}} +return this;};return x;} +function type(s,f){var x=delim(s);x.type=s;x.nud=f;return x;} +function reserve(s,f){var x=type(s,f);x.identifier=x.reserved=true;return x;} +function reservevar(s,v){return reserve(s,function(){if(this.id==='this'||this.id==='arguments'){if(strict_mode&&funct['(global)']){warning("Strict violation.",this);}else if(option.safe){warning("ADsafe violation.",this);}} +return this;});} +function infix(s,f,p,w){var x=symbol(s,p);reserveName(x);x.led=function(left){if(!w){nobreaknonadjacent(prevtoken,token);nonadjacent(token,nexttoken);} +if(typeof f==='function'){return f(left,this);}else{this.left=left;this.right=parse(p);return this;}};return x;} +function relation(s,f){var x=symbol(s,100);x.led=function(left){nobreaknonadjacent(prevtoken,token);nonadjacent(token,nexttoken);var right=parse(100);if((left&&left.id==='NaN')||(right&&right.id==='NaN')){warning("Use the isNaN function to compare with NaN.",this);}else if(f){f.apply(this,[left,right]);} +if(left.id==='!'){warning("Confusing use of '{a}'.",left,'!');} +if(right.id==='!'){warning("Confusing use of '{a}'.",left,'!');} +this.left=left;this.right=right;return this;};return x;} +function isPoorRelation(node){return node&&((node.type==='(number)'&&+node.value===0)||(node.type==='(string)'&&node.value===' ')||node.type==='true'||node.type==='false'||node.type==='undefined'||node.type==='null');} +function assignop(s,f){symbol(s,20).exps=true;return infix(s,function(left,that){var l;that.left=left;if(predefined[left.value]===false&&scope[left.value]['(global)']===true){warning('Read only.',left);} +if(option.safe){l=left;do{if(typeof predefined[l.value]==='boolean'){warning('ADsafe violation.',l);} +l=l.left;}while(l);} +if(left){if(left.id==='.'||left.id==='['){if(!left.left||left.left.value==='arguments'){warning('Bad assignment.',that);} +that.right=parse(19);return that;}else if(left.identifier&&!left.reserved){if(funct[left.value]==='exception'){warning("Do not assign to the exception parameter.",left);} +that.right=parse(19);return that;} +if(left===syntax['function']){warning("Expected an identifier in an assignment and instead saw a function invocation.",token);}} +error("Bad assignment.",that);},20);} +function bitwise(s,f,p){var x=symbol(s,p);reserveName(x);x.led=(typeof f==='function')?f:function(left){if(option.bitwise){warning("Unexpected use of '{a}'.",this,this.id);} +this.left=left;this.right=parse(p);return this;};return x;} +function bitwiseassignop(s){symbol(s,20).exps=true;return infix(s,function(left,that){if(option.bitwise){warning("Unexpected use of '{a}'.",that,that.id);} +nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);if(left){if(left.id==='.'||left.id==='['||(left.identifier&&!left.reserved)){parse(19);return that;} +if(left===syntax['function']){warning("Expected an identifier in an assignment, and instead saw a function invocation.",token);} +return that;} +error("Bad assignment.",that);},20);} +function suffix(s,f){var x=symbol(s,150);x.led=function(left){if(option.plusplus){warning("Unexpected use of '{a}'.",this,this.id);}else if((!left.identifier||left.reserved)&&left.id!=='.'&&left.id!=='['){warning("Bad operand.",this);} +this.left=left;return this;};return x;} +function optionalidentifier(){if(nexttoken.reserved){warning("Expected an identifier and instead saw '{a}' (a reserved word).",nexttoken,nexttoken.id);} +if(nexttoken.identifier){advance();return token.value;}} +function identifier(){var i=optionalidentifier();if(i){return i;} +if(token.id==='function'&&nexttoken.id==='('){warning("Missing name in function statement.");}else{error("Expected an identifier and instead saw '{a}'.",nexttoken,nexttoken.value);}} +function reachable(s){var i=0,t;if(nexttoken.id!==';'||noreach){return;} +for(;;){t=peek(i);if(t.reach){return;} +if(t.id!=='(endline)'){if(t.id==='function'){warning("Inner functions should be listed at the top of the outer function.",t);break;} +warning("Unreachable '{a}' after '{b}'.",t,t.value,s);break;} +i+=1;}} +function statement(noindent){var i=indent,r,s=scope,t=nexttoken;if(t.id===';'){warning("Unnecessary semicolon.",t);advance(';');return;} +if(t.identifier&&!t.reserved&&peek().id===':'){advance();advance(':');scope=Object.create(s);addlabel(t.value,'label');if(!nexttoken.labelled){warning("Label '{a}' on {b} statement.",nexttoken,t.value,nexttoken.value);} +if(jx.test(t.value+':')){warning("Label '{a}' looks like a javascript url.",t,t.value);} +nexttoken.label=t.value;t=nexttoken;} +if(!noindent){indentation();} +if(nexttoken.id==='new'){warning("'new' should not be used as a statement.");} +r=parse(0,true);if(!t.block){if(!r||!r.exps){warning("Expected an assignment or function call and instead saw an expression.",token);} +if(nexttoken.id!==';'){warningAt("Missing semicolon.",token.line,token.from+token.value.length);}else{adjacent(token,nexttoken);advance(';');nonadjacent(token,nexttoken);}} +indent=i;scope=s;return r;} +function use_strict(){if(nexttoken.value==='use strict'){advance();advance(';');strict_mode=true;return true;}else{return false;}} +function statements(begin){var a=[],f,p;if(begin&&!use_strict()&&option.strict){warning('Missing "use strict" statement.',nexttoken);} +if(option.adsafe){switch(begin){case'script':if(!adsafe_may){if(nexttoken.value!=='ADSAFE'||peek(0).id!=='.'||(peek(1).value!=='id'&&peek(1).value!=='go')){error('ADsafe violation: Missing ADSAFE.id or ADSAFE.go.',nexttoken);}} +if(nexttoken.value==='ADSAFE'&&peek(0).id==='.'&&peek(1).value==='id'){if(adsafe_may){error('ADsafe violation.',nexttoken);} +advance('ADSAFE');advance('.');advance('id');advance('(');if(nexttoken.value!==adsafe_id){error('ADsafe violation: id does not match.',nexttoken);} +advance('(string)');advance(')');advance(';');adsafe_may=true;} +break;case'lib':if(nexttoken.value==='ADSAFE'){advance('ADSAFE');advance('.');advance('lib');advance('(');advance('(string)');comma();f=parse(0);if(f.id!=='function'){error('The second argument to lib must be a function.',f);} +p=f.funct['(params)'];p=p&&p.join(', ');if(p&&p!=='lib'){error("Expected '{a}' and instead saw '{b}'.",f,'(lib)','('+p+')');} +advance(')');advance(';');return a;}else{error("ADsafe lib violation.");}}} +while(!nexttoken.reach&&nexttoken.id!=='(end)'){if(nexttoken.id===';'){warning("Unnecessary semicolon.");advance(';');}else{a.push(statement());}} +return a;} +function block(f){var a,b=inblock,old_indent=indent,s=scope,t;inblock=f;scope=Object.create(scope);nonadjacent(token,nexttoken);t=nexttoken;if(nexttoken.id==='{'){advance('{');if(nexttoken.id!=='}'||token.line!==nexttoken.line){indent+=option.indent;while(!f&&nexttoken.from>indent){indent+=option.indent;} +if(!f){use_strict();} +a=statements();indent-=option.indent;indentation();} +advance('}',t);indent=old_indent;}else{warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'{',nexttoken.value);noreach=true;a=[statement()];noreach=false;} +funct['(verb)']=null;scope=s;inblock=b;return a;} +function idValue(){return this;} +function countMember(m){if(membersOnly&&typeof membersOnly[m]!=='boolean'){warning("Unexpected /*member '{a}'.",token,m);} +if(typeof member[m]==='number'){member[m]+=1;}else{member[m]=1;}} +function note_implied(token){var name=token.value,line=token.line,a=implied[name];if(typeof a==='function'){a=false;} +if(!a){a=[line];implied[name]=a;}else if(a[a.length-1]!==line){a.push(line);}} +function cssName(){if(nexttoken.identifier){advance();return true;}} +function cssNumber(){if(nexttoken.id==='-'){advance('-');adjacent();nolinebreak();} +if(nexttoken.type==='(number)'){advance('(number)');return true;}} +function cssString(){if(nexttoken.type==='(string)'){advance();return true;}} +function cssColor(){var i,number;if(nexttoken.identifier){if(nexttoken.value==='rgb'){advance();advance('(');for(i=0;i<3;i+=1){if(i){advance(',');} +number=nexttoken.value;if(nexttoken.type!=='(number)'||number<0){warning("Expected a positive number and instead saw '{a}'",nexttoken,number);advance();}else{advance();if(nexttoken.id==='%'){advance('%');if(number>100){warning("Expected a percentage and instead saw '{a}'",token,number);}}else{if(number>255){warning("Expected a small number and instead saw '{a}'",token,number);}}}} +advance(')');return true;}else if(cssColorData[nexttoken.value]===true){advance();return true;}}else if(nexttoken.type==='(color)'){advance();return true;} +return false;} +function cssLength(){if(nexttoken.id==='-'){advance('-');adjacent();nolinebreak();} +if(nexttoken.type==='(number)'){advance();if(nexttoken.type!=='(string)'&&cssLengthData[nexttoken.value]===true){adjacent();advance();}else if(+token.value!==0){warning("Expected a linear unit and instead saw '{a}'.",nexttoken,nexttoken.value);} +return true;} +return false;} +function cssLineHeight(){if(nexttoken.id==='-'){advance('-');adjacent();} +if(nexttoken.type==='(number)'){advance();if(nexttoken.type!=='(string)'&&cssLengthData[nexttoken.value]===true){adjacent();advance();} +return true;} +return false;} +function cssWidth(){if(nexttoken.identifier){switch(nexttoken.value){case'thin':case'medium':case'thick':advance();return true;}}else{return cssLength();}} +function cssMargin(){if(nexttoken.identifier){if(nexttoken.value==='auto'){advance();return true;}}else{return cssLength();}} +function cssAttr(){if(nexttoken.identifier&&nexttoken.value==='attr'){advance();advance('(');if(!nexttoken.identifier){warning("Expected a name and instead saw '{a}'.",nexttoken,nexttoken.value);} +advance();advance(')');return true;} +return false;} +function cssCommaList(){while(nexttoken.id!==';'){if(!cssName()&&!cssString()){warning("Expected a name and instead saw '{a}'.",nexttoken,nexttoken.value);} +if(nexttoken.id!==','){return true;} +comma();}} +function cssCounter(){if(nexttoken.identifier&&nexttoken.value==='counter'){advance();advance('(');if(!nexttoken.identifier){} +advance();if(nexttoken.id===','){comma();if(nexttoken.type!=='(string)'){warning("Expected a string and instead saw '{a}'.",nexttoken,nexttoken.value);} +advance();} +advance(')');return true;} +if(nexttoken.identifier&&nexttoken.value==='counters'){advance();advance('(');if(!nexttoken.identifier){warning("Expected a name and instead saw '{a}'.",nexttoken,nexttoken.value);} +advance();if(nexttoken.id===','){comma();if(nexttoken.type!=='(string)'){warning("Expected a string and instead saw '{a}'.",nexttoken,nexttoken.value);} +advance();} +if(nexttoken.id===','){comma();if(nexttoken.type!=='(string)'){warning("Expected a string and instead saw '{a}'.",nexttoken,nexttoken.value);} +advance();} +advance(')');return true;} +return false;} +function cssShape(){var i;if(nexttoken.identifier&&nexttoken.value==='rect'){advance();advance('(');for(i=0;i<4;i+=1){if(!cssLength()){warning("Expected a number and instead saw '{a}'.",nexttoken,nexttoken.value);break;}} +advance(')');return true;} +return false;} +function cssUrl(){var c,url;if(nexttoken.identifier&&nexttoken.value==='url'){nexttoken=lex.range('(',')');url=nexttoken.value;c=url.charAt(0);if(c==='"'||c==='\''){if(url.slice(-1)!==c){warning("Bad url string.");}else{url=url.slice(1,-1);if(url.indexOf(c)>=0){warning("Bad url string.");}}} +if(!url){warning("Missing url.");} +advance();if(option.safe&&ux.test(url)){error("ADsafe URL violation.");} +urls.push(url);return true;} +return false;} +cssAny=[cssUrl,function(){for(;;){if(nexttoken.identifier){switch(nexttoken.value.toLowerCase()){case'url':cssUrl();break;case'expression':warning("Unexpected expression '{a}'.",nexttoken,nexttoken.value);advance();break;default:advance();}}else{if(nexttoken.id===';'||nexttoken.id==='!'||nexttoken.id==='(end)'||nexttoken.id==='}'){return true;} +advance();}}}];cssBorderStyle=['none','hidden','dotted','dashed','solid','double','ridge','inset','outset'];cssBreak=['auto','always','avoid','left','right'];cssOverflow=['auto','hidden','scroll','visible'];cssAttributeData={background:[true,'background-attachment','background-color','background-image','background-position','background-repeat'],'background-attachment':['scroll','fixed'],'background-color':['transparent',cssColor],'background-image':['none',cssUrl],'background-position':[2,[cssLength,'top','bottom','left','right','center']],'background-repeat':['repeat','repeat-x','repeat-y','no-repeat'],'border':[true,'border-color','border-style','border-width'],'border-bottom':[true,'border-bottom-color','border-bottom-style','border-bottom-width'],'border-bottom-color':cssColor,'border-bottom-style':cssBorderStyle,'border-bottom-width':cssWidth,'border-collapse':['collapse','separate'],'border-color':['transparent',4,cssColor],'border-left':[true,'border-left-color','border-left-style','border-left-width'],'border-left-color':cssColor,'border-left-style':cssBorderStyle,'border-left-width':cssWidth,'border-right':[true,'border-right-color','border-right-style','border-right-width'],'border-right-color':cssColor,'border-right-style':cssBorderStyle,'border-right-width':cssWidth,'border-spacing':[2,cssLength],'border-style':[4,cssBorderStyle],'border-top':[true,'border-top-color','border-top-style','border-top-width'],'border-top-color':cssColor,'border-top-style':cssBorderStyle,'border-top-width':cssWidth,'border-width':[4,cssWidth],bottom:[cssLength,'auto'],'caption-side':['bottom','left','right','top'],clear:['both','left','none','right'],clip:[cssShape,'auto'],color:cssColor,content:['open-quote','close-quote','no-open-quote','no-close-quote',cssString,cssUrl,cssCounter,cssAttr],'counter-increment':[cssName,'none'],'counter-reset':[cssName,'none'],cursor:[cssUrl,'auto','crosshair','default','e-resize','help','move','n-resize','ne-resize','nw-resize','pointer','s-resize','se-resize','sw-resize','w-resize','text','wait'],direction:['ltr','rtl'],display:['block','compact','inline','inline-block','inline-table','list-item','marker','none','run-in','table','table-caption','table-cell','table-column','table-column-group','table-footer-group','table-header-group','table-row','table-row-group'],'empty-cells':['show','hide'],'float':['left','none','right'],font:['caption','icon','menu','message-box','small-caption','status-bar',true,'font-size','font-style','font-weight','font-family'],'font-family':cssCommaList,'font-size':['xx-small','x-small','small','medium','large','x-large','xx-large','larger','smaller',cssLength],'font-size-adjust':['none',cssNumber],'font-stretch':['normal','wider','narrower','ultra-condensed','extra-condensed','condensed','semi-condensed','semi-expanded','expanded','extra-expanded'],'font-style':['normal','italic','oblique'],'font-variant':['normal','small-caps'],'font-weight':['normal','bold','bolder','lighter',cssNumber],height:[cssLength,'auto'],left:[cssLength,'auto'],'letter-spacing':['normal',cssLength],'line-height':['normal',cssLineHeight],'list-style':[true,'list-style-image','list-style-position','list-style-type'],'list-style-image':['none',cssUrl],'list-style-position':['inside','outside'],'list-style-type':['circle','disc','square','decimal','decimal-leading-zero','lower-roman','upper-roman','lower-greek','lower-alpha','lower-latin','upper-alpha','upper-latin','hebrew','katakana','hiragana-iroha','katakana-oroha','none'],margin:[4,cssMargin],'margin-bottom':cssMargin,'margin-left':cssMargin,'margin-right':cssMargin,'margin-top':cssMargin,'marker-offset':[cssLength,'auto'],'max-height':[cssLength,'none'],'max-width':[cssLength,'none'],'min-height':cssLength,'min-width':cssLength,opacity:cssNumber,outline:[true,'outline-color','outline-style','outline-width'],'outline-color':['invert',cssColor],'outline-style':['dashed','dotted','double','groove','inset','none','outset','ridge','solid'],'outline-width':cssWidth,overflow:cssOverflow,'overflow-x':cssOverflow,'overflow-y':cssOverflow,padding:[4,cssLength],'padding-bottom':cssLength,'padding-left':cssLength,'padding-right':cssLength,'padding-top':cssLength,'page-break-after':cssBreak,'page-break-before':cssBreak,position:['absolute','fixed','relative','static'],quotes:[8,cssString],right:[cssLength,'auto'],'table-layout':['auto','fixed'],'text-align':['center','justify','left','right'],'text-decoration':['none','underline','overline','line-through','blink'],'text-indent':cssLength,'text-shadow':['none',4,[cssColor,cssLength]],'text-transform':['capitalize','uppercase','lowercase','none'],top:[cssLength,'auto'],'unicode-bidi':['normal','embed','bidi-override'],'vertical-align':['baseline','bottom','sub','super','top','text-top','middle','text-bottom',cssLength],visibility:['visible','hidden','collapse'],'white-space':['normal','nowrap','pre','pre-line','pre-wrap','inherit'],width:[cssLength,'auto'],'word-spacing':['normal',cssLength],'word-wrap':['break-word','normal'],'z-index':['auto',cssNumber]};function styleAttribute(){var v;while(nexttoken.id==='*'||nexttoken.id==='#'||nexttoken.value==='_'){if(!option.css){warning("Unexpected '{a}'.",nexttoken,nexttoken.value);} +advance();} +if(nexttoken.id==='-'){if(!option.css){warning("Unexpected '{a}'.",nexttoken,nexttoken.value);} +advance('-');if(!nexttoken.identifier){warning("Expected a non-standard style attribute and instead saw '{a}'.",nexttoken,nexttoken.value);} +advance();return cssAny;}else{if(!nexttoken.identifier){warning("Excepted a style attribute, and instead saw '{a}'.",nexttoken,nexttoken.value);}else{if(is_own(cssAttributeData,nexttoken.value)){v=cssAttributeData[nexttoken.value];}else{v=cssAny;if(!option.css){warning("Unrecognized style attribute '{a}'.",nexttoken,nexttoken.value);}}} +advance();return v;}} +function styleValue(v){var i=0,n,once,match,round,start=0,vi;switch(typeof v){case'function':return v();case'string':if(nexttoken.identifier&&nexttoken.value===v){advance();return true;} +return false;} +for(;;){if(i>=v.length){return false;} +vi=v[i];i+=1;if(vi===true){break;}else if(typeof vi==='number'){n=vi;vi=v[i];i+=1;}else{n=1;} +match=false;while(n>0){if(styleValue(vi)){match=true;n-=1;}else{break;}} +if(match){return true;}} +start=i;once=[];for(;;){round=false;for(i=start;i<v.length;i+=1){if(!once[i]){if(styleValue(cssAttributeData[v[i]])){match=true;round=true;once[i]=true;break;}}} +if(!round){return match;}}} +function styleChild(){if(nexttoken.id==='(number)'){advance();if(nexttoken.value==='n'&&nexttoken.identifier){adjacent();advance();if(nexttoken.id==='+'){adjacent();advance('+');adjacent();advance('(number)');}} +return;}else{switch(nexttoken.value){case'odd':case'even':if(nexttoken.identifier){advance();return;}}} +warning("Unexpected token '{a}'.",nexttoken,nexttoken.value);} +function substyle(){var v;for(;;){if(nexttoken.id==='}'||nexttoken.id==='(end)'||xquote&&nexttoken.id===xquote){return;} +while(nexttoken.id===';'){warning("Misplaced ';'.");advance(';');} +v=styleAttribute();advance(':');if(nexttoken.identifier&&nexttoken.value==='inherit'){advance();}else{if(!styleValue(v)){warning("Unexpected token '{a}'.",nexttoken,nexttoken.value);advance();}} +if(nexttoken.id==='!'){advance('!');adjacent();if(nexttoken.identifier&&nexttoken.value==='important'){advance();}else{warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'important',nexttoken.value);}} +if(nexttoken.id==='}'||nexttoken.id===xquote){warning("Missing '{a}'.",nexttoken,';');}else{advance(';');}}} +function styleSelector(){if(nexttoken.identifier){if(!is_own(htmltag,nexttoken.value)){warning("Expected a tagName, and instead saw {a}.",nexttoken,nexttoken.value);} +advance();}else{switch(nexttoken.id){case'>':case'+':advance();styleSelector();break;case':':advance(':');switch(nexttoken.value){case'active':case'after':case'before':case'checked':case'disabled':case'empty':case'enabled':case'first-child':case'first-letter':case'first-line':case'first-of-type':case'focus':case'hover':case'last-of-type':case'link':case'only-of-type':case'root':case'target':case'visited':advance();break;case'lang':advance();advance('(');if(!nexttoken.identifier){warning("Expected a lang code, and instead saw :{a}.",nexttoken,nexttoken.value);} +advance(')');break;case'nth-child':case'nth-last-child':case'nth-last-of-type':case'nth-of-type':advance();advance('(');styleChild();advance(')');break;case'not':advance();advance('(');if(nexttoken.id===':'&&peek(0).value==='not'){warning("Nested not.");} +styleSelector();advance(')');break;default:warning("Expected a pseudo, and instead saw :{a}.",nexttoken,nexttoken.value);} +break;case'#':advance('#');if(!nexttoken.identifier){warning("Expected an id, and instead saw #{a}.",nexttoken,nexttoken.value);} +advance();break;case'*':advance('*');break;case'.':advance('.');if(!nexttoken.identifier){warning("Expected a class, and instead saw #.{a}.",nexttoken,nexttoken.value);} +advance();break;case'[':advance('[');if(!nexttoken.identifier){warning("Expected an attribute, and instead saw [{a}].",nexttoken,nexttoken.value);} +advance();if(nexttoken.id==='='||nexttoken.value==='~='||nexttoken.value==='$='||nexttoken.value==='|='||nexttoken.id==='*='||nexttoken.id==='^='){advance();if(nexttoken.type!=='(string)'){warning("Expected a string, and instead saw {a}.",nexttoken,nexttoken.value);} +advance();} +advance(']');break;default:error("Expected a CSS selector, and instead saw {a}.",nexttoken,nexttoken.value);}}} +function stylePattern(){var name;if(nexttoken.id==='{'){warning("Expected a style pattern, and instead saw '{a}'.",nexttoken,nexttoken.id);}else if(nexttoken.id==='@'){advance('@');name=nexttoken.value;if(nexttoken.identifier&&atrule[name]===true){advance();return name;} +warning("Expected an at-rule, and instead saw @{a}.",nexttoken,name);} +for(;;){styleSelector();if(nexttoken.id==='</'||nexttoken.id==='{'||nexttoken.id==='(end)'){return'';} +if(nexttoken.id===','){comma();}}} +function styles(){var i;while(nexttoken.id==='@'){i=peek();if(i.identifier&&i.value==='import'){advance('@');advance();if(!cssUrl()){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'url',nexttoken.value);advance();} +advance(';');}else{break;}} +while(nexttoken.id!=='</'&&nexttoken.id!=='(end)'){stylePattern();xmode='styleproperty';if(nexttoken.id===';'){advance(';');}else{advance('{');substyle();xmode='style';advance('}');}}} +function doBegin(n){if(n!=='html'&&!option.fragment){if(n==='div'&&option.adsafe){error("ADSAFE: Use the fragment option.");}else{error("Expected '{a}' and instead saw '{b}'.",token,'html',n);}} +if(option.adsafe){if(n==='html'){error("Currently, ADsafe does not operate on whole HTML documents. It operates on <div> fragments and .js files.",token);} +if(option.fragment){if(n!=='div'){error("ADsafe violation: Wrap the widget in a div.",token);}}else{error("Use the fragment option.",token);}} +option.browser=true;assume();} +function doAttribute(n,a,v){var u,x;if(a==='id'){u=typeof v==='string'?v.toUpperCase():'';if(ids[u]===true){warning("Duplicate id='{a}'.",nexttoken,v);} +if(option.adsafe){if(adsafe_id){if(v.slice(0,adsafe_id.length)!==adsafe_id){warning("ADsafe violation: An id must have a '{a}' prefix",nexttoken,adsafe_id);}else if(!/^[A-Z]+_[A-Z]+$/.test(v)){warning("ADSAFE violation: bad id.");}}else{adsafe_id=v;if(!/^[A-Z]+_$/.test(v)){warning("ADSAFE violation: bad id.");}}} +x=v.search(dx);if(x>=0){warning("Unexpected character '{a}' in {b}.",token,v.charAt(x),a);} +ids[u]=true;}else if(a==='class'||a==='type'||a==='name'){x=v.search(qx);if(x>=0){warning("Unexpected character '{a}' in {b}.",token,v.charAt(x),a);} +ids[u]=true;}else if(a==='href'||a==='background'||a==='content'||a==='data'||a.indexOf('src')>=0||a.indexOf('url')>=0){if(option.safe&&ux.test(v)){error("ADsafe URL violation.");} +urls.push(v);}else if(a==='for'){if(option.adsafe){if(adsafe_id){if(v.slice(0,adsafe_id.length)!==adsafe_id){warning("ADsafe violation: An id must have a '{a}' prefix",nexttoken,adsafe_id);}else if(!/^[A-Z]+_[A-Z]+$/.test(v)){warning("ADSAFE violation: bad id.");}}else{warning("ADSAFE violation: bad id.");}}}else if(a==='name'){if(option.adsafe&&v.indexOf('_')>=0){warning("ADsafe name violation.");}}} +function doTag(n,a){var i,t=htmltag[n],x;src=false;if(!t){error("Unrecognized tag '<{a}>'.",nexttoken,n===n.toLowerCase()?n:n+' (capitalization error)');} +if(stack.length>0){if(n==='html'){error("Too many <html> tags.",token);} +x=t.parent;if(x){if(x.indexOf(' '+stack[stack.length-1].name+' ')<0){error("A '<{a}>' must be within '<{b}>'.",token,n,x);}}else if(!option.adsafe&&!option.fragment){i=stack.length;do{if(i<=0){error("A '<{a}>' must be within '<{b}>'.",token,n,'body');} +i-=1;}while(stack[i].name!=='body');}} +switch(n){case'div':if(option.adsafe&&stack.length===1&&!adsafe_id){warning("ADSAFE violation: missing ID_.");} +break;case'script':xmode='script';advance('>');indent=nexttoken.from;if(a.lang){warning("lang is deprecated.",token);} +if(option.adsafe&&stack.length!==1){warning("ADsafe script placement violation.",token);} +if(a.src){if(option.adsafe&&(!adsafe_may||!approved[a.src])){warning("ADsafe unapproved script source.",token);} +if(a.type){warning("type is unnecessary.",token);}}else{if(adsafe_went){error("ADsafe script violation.",token);} +statements('script');} +xmode='html';advance('</');if(!nexttoken.identifier&&nexttoken.value!=='script'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'script',nexttoken.value);} +advance();xmode='outer';break;case'style':xmode='style';advance('>');styles();xmode='html';advance('</');if(!nexttoken.identifier&&nexttoken.value!=='style'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'style',nexttoken.value);} +advance();xmode='outer';break;case'input':switch(a.type){case'radio':case'checkbox':case'button':case'reset':case'submit':break;case'text':case'file':case'password':case'file':case'hidden':case'image':if(option.adsafe&&a.autocomplete!=='off'){warning("ADsafe autocomplete violation.");} +break;default:warning("Bad input type.");} +break;case'applet':case'body':case'embed':case'frame':case'frameset':case'head':case'iframe':case'noembed':case'noframes':case'object':case'param':if(option.adsafe){warning("ADsafe violation: Disallowed tag: "+n);} +break;}} +function closetag(n){return'</'+n+'>';} +function html(){var a,attributes,e,n,q,t,v,w=option.white,wmode;xmode='html';xquote='';stack=null;for(;;){switch(nexttoken.value){case'<':xmode='html';advance('<');attributes={};t=nexttoken;if(!t.identifier){warning("Bad identifier {a}.",t,t.value);} +n=t.value;if(option.cap){n=n.toLowerCase();} +t.name=n;advance();if(!stack){stack=[];doBegin(n);} +v=htmltag[n];if(typeof v!=='object'){error("Unrecognized tag '<{a}>'.",t,n);} +e=v.empty;t.type=n;for(;;){if(nexttoken.id==='/'){advance('/');if(nexttoken.id!=='>'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'>',nexttoken.value);} +break;} +if(nexttoken.id&&nexttoken.id.substr(0,1)==='>'){break;} +if(!nexttoken.identifier){if(nexttoken.id==='(end)'||nexttoken.id==='(error)'){error("Missing '>'.",nexttoken);} +warning("Bad identifier.");} +option.white=true;nonadjacent(token,nexttoken);a=nexttoken.value;option.white=w;advance();if(!option.cap&&a!==a.toLowerCase()){warning("Attribute '{a}' not all lower case.",nexttoken,a);} +a=a.toLowerCase();xquote='';if(is_own(attributes,a)){warning("Attribute '{a}' repeated.",nexttoken,a);} +if(a.slice(0,2)==='on'){if(!option.on){warning("Avoid HTML event handlers.");} +xmode='scriptstring';advance('=');q=nexttoken.id;if(q!=='"'&&q!=="'"){error("Missing quote.");} +xquote=q;wmode=option.white;option.white=false;advance(q);statements('on');option.white=wmode;if(nexttoken.id!==q){error("Missing close quote on script attribute.");} +xmode='html';xquote='';advance(q);v=false;}else if(a==='style'){xmode='scriptstring';advance('=');q=nexttoken.id;if(q!=='"'&&q!=="'"){error("Missing quote.");} +xmode='styleproperty';xquote=q;advance(q);substyle();xmode='html';xquote='';advance(q);v=false;}else{if(nexttoken.id==='='){advance('=');v=nexttoken.value;if(!nexttoken.identifier&&nexttoken.id!=='"'&&nexttoken.id!=='\''&&nexttoken.type!=='(string)'&&nexttoken.type!=='(number)'&&nexttoken.type!=='(color)'){warning("Expected an attribute value and instead saw '{a}'.",token,a);} +advance();}else{v=true;}} +attributes[a]=v;doAttribute(n,a,v);} +doTag(n,attributes);if(!e){stack.push(t);} +xmode='outer';advance('>');break;case'</':xmode='html';advance('</');if(!nexttoken.identifier){warning("Bad identifier.");} +n=nexttoken.value;if(option.cap){n=n.toLowerCase();} +advance();if(!stack){error("Unexpected '{a}'.",nexttoken,closetag(n));} +t=stack.pop();if(!t){error("Unexpected '{a}'.",nexttoken,closetag(n));} +if(t.name!==n){error("Expected '{a}' and instead saw '{b}'.",nexttoken,closetag(t.name),closetag(n));} +if(nexttoken.id!=='>'){error("Missing '{a}'.",nexttoken,'>');} +xmode='outer';advance('>');break;case'<!':if(option.safe){warning("ADsafe HTML violation.");} +xmode='html';for(;;){advance();if(nexttoken.id==='>'||nexttoken.id==='(end)'){break;} +if(nexttoken.value.indexOf('--')>=0){warning("Unexpected --.");} +if(nexttoken.value.indexOf('<')>=0){warning("Unexpected <.");} +if(nexttoken.value.indexOf('>')>=0){warning("Unexpected >.");}} +xmode='outer';advance('>');break;case'(end)':return;default:if(nexttoken.id==='(end)'){error("Missing '{a}'.",nexttoken,'</'+stack[stack.length-1].value+'>');}else{advance();}} +if(stack&&stack.length===0&&(option.adsafe||!option.fragment||nexttoken.id==='(end)')){break;}} +if(nexttoken.id!=='(end)'){error("Unexpected material after the end.");}} +type('(number)',idValue);type('(string)',idValue);syntax['(identifier)']={type:'(identifier)',lbp:0,identifier:true,nud:function(){var v=this.value,s=scope[v],f;if(typeof s==='function'){s=undefined;}else if(typeof s==='boolean'){f=funct;funct=functions[0];addlabel(v,'var');s=funct;funct=f;} +if(funct===s){switch(funct[v]){case'unused':funct[v]='var';break;case'label':warning("'{a}' is a statement label.",token,v);break;}}else if(funct['(global)']){if(option.undef&&predefined[v]!=='boolean'){warning("'{a}' is not defined.",token,v);} +note_implied(token);}else{switch(funct[v]){case'closure':case'function':case'var':case'unused':warning("'{a}' used out of scope.",token,v);break;case'label':warning("'{a}' is a statement label.",token,v);break;case'outer':case'global':break;default:if(s===true){funct[v]=true;}else if(s===null){warning("'{a}' is not allowed.",token,v);note_implied(token);}else if(typeof s!=='object'){if(option.undef){warning("'{a}' is not defined.",token,v);}else{funct[v]=true;} +note_implied(token);}else{switch(s[v]){case'function':case'var':case'unused':s[v]='closure';funct[v]=s['(global)']?'global':'outer';break;case'closure':case'parameter':funct[v]=s['(global)']?'global':'outer';break;case'label':warning("'{a}' is a statement label.",token,v);}}}} +return this;},led:function(){error("Expected an operator and instead saw '{a}'.",nexttoken,nexttoken.value);}};type('(regexp)',function(){return this;});delim('(endline)');delim('(begin)');delim('(end)').reach=true;delim('</').reach=true;delim('<!');delim('<!--');delim('-->');delim('(error)').reach=true;delim('}').reach=true;delim(')');delim(']');delim('"').reach=true;delim("'").reach=true;delim(';');delim(':').reach=true;delim(',');delim('#');delim('@');reserve('else');reserve('case').reach=true;reserve('catch');reserve('default').reach=true;reserve('finally');reservevar('arguments');reservevar('eval');reservevar('false');reservevar('Infinity');reservevar('NaN');reservevar('null');reservevar('this');reservevar('true');reservevar('undefined');assignop('=','assign',20);assignop('+=','assignadd',20);assignop('-=','assignsub',20);assignop('*=','assignmult',20);assignop('/=','assigndiv',20).nud=function(){error("A regular expression literal can be confused with '/='.");};assignop('%=','assignmod',20);bitwiseassignop('&=','assignbitand',20);bitwiseassignop('|=','assignbitor',20);bitwiseassignop('^=','assignbitxor',20);bitwiseassignop('<<=','assignshiftleft',20);bitwiseassignop('>>=','assignshiftright',20);bitwiseassignop('>>>=','assignshiftrightunsigned',20);infix('?',function(left,that){that.left=left;that.right=parse(10);advance(':');that['else']=parse(10);return that;},30);infix('||','or',40);infix('&&','and',50);bitwise('|','bitor',70);bitwise('^','bitxor',80);bitwise('&','bitand',90);relation('==',function(left,right){if(option.eqeqeq){warning("Expected '{a}' and instead saw '{b}'.",this,'===','==');}else if(isPoorRelation(left)){warning("Use '{a}' to compare with '{b}'.",this,'===',left.value);}else if(isPoorRelation(right)){warning("Use '{a}' to compare with '{b}'.",this,'===',right.value);} +return this;});relation('===');relation('!=',function(left,right){if(option.eqeqeq){warning("Expected '{a}' and instead saw '{b}'.",this,'!==','!=');}else if(isPoorRelation(left)){warning("Use '{a}' to compare with '{b}'.",this,'!==',left.value);}else if(isPoorRelation(right)){warning("Use '{a}' to compare with '{b}'.",this,'!==',right.value);} +return this;});relation('!==');relation('<');relation('>');relation('<=');relation('>=');bitwise('<<','shiftleft',120);bitwise('>>','shiftright',120);bitwise('>>>','shiftrightunsigned',120);infix('in','in',120);infix('instanceof','instanceof',120);infix('+',function(left,that){var right=parse(130);if(left&&right&&left.id==='(string)'&&right.id==='(string)'){left.value+=right.value;left.character=right.character;if(jx.test(left.value)){warning("JavaScript URL.",left);} +return left;} +that.left=left;that.right=right;return that;},130);prefix('+','num');infix('-','sub',130);prefix('-','neg');infix('*','mult',140);infix('/','div',140);infix('%','mod',140);suffix('++','postinc');prefix('++','preinc');syntax['++'].exps=true;suffix('--','postdec');prefix('--','predec');syntax['--'].exps=true;prefix('delete',function(){var p=parse(0);if(!p||(p.id!=='.'&&p.id!=='[')){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'.',nexttoken.value);} +this.first=p;return this;}).exps=true;prefix('~',function(){if(option.bitwise){warning("Unexpected '{a}'.",this,'~');} +parse(150);return this;});prefix('!',function(){this.right=parse(150);this.arity='unary';if(bang[this.right.id]===true){warning("Confusing use of '{a}'.",this,'!');} +return this;});prefix('typeof','typeof');prefix('new',function(){var c=parse(155),i;if(c&&c.id!=='function'){if(c.identifier){c['new']=true;switch(c.value){case'Object':warning("Use the object literal notation {}.",token);break;case'Array':if(nexttoken.id!=='('){warning("Use the array literal notation [].",token);}else{advance('(');if(nexttoken.id===')'){warning("Use the array literal notation [].",token);}else{i=parse(0);c.dimension=i;if((i.id==='(number)'&&/[.+\-Ee]/.test(i.value))||(i.id==='-'&&!i.right)||i.id==='(string)'||i.id==='['||i.id==='{'||i.id==='true'||i.id==='false'||i.id==='null'||i.id==='undefined'||i.id==='Infinity'){warning("Use the array literal notation [].",token);} +if(nexttoken.id!==')'){error("Use the array literal notation [].",token);}} +advance(')');} +this.first=c;return this;case'Number':case'String':case'Boolean':case'Math':case'JSON':warning("Do not use {a} as a constructor.",token,c.value);break;case'Function':if(!option.evil){warning("The Function constructor is eval.");} +break;case'Date':case'RegExp':break;default:if(c.id!=='function'){i=c.value.substr(0,1);if(option.newcap&&(i<'A'||i>'Z')){warning("A constructor name should start with an uppercase letter.",token);}}}}else{if(c.id!=='.'&&c.id!=='['&&c.id!=='('){warning("Bad constructor.",token);}}}else{warning("Weird construction. Delete 'new'.",this);} +adjacent(token,nexttoken);if(nexttoken.id!=='('){warning("Missing '()' invoking a constructor.");} +this.first=c;return this;});syntax['new'].exps=true;infix('.',function(left,that){adjacent(prevtoken,token);var m=identifier();if(typeof m==='string'){countMember(m);} +that.left=left;that.right=m;if(!option.evil&&left&&left.value==='document'&&(m==='write'||m==='writeln')){warning("document.write can be a form of eval.",left);}else if(option.adsafe){if(left&&left.value==='ADSAFE'){if(m==='id'||m==='lib'){warning("ADsafe violation.",that);}else if(m==='go'){if(xmode!=='script'){warning("ADsafe violation.",that);}else if(adsafe_went||nexttoken.id!=='('||peek(0).id!=='(string)'||peek(0).value!==adsafe_id||peek(1).id!==','){error("ADsafe violation: go.",that);} +adsafe_went=true;adsafe_may=false;}}} +if(!option.evil&&(m==='eval'||m==='execScript')){warning('eval is evil.');}else if(option.safe){for(;;){if(banned[m]===true){warning("ADsafe restricted word '{a}'.",token,m);} +if(typeof predefined[left.value]!=='boolean'||nexttoken.id==='('){break;} +if(standard_member[m]===true){if(nexttoken.id==='.'){warning("ADsafe violation.",that);} +break;} +if(nexttoken.id!=='.'){warning("ADsafe violation.",that);break;} +advance('.');token.left=that;token.right=m;that=token;m=identifier();if(typeof m==='string'){countMember(m);}}} +return that;},160,true);infix('(',function(left,that){adjacent(prevtoken,token);nospace();var n=0,p=[];if(left){if(left.type==='(identifier)'){if(left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)){if(left.value!=='Number'&&left.value!=='String'&&left.value!=='Boolean'&&left.value!=='Date'){if(left.value==='Math'){warning("Math is not a function.",left);}else if(option.newcap){warning("Missing 'new' prefix when invoking a constructor.",left);}}}}else if(left.id==='.'){if(option.safe&&left.left.value==='Math'&&left.right==='random'){warning("ADsafe violation.",left);}}} +if(nexttoken.id!==')'){for(;;){p[p.length]=parse(10);n+=1;if(nexttoken.id!==','){break;} +comma();}} +advance(')');if(option.immed&&left.id==='function'&&nexttoken.id!==')'){warning("Wrap the entire immediate function invocation in parens.",that);} +nospace(prevtoken,token);if(typeof left==='object'){if(left.value==='parseInt'&&n===1){warning("Missing radix parameter.",left);} +if(!option.evil){if(left.value==='eval'||left.value==='Function'||left.value==='execScript'){warning("eval is evil.",left);}else if(p[0]&&p[0].id==='(string)'&&(left.value==='setTimeout'||left.value==='setInterval')){warning("Implied eval is evil. Pass a function instead of a string.",left);}} +if(!left.identifier&&left.id!=='.'&&left.id!=='['&&left.id!=='('&&left.id!=='&&'&&left.id!=='||'&&left.id!=='?'){warning("Bad invocation.",left);}} +that.left=left;return that;},155,true).exps=true;prefix('(',function(){nospace();var v=parse(0);advance(')',this);nospace(prevtoken,token);if(option.immed&&v.id==='function'){if(nexttoken.id==='('){warning("Move the invocation into the parens that contain the function.",nexttoken);}else{warning("Do not wrap function literals in parens unless they are to be immediately invoked.",this);}} +return v;});infix('[',function(left,that){nospace();var e=parse(0),s;if(e&&e.type==='(string)'){if(option.safe&&banned[e.value]===true){warning("ADsafe restricted word '{a}'.",that,e.value);}else if(!option.evil&&(e.value==='eval'||e.value==='execScript')){warning("eval is evil.",that);}else if(option.safe&&(e.value.charAt(0)==='_'||e.value.charAt(0)==='-')){warning("ADsafe restricted subscript '{a}'.",that,e.value);} +countMember(e.value);if(!option.sub&&ix.test(e.value)){s=syntax[e.value];if(!s||!s.reserved){warning("['{a}'] is better written in dot notation.",e,e.value);}}}else if(!e||e.type!=='(number)'||e.value<0){if(option.safe){warning('ADsafe subscripting.');}} +advance(']',that);nospace(prevtoken,token);that.left=left;that.right=e;return that;},160,true);prefix('[',function(){var b=token.line!==nexttoken.line;this.first=[];if(b){indent+=option.indent;if(nexttoken.from===indent+option.indent){indent+=option.indent;}} +while(nexttoken.id!=='(end)'){while(nexttoken.id===','){warning("Extra comma.");advance(',');} +if(nexttoken.id===']'){break;} +if(b&&token.line!==nexttoken.line){indentation();} +this.first.push(parse(10));if(nexttoken.id===','){comma();if(nexttoken.id===']'){warning("Extra comma.",token);break;}}else{break;}} +if(b){indent-=option.indent;indentation();} +advance(']',this);return this;},160);(function(x){x.nud=function(){var b,i,s,seen={};b=token.line!==nexttoken.line;if(b){indent+=option.indent;if(nexttoken.from===indent+option.indent){indent+=option.indent;}} +for(;;){if(nexttoken.id==='}'){break;} +if(b){indentation();} +i=optionalidentifier(true);if(!i){if(nexttoken.id==='(string)'){i=nexttoken.value;if(ix.test(i)){s=syntax[i];} +advance();}else if(nexttoken.id==='(number)'){i=nexttoken.value.toString();advance();}else{error("Expected '{a}' and instead saw '{b}'.",nexttoken,'}',nexttoken.value);}} +if(seen[i]===true){warning("Duplicate member '{a}'.",nexttoken,i);} +seen[i]=true;countMember(i);advance(':');nonadjacent(token,nexttoken);parse(10);if(nexttoken.id===','){comma();if(nexttoken.id===','||nexttoken.id==='}'){warning("Extra comma.",token);}}else{break;}} +if(b){indent-=option.indent;indentation();} +advance('}',this);return this;};x.fud=function(){error("Expected to see a statement and instead saw a block.",token);};}(delim('{')));function varstatement(prefix){var id,name,value;if(funct['(onevar)']&&option.onevar){warning("Too many var statements.");}else if(!funct['(global)']){funct['(onevar)']=true;} +this.first=[];for(;;){nonadjacent(token,nexttoken);id=identifier();if(funct['(global)']&&predefined[id]===false){warning("Redefinition of '{a}'.",token,id);} +addlabel(id,'unused');if(prefix){break;} +name=token;this.first.push(token);if(nexttoken.id==='='){nonadjacent(token,nexttoken);advance('=');nonadjacent(token,nexttoken);if(peek(0).id==='='&&nexttoken.identifier){error("Variable {a} was not declared correctly.",nexttoken,nexttoken.value);} +value=parse(0);name.first=value;} +if(nexttoken.id!==','){break;} +comma();} +return this;} +stmt('var',varstatement).exps=true;function functionparams(){var i,t=nexttoken,p=[];advance('(');nospace();if(nexttoken.id===')'){advance(')');nospace(prevtoken,token);return;} +for(;;){i=identifier();p.push(i);addlabel(i,'parameter');if(nexttoken.id===','){comma();}else{advance(')',t);nospace(prevtoken,token);return p;}}} +function doFunction(i){var s=scope;scope=Object.create(s);funct={'(name)':i||'"'+anonname+'"','(line)':nexttoken.line,'(context)':funct,'(breakage)':0,'(loopage)':0,'(scope)':scope};token.funct=funct;functions.push(funct);if(i){addlabel(i,'function');} +funct['(params)']=functionparams();block(false);scope=s;funct['(last)']=token.line;funct=funct['(context)'];} +blockstmt('function',function(){if(inblock){warning("Function statements cannot be placed in blocks. Use a function expression or move the statement to the top of the outer function.",token);} +var i=identifier();adjacent(token,nexttoken);addlabel(i,'unused');doFunction(i);if(nexttoken.id==='('&&nexttoken.line===token.line){error("Function statements are not invocable. Wrap the whole function invocation in parens.");} +return this;});prefix('function',function(){var i=optionalidentifier();if(i){adjacent(token,nexttoken);}else{nonadjacent(token,nexttoken);} +doFunction(i);if(funct['(loopage)']&&nexttoken.id!=='('){warning("Be careful when making functions within a loop. Consider putting the function in a closure.");} +return this;});blockstmt('if',function(){var t=nexttoken;advance('(');nonadjacent(this,t);nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);} +advance(')',t);nospace(prevtoken,token);block(true);if(nexttoken.id==='else'){nonadjacent(token,nexttoken);advance('else');if(nexttoken.id==='if'||nexttoken.id==='switch'){statement(true);}else{block(true);}} +return this;});blockstmt('try',function(){var b,e,s;if(option.adsafe){warning("ADsafe try violation.",this);} +block(false);if(nexttoken.id==='catch'){advance('catch');nonadjacent(token,nexttoken);advance('(');s=scope;scope=Object.create(s);e=nexttoken.value;if(nexttoken.type!=='(identifier)'){warning("Expected an identifier and instead saw '{a}'.",nexttoken,e);}else{addlabel(e,'exception');} +advance();advance(')');block(false);b=true;scope=s;} +if(nexttoken.id==='finally'){advance('finally');block(false);return;}else if(!b){error("Expected '{a}' and instead saw '{b}'.",nexttoken,'catch',nexttoken.value);} +return this;});blockstmt('while',function(){var t=nexttoken;funct['(breakage)']+=1;funct['(loopage)']+=1;advance('(');nonadjacent(this,t);nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);} +advance(')',t);nospace(prevtoken,token);block(true);funct['(breakage)']-=1;funct['(loopage)']-=1;return this;}).labelled=true;reserve('with');blockstmt('switch',function(){var t=nexttoken,g=false;funct['(breakage)']+=1;advance('(');nonadjacent(this,t);nospace();this.condition=parse(20);advance(')',t);nospace(prevtoken,token);nonadjacent(token,nexttoken);t=nexttoken;advance('{');nonadjacent(token,nexttoken);indent+=option.indent;this.cases=[];for(;;){switch(nexttoken.id){case'case':switch(funct['(verb)']){case'break':case'case':case'continue':case'return':case'switch':case'throw':break;default:warning("Expected a 'break' statement before 'case'.",token);} +indentation(-option.indent);advance('case');this.cases.push(parse(20));g=true;advance(':');funct['(verb)']='case';break;case'default':switch(funct['(verb)']){case'break':case'continue':case'return':case'throw':break;default:warning("Expected a 'break' statement before 'default'.",token);} +indentation(-option.indent);advance('default');g=true;advance(':');break;case'}':indent-=option.indent;indentation();advance('}',t);if(this.cases.length===1||this.condition.id==='true'||this.condition.id==='false'){warning("This 'switch' should be an 'if'.",this);} +funct['(breakage)']-=1;funct['(verb)']=undefined;return;case'(end)':error("Missing '{a}'.",nexttoken,'}');return;default:if(g){switch(token.id){case',':error("Each value should have its own case label.");return;case':':statements();break;default:error("Missing ':' on a case clause.",token);}}else{error("Expected '{a}' and instead saw '{b}'.",nexttoken,'case',nexttoken.value);}}}}).labelled=true;stmt('debugger',function(){if(!option.debug){warning("All 'debugger' statements should be removed.");} +return this;}).exps=true;(function(){var x=stmt('do',function(){funct['(breakage)']+=1;funct['(loopage)']+=1;this.first=block(true);advance('while');var t=nexttoken;nonadjacent(token,t);advance('(');nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);} +advance(')',t);nospace(prevtoken,token);funct['(breakage)']-=1;funct['(loopage)']-=1;return this;});x.labelled=true;x.exps=true;}());blockstmt('for',function(){var f=option.forin,s,t=nexttoken;funct['(breakage)']+=1;funct['(loopage)']+=1;advance('(');nonadjacent(this,t);nospace();if(peek(nexttoken.id==='var'?1:0).id==='in'){if(nexttoken.id==='var'){advance('var');varstatement(true);}else{switch(funct[nexttoken.value]){case'unused':funct[nexttoken.value]='var';break;case'var':break;default:warning("Bad for in variable '{a}'.",nexttoken,nexttoken.value);} +advance();} +advance('in');parse(20);advance(')',t);s=block(true);if(!f&&(s.length>1||typeof s[0]!=='object'||s[0].value!=='if')){warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.",this);} +funct['(breakage)']-=1;funct['(loopage)']-=1;return this;}else{if(nexttoken.id!==';'){if(nexttoken.id==='var'){advance('var');varstatement();}else{for(;;){parse(0,'for');if(nexttoken.id!==','){break;} +comma();}}} +nolinebreak(token);advance(';');if(nexttoken.id!==';'){parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);}} +nolinebreak(token);advance(';');if(nexttoken.id===';'){error("Expected '{a}' and instead saw '{b}'.",nexttoken,')',';');} +if(nexttoken.id!==')'){for(;;){parse(0,'for');if(nexttoken.id!==','){break;} +comma();}} +advance(')',t);nospace(prevtoken,token);block(true);funct['(breakage)']-=1;funct['(loopage)']-=1;return this;}}).labelled=true;stmt('break',function(){var v=nexttoken.value;if(funct['(breakage)']===0){warning("Unexpected '{a}'.",nexttoken,this.value);} +nolinebreak(this);if(nexttoken.id!==';'){if(token.line===nexttoken.line){if(funct[v]!=='label'){warning("'{a}' is not a statement label.",nexttoken,v);}else if(scope[v]!==funct){warning("'{a}' is out of scope.",nexttoken,v);} +this.first=nexttoken;advance();}} +reachable('break');return this;}).exps=true;stmt('continue',function(){var v=nexttoken.value;if(funct['(breakage)']===0){warning("Unexpected '{a}'.",nexttoken,this.value);} +nolinebreak(this);if(nexttoken.id!==';'){if(token.line===nexttoken.line){if(funct[v]!=='label'){warning("'{a}' is not a statement label.",nexttoken,v);}else if(scope[v]!==funct){warning("'{a}' is out of scope.",nexttoken,v);} +this.first=nexttoken;advance();}} +reachable('continue');return this;}).exps=true;stmt('return',function(){nolinebreak(this);if(nexttoken.id==='(regexp)'){warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");} +if(nexttoken.id!==';'&&!nexttoken.reach){nonadjacent(token,nexttoken);this.first=parse(20);} +reachable('return');return this;}).exps=true;stmt('throw',function(){nolinebreak(this);nonadjacent(token,nexttoken);this.first=parse(20);reachable('throw');return this;}).exps=true;reserve('void');reserve('class');reserve('const');reserve('enum');reserve('export');reserve('extends');reserve('import');reserve('super');reserve('let');reserve('yield');reserve('implements');reserve('interface');reserve('package');reserve('private');reserve('protected');reserve('public');reserve('static');function jsonValue(){function jsonObject(){var o={},t=nexttoken;advance('{');if(nexttoken.id!=='}'){for(;;){if(nexttoken.id==='(end)'){error("Missing '}' to match '{' from line {a}.",nexttoken,t.line);}else if(nexttoken.id==='}'){warning("Unexpected comma.",token);break;}else if(nexttoken.id===','){error("Unexpected comma.",nexttoken);}else if(nexttoken.id!=='(string)'){warning("Expected a string and instead saw {a}.",nexttoken,nexttoken.value);} +if(o[nexttoken.value]===true){warning("Duplicate key '{a}'.",nexttoken,nexttoken.value);}else if(nexttoken.value==='__proto__'){warning("Stupid key '{a}'.",nexttoken,nexttoken.value);}else{o[nexttoken.value]=true;} +advance();advance(':');jsonValue();if(nexttoken.id!==','){break;} +advance(',');}} +advance('}');} +function jsonArray(){var t=nexttoken;advance('[');if(nexttoken.id!==']'){for(;;){if(nexttoken.id==='(end)'){error("Missing ']' to match '[' from line {a}.",nexttoken,t.line);}else if(nexttoken.id===']'){warning("Unexpected comma.",token);break;}else if(nexttoken.id===','){error("Unexpected comma.",nexttoken);} +jsonValue();if(nexttoken.id!==','){break;} +advance(',');}} +advance(']');} +switch(nexttoken.id){case'{':jsonObject();break;case'[':jsonArray();break;case'true':case'false':case'null':case'(number)':case'(string)':advance();break;case'-':advance('-');if(token.character!==nexttoken.from){warning("Unexpected space after '-'.",token);} +adjacent(token,nexttoken);advance('(number)');break;default:error("Expected a JSON value.",nexttoken);}} +var itself=function(s,o){var a,i;JSLINT.errors=[];predefined=Object.create(standard);if(o){a=o.predef;if(a instanceof Array){for(i=0;i<a.length;i+=1){predefined[a[i]]=true;}} +if(o.adsafe){o.safe=true;} +if(o.safe){o.browser=false;o.css=false;o.debug=false;o.eqeqeq=true;o.evil=false;o.forin=false;o.nomen=true;o.on=false;o.rhino=false;o.safe=true;o.sidebar=false;o.strict=true;o.sub=false;o.undef=true;o.widget=false;predefined.Date=null;predefined['eval']=null;predefined.Function=null;predefined.Object=null;predefined.ADSAFE=false;predefined.lib=false;} +option=o;}else{option={};} +option.indent=option.indent||4;option.maxerr=option.maxerr||50;adsafe_id='';adsafe_may=false;adsafe_went=false;approved={};if(option.approved){for(i=0;i<option.approved.length;i+=1){approved[option.approved[i]]=option.approved[i];}}else{approved.test='test';} +tab='';for(i=0;i<option.indent;i+=1){tab+=' ';} +indent=1;global=Object.create(predefined);scope=global;funct={'(global)':true,'(name)':'(global)','(scope)':scope,'(breakage)':0,'(loopage)':0};functions=[funct];ids={};urls=[];src=false;xmode=false;stack=null;member={};membersOnly=null;implied={};inblock=false;lookahead=[];jsonmode=false;warnings=0;lex.init(s);prereg=true;strict_mode=false;prevtoken=token=nexttoken=syntax['(begin)'];assume();try{advance();if(nexttoken.value.charAt(0)==='<'){html();if(option.adsafe&&!adsafe_went){warning("ADsafe violation: Missing ADSAFE.go.",this);}}else{switch(nexttoken.id){case'{':case'[':option.laxbreak=true;jsonmode=true;jsonValue();break;case'@':case'*':case'#':case'.':case':':xmode='style';advance();if(token.id!=='@'||!nexttoken.identifier||nexttoken.value!=='charset'||token.line!==1||token.from!==1){error('A css file should begin with @charset "UTF-8";');} +advance();if(nexttoken.type!=='(string)'&&nexttoken.value!=='UTF-8'){error('A css file should begin with @charset "UTF-8";');} +advance();advance(';');styles();break;default:if(option.adsafe&&option.fragment){error("Expected '{a}' and instead saw '{b}'.",nexttoken,'<div>',nexttoken.value);} +statements('lib');}} +advance('(end)');}catch(e){if(e){JSLINT.errors.push({reason:e.message,line:e.line||nexttoken.line,character:e.character||nexttoken.from},null);}} +return JSLINT.errors.length===0;};function is_array(o){return Object.prototype.toString.apply(o)==='[object Array]';} +function to_array(o){var a=[],k;for(k in o){if(is_own(o,k)){a.push(k);}} +return a;} +itself.data=function(){var data={functions:[]},fu,globals,implieds=[],f,i,j,members=[],n,unused=[],v;if(itself.errors.length){data.errors=itself.errors;} +if(jsonmode){data.json=true;} +for(n in implied){if(is_own(implied,n)){implieds.push({name:n,line:implied[n]});}} +if(implieds.length>0){data.implieds=implieds;} +if(urls.length>0){data.urls=urls;} +globals=to_array(scope);if(globals.length>0){data.globals=globals;} +for(i=1;i<functions.length;i+=1){f=functions[i];fu={};for(j=0;j<functionicity.length;j+=1){fu[functionicity[j]]=[];} +for(n in f){if(is_own(f,n)&&n.charAt(0)!=='('){v=f[n];if(is_array(fu[v])){fu[v].push(n);if(v==='unused'){unused.push({name:n,line:f['(line)'],'function':f['(name)']});}}}} +for(j=0;j<functionicity.length;j+=1){if(fu[functionicity[j]].length===0){delete fu[functionicity[j]];}} +fu.name=f['(name)'];fu.param=f['(params)'];fu.line=f['(line)'];fu.last=f['(last)'];data.functions.push(fu);} +if(unused.length>0){data.unused=unused;} +members=[];for(n in member){if(typeof member[n]==='number'){data.member=member;break;}} +return data;};itself.report=function(option){var data=itself.data();var a=[],c,e,err,f,i,k,l,m='',n,o=[],s;function detail(h,s){if(s){o.push('<div><i>'+h+'</i> '+ +s.sort().join(', ')+'</div>');}} +if(data.errors||data.implieds||data.unused){err=true;o.push('<div id=errors><i>Error:</i>');if(data.errors){for(i=0;i<data.errors.length;i+=1){c=data.errors[i];if(c){e=c.evidence||'';o.push('<p>Problem'+(isFinite(c.line)?' at line '+ +c.line+' character '+c.character:'')+': '+c.reason.entityify()+'</p><p class=evidence>'+ +(e&&(e.length>80?e.slice(0,77)+'...':e).entityify())+'</p>');}}} +if(data.implieds){s=[];for(i=0;i<data.implieds.length;i+=1){s[i]='<code>'+data.implieds[i].name+'</code> <i>'+ +data.implieds[i].line+'</i>';} +o.push('<p><i>Implied global:</i> '+s.join(', ')+'</p>');} +if(data.unused){s=[];for(i=0;i<data.unused.length;i+=1){s[i]='<code><u>'+data.unused[i].name+'</u></code> <i>'+ +data.unused[i].line+'</i> <code>'+ +data.unused[i]['function']+'</code>';} +o.push('<p><i>Unused variable:</i> '+s.join(', ')+'</p>');} +if(data.json){o.push('<p>JSON: bad.</p>');} +o.push('</div>');} +if(!option){o.push('<br><div id=functions>');if(data.urls){detail("URLs<br>",data.urls,'<br>');} +if(data.json&&!err){o.push('<p>JSON: good.</p>');}else if(data.globals){o.push('<div><i>Global</i> '+ +data.globals.sort().join(', ')+'</div>');}else{o.push('<div><i>No new global variables introduced.</i></div>');} +for(i=0;i<data.functions.length;i+=1){f=data.functions[i];o.push('<br><div class=function><i>'+f.line+'-'+ +f.last+'</i> '+(f.name||'')+'('+ +(f.param?f.param.join(', '):'')+')</div>');detail('<big><b>Unused</b></big>',f.unused);detail('Closure',f.closure);detail('Variable',f['var']);detail('Exception',f.exception);detail('Outer',f.outer);detail('Global',f.global);detail('Label',f.label);} +if(data.member){a=to_array(data.member);if(a.length){a=a.sort();m='<br><pre id=members>/*members ';l=10;for(i=0;i<a.length;i+=1){k=a[i];n=k.name();if(l+n.length>72){o.push(m+'<br>');m=' ';l=1;} +l+=n.length+2;if(data.member[k]===1){n='<i>'+n+'</i>';} +if(i<a.length-1){n+=', ';} +m+=n;} +o.push(m+'<br>*/</pre>');} +o.push('</div>');}} +return o.join('');};itself.jslint=itself;itself.edition='2009-10-04';return itself;}());(function(a){var e,i,input;if(!a[0]){print("Usage: jslint.js file.js");quit(1);} +input=readFile(a[0]);if(!input){print("jslint: Couldn't open file '"+a[0]+"'.");quit(1);} +if(!JSLINT(input,{bitwise:true,eqeqeq:true,immed:true,newcap:true,nomen:true,onevar:true,plusplus:true,regexp:true,rhino:true,undef:true,white:true})){for(i=0;i<JSLINT.errors.length;i+=1){e=JSLINT.errors[i];if(e){print('Lint at line '+e.line+' character '+ +e.character+': '+e.reason);print((e.evidence||'').replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1"));print('');}} +quit(0);}else{print("jslint: No problems found in "+a[0]);quit();}}(arguments)); diff --git a/emacs/nxhtml/related/moz.el b/emacs/nxhtml/related/moz.el new file mode 100644 index 0000000..e910286 --- /dev/null +++ b/emacs/nxhtml/related/moz.el @@ -0,0 +1,289 @@ +;;; moz.el --- Lets current buffer interact with inferior mozilla. + +;; URL: http://github.com/bard/mozrepl/raw/master/chrome/content/moz.el + +;; Copyright (C) 2006 by Massimiliano Mirra +;; +;; 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +;; +;; Author: Massimiliano Mirra, <bard [at] hyperstruct [dot] net> +;; Contributors: +;; - Lennart Borgman + +;;; Commentary: +;; +;; This file implements communication with Firefox via MozRepl +;; (http://hyperstruct.net/projects/mozrepl). It is a slightly +;; modified version of the file moz.el that comes with MozLab. To use +;; it you have to install the MozRepl addon in Firefox. +;; +;; This file contains +;; +;; * a major mode for direct interaction in a buffer (as with +;; telnet) with MozRepl, `inferior-moz-mode'. +;; * a minor mode for sending code portions or whole files from +;; other buffers to MozRepl, `moz-minor-mode'. +;; +;; Assuming you want to use javascript-mode to edit Javascript files, +;; enter the following in your .emacs initialization file (from Emacs +;; integration in the help text): +;; +;; (add-to-list 'auto-mode-alist '("\\.js$" . javascript-mode)) +;; (autoload 'inferior-moz-mode "moz" "MozRepl Inferior Mode" t) +;; (autoload 'moz-minor-mode "moz" "MozRepl Minor Mode" t) +;; (add-hook 'javascript-mode-hook 'javascript-moz-setup) +;; (defun javascript-moz-setup () (moz-minor-mode 1)) +;; +;; Replace javascript-mode above with the name of your favorite +;; javascript mode. +;; +;; If you got this with nXhtml the setup above is already done for +;; you. +;; +;; *Note 1* You have to start the MozRepl server in Firefox (or +;; whatever Mozilla browser you use). From the menus do +;; +;; Tools - MozRepl - Start +;; +;; *Note 2* For clearness and brevity the documentation says Firefox +;; where the correct term should rather be "your Mozilla web +;; browser". + +;;; Change log: +;; +;; 2008-07-20: Lennart Borgman +;; - Add `moz-minor-mode-map'. +;; - Add `inferior-moz-insert-moz-repl'. +;; - Add `inferior-moz-mode-map'. +;; - Add doc strings to interactive functions. +;; - Make minor enhancements to documentation etc. +;; - Change Mozilla to Firefox/MozRepl for clarity and brevity. +;; - Add error handling when starting MozRepl. + +;;; Code: + +(require 'comint) +(require 'cc-cmds) + +;; Maybe fix-me: C-c control-char are reserved for major modes. But +;; this minor mode is used in only one major mode (or one family of +;; major modes) so it complies I think ... +(defvar moz-minor-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-s" 'run-mozilla) + (define-key map "\C-\M-x" 'moz-send-defun) + (define-key map "\C-c\C-c" 'moz-send-defun-and-go) + (define-key map "\C-c\C-r" 'moz-send-region) + (define-key map "\C-c\C-l" 'moz-save-buffer-and-send) + map)) + +;;;###autoload +(define-minor-mode moz-minor-mode + "MozRepl minor mode for interaction with Firefox. +With no argument, this command toggles the mode. +Non-null prefix argument turns on the mode. +Null prefix argument turns off the mode. + +When this minor mode is enabled, some commands become available +to send current code area \(as understood by c-mark-function) or +region or buffer to an inferior MozRepl process (which will be +started as needed). + +The following keys are bound in this minor mode: + +\\{moz-minor-mode-map}" + nil + " Moz" + :keymap moz-minor-mode-map + :group 'moz) + +(defalias 'run-mozilla 'inferior-moz-switch-to-mozilla) + +(defvar moz-repl-name "repl" + "The current name of the repl.") + +(defvar moz-input-separator "\n--end-remote-input\n") + +(defvar moz-repl-host "localhost") + +(defvar moz-repl-port 4242) + +(defvar moz-temporary-file nil) + +(defun moz-temporary-file () + (if (and moz-temporary-file + (file-readable-p moz-temporary-file)) + moz-temporary-file + (setq moz-temporary-file (make-temp-file "emacs-mozrepl")))) + +(defun moz-send-region (start end) + "Send the region to Firefox via MozRepl." + (interactive "r") + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".pushenv('printPrompt', 'inputMode'); " + moz-repl-name ".setenv('printPrompt', false); " + moz-repl-name ".setenv('inputMode', 'multiline'); " + "undefined; \n")) + ;; Give the previous line a chance to be evaluated on its own. If + ;; it gets concatenated to the following ones, we are doomed. + (sleep-for 0 1) + (comint-send-region (inferior-moz-process) + start end) + (comint-send-string (inferior-moz-process) + "\n--end-remote-input\n") + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".popenv('inputMode', 'printPrompt'); " + "undefined; \n")) + (comint-send-string (inferior-moz-process) + "\n--end-remote-input\n") + (display-buffer (process-buffer (inferior-moz-process)))) + +(defun moz-send-defun () + "Send the current function to Firefox via MozRepl. +Curent function is the one recognized by c-mark-function." + (interactive) + (save-excursion + (c-mark-function) + (moz-send-region (point) (mark)))) + +(defun moz-send-defun-and-go () + "Send the current function to Firefox via MozRepl. +Also switch to the interaction buffer." + (interactive) + (moz-send-defun) + (inferior-moz-switch-to-mozilla nil)) + +(defun moz-save-buffer-and-send () + "Save the current buffer and load it in Firefox via MozRepl." + (interactive) + (save-buffer) + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".pushenv('printPrompt', 'inputMode'); " + moz-repl-name ".setenv('inputMode', 'line'); " + moz-repl-name ".setenv('printPrompt', false); undefined; ")) + (comint-send-string (inferior-moz-process) + (concat moz-repl-name ".load('file://localhost/" (buffer-file-name) "');\n" + moz-repl-name ".popenv('inputMode', 'printPrompt'); undefined;\n")) + (display-buffer (process-buffer (inferior-moz-process)))) + +;;; Inferior Mode + +(defvar inferior-moz-buffer nil + "The buffer in which the inferior process is running.") + +(defun inferior-moz-insert-moz-repl () + "Insert value of `moz-repl-name' and a dot (.)." + (interactive) (insert moz-repl-name ".")) + +(defvar inferior-moz-mode-map + (let ((map (make-sparse-keymap))) + ;; Note: changed from C-c c which is reserved for users. + (define-key map "\C-c\C-c" 'inferior-moz-insert-moz-repl) + map)) + +;;;###autoload +(define-derived-mode inferior-moz-mode comint-mode "Inf-MozRepl" + "Major mode for interacting with Firefox via MozRepl." + (setq comint-input-sender 'inferior-moz-input-sender) + (add-hook 'comint-output-filter-functions 'inferior-moz-track-repl-name nil t)) + +(defun inferior-moz-track-repl-name (comint-output) + (save-match-data + (when (string-match "\\(\\w+\\)> $" comint-output) + (setq moz-repl-name (match-string 1 comint-output))))) + +(defun inferior-moz-self-insert-or-repl-name () + (interactive) + (if (looking-back "\\(\\w+\\)> $") + (insert moz-repl-name ".") + (insert last-command-event))) + +(defun inferior-moz-input-sender (proc string) + "Custom function to send input with comint-send-input. +Instead of sending input and newline separately like in +comint-simple-send, here we *first* concatenate input and +newline, then send it all together. This prevents newline to be +interpreted on its own." + (comint-send-string proc (concat string "\n"))) + +(defun inferior-moz-switch-to-mozilla (arg) + "Switch to the inferior MozRepl buffer. +Create the buffer and start the MozRepl process and connect to +Firefox if needed. + +See also `inferior-moz-start-process'." + (interactive "P") + (when arg + (setq moz-repl-host (read-string "Host: " "localhost")) + (setq moz-repl-port (read-number "Port: " 4242))) + (pop-to-buffer (process-buffer (inferior-moz-process))) + (goto-char (process-mark (inferior-moz-process)))) + +(defun inferior-moz-process () + "Return inferior MozRepl process. Start it if necessary. +See also `inferior-moz-start-process'." + (or (if (buffer-live-p inferior-moz-buffer) + (get-buffer-process inferior-moz-buffer)) + (progn + (inferior-moz-start-process) + (inferior-moz-process)))) + +(defvar mozrepl-home-page "http://hyperstruct.net/projects/mozrepl") + +(defun inferior-moz-start-process () + "Start an inferior Mozrepl process and connect to Firefox. +It runs the hook `inferior-moz-hook' after starting the process +and setting up the inferior Firefox buffer. + +Note that you have to start the MozRepl server from Firefox." + (interactive) + (condition-case err + (progn + (setq inferior-moz-buffer + (apply 'make-comint "MozRepl" (cons moz-repl-host moz-repl-port) nil nil)) + (sleep-for 0 100) + (with-current-buffer inferior-moz-buffer + (inferior-moz-mode) + (run-hooks 'inferior-moz-hook))) + (file-error + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'describe-function 'inferior-moz-start-process) (interactive-p)) + (with-current-buffer (help-buffer) + (insert "Can't start MozRepl, the error message was:\n\n " + (error-message-string err) + "\n" + "\nA possible reason is that you have not installed" + "\nthe MozRepl add-on to Firefox or that you have not" + "\nstarted it. You start it from the menus in Firefox:" + "\n\n Tools / MozRepl / Start" + "\n" + "\nSee ") + (insert-text-button + "MozRepl home page" + 'action (lambda (button) + (browse-url mozrepl-home-page)) + 'help-echo mozrepl-home-page + 'face 'button) + (insert + " for more information." + "\n" + "\nMozRepl is also available directly from Firefox add-on" + "\npages, but is updated less frequently there.") + )) + (error "Can't start MozRepl")))) + +(provide 'moz) + +;;; moz.el ends here diff --git a/emacs/nxhtml/related/mozadd.el b/emacs/nxhtml/related/mozadd.el new file mode 100644 index 0000000..a303fe4 --- /dev/null +++ b/emacs/nxhtml/related/mozadd.el @@ -0,0 +1,369 @@ +;;; mozadd.el --- Additional functionality for MozRepl +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-07-22 Wed +(defconst mozadd:version "0.2") ;; Version: +;; Last-Updated: 2009-08-04 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `cc-cmds', `cc-defs', `cc-engine', `cc-vars', `comint', `json', + ;; `moz', `regexp-opt', `ring'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Live tracking of editing changes, see +;; `mozadd-mirror-mode' +;; `mozadd-refresh-edited-on-save-mode' +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(require 'moz) +(require 'json) + +(defun mozadd-warning (format-string &rest args) + (let ((str (apply 'format format-string args))) + (message "%s" (propertize str 'face 'secondary-selection)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Refresh Firefox after save etc + +;; Partly after an idea on EmacsWiki + +(defvar mozadd-edited-buffer nil) +(setq mozadd-edited-buffer nil) + +;;;###autoload +(define-minor-mode mozadd-refresh-edited-on-save-mode + "Refresh mozadd edited file in Firefox when saving file. +The mozadd edited file is the file in the last buffer visited in +`mozadd-mirror-mode'. + +You can use this for example when you edit CSS files. + +The mozadd edited file must be shown in Firefox and visible." + :lighter "MozRefresh" + (if mozadd-refresh-edited-on-save-mode + (add-hook 'after-save-hook 'mozadd-queue-reload-mozilla-edited-file nil t) + (remove-hook 'after-save-hook 'mozadd-queue-reload-mozilla-edited-file t))) +(put 'mozadd-refresh-edited-on-save-mode 'permanent-local t) + +;;;###autoload +(define-globalized-minor-mode global-mozadd-refresh-edited-on-save-mode + mozadd-refresh-edited-on-save-mode + (lambda () + (when (or (derived-mode-p 'css-mode) + (mozadd-html-buffer-file-p)) + (mozadd-refresh-edited-on-save-mode 1)))) + +(defun mozadd-queue-reload-mozilla-edited-file () + "Reload edited file." + (when (buffer-live-p mozadd-edited-buffer) + (if (buffer-modified-p mozadd-edited-buffer) + (mozadd-warning "Mozadd: Edited buffer %s is not saved, can't reload browser." + (buffer-name mozadd-edited-buffer)) + (mozadd-add-queue-get-mirror-location) + (mozadd-add-task-1 'mozadd-send-refresh-edited-to-mozilla)))) + +(defun mozadd-send-refresh-edited-to-mozilla () + "Update the remote mozrepl instance" + (with-current-buffer mozadd-edited-buffer + (if (not (mozadd-edited-file-is-shown)) + (mozadd-warning "Mozadd: Edited buffer %s is not shown, can't reload browser." + (buffer-name mozadd-edited-buffer)) + (comint-send-string (inferior-moz-process) + "setTimeout(BrowserReload(), \"1000\");"))) + (mozadd-exec-next)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mirror html buffer in Firefox + +;; Partly after an idea on +;; http://people.internetconnection.net/2009/02/interactive-html-development-in-emacs/ + +;; Fun, it kind of works, but is perhaps totally useless .... - slow +;; and maybe scrolling... - but the file I am testing with have 3000 +;; lines... + +;; Fix-me: How do you get the currently shown page in Firefox? + +(defun mozadd-perhaps-start () + "Start if MozRepl if not running. Return message if not ok." + (unless (buffer-live-p inferior-moz-buffer) + (condition-case err + (progn + (inferior-moz-start-process) + nil) + (error (error-message-string err))))) + +(defvar mozadd-mirror-location nil) +(make-variable-buffer-local 'mozadd-mirror-location) +(put 'mozadd-mirror-location 'permanent-local t) + +(defvar mozadd-initial-mirror-location nil) +(make-variable-buffer-local 'mozadd-initial-mirror-location) +(put 'mozadd-initial-mirror-location 'permanent-local t) + +;;(mozadd-get-comint-string-part "\"hi\" there") +(defun mozadd-get-comint-string-part (comint-output) + (save-match-data + (if (string-match "^\".*?\"" comint-output) + (match-string 0 comint-output) + comint-output))) + +(defun mozadd-get-initial-mirror-location (comint-output) + ;;(message "mozadd-get-initial-mirror-location %S" comint-output) + (with-current-buffer mozadd-edited-buffer + (setq mozadd-initial-mirror-location (mozadd-get-comint-string-part comint-output))) + (mozadd-exec-next) + comint-output) + +(defun mozadd-get-mirror-location (comint-output) + ;;(message "mozadd-get-mirror-location %S" comint-output) + (with-current-buffer mozadd-edited-buffer + (setq mozadd-mirror-location (mozadd-get-comint-string-part comint-output))) + (mozadd-exec-next) + comint-output) + +(defun mozadd-add-queue-get-mirror-location () + (mozadd-add-task "content.location.href" 'mozadd-get-mirror-location)) + +(defun mozadd-skip-output-until-prompt (comint-output) + ;;(message "mozadd-skip-output-until-prompt %S" comint-output) + (if (not (string-match-p "\\(\\w+\\)> $" comint-output)) + "" + ;;(message "done recieve %s" (current-time-string)) + (mozadd-exec-next) + comint-output + "" + )) + +(defun mozadd-queue-send-buffer-content-to-mozilla (buffer) + (mozadd-add-queue-get-mirror-location) + (setq mozadd-edited-buffer buffer) + (mozadd-add-task-1 'mozadd-send-buffer-content-to-mozilla)) + +(defun mozadd-edited-file-is-shown () + (with-current-buffer mozadd-edited-buffer + (string= mozadd-mirror-location mozadd-initial-mirror-location))) + +(defvar mozadd-xml-path-outline-style "2px solid red") +(defun mozadd-send-buffer-content-to-mozilla () + "Update the remote mozrepl instance" + (with-current-buffer mozadd-edited-buffer + (if (mozadd-edited-file-is-shown) + (mozadd-requeue-me-as-task + (concat "content.document.body.innerHTML=" + (json-encode + (save-restriction + (widen) + (let ((where-points nil) + (str "") + (p1 (point-min)) + p2) + ;; If nxml-where-mode is on add corresponding outline style. + (when (and (boundp 'nxml-where-mode) nxml-where-mode) + (mapc (lambda (ovl) + (when (overlay-get ovl 'nxml-where) + (when (/= ?/ (1+ (char-after (overlay-start ovl)))) + (push (1- (overlay-end ovl)) where-points)))) + (overlays-in (point-min) (point-max))) + (setq where-points (sort where-points '<))) + (dolist (p2 where-points) + (setq str (concat str + (buffer-substring-no-properties p1 + p2))) + (setq str (concat str + " style=\"outline: " + mozadd-xml-path-outline-style + "\"")) + (setq p1 p2) + ) + (setq str (concat str + (buffer-substring-no-properties p1 + (point-max)))) + str)) + ) + ";") + 'mozadd-skip-output-until-prompt) + (mozadd-skip-current-task)) + ;; Timer to avoid looping + (run-with-idle-timer 0 nil 'mozadd-maybe-exec-next) + )) + +(defvar mozadd-current-task nil) +(setq mozadd-current-task nil) + +(defvar mozadd-task-queue nil) +(setq mozadd-task-queue nil) +;;(mozadd-add-task "content.location.href" 'mozadd-get-initial-mirror-location) +;;(mozadd-add-task "hi" 1) +;;(mozadd-add-task "hm" 2) + +(defun mozadd-clear-exec-queue () + (setq mozadd-current-task nil) + (setq mozadd-task-queue nil) + (when (buffer-live-p inferior-moz-buffer) + (with-current-buffer inferior-moz-buffer + (dolist (fun (buffer-local-value 'comint-preoutput-filter-functions (current-buffer))) + (remove-hook 'comint-preoutput-filter-functions fun t))))) + +(defun mozadd-add-task (input task) + (mozadd-add-task-1 (list input task))) + +(defun mozadd-add-task-1 (task) + (setq mozadd-task-queue (cons task mozadd-task-queue)) + (setq mozadd-task-queue (reverse mozadd-task-queue)) + ;;(message "add-task: mozadd-task-queue=%S, current=%s" mozadd-task-queue mozadd-current-task) + (mozadd-maybe-exec-next)) + +(defun mozadd-maybe-exec-next () + ;;(message "mozadd-maybe-exec-next, current=%s" mozadd-current-task) + (unless mozadd-current-task + (mozadd-exec-next))) + +(defun mozadd-exec-next () + (when mozadd-current-task + (let* ((old-task mozadd-current-task) ;;(pop mozadd-task-queue)) + (old-filter (when (listp old-task) (nth 1 old-task)))) + (when (and old-filter (buffer-live-p inferior-moz-buffer)) + (with-current-buffer inferior-moz-buffer + (remove-hook 'comint-preoutput-filter-functions old-filter t))))) + (setq mozadd-current-task nil) + (when mozadd-task-queue + (let* ((this (pop mozadd-task-queue)) + (input (when (listp this) (nth 0 this))) + (task (when (listp this) (nth 1 this))) + ) + (setq mozadd-current-task this) + ;;(message "EXEC: %s" this) + (if (not (listp this)) + (funcall this) + (when (buffer-live-p inferior-moz-buffer) + (with-current-buffer inferior-moz-buffer + (add-hook 'comint-preoutput-filter-functions task nil t))) + (comint-send-string (inferior-moz-process) input))))) + +(defun mozadd-skip-current-task () + ;;(message "mozadd-skip-current-task") + ;;(pop mozadd-task-queue) + (setq mozadd-current-task nil)) + +(defun mozadd-requeue-me-as-task (input task) + (mozadd-skip-current-task) + ;;(message "mozadd-requeue-me-as-task %S %S" input task) + (setq mozadd-task-queue (cons (list input task) mozadd-task-queue))) + +(defcustom mozadd-browseable-file-extensions + '("html" "htm" "xhtml") + "File extensions possibly viewable in a web browser." + :type '(repeat (string :tag "File extension (without leading dot)")) + :group 'mozadd) + +(defun mozadd-html-buffer-file-p () + "Return non-nil if buffer file is viewable in a web browser." + (when (buffer-file-name) + (member (file-name-extension (buffer-file-name)) + mozadd-browseable-file-extensions))) + +;;;###autoload +(define-minor-mode mozadd-mirror-mode + "Mirror content of current file buffer immediately in Firefox. +When you turn on this mode the file will be opened in Firefox. +Every change you make in the buffer will trigger a redraw in +Firefox - regardless of if you save the file or not. + +For the mirroring to work the edited file must be shown in +Firefox and visible. + +If `nxml-where-mode' is on the marks will also be shown in +Firefox as CSS outline style. You can customize the style +through the option `mozadd-xml-path-outline-style'. + +See also `mozadd-refresh-edited-on-save-mode'." + nil + :lighter " MozMirror" + :group 'mozadd + (if mozadd-mirror-mode + (unless (catch 'ok + (unless (mozadd-html-buffer-file-p) + (mozadd-warning "You can only mirror html file buffers") + (throw 'ok nil)) + (when (buffer-modified-p) + (mozadd-warning "Please save buffer first") + (throw 'ok nil)) + (let ((msg (mozadd-perhaps-start))) + (when msg + (mozadd-warning msg) + (throw 'ok nil))) + (mozadd-clear-exec-queue) + (setq mozadd-edited-buffer (current-buffer)) + (mozadd-add-task (concat "content.location.href = " + "\"file:///" (buffer-file-name) "\";") + 'mozadd-get-initial-mirror-location) + (add-hook 'after-change-functions 'mozadd-update-mozilla t t) + (add-hook 'nxhtml-where-hook 'mozadd-update-mozilla t t) + (add-hook 'post-command-hook 'mozadd-edited-buffer-post-command) + t) + (setq mozadd-mirror-mode nil)) + (setq mozadd-edited-buffer nil) + (remove-hook 'post-command-hook 'mozadd-edited-buffer-post-command) + (remove-hook 'nxhtml-where-hook 'mozadd-update-mozilla t) + (remove-hook 'after-change-functions 'mozadd-update-mozilla t))) +(put 'mozadd-mirror-mode 'permanent-local t) + +;;;###autoload +(define-globalized-minor-mode global-mozadd-mirror-mode mozadd-mirror-mode + (lambda () + (when (mozadd-html-buffer-file-p) + (mozadd-mirror-mode 1)))) + +(defun mozadd-edited-buffer-post-command () + "Check if we are in a new edited buffer." + (when mozadd-mirror-mode + (setq mozadd-edited-buffer (current-buffer)))) + + +(defvar mozadd-buffer-content-to-mozilla-timer nil) + +(defun mozadd-update-mozilla (&rest ignored) + (when (timerp mozadd-buffer-content-to-mozilla-timer) + (cancel-timer mozadd-buffer-content-to-mozilla-timer)) + (setq mozadd-buffer-content-to-mozilla-timer + (run-with-idle-timer 1 nil 'mozadd-queue-send-buffer-content-to-mozilla (current-buffer)))) +(put 'mozadd-update-mozilla 'permanent-local-hook t) + + +(provide 'mozadd) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mozadd.el ends here diff --git a/emacs/nxhtml/related/php-imenu.el b/emacs/nxhtml/related/php-imenu.el new file mode 100644 index 0000000..560bac0 --- /dev/null +++ b/emacs/nxhtml/related/php-imenu.el @@ -0,0 +1,174 @@ +;;; php-imenu.el --- object-oriented, hierarchical imenu for PHP +;;; +;;; Maintainer: Marcel Cary <marcel-cary of care2.com> +;;; Keywords: php languages oop +;;; Created: 2008-06-23 +;;; Modified: 2008-07-18 +;;; X-URL: http://www.oak.homeunix.org/~marcel/blog/articles/2008/07/14/nested-imenu-for-php +;;; +;;; Copyright (C) 2008 Marcel Cary +;;; +;;; License +;;; +;;; 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +;;; +;;; +;;; Usage +;;; +;;; Rename this file to php-imenu.el if it isn't already then place it in +;;; your Emacs lisp path (eg. site-lisp) and add to your .emacs file: +;;; +;;;--------------cut here------------------------------------------- +; ;; Load the php-imenu index function +; (autoload 'php-imenu-create-index "php-imenu" nil t) +; ;; Add the index creation function to the php-mode-hook +; (add-hook 'php-mode-user-hook 'php-imenu-setup) +; (defun php-imenu-setup () +; (setq imenu-create-index-function (function php-imenu-create-index)) +; ;; uncomment if you prefer speedbar: +; ;(setq php-imenu-alist-postprocessor (function reverse)) +; (imenu-add-menubar-index) +; ) +;;;----------------end here-------------------------------------------- +;;; +;;; Commentary +;;; +;;; Refines php-mode's imenu support. Imenu provides a menubar entry called +;;; "Index" that allows you to jump to a structural element of a file. While +;;; php-mode generates separate lists of functions and classes in imenu, +;;; php-imenu.el (this code) generates a tree of class and function +;;; definitions. It lists functions under the classes in which they're +;;; defined. The hierarchical display of functions within their classes makes +;;; the "Index" menu far more useful in understanding the high-level structure +;;; of a file, and it makes it easier to find a method when a file contains +;;; multiple by the same name. +;;; +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'imenu) +(require 'thingatpt) + +;;; Alas, speedbar shows menu items in reverse, but only below the top level. +;;; Provide a way to fix it. See sample configuration in file comment. +(defvar php-imenu-alist-postprocessor (function identity)) + +;;; Want to see properties or defines? Add an entry for them here. +(defvar php-imenu-patterns nil) +(setq php-imenu-patterns + (list + ;; types: classes and interfaces + (list + ;; for some reason [:space:] and \s- aren't matching \n + (concat "^\\s-*" + "\\(\\(abstract[[:space:]\n]+\\)?class\\|interface\\)" + "[[:space:]\n]+" + "\\([a-zA-Z0-9_]+\\)[[:space:]\n]*" ; class/iface name + "\\([a-zA-Z0-9_[:space:]\n]*\\)" ; extends / implements clauses + "[{]") + (lambda () + (message "%S %S" + (match-string-no-properties 3) + (match-string-no-properties 1)) + (concat (match-string-no-properties 3) + " - " + (match-string-no-properties 1))) + (lambda () + (save-excursion + (backward-up-list 1) + (forward-sexp) + (point)))) + ;; functions + (list + (concat "^[[:space:]\n]*" + "\\(\\(public\\|protected\\|private\\|" + "static\\|abstract\\)[[:space:]\n]+\\)*" + "function[[:space:]\n]*&?[[:space:]\n]*" + "\\([a-zA-Z0-9_]+\\)[[:space:]\n]*" ; function name + "[(]") + (lambda () + (concat (match-string-no-properties 3) "()")) + (lambda () + (save-excursion + (backward-up-list 1) + (forward-sexp) + (when (not (looking-at "\\s-*;")) + (forward-sexp)) + (point)))) + )) + +;;; Global variable to pass to imenu-progress-message in multiple functions +(defvar php-imenu-prev-pos nil) + +;;; An implementation of imenu-create-index-function +(defun php-imenu-create-index () + (let (prev-pos) + (imenu-progress-message php-imenu-prev-pos 0) + (let ((result (php-imenu-create-index-helper (point-min) (point-max) nil))) + ;(message "bye %S" result) + (imenu-progress-message php-imenu-prev-pos 100) + result))) + +(defun php-imenu-create-index-helper (min max name) + (let ((combined-pattern + (concat "\\(" + (mapconcat + (function (lambda (pat) (first pat))) + php-imenu-patterns "\\)\\|\\(") + "\\)")) + (index-alist '())) + (goto-char min) + (save-match-data + (while (re-search-forward combined-pattern max t) + (let ((pos (set-marker (make-marker) (match-beginning 0))) + (min (match-end 0)) + (pat (save-excursion + (goto-char (match-beginning 0)) + (find-if (function + (lambda (pat) (looking-at (first pat)))) + php-imenu-patterns)))) + (when (not pat) + (message "php-imenu: How can no pattern get us here! %S" pos)) + (when (and pat + (not (php-imenu-in-string-p)) + ) + (let* ((name (funcall (second pat))) + (max (funcall (third pat))) + (children (php-imenu-create-index-helper min max name))) + ;; should validate max: what happens if unmatched curly? + ;(message "%S %S %S" nm name (mapcar (function first) children)) + (if (equal '() children) + (push (cons name pos) index-alist) + (push (cons name + (funcall php-imenu-alist-postprocessor + (cons (cons "*go*" pos) + children))) + index-alist)) + )) + (imenu-progress-message php-imenu-prev-pos nil) + ))) + (reverse index-alist))) + +;;; Recognize when in quoted strings or heredoc-style string literals +(defun php-imenu-in-string-p () + (save-match-data + (or (in-string-p) + (let ((pt (point))) + (save-excursion + (and (re-search-backward "<<<\\([A-Za-z0-9_]+\\)$" nil t) + (not (re-search-forward (concat "^" + (match-string-no-properties 1) + ";$") + pt t)))))))) diff --git a/emacs/nxhtml/related/php-mode.el b/emacs/nxhtml/related/php-mode.el new file mode 100644 index 0000000..a25fb82 --- /dev/null +++ b/emacs/nxhtml/related/php-mode.el @@ -0,0 +1,1231 @@ +;;; php-mode.el --- major mode for editing PHP code + +;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad +;; 2008 Aaron S. Hawley + +;; Maintainer: Aaron S. Hawley <ashawley at users.sourceforge.net> +;; Author: Turadg Aleahmad, 1999-2004 +;; Keywords: php languages oop +;; Created: 1999-05-17 +;; Modified: 2008-11-28 Fri +;; X-URL: http://php-mode.sourceforge.net/ + +(defconst php-mode-version-number "1.5.0-nxhtml-1.94" + "PHP Mode version number.") + +;;; License + +;; 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 3 +;; of the License, 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 this file; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +;;; Usage + +;; Put this file in your Emacs lisp path (eg. site-lisp) and add to +;; your .emacs file: +;; +;; (require 'php-mode) + +;; To use abbrev-mode, add lines like this: +;; (add-hook 'php-mode-hook +;; '(lambda () (define-abbrev php-mode-abbrev-table "ex" "extends"))) + +;; To make php-mode compatible with html-mode, see http://php-mode.sf.net + +;; Many options available under Help:Customize +;; Options specific to php-mode are in +;; Programming/Languages/Php +;; Since it inherits much functionality from c-mode, look there too +;; Programming/Languages/C + +;;; Commentary: + +;; PHP mode is a major mode for editing PHP 3 and 4 source code. It's +;; an extension of C mode; thus it inherits all C mode's navigation +;; functionality. But it colors according to the PHP grammar and indents +;; according to the PEAR coding guidelines. It also includes a couple +;; handy IDE-type features such as documentation search and a source +;; and class browser. + +;;; Contributors: (in chronological order) + +;; Juanjo, Torsten Martinsen, Vinai Kopp, Sean Champ, Doug Marcey, +;; Kevin Blake, Rex McMaster, Mathias Meyer, Boris Folgmann, Roland +;; Rosenfeld, Fred Yankowski, Craig Andrews, John Keller, Ryan +;; Sammartino, ppercot, Valentin Funk, Stig Bakken, Gregory Stark, +;; Chris Morris, Nils Rennebarth, Gerrit Riessen, Eric Mc Sween, +;; Ville Skytta, Giacomo Tesio, Lennart Borgman, Stefan Monnier, +;; Aaron S. Hawley, Ian Eure, Bill Lovett, Dias Badekas, David House + +;;; Changelog: + +;; 1.5.0-nxhtml-1.88 (Lennart Borgman) +;; Don't indent heredoc end mark +;; 1.5.0-nxhtml-1.61 (Lennart Borgman) +;; Added php-mode-to-use. +;; Made underscore be part of identifiers. +;; Remove php-mode-to. +;; Make the indentation check only on current line. +;; Warn only once per session about indentation. +;; Tell if can't complete in `php-complete-function'. +;; Move back point after checking indentation in +;; `php-check-html-for-indentation'. +;; Add `c-at-vsemi-p-fn' etc after advice from Alan Mackenzie. +;; +;; 1.5 +;; Support function keywords like public, private and the ampersand +;; character for function-based commands. Support abstract, final, +;; static, public, private and protected keywords in Imenu. Fix +;; reversed order of Imenu entries. Use font-lock-preprocessor-face +;; for PHP and ASP tags. Make php-mode-modified a literal value +;; rather than a computed string. Add date and time constants of +;; PHP. (Dias Badekas) Fix false syntax highlighting of keywords +;; because of underscore character. Change HTML indentation warning +;; to match only HTML at the beginning of the line. Fix +;; byte-compiler warnings. Clean-up whitespace and audited style +;; consistency of code. Remove conditional bindings and XEmacs code +;; that likely does nothing. +;; +;; 1.4 +;; Updated GNU GPL to version 3. Ported to Emacs 22 (CC mode +;; 5.31). M-x php-mode-version shows version. Provide end-of-defun +;; beginning-of-defun functionality. Support add-log library. +;; Fix __CLASS__ constant (Ian Eure). Allow imenu to see visibility +;; declarations -- "private", "public", "protected". (Bill Lovett) +;; +;; 1.3 +;; Changed the definition of # using a tip from Stefan +;; Monnier to correct highlighting and indentation. (Lennart Borgman) +;; Changed the highlighting of the HTML part. (Lennart Borgman) +;; +;; See the ChangeLog file included with the source package. + + +;;; Code: + +(require 'add-log) +(require 'speedbar) +(require 'font-lock) +(require 'cc-mode) +(require 'cc-langs) +(require 'custom) +(require 'etags) +(eval-when-compile + (require 'regexp-opt)) + +;; Local variables +;;;###autoload +(defgroup php nil + "Major mode `php-mode' for editing PHP code." + :prefix "php-" + :group 'languages) + +(defcustom php-default-face 'default + "Default face in `php-mode' buffers." + :type 'face + :group 'php) + +(defcustom php-speedbar-config t + "When set to true automatically configures Speedbar to observe PHP files. +Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s34]?\\)\"" + :type 'boolean + :set (lambda (sym val) + (set-default sym val) + (if (and val (boundp 'speedbar)) + (speedbar-add-supported-extension + "\\.\\(inc\\|php[s34]?\\|phtml\\)"))) + :group 'php) + +(defcustom php-mode-speedbar-open nil + "Normally `php-mode' starts with the speedbar closed. +Turning this on will open it whenever `php-mode' is loaded." + :type 'boolean + :set (lambda (sym val) + (set-default sym val) + (when val + (speedbar 1))) + :group 'php) + +(defvar php-imenu-generic-expression + '( + ("Private Methods" + "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?private\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) + ("Protected Methods" + "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?protected\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) + ("Public Methods" + "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?public\\s-+\\(?:static\\s-+\\)?function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) + ("Classes" + "^\\s-*class\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*" 1) + ("All Functions" + "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1) + ) + "Imenu generic expression for PHP Mode. See `imenu-generic-expression'." + ) + +(defcustom php-manual-url "http://www.php.net/manual/en/" + "URL at which to find PHP manual. +You can replace \"en\" with your ISO language code." + :type 'string + :group 'php) + +(defcustom php-search-url "http://www.php.net/" + "URL at which to search for documentation on a word." + :type 'string + :group 'php) + +(defcustom php-completion-file "" + "Path to the file which contains the function names known to PHP." + :type 'string + :group 'php) + +(defcustom php-manual-path "" + "Path to the directory which contains the PHP manual." + :type 'string + :group 'php) + +;;;###autoload +(defcustom php-file-patterns '("\\.php[s34]?\\'" "\\.phtml\\'" "\\.inc\\'") + "List of file patterns for which to automatically invoke `php-mode'." + :type '(repeat (regexp :tag "Pattern")) + :set (lambda (sym val) + (set-default sym val) + (let ((php-file-patterns-temp val)) + (while php-file-patterns-temp + (add-to-list 'auto-mode-alist + (cons (car php-file-patterns-temp) 'php-mode)) + (setq php-file-patterns-temp (cdr php-file-patterns-temp))))) + :group 'php) + +(defcustom php-mode-hook nil + "List of functions to be executed on entry to `php-mode'." + :type 'hook + :group 'php) + +(defcustom php-mode-pear-hook nil + "Hook called when a PHP PEAR file is opened with `php-mode'." + :type 'hook + :group 'php) + +(defcustom php-mode-force-pear nil + "Normally PEAR coding rules are enforced only when the filename contains \"PEAR.\" +Turning this on will force PEAR rules on all PHP files." + :type 'boolean + :group 'php) + +(defconst php-mode-modified "2009-08-12" + "PHP Mode build date.") + +(defun php-mode-version () + "Display string describing the version of PHP mode." + (interactive) + (message "PHP mode %s of %s" + php-mode-version-number php-mode-modified)) + +(defconst php-beginning-of-defun-regexp + "^\\s-*\\(?:\\(?:abstract\\|final\\|private\\|protected\\|public\\|static\\)\\s-+\\)*function\\s-+&?\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" + "Regular expression for a PHP function.") + +(defun php-beginning-of-defun (&optional arg) + "Move to the beginning of the ARGth PHP function from point. +Implements PHP version of `beginning-of-defun-function'." + (interactive "p") + (let ((arg (or arg 1))) + (while (> arg 0) + (re-search-backward php-beginning-of-defun-regexp + nil 'noerror) + (setq arg (1- arg))) + (while (< arg 0) + (end-of-line 1) + (let ((opoint (point))) + (beginning-of-defun 1) + (forward-list 2) + (forward-line 1) + (if (eq opoint (point)) + (re-search-forward php-beginning-of-defun-regexp + nil 'noerror)) + (setq arg (1+ arg)))))) + +(defun php-end-of-defun (&optional arg) + "Move the end of the ARGth PHP function from point. +Implements PHP befsion of `end-of-defun-function' + +See `php-beginning-of-defun'." + (interactive "p") + (php-beginning-of-defun (- (or arg 1)))) + + +(defvar php-warned-bad-indent nil) +;;(make-variable-buffer-local 'php-warned-bad-indent) + +;; Do it but tell it is not good if html tags in buffer. +(defun php-check-html-for-indentation () + (let ((html-tag-re "^\\s-*</?\\sw+.*?>") + (here (point))) + (goto-char (line-beginning-position)) + (if (or (when (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + ;; Fix-me: no idea how to check for mmm or multi-mode + (save-match-data + (not (or (re-search-forward html-tag-re (line-end-position) t) + (re-search-backward html-tag-re (line-beginning-position) t))))) + (progn + (goto-char here) + t) + (goto-char here) + (setq php-warned-bad-indent t) + ;;(setq php-warned-bad-indent nil) + (let* ((known-multi-libs '(("mumamo" mumamo (lambda () (nxhtml-mumamo))) + ("mmm-mode" mmm-mode (lambda () (mmm-mode 1))) + ("multi-mode" multi-mode (lambda () (multi-mode 1))))) + (known-names (mapcar (lambda (lib) (car lib)) known-multi-libs)) + (available-multi-libs (delq nil + (mapcar + (lambda (lib) + (when (locate-library (car lib)) lib)) + known-multi-libs))) + (available-names (mapcar (lambda (lib) (car lib)) available-multi-libs)) + (base-msg + (concat + "Indentation fails badly with mixed HTML/PHP in the HTML part in +plaín `php-mode'. To get indentation to work you must use an +Emacs library that supports 'multiple major modes' in a buffer. +Parts of the buffer will then be in `php-mode' and parts in for +example `html-mode'. Known such libraries are:\n\t" + (mapconcat 'identity known-names ", ") + "\n" + (if available-multi-libs + (concat + "You have these available in your `load-path':\n\t" + (mapconcat 'identity available-names ", ") + "\n\n" + "Do you want to turn any of those on? ") + "You do not have any of those in your `load-path'."))) + (is-using-multi + (catch 'is-using + (dolist (lib available-multi-libs) + (when (and (boundp (cadr lib)) + (symbol-value (cadr lib))) + (throw 'is-using t)))))) + (unless is-using-multi + (if available-multi-libs + (if (not (y-or-n-p base-msg)) + (message "Did not do indentation, but you can try again now if you want") + (let* ((name + (if (= 1 (length available-multi-libs)) + (car available-names) + ;; Minibuffer window is more than one line, fix that first: + (message "") + (completing-read "Choose multiple major mode support library: " + available-names nil t + (car available-names) + '(available-names . 1) + ))) + (mode (when name + (caddr (assoc name available-multi-libs))))) + (when mode + ;; Minibuffer window is more than one line, fix that first: + (message "") + (load name) + (funcall mode)))) + (lwarn 'php-indent :warning base-msg))) + nil)))) + +(defun php-cautious-indent-region (start end &optional quiet) + (if (or php-warned-bad-indent + (php-check-html-for-indentation)) + (funcall 'c-indent-region start end quiet))) + +(defun php-cautious-indent-line () + (if (or php-warned-bad-indent + (php-check-html-for-indentation)) + (let ((here (point)) + doit) + (move-beginning-of-line nil) + ;; Don't indent heredoc end mark + (save-match-data + (unless (looking-at "[a-zA-Z0-9_]+;\n") + (setq doit t))) + (goto-char here) + (when doit + (funcall 'c-indent-line))))) + +(defconst php-tags '("<?php" "?>" "<?" "<?=")) +(defconst php-tags-key (regexp-opt php-tags)) + +(defconst php-block-stmt-1-kwds '("do" "else" "finally" "try")) +(defconst php-block-stmt-2-kwds + '("for" "if" "while" "switch" "foreach" "elseif" "catch all")) + +(defconst php-block-stmt-1-key + (regexp-opt php-block-stmt-1-kwds)) +(defconst php-block-stmt-2-key + (regexp-opt php-block-stmt-2-kwds)) + +(defconst php-class-decl-kwds '("class" "interface")) + +(defconst php-class-key + (concat + "\\(" (regexp-opt php-class-decl-kwds) "\\)\\s-+" + (c-lang-const c-symbol-key c) ;; Class name. + "\\(\\s-+extends\\s-+" (c-lang-const c-symbol-key c) "\\)?" ;; Name of superclass. + "\\(\\s-+implements\\s-+[^{]+{\\)?")) ;; List of any adopted protocols. + + +(defun php-c-at-vsemi-p (&optional pos) + "Return t on html lines (including php region border), otherwise nil. +POS is a position on the line in question. + +This is was done due to the problem reported here: + + URL `https://answers.launchpad.net/nxhtml/+question/43320'" + (setq pos (or pos (point))) + (let ((here (point)) + ret) + (save-match-data + (goto-char pos) + (beginning-of-line) + (setq ret (looking-at + (rx + (or (seq + bol + (0+ space) + "<" + (in "a-z\\?")) + (seq + ;;(0+ anything) + (0+ not-newline) + (in "a-z\\?") + ">" + (0+ space) + eol)))))) + (goto-char here) + ret)) + +(defun php-c-vsemi-status-unknown-p () + "See `php-c-at-vsemi-p'." + ) + +;;;###autoload +(define-derived-mode php-mode c-mode "PHP" + "Major mode for editing PHP code.\n\n\\{php-mode-map}" + (c-add-language 'php-mode 'c-mode) + +;; PHP doesn't have C-style macros. +;; HACK: Overwrite this syntax with rules to match <?php and others. +;; (c-lang-defconst c-opt-cpp-start php php-tags-key) +;; (c-lang-defvar c-opt-cpp-start (c-lang-const c-opt-cpp-start)) + (set (make-local-variable 'c-opt-cpp-start) php-tags-key) +;; (c-lang-defconst c-opt-cpp-start php php-tags-key) +;; (c-lang-defvar c-opt-cpp-start (c-lang-const c-opt-cpp-start)) + (set (make-local-variable 'c-opt-cpp-prefix) php-tags-key) + + (c-set-offset 'cpp-macro 0) + +;; (c-lang-defconst c-block-stmt-1-kwds php php-block-stmt-1-kwds) +;; (c-lang-defvar c-block-stmt-1-kwds (c-lang-const c-block-stmt-1-kwds)) + (set (make-local-variable 'c-block-stmt-1-key) php-block-stmt-1-key) + +;; (c-lang-defconst c-block-stmt-2-kwds php php-block-stmt-2-kwds) +;; (c-lang-defvar c-block-stmt-2-kwds (c-lang-const c-block-stmt-2-kwds)) + (set (make-local-variable 'c-block-stmt-2-key) php-block-stmt-2-key) + + ;; Specify that cc-mode recognize Javadoc comment style + (set (make-local-variable 'c-doc-comment-style) + '((php-mode . javadoc))) + +;; (c-lang-defconst c-class-decl-kwds +;; php php-class-decl-kwds) + (set (make-local-variable 'c-class-key) php-class-key) + + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + '((php-font-lock-keywords-1 + php-font-lock-keywords-2 + ;; Comment-out the next line if the font-coloring is too + ;; extreme/ugly for you. + php-font-lock-keywords-3) + nil ; KEYWORDS-ONLY + t ; CASE-FOLD + (("_" . "w")) ; SYNTAX-ALIST + nil)) ; SYNTAX-BEGIN + (modify-syntax-entry ?# "< b" php-mode-syntax-table) + ;;(modify-syntax-entry ?_ "w" php-mode-syntax-table) + + ;; Electric behaviour must be turned off, they do not work since + ;; they can not find the correct syntax in embedded PHP. + ;; + ;; Seems to work with narrowing so let it be on if the user prefers it. + ;;(setq c-electric-flag nil) + + (setq font-lock-maximum-decoration t + case-fold-search t ; PHP vars are case-sensitive + imenu-generic-expression php-imenu-generic-expression) + + ;; Do not force newline at end of file. Such newlines can cause + ;; trouble if the PHP file is included in another file before calls + ;; to header() or cookie(). + (set (make-local-variable 'require-final-newline) nil) + (set (make-local-variable 'next-line-add-newlines) nil) + + ;; PEAR coding standards + (add-hook 'php-mode-pear-hook + (lambda () + (set (make-local-variable 'tab-width) 4) + (set (make-local-variable 'c-basic-offset) 4) + (set (make-local-variable 'indent-tabs-mode) nil) + (c-set-offset 'block-open' - ) + (c-set-offset 'block-close' 0 )) nil t) + + (if (or php-mode-force-pear + (and (stringp buffer-file-name) + (string-match "PEAR\\|pear" + (buffer-file-name)) + (string-match "\\.php$" (buffer-file-name)))) + (run-hooks 'php-mode-pear-hook)) + + (setq indent-line-function 'php-cautious-indent-line) + (setq indent-region-function 'php-cautious-indent-region) + (setq c-special-indent-hook nil) + (setq c-at-vsemi-p-fn 'php-c-at-vsemi-p) + (setq c-vsemi-status-unknown-p 'php-c-vsemi-status-unknown-p) + + (set (make-local-variable 'syntax-begin-function) + 'c-beginning-of-syntax) + (set (make-local-variable 'beginning-of-defun-function) + 'php-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) + 'php-end-of-defun) + (set (make-local-variable 'open-paren-in-column-0-is-defun-start) + nil) + (set (make-local-variable 'defun-prompt-regexp) + "^\\s-*function\\s-+&?\\s-*\\(\\(\\sw\\|\\s_\\)+\\)\\s-*") + (set (make-local-variable 'add-log-current-defun-header-regexp) + php-beginning-of-defun-regexp) + + (run-hooks 'php-mode-hook)) + +;; Make a menu keymap (with a prompt string) +;; and make it the menu bar item's definition. +(define-key php-mode-map [menu-bar] (make-sparse-keymap)) +(define-key php-mode-map [menu-bar php] + (cons "PHP" (make-sparse-keymap "PHP"))) + +;; Define specific subcommands in this menu. +(define-key php-mode-map [menu-bar php complete-function] + '("Complete function name" . php-complete-function)) +(define-key php-mode-map + [menu-bar php browse-manual] + '("Browse manual" . php-browse-manual)) +(define-key php-mode-map + [menu-bar php search-documentation] + '("Search documentation" . php-search-documentation)) + +;; Define function name completion function +(defvar php-completion-table nil + "Obarray of tag names defined in current tags table and functions known to PHP.") + +(defun php-complete-function () + "Perform function completion on the text around point. +Completes to the set of names listed in the current tags table +and the standard php functions. +The string to complete is chosen in the same way as the default +for \\[find-tag] (which see)." + (interactive) + (let ((pattern (php-get-pattern)) + beg + completion + (php-functions (php-completion-table))) + (if (not pattern) (message "Nothing to complete") + (if (not (search-backward pattern nil t)) + (message "Can't complete here") + (setq beg (point)) + (forward-char (length pattern)) + (setq completion (try-completion pattern php-functions nil)) + (cond ((eq completion t)) + ((null completion) + (message "Can't find completion for \"%s\"" pattern) + (ding)) + ((not (string= pattern completion)) + (delete-region beg (point)) + (insert completion)) + (t + (message "Making completion list...") + (with-output-to-temp-buffer "*Completions*" + (display-completion-list + (all-completions pattern php-functions))) + (message "Making completion list...%s" "done"))))))) + +(defun php-completion-table () + "Build variable `php-completion-table' on demand. +The table includes the PHP functions and the tags from the +current `tags-file-name'." + (or (and tags-file-name + (save-excursion (tags-verify-table tags-file-name)) + php-completion-table) + (let ((tags-table + (if (and tags-file-name + (functionp 'etags-tags-completion-table)) + (with-current-buffer (get-file-buffer tags-file-name) + (etags-tags-completion-table)) + nil)) + (php-table + (cond ((and (not (string= "" php-completion-file)) + (file-readable-p php-completion-file)) + (php-build-table-from-file php-completion-file)) + (php-manual-path + (php-build-table-from-path php-manual-path)) + (t nil)))) + (unless (or php-table tags-table) + (error + (concat "No TAGS file active nor are " + "`php-completion-file' or `php-manual-path' set"))) + (when tags-table + ;; Combine the tables. + (mapatoms (lambda (sym) (intern (symbol-name sym) php-table)) + tags-table)) + (setq php-completion-table php-table)))) + +(defun php-build-table-from-file (filename) + (let ((table (make-vector 1022 0)) + (buf (find-file-noselect filename))) + (save-excursion + (set-buffer buf) + (goto-char (point-min)) + (while (re-search-forward + "^\\([-a-zA-Z0-9_.]+\\)\n" + nil t) + (intern (buffer-substring (match-beginning 1) (match-end 1)) + table))) + (kill-buffer buf) + table)) + +(defun php-build-table-from-path (path) + (let ((table (make-vector 1022 0)) + (files (directory-files + path + nil + "^function\\..+\\.html$"))) + (mapc (lambda (file) + (string-match "\\.\\([-a-zA-Z_0-9]+\\)\\.html$" file) + (intern + (replace-regexp-in-string + "-" "_" (substring file (match-beginning 1) (match-end 1)) t) + table)) + files) + table)) + +;; Find the pattern we want to complete +;; find-tag-default from GNU Emacs etags.el +(defun php-get-pattern () + (save-excursion + (while (looking-at "\\sw\\|\\s_") + (forward-char 1)) + (if (or (re-search-backward "\\sw\\|\\s_" + (save-excursion (beginning-of-line) (point)) + t) + (re-search-forward "\\(\\sw\\|\\s_\\)+" + (save-excursion (end-of-line) (point)) + t)) + (progn (goto-char (match-end 0)) + (buffer-substring-no-properties + (point) + (progn (forward-sexp -1) + (while (looking-at "\\s'") + (forward-char 1)) + (point)))) + nil))) + +(defun php-show-arglist () + (interactive) + (let* ((tagname (php-get-pattern)) + (buf (find-tag-noselect tagname nil nil)) + arglist) + (save-excursion + (set-buffer buf) + (goto-char (point-min)) + (when (re-search-forward + (format "function\\s-+%s\\s-*(\\([^{]*\\))" tagname) + nil t) + (setq arglist (buffer-substring-no-properties + (match-beginning 1) (match-end 1))))) + (if arglist + (message "Arglist for %s: %s" tagname arglist) + (message "Unknown function: %s" tagname)))) + +;; Define function documentation function +(defun php-search-documentation () + "Search PHP documentation for the word at point." + (interactive) + (browse-url (concat php-search-url (current-word t)))) + +;; Define function for browsing manual +(defun php-browse-manual () + "Bring up manual for PHP." + (interactive) + (browse-url php-manual-url)) + +;; Define shortcut +(define-key php-mode-map + "\C-c\C-f" + 'php-search-documentation) + +;; Define shortcut +(define-key php-mode-map + [(meta tab)] + 'php-complete-function) + +;; Define shortcut +(define-key php-mode-map + "\C-c\C-m" + 'php-browse-manual) + +;; Define shortcut +(define-key php-mode-map + '[(control .)] + 'php-show-arglist) + +;; Use the Emacs standard indentation binding. This may upset c-mode +;; which does not follow this at the moment, but I see no better +;; choice. +(define-key php-mode-map [?\t] 'indent-for-tab-command) + + +(defconst php-constants + (eval-when-compile + (regexp-opt + '(;; core constants + "__LINE__" "__FILE__" + "__FUNCTION__" "__CLASS__" "__METHOD__" + "PHP_OS" "PHP_VERSION" + "TRUE" "FALSE" "NULL" + "E_ERROR" "E_NOTICE" "E_PARSE" "E_WARNING" "E_ALL" "E_STRICT" + "E_USER_ERROR" "E_USER_WARNING" "E_USER_NOTICE" + "DEFAULT_INCLUDE_PATH" "PEAR_INSTALL_DIR" "PEAR_EXTENSION_DIR" + "PHP_BINDIR" "PHP_LIBDIR" "PHP_DATADIR" "PHP_SYSCONFDIR" + "PHP_LOCALSTATEDIR" "PHP_CONFIG_FILE_PATH" + "PHP_EOL" + + ;; date and time constants + "DATE_ATOM" "DATE_COOKIE" "DATE_ISO8601" + "DATE_RFC822" "DATE_RFC850" "DATE_RFC1036" "DATE_RFC1123" + "DATE_RFC2822" "DATE_RFC3339" + "DATE_RSS" "DATE_W3C" + + ;; from ext/standard: + "EXTR_OVERWRITE" "EXTR_SKIP" "EXTR_PREFIX_SAME" + "EXTR_PREFIX_ALL" "EXTR_PREFIX_INVALID" "SORT_ASC" "SORT_DESC" + "SORT_REGULAR" "SORT_NUMERIC" "SORT_STRING" "ASSERT_ACTIVE" + "ASSERT_CALLBACK" "ASSERT_BAIL" "ASSERT_WARNING" + "ASSERT_QUIET_EVAL" "CONNECTION_ABORTED" "CONNECTION_NORMAL" + "CONNECTION_TIMEOUT" "M_E" "M_LOG2E" "M_LOG10E" "M_LN2" + "M_LN10" "M_PI" "M_PI_2" "M_PI_4" "M_1_PI" "M_2_PI" + "M_2_SQRTPI" "M_SQRT2" "M_SQRT1_2" "CRYPT_SALT_LENGTH" + "CRYPT_STD_DES" "CRYPT_EXT_DES" "CRYPT_MD5" "CRYPT_BLOWFISH" + "DIRECTORY_SEPARATOR" "SEEK_SET" "SEEK_CUR" "SEEK_END" + "LOCK_SH" "LOCK_EX" "LOCK_UN" "LOCK_NB" "HTML_SPECIALCHARS" + "HTML_ENTITIES" "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" + "INFO_GENERAL" "INFO_CREDITS" "INFO_CONFIGURATION" + "INFO_ENVIRONMENT" "INFO_VARIABLES" "INFO_LICENSE" "INFO_ALL" + "CREDITS_GROUP" "CREDITS_GENERAL" "CREDITS_SAPI" + "CREDITS_MODULES" "CREDITS_DOCS" "CREDITS_FULLPAGE" + "CREDITS_QA" "CREDITS_ALL" "PHP_OUTPUT_HANDLER_START" + "PHP_OUTPUT_HANDLER_CONT" "PHP_OUTPUT_HANDLER_END" + "STR_PAD_LEFT" "STR_PAD_RIGHT" "STR_PAD_BOTH" + "PATHINFO_DIRNAME" "PATHINFO_BASENAME" "PATHINFO_EXTENSION" + "CHAR_MAX" "LC_CTYPE" "LC_NUMERIC" "LC_TIME" "LC_COLLATE" + "LC_MONETARY" "LC_ALL" "LC_MESSAGES" "LOG_EMERG" "LOG_ALERT" + "LOG_CRIT" "LOG_ERR" "LOG_WARNING" "LOG_NOTICE" "LOG_INFO" + "LOG_DEBUG" "LOG_KERN" "LOG_USER" "LOG_MAIL" "LOG_DAEMON" + "LOG_AUTH" "LOG_SYSLOG" "LOG_LPR" "LOG_NEWS" "LOG_UUCP" + "LOG_CRON" "LOG_AUTHPRIV" "LOG_LOCAL0" "LOG_LOCAL1" + "LOG_LOCAL2" "LOG_LOCAL3" "LOG_LOCAL4" "LOG_LOCAL5" + "LOG_LOCAL6" "LOG_LOCAL7" "LOG_PID" "LOG_CONS" "LOG_ODELAY" + "LOG_NDELAY" "LOG_NOWAIT" "LOG_PERROR" + + ;; Disabled by default because they slow buffer loading + ;; If you have use for them, uncomment the strings + ;; that you want colored. + ;; To compile, you may have to increase 'max-specpdl-size' + + ;; from other bundled extensions: +; "CAL_EASTER_TO_xxx" "VT_NULL" "VT_EMPTY" "VT_UI1" "VT_I2" +; "VT_I4" "VT_R4" "VT_R8" "VT_BOOL" "VT_ERROR" "VT_CY" "VT_DATE" +; "VT_BSTR" "VT_DECIMAL" "VT_UNKNOWN" "VT_DISPATCH" "VT_VARIANT" +; "VT_I1" "VT_UI2" "VT_UI4" "VT_INT" "VT_UINT" "VT_ARRAY" +; "VT_BYREF" "CP_ACP" "CP_MACCP" "CP_OEMCP" "CP_SYMBOL" +; "CP_THREAD_ACP" "CP_UTF7" "CP_UTF8" "CPDF_PM_NONE" +; "CPDF_PM_OUTLINES" "CPDF_PM_THUMBS" "CPDF_PM_FULLSCREEN" +; "CPDF_PL_SINGLE" "CPDF_PL_1COLUMN" "CPDF_PL_2LCOLUMN" +; "CPDF_PL_2RCOLUMN" "CURLOPT_PORT" "CURLOPT_FILE" +; "CURLOPT_INFILE" "CURLOPT_INFILESIZE" "CURLOPT_URL" +; "CURLOPT_PROXY" "CURLOPT_VERBOSE" "CURLOPT_HEADER" +; "CURLOPT_HTTPHEADER" "CURLOPT_NOPROGRESS" "CURLOPT_NOBODY" +; "CURLOPT_FAILONERROR" "CURLOPT_UPLOAD" "CURLOPT_POST" +; "CURLOPT_FTPLISTONLY" "CURLOPT_FTPAPPEND" "CURLOPT_NETRC" +; "CURLOPT_FOLLOWLOCATION" "CURLOPT_FTPASCII" "CURLOPT_PUT" +; "CURLOPT_MUTE" "CURLOPT_USERPWD" "CURLOPT_PROXYUSERPWD" +; "CURLOPT_RANGE" "CURLOPT_TIMEOUT" "CURLOPT_POSTFIELDS" +; "CURLOPT_REFERER" "CURLOPT_USERAGENT" "CURLOPT_FTPPORT" +; "CURLOPT_LOW_SPEED_LIMIT" "CURLOPT_LOW_SPEED_TIME" +; "CURLOPT_RESUME_FROM" "CURLOPT_COOKIE" "CURLOPT_SSLCERT" +; "CURLOPT_SSLCERTPASSWD" "CURLOPT_WRITEHEADER" +; "CURLOPT_COOKIEFILE" "CURLOPT_SSLVERSION" +; "CURLOPT_TIMECONDITION" "CURLOPT_TIMEVALUE" +; "CURLOPT_CUSTOMREQUEST" "CURLOPT_STDERR" "CURLOPT_TRANSFERTEXT" +; "CURLOPT_RETURNTRANSFER" "CURLOPT_QUOTE" "CURLOPT_POSTQUOTE" +; "CURLOPT_INTERFACE" "CURLOPT_KRB4LEVEL" +; "CURLOPT_HTTPPROXYTUNNEL" "CURLOPT_FILETIME" +; "CURLOPT_WRITEFUNCTION" "CURLOPT_READFUNCTION" +; "CURLOPT_PASSWDFUNCTION" "CURLOPT_HEADERFUNCTION" +; "CURLOPT_MAXREDIRS" "CURLOPT_MAXCONNECTS" "CURLOPT_CLOSEPOLICY" +; "CURLOPT_FRESH_CONNECT" "CURLOPT_FORBID_REUSE" +; "CURLOPT_RANDOM_FILE" "CURLOPT_EGDSOCKET" +; "CURLOPT_CONNECTTIMEOUT" "CURLOPT_SSL_VERIFYPEER" +; "CURLOPT_CAINFO" "CURLOPT_BINARYTRANSER" +; "CURLCLOSEPOLICY_LEAST_RECENTLY_USED" "CURLCLOSEPOLICY_OLDEST" +; "CURLINFO_EFFECTIVE_URL" "CURLINFO_HTTP_CODE" +; "CURLINFO_HEADER_SIZE" "CURLINFO_REQUEST_SIZE" +; "CURLINFO_TOTAL_TIME" "CURLINFO_NAMELOOKUP_TIME" +; "CURLINFO_CONNECT_TIME" "CURLINFO_PRETRANSFER_TIME" +; "CURLINFO_SIZE_UPLOAD" "CURLINFO_SIZE_DOWNLOAD" +; "CURLINFO_SPEED_DOWNLOAD" "CURLINFO_SPEED_UPLOAD" +; "CURLINFO_FILETIME" "CURLE_OK" "CURLE_UNSUPPORTED_PROTOCOL" +; "CURLE_FAILED_INIT" "CURLE_URL_MALFORMAT" +; "CURLE_URL_MALFORMAT_USER" "CURLE_COULDNT_RESOLVE_PROXY" +; "CURLE_COULDNT_RESOLVE_HOST" "CURLE_COULDNT_CONNECT" +; "CURLE_FTP_WEIRD_SERVER_REPLY" "CURLE_FTP_ACCESS_DENIED" +; "CURLE_FTP_USER_PASSWORD_INCORRECT" +; "CURLE_FTP_WEIRD_PASS_REPLY" "CURLE_FTP_WEIRD_USER_REPLY" +; "CURLE_FTP_WEIRD_PASV_REPLY" "CURLE_FTP_WEIRD_227_FORMAT" +; "CURLE_FTP_CANT_GET_HOST" "CURLE_FTP_CANT_RECONNECT" +; "CURLE_FTP_COULDNT_SET_BINARY" "CURLE_PARTIAL_FILE" +; "CURLE_FTP_COULDNT_RETR_FILE" "CURLE_FTP_WRITE_ERROR" +; "CURLE_FTP_QUOTE_ERROR" "CURLE_HTTP_NOT_FOUND" +; "CURLE_WRITE_ERROR" "CURLE_MALFORMAT_USER" +; "CURLE_FTP_COULDNT_STOR_FILE" "CURLE_READ_ERROR" +; "CURLE_OUT_OF_MEMORY" "CURLE_OPERATION_TIMEOUTED" +; "CURLE_FTP_COULDNT_SET_ASCII" "CURLE_FTP_PORT_FAILED" +; "CURLE_FTP_COULDNT_USE_REST" "CURLE_FTP_COULDNT_GET_SIZE" +; "CURLE_HTTP_RANGE_ERROR" "CURLE_HTTP_POST_ERROR" +; "CURLE_SSL_CONNECT_ERROR" "CURLE_FTP_BAD_DOWNLOAD_RESUME" +; "CURLE_FILE_COULDNT_READ_FILE" "CURLE_LDAP_CANNOT_BIND" +; "CURLE_LDAP_SEARCH_FAILED" "CURLE_LIBRARY_NOT_FOUND" +; "CURLE_FUNCTION_NOT_FOUND" "CURLE_ABORTED_BY_CALLBACK" +; "CURLE_BAD_FUNCTION_ARGUMENT" "CURLE_BAD_CALLING_ORDER" +; "CURLE_HTTP_PORT_FAILED" "CURLE_BAD_PASSWORD_ENTERED" +; "CURLE_TOO_MANY_REDIRECTS" "CURLE_UNKOWN_TELNET_OPTION" +; "CURLE_TELNET_OPTION_SYNTAX" "CURLE_ALREADY_COMPLETE" +; "DBX_MYSQL" "DBX_ODBC" "DBX_PGSQL" "DBX_MSSQL" "DBX_PERSISTENT" +; "DBX_RESULT_INFO" "DBX_RESULT_INDEX" "DBX_RESULT_ASSOC" +; "DBX_CMP_TEXT" "DBX_CMP_NUMBER" "XML_ELEMENT_NODE" +; "XML_ATTRIBUTE_NODE" "XML_TEXT_NODE" "XML_CDATA_SECTION_NODE" +; "XML_ENTITY_REF_NODE" "XML_ENTITY_NODE" "XML_PI_NODE" +; "XML_COMMENT_NODE" "XML_DOCUMENT_NODE" "XML_DOCUMENT_TYPE_NODE" +; "XML_DOCUMENT_FRAG_NODE" "XML_NOTATION_NODE" +; "XML_HTML_DOCUMENT_NODE" "XML_DTD_NODE" "XML_ELEMENT_DECL_NODE" +; "XML_ATTRIBUTE_DECL_NODE" "XML_ENTITY_DECL_NODE" +; "XML_NAMESPACE_DECL_NODE" "XML_GLOBAL_NAMESPACE" +; "XML_LOCAL_NAMESPACE" "XML_ATTRIBUTE_CDATA" "XML_ATTRIBUTE_ID" +; "XML_ATTRIBUTE_IDREF" "XML_ATTRIBUTE_IDREFS" +; "XML_ATTRIBUTE_ENTITY" "XML_ATTRIBUTE_NMTOKEN" +; "XML_ATTRIBUTE_NMTOKENS" "XML_ATTRIBUTE_ENUMERATION" +; "XML_ATTRIBUTE_NOTATION" "XPATH_UNDEFINED" "XPATH_NODESET" +; "XPATH_BOOLEAN" "XPATH_NUMBER" "XPATH_STRING" "XPATH_POINT" +; "XPATH_RANGE" "XPATH_LOCATIONSET" "XPATH_USERS" "FBSQL_ASSOC" +; "FBSQL_NUM" "FBSQL_BOTH" "FDFValue" "FDFStatus" "FDFFile" +; "FDFID" "FDFFf" "FDFSetFf" "FDFClearFf" "FDFFlags" "FDFSetF" +; "FDFClrF" "FDFAP" "FDFAS" "FDFAction" "FDFAA" "FDFAPRef" +; "FDFIF" "FDFEnter" "FDFExit" "FDFDown" "FDFUp" "FDFFormat" +; "FDFValidate" "FDFKeystroke" "FDFCalculate" +; "FRIBIDI_CHARSET_UTF8" "FRIBIDI_CHARSET_8859_6" +; "FRIBIDI_CHARSET_8859_8" "FRIBIDI_CHARSET_CP1255" +; "FRIBIDI_CHARSET_CP1256" "FRIBIDI_CHARSET_ISIRI_3342" +; "FTP_ASCII" "FTP_BINARY" "FTP_IMAGE" "FTP_TEXT" "IMG_GIF" +; "IMG_JPG" "IMG_JPEG" "IMG_PNG" "IMG_WBMP" "IMG_COLOR_TILED" +; "IMG_COLOR_STYLED" "IMG_COLOR_BRUSHED" +; "IMG_COLOR_STYLEDBRUSHED" "IMG_COLOR_TRANSPARENT" +; "IMG_ARC_ROUNDED" "IMG_ARC_PIE" "IMG_ARC_CHORD" +; "IMG_ARC_NOFILL" "IMG_ARC_EDGED" "GMP_ROUND_ZERO" +; "GMP_ROUND_PLUSINF" "GMP_ROUND_MINUSINF" "HW_ATTR_LANG" +; "HW_ATTR_NR" "HW_ATTR_NONE" "IIS_READ" "IIS_WRITE" +; "IIS_EXECUTE" "IIS_SCRIPT" "IIS_ANONYMOUS" "IIS_BASIC" +; "IIS_NTLM" "NIL" "OP_DEBUG" "OP_READONLY" "OP_ANONYMOUS" +; "OP_SHORTCACHE" "OP_SILENT" "OP_PROTOTYPE" "OP_HALFOPEN" +; "OP_EXPUNGE" "OP_SECURE" "CL_EXPUNGE" "FT_UID" "FT_PEEK" +; "FT_NOT" "FT_INTERNAL" "FT_PREFETCHTEXT" "ST_UID" "ST_SILENT" +; "ST_SET" "CP_UID" "CP_MOVE" "SE_UID" "SE_FREE" "SE_NOPREFETCH" +; "SO_FREE" "SO_NOSERVER" "SA_MESSAGES" "SA_RECENT" "SA_UNSEEN" +; "SA_UIDNEXT" "SA_UIDVALIDITY" "SA_ALL" "LATT_NOINFERIORS" +; "LATT_NOSELECT" "LATT_MARKED" "LATT_UNMARKED" "SORTDATE" +; "SORTARRIVAL" "SORTFROM" "SORTSUBJECT" "SORTTO" "SORTCC" +; "SORTSIZE" "TYPETEXT" "TYPEMULTIPART" "TYPEMESSAGE" +; "TYPEAPPLICATION" "TYPEAUDIO" "TYPEIMAGE" "TYPEVIDEO" +; "TYPEOTHER" "ENC7BIT" "ENC8BIT" "ENCBINARY" "ENCBASE64" +; "ENCQUOTEDPRINTABLE" "ENCOTHER" "INGRES_ASSOC" "INGRES_NUM" +; "INGRES_BOTH" "IBASE_DEFAULT" "IBASE_TEXT" "IBASE_UNIXTIME" +; "IBASE_READ" "IBASE_COMMITTED" "IBASE_CONSISTENCY" +; "IBASE_NOWAIT" "IBASE_TIMESTAMP" "IBASE_DATE" "IBASE_TIME" +; "LDAP_DEREF_NEVER" "LDAP_DEREF_SEARCHING" "LDAP_DEREF_FINDING" +; "LDAP_DEREF_ALWAYS" "LDAP_OPT_DEREF" "LDAP_OPT_SIZELIMIT" +; "LDAP_OPT_TIMELIMIT" "LDAP_OPT_PROTOCOL_VERSION" +; "LDAP_OPT_ERROR_NUMBER" "LDAP_OPT_REFERRALS" "LDAP_OPT_RESTART" +; "LDAP_OPT_HOST_NAME" "LDAP_OPT_ERROR_STRING" +; "LDAP_OPT_MATCHED_DN" "LDAP_OPT_SERVER_CONTROLS" +; "LDAP_OPT_CLIENT_CONTROLS" "GSLC_SSL_NO_AUTH" +; "GSLC_SSL_ONEWAY_AUTH" "GSLC_SSL_TWOWAY_AUTH" "MCAL_SUNDAY" +; "MCAL_MONDAY" "MCAL_TUESDAY" "MCAL_WEDNESDAY" "MCAL_THURSDAY" +; "MCAL_FRIDAY" "MCAL_SATURDAY" "MCAL_JANUARY" "MCAL_FEBRUARY" +; "MCAL_MARCH" "MCAL_APRIL" "MCAL_MAY" "MCAL_JUNE" "MCAL_JULY" +; "MCAL_AUGUST" "MCAL_SEPTEMBER" "MCAL_OCTOBER" "MCAL_NOVEMBER" +; "MCAL_RECUR_NONE" "MCAL_RECUR_DAILY" "MCAL_RECUR_WEEKLY" +; "MCAL_RECUR_MONTHLY_MDAY" "MCAL_RECUR_MONTHLY_WDAY" +; "MCAL_RECUR_YEARLY" "MCAL_M_SUNDAY" "MCAL_M_MONDAY" +; "MCAL_M_TUESDAY" "MCAL_M_WEDNESDAY" "MCAL_M_THURSDAY" +; "MCAL_M_FRIDAY" "MCAL_M_SATURDAY" "MCAL_M_WEEKDAYS" +; "MCAL_M_WEEKEND" "MCAL_M_ALLDAYS" "MCRYPT_" "MCRYPT_" +; "MCRYPT_ENCRYPT" "MCRYPT_DECRYPT" "MCRYPT_DEV_RANDOM" +; "MCRYPT_DEV_URANDOM" "MCRYPT_RAND" "SWFBUTTON_HIT" +; "SUNFUNCS_RET_STRING" "SUNFUNCS_RET_DOUBLE" +; "SWFBUTTON_DOWN" "SWFBUTTON_OVER" "SWFBUTTON_UP" +; "SWFBUTTON_MOUSEUPOUTSIDE" "SWFBUTTON_DRAGOVER" +; "SWFBUTTON_DRAGOUT" "SWFBUTTON_MOUSEUP" "SWFBUTTON_MOUSEDOWN" +; "SWFBUTTON_MOUSEOUT" "SWFBUTTON_MOUSEOVER" +; "SWFFILL_RADIAL_GRADIENT" "SWFFILL_LINEAR_GRADIENT" +; "SWFFILL_TILED_BITMAP" "SWFFILL_CLIPPED_BITMAP" +; "SWFTEXTFIELD_HASLENGTH" "SWFTEXTFIELD_NOEDIT" +; "SWFTEXTFIELD_PASSWORD" "SWFTEXTFIELD_MULTILINE" +; "SWFTEXTFIELD_WORDWRAP" "SWFTEXTFIELD_DRAWBOX" +; "SWFTEXTFIELD_NOSELECT" "SWFTEXTFIELD_HTML" +; "SWFTEXTFIELD_ALIGN_LEFT" "SWFTEXTFIELD_ALIGN_RIGHT" +; "SWFTEXTFIELD_ALIGN_CENTER" "SWFTEXTFIELD_ALIGN_JUSTIFY" +; "UDM_FIELD_URLID" "UDM_FIELD_URL" "UDM_FIELD_CONTENT" +; "UDM_FIELD_TITLE" "UDM_FIELD_KEYWORDS" "UDM_FIELD_DESC" +; "UDM_FIELD_DESCRIPTION" "UDM_FIELD_TEXT" "UDM_FIELD_SIZE" +; "UDM_FIELD_RATING" "UDM_FIELD_SCORE" "UDM_FIELD_MODIFIED" +; "UDM_FIELD_ORDER" "UDM_FIELD_CRC" "UDM_FIELD_CATEGORY" +; "UDM_PARAM_PAGE_SIZE" "UDM_PARAM_PAGE_NUM" +; "UDM_PARAM_SEARCH_MODE" "UDM_PARAM_CACHE_MODE" +; "UDM_PARAM_TRACK_MODE" "UDM_PARAM_PHRASE_MODE" +; "UDM_PARAM_CHARSET" "UDM_PARAM_STOPTABLE" +; "UDM_PARAM_STOP_TABLE" "UDM_PARAM_STOPFILE" +; "UDM_PARAM_STOP_FILE" "UDM_PARAM_WEIGHT_FACTOR" +; "UDM_PARAM_WORD_MATCH" "UDM_PARAM_MAX_WORD_LEN" +; "UDM_PARAM_MAX_WORDLEN" "UDM_PARAM_MIN_WORD_LEN" +; "UDM_PARAM_MIN_WORDLEN" "UDM_PARAM_ISPELL_PREFIXES" +; "UDM_PARAM_ISPELL_PREFIX" "UDM_PARAM_PREFIXES" +; "UDM_PARAM_PREFIX" "UDM_PARAM_CROSS_WORDS" +; "UDM_PARAM_CROSSWORDS" "UDM_LIMIT_CAT" "UDM_LIMIT_URL" +; "UDM_LIMIT_TAG" "UDM_LIMIT_LANG" "UDM_LIMIT_DATE" +; "UDM_PARAM_FOUND" "UDM_PARAM_NUM_ROWS" "UDM_PARAM_WORDINFO" +; "UDM_PARAM_WORD_INFO" "UDM_PARAM_SEARCHTIME" +; "UDM_PARAM_SEARCH_TIME" "UDM_PARAM_FIRST_DOC" +; "UDM_PARAM_LAST_DOC" "UDM_MODE_ALL" "UDM_MODE_ANY" +; "UDM_MODE_BOOL" "UDM_MODE_PHRASE" "UDM_CACHE_ENABLED" +; "UDM_CACHE_DISABLED" "UDM_TRACK_ENABLED" "UDM_TRACK_DISABLED" +; "UDM_PHRASE_ENABLED" "UDM_PHRASE_DISABLED" +; "UDM_CROSS_WORDS_ENABLED" "UDM_CROSSWORDS_ENABLED" +; "UDM_CROSS_WORDS_DISABLED" "UDM_CROSSWORDS_DISABLED" +; "UDM_PREFIXES_ENABLED" "UDM_PREFIX_ENABLED" +; "UDM_ISPELL_PREFIXES_ENABLED" "UDM_ISPELL_PREFIX_ENABLED" +; "UDM_PREFIXES_DISABLED" "UDM_PREFIX_DISABLED" +; "UDM_ISPELL_PREFIXES_DISABLED" "UDM_ISPELL_PREFIX_DISABLED" +; "UDM_ISPELL_TYPE_AFFIX" "UDM_ISPELL_TYPE_SPELL" +; "UDM_ISPELL_TYPE_DB" "UDM_ISPELL_TYPE_SERVER" "UDM_MATCH_WORD" +; "UDM_MATCH_BEGIN" "UDM_MATCH_SUBSTR" "UDM_MATCH_END" +; "MSQL_ASSOC" "MSQL_NUM" "MSQL_BOTH" "MYSQL_ASSOC" "MYSQL_NUM" +; "MYSQL_BOTH" "MYSQL_USE_RESULT" "MYSQL_STORE_RESULT" +; "OCI_DEFAULT" "OCI_DESCRIBE_ONLY" "OCI_COMMIT_ON_SUCCESS" +; "OCI_EXACT_FETCH" "SQLT_BFILEE" "SQLT_CFILEE" "SQLT_CLOB" +; "SQLT_BLOB" "SQLT_RDD" "OCI_B_SQLT_NTY" "OCI_SYSDATE" +; "OCI_B_BFILE" "OCI_B_CFILEE" "OCI_B_CLOB" "OCI_B_BLOB" +; "OCI_B_ROWID" "OCI_B_CURSOR" "OCI_B_BIN" "OCI_ASSOC" "OCI_NUM" +; "OCI_BOTH" "OCI_RETURN_NULLS" "OCI_RETURN_LOBS" +; "OCI_DTYPE_FILE" "OCI_DTYPE_LOB" "OCI_DTYPE_ROWID" "OCI_D_FILE" +; "OCI_D_LOB" "OCI_D_ROWID" "ODBC_TYPE" "ODBC_BINMODE_PASSTHRU" +; "ODBC_BINMODE_RETURN" "ODBC_BINMODE_CONVERT" "SQL_ODBC_CURSORS" +; "SQL_CUR_USE_DRIVER" "SQL_CUR_USE_IF_NEEDED" "SQL_CUR_USE_ODBC" +; "SQL_CONCURRENCY" "SQL_CONCUR_READ_ONLY" "SQL_CONCUR_LOCK" +; "SQL_CONCUR_ROWVER" "SQL_CONCUR_VALUES" "SQL_CURSOR_TYPE" +; "SQL_CURSOR_FORWARD_ONLY" "SQL_CURSOR_KEYSET_DRIVEN" +; "SQL_CURSOR_DYNAMIC" "SQL_CURSOR_STATIC" "SQL_KEYSET_SIZE" +; "SQL_CHAR" "SQL_VARCHAR" "SQL_LONGVARCHAR" "SQL_DECIMAL" +; "SQL_NUMERIC" "SQL_BIT" "SQL_TINYINT" "SQL_SMALLINT" +; "SQL_INTEGER" "SQL_BIGINT" "SQL_REAL" "SQL_FLOAT" "SQL_DOUBLE" +; "SQL_BINARY" "SQL_VARBINARY" "SQL_LONGVARBINARY" "SQL_DATE" +; "SQL_TIME" "SQL_TIMESTAMP" "SQL_TYPE_DATE" "SQL_TYPE_TIME" +; "SQL_TYPE_TIMESTAMP" "SQL_BEST_ROWID" "SQL_ROWVER" +; "SQL_SCOPE_CURROW" "SQL_SCOPE_TRANSACTION" "SQL_SCOPE_SESSION" +; "SQL_NO_NULLS" "SQL_NULLABLE" "SQL_INDEX_UNIQUE" +; "SQL_INDEX_ALL" "SQL_ENSURE" "SQL_QUICK" +; "X509_PURPOSE_SSL_CLIENT" "X509_PURPOSE_SSL_SERVER" +; "X509_PURPOSE_NS_SSL_SERVER" "X509_PURPOSE_SMIME_SIGN" +; "X509_PURPOSE_SMIME_ENCRYPT" "X509_PURPOSE_CRL_SIGN" +; "X509_PURPOSE_ANY" "PKCS7_DETACHED" "PKCS7_TEXT" +; "PKCS7_NOINTERN" "PKCS7_NOVERIFY" "PKCS7_NOCHAIN" +; "PKCS7_NOCERTS" "PKCS7_NOATTR" "PKCS7_BINARY" "PKCS7_NOSIGS" +; "OPENSSL_PKCS1_PADDING" "OPENSSL_SSLV23_PADDING" +; "OPENSSL_NO_PADDING" "OPENSSL_PKCS1_OAEP_PADDING" +; "ORA_BIND_INOUT" "ORA_BIND_IN" "ORA_BIND_OUT" +; "ORA_FETCHINTO_ASSOC" "ORA_FETCHINTO_NULLS" +; "PREG_PATTERN_ORDER" "PREG_SET_ORDER" "PREG_SPLIT_NO_EMPTY" +; "PREG_SPLIT_DELIM_CAPTURE" +; "PGSQL_ASSOC" "PGSQL_NUM" "PGSQL_BOTH" +; "PRINTER_COPIES" "PRINTER_MODE" "PRINTER_TITLE" +; "PRINTER_DEVICENAME" "PRINTER_DRIVERVERSION" +; "PRINTER_RESOLUTION_Y" "PRINTER_RESOLUTION_X" "PRINTER_SCALE" +; "PRINTER_BACKGROUND_COLOR" "PRINTER_PAPER_LENGTH" +; "PRINTER_PAPER_WIDTH" "PRINTER_PAPER_FORMAT" +; "PRINTER_FORMAT_CUSTOM" "PRINTER_FORMAT_LETTER" +; "PRINTER_FORMAT_LEGAL" "PRINTER_FORMAT_A3" "PRINTER_FORMAT_A4" +; "PRINTER_FORMAT_A5" "PRINTER_FORMAT_B4" "PRINTER_FORMAT_B5" +; "PRINTER_FORMAT_FOLIO" "PRINTER_ORIENTATION" +; "PRINTER_ORIENTATION_PORTRAIT" "PRINTER_ORIENTATION_LANDSCAPE" +; "PRINTER_TEXT_COLOR" "PRINTER_TEXT_ALIGN" "PRINTER_TA_BASELINE" +; "PRINTER_TA_BOTTOM" "PRINTER_TA_TOP" "PRINTER_TA_CENTER" +; "PRINTER_TA_LEFT" "PRINTER_TA_RIGHT" "PRINTER_PEN_SOLID" +; "PRINTER_PEN_DASH" "PRINTER_PEN_DOT" "PRINTER_PEN_DASHDOT" +; "PRINTER_PEN_DASHDOTDOT" "PRINTER_PEN_INVISIBLE" +; "PRINTER_BRUSH_SOLID" "PRINTER_BRUSH_CUSTOM" +; "PRINTER_BRUSH_DIAGONAL" "PRINTER_BRUSH_CROSS" +; "PRINTER_BRUSH_DIAGCROSS" "PRINTER_BRUSH_FDIAGONAL" +; "PRINTER_BRUSH_HORIZONTAL" "PRINTER_BRUSH_VERTICAL" +; "PRINTER_FW_THIN" "PRINTER_FW_ULTRALIGHT" "PRINTER_FW_LIGHT" +; "PRINTER_FW_NORMAL" "PRINTER_FW_MEDIUM" "PRINTER_FW_BOLD" +; "PRINTER_FW_ULTRABOLD" "PRINTER_FW_HEAVY" "PRINTER_ENUM_LOCAL" +; "PRINTER_ENUM_NAME" "PRINTER_ENUM_SHARED" +; "PRINTER_ENUM_DEFAULT" "PRINTER_ENUM_CONNECTIONS" +; "PRINTER_ENUM_NETWORK" "PRINTER_ENUM_REMOTE" "PSPELL_FAST" +; "PSPELL_NORMAL" "PSPELL_BAD_SPELLERS" "PSPELL_RUN_TOGETHER" +; "SID" "SID" "AF_UNIX" "AF_INET" "SOCK_STREAM" "SOCK_DGRAM" +; "SOCK_RAW" "SOCK_SEQPACKET" "SOCK_RDM" "MSG_OOB" "MSG_WAITALL" +; "MSG_PEEK" "MSG_DONTROUTE" "SO_DEBUG" "SO_REUSEADDR" +; "SO_KEEPALIVE" "SO_DONTROUTE" "SO_LINGER" "SO_BROADCAST" +; "SO_OOBINLINE" "SO_SNDBUF" "SO_RCVBUF" "SO_SNDLOWAT" +; "SO_RCVLOWAT" "SO_SNDTIMEO" "SO_RCVTIMEO" "SO_TYPE" "SO_ERROR" +; "SOL_SOCKET" "PHP_NORMAL_READ" "PHP_BINARY_READ" +; "PHP_SYSTEM_READ" "SOL_TCP" "SOL_UDP" "MOD_COLOR" "MOD_MATRIX" +; "TYPE_PUSHBUTTON" "TYPE_MENUBUTTON" "BSHitTest" "BSDown" +; "BSOver" "BSUp" "OverDowntoIdle" "IdletoOverDown" +; "OutDowntoIdle" "OutDowntoOverDown" "OverDowntoOutDown" +; "OverUptoOverDown" "OverUptoIdle" "IdletoOverUp" "ButtonEnter" +; "ButtonExit" "MenuEnter" "MenuExit" "XML_ERROR_NONE" +; "XML_ERROR_NO_MEMORY" "XML_ERROR_SYNTAX" +; "XML_ERROR_NO_ELEMENTS" "XML_ERROR_INVALID_TOKEN" +; "XML_ERROR_UNCLOSED_TOKEN" "XML_ERROR_PARTIAL_CHAR" +; "XML_ERROR_TAG_MISMATCH" "XML_ERROR_DUPLICATE_ATTRIBUTE" +; "XML_ERROR_JUNK_AFTER_DOC_ELEMENT" "XML_ERROR_PARAM_ENTITY_REF" +; "XML_ERROR_UNDEFINED_ENTITY" "XML_ERROR_RECURSIVE_ENTITY_REF" +; "XML_ERROR_ASYNC_ENTITY" "XML_ERROR_BAD_CHAR_REF" +; "XML_ERROR_BINARY_ENTITY_REF" +; "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF" +; "XML_ERROR_MISPLACED_XML_PI" "XML_ERROR_UNKNOWN_ENCODING" +; "XML_ERROR_INCORRECT_ENCODING" +; "XML_ERROR_UNCLOSED_CDATA_SECTION" +; "XML_ERROR_EXTERNAL_ENTITY_HANDLING" "XML_OPTION_CASE_FOLDING" +; "XML_OPTION_TARGET_ENCODING" "XML_OPTION_SKIP_TAGSTART" +; "XML_OPTION_SKIP_WHITE" "YPERR_BADARGS" "YPERR_BADDB" +; "YPERR_BUSY" "YPERR_DOMAIN" "YPERR_KEY" "YPERR_MAP" +; "YPERR_NODOM" "YPERR_NOMORE" "YPERR_PMAP" "YPERR_RESRC" +; "YPERR_RPC" "YPERR_YPBIND" "YPERR_YPERR" "YPERR_YPSERV" +; "YPERR_VERS" "FORCE_GZIP" "FORCE_DEFLATE" + + ;; PEAR constants +; "PEAR_ERROR_RETURN" "PEAR_ERROR_PRINT" "PEAR_ERROR_TRIGGER" +; "PEAR_ERROR_DIE" "PEAR_ERROR_CALLBACK" "OS_WINDOWS" "OS_UNIX" +; "PEAR_OS" "DB_OK" "DB_ERROR" "DB_ERROR_SYNTAX" +; "DB_ERROR_CONSTRAINT" "DB_ERROR_NOT_FOUND" +; "DB_ERROR_ALREADY_EXISTS" "DB_ERROR_UNSUPPORTED" +; "DB_ERROR_MISMATCH" "DB_ERROR_INVALID" "DB_ERROR_NOT_CAPABLE" +; "DB_ERROR_TRUNCATED" "DB_ERROR_INVALID_NUMBER" +; "DB_ERROR_INVALID_DATE" "DB_ERROR_DIVZERO" +; "DB_ERROR_NODBSELECTED" "DB_ERROR_CANNOT_CREATE" +; "DB_ERROR_CANNOT_DELETE" "DB_ERROR_CANNOT_DROP" +; "DB_ERROR_NOSUCHTABLE" "DB_ERROR_NOSUCHFIELD" +; "DB_ERROR_NEED_MORE_DATA" "DB_ERROR_NOT_LOCKED" +; "DB_ERROR_VALUE_COUNT_ON_ROW" "DB_ERROR_INVALID_DSN" +; "DB_ERROR_CONNECT_FAILED" "DB_WARNING" "DB_WARNING_READ_ONLY" +; "DB_PARAM_SCALAR" "DB_PARAM_OPAQUE" "DB_BINMODE_PASSTHRU" +; "DB_BINMODE_RETURN" "DB_BINMODE_CONVERT" "DB_FETCHMODE_DEFAULT" +; "DB_FETCHMODE_ORDERED" "DB_FETCHMODE_ASSOC" +; "DB_FETCHMODE_FLIPPED" "DB_GETMODE_ORDERED" "DB_GETMODE_ASSOC" +; "DB_GETMODE_FLIPPED" "DB_TABLEINFO_ORDER" +; "DB_TABLEINFO_ORDERTABLE" "DB_TABLEINFO_FULL" + + ))) + "PHP constants.") + +(defconst php-keywords + (eval-when-compile + (regexp-opt + ;; "class", "new" and "extends" get special treatment + ;; "case" and "default" get special treatment elsewhere + '("and" "as" "break" "continue" "declare" "do" "echo" "else" "elseif" + "endfor" "endforeach" "endif" "endswitch" "endwhile" "exit" + "extends" "for" "foreach" "global" "if" "include" "include_once" + "next" "or" "require" "require_once" "return" "static" "switch" + "then" "var" "while" "xor" "throw" "catch" "try" + "instanceof" "catch all" "finally"))) + "PHP keywords.") + +(defconst php-identifier + (eval-when-compile + '"[a-zA-Z\_\x7f-\xff][a-zA-Z0-9\_\x7f-\xff]*") + "Characters in a PHP identifier.") + +(defconst php-types + (eval-when-compile + (regexp-opt '("array" "bool" "boolean" "char" "const" "double" "float" + "int" "integer" "long" "mixed" "object" "real" + "string"))) + "PHP types.") + +(defconst php-superglobals + (eval-when-compile + (regexp-opt '("_GET" "_POST" "_COOKIE" "_SESSION" "_ENV" "GLOBALS" + "_SERVER" "_FILES" "_REQUEST"))) + "PHP superglobal variables.") + +;; Set up font locking +(defconst php-font-lock-keywords-1 + (list + ;; Fontify constants + (cons + (concat "[^_$]?\\<\\(" php-constants "\\)\\>[^_]?") + '(1 font-lock-constant-face)) + + ;; Fontify keywords + (cons + (concat "[^_$]?\\<\\(" php-keywords "\\)\\>[^_]?") + '(1 font-lock-keyword-face)) + + ;; Fontify keywords and targets, and case default tags. + (list "\\<\\(break\\|case\\|continue\\)\\>\\s-+\\(-?\\sw+\\)?" + '(1 font-lock-keyword-face) '(2 font-lock-constant-face t t)) + ;; This must come after the one for keywords and targets. + '(":" ("^\\s-+\\(\\sw+\\)\\s-+\\s-+$" + (beginning-of-line) (end-of-line) + (1 font-lock-constant-face))) + + ;; treat 'print' as keyword only when not used like a function name + '("\\<print\\s-*(" . php-default-face) + '("\\<print\\>" . font-lock-keyword-face) + + ;; Fontify PHP tag + (cons php-tags-key font-lock-preprocessor-face) + + ;; Fontify ASP-style tag + '("<\\%\\(=\\)?" . font-lock-preprocessor-face) + '("\\%>" . font-lock-preprocessor-face) + + ) + "Subdued level highlighting for PHP mode.") + +(defconst php-font-lock-keywords-2 + (append + php-font-lock-keywords-1 + (list + + ;; class declaration + '("\\<\\(class\\|interface\\)\\s-+\\(\\sw+\\)?" + (1 font-lock-keyword-face) (2 font-lock-type-face nil t)) + ;; handle several words specially, to include following word, + ;; thereby excluding it from unknown-symbol checks later + ;; FIX to handle implementing multiple + ;; currently breaks on "class Foo implements Bar, Baz" + '("\\<\\(new\\|extends\\|implements\\)\\s-+\\$?\\(\\sw+\\)" + (1 font-lock-keyword-face) (2 font-lock-type-face)) + + ;; function declaration + '("\\<\\(function\\)\\s-+&?\\(\\sw+\\)\\s-*(" + (1 font-lock-keyword-face) + (2 font-lock-function-name-face nil t)) + + ;; class hierarchy + '("\\<\\(self\\|parent\\)\\>" (1 font-lock-constant-face nil nil)) + + ;; method and variable features + '("\\<\\(private\\|protected\\|public\\)\\s-+\\$?\\sw+" + (1 font-lock-keyword-face)) + + ;; method features + '("^\\s-*\\(abstract\\|static\\|final\\)\\s-+\\$?\\sw+" + (1 font-lock-keyword-face)) + + ;; variable features + '("^\\s-*\\(static\\|const\\)\\s-+\\$?\\sw+" + (1 font-lock-keyword-face)) + )) + "Medium level highlighting for PHP mode.") + +(defconst php-font-lock-keywords-3 + (append + php-font-lock-keywords-2 + (list + + ;; <word> or </word> for HTML + ;;'("</?\\sw+[^> ]*>" . font-lock-constant-face) + ;;'("</?\\sw+[^>]*" . font-lock-constant-face) + ;;'("<!DOCTYPE" . font-lock-constant-face) + '("</?[a-z!:]+" . font-lock-constant-face) + + ;; HTML > + '("<[^>]*\\(>\\)" (1 font-lock-constant-face)) + + ;; HTML tags + '("\\(<[a-z]+\\)[[:space:]]+\\([a-z:]+=\\)[^>]*?" (1 font-lock-constant-face) (2 font-lock-constant-face) ) + '("\"[[:space:]]+\\([a-z:]+=\\)" (1 font-lock-constant-face)) + + ;; HTML entities + ;;'("&\\w+;" . font-lock-variable-name-face) + + ;; warn about '$' immediately after -> + '("\\$\\sw+->\\s-*\\(\\$\\)\\(\\sw+\\)" + (1 font-lock-warning-face) (2 php-default-face)) + + ;; warn about $word.word -- it could be a valid concatenation, + ;; but without any spaces we'll assume $word->word was meant. + '("\\$\\sw+\\(\\.\\)\\sw" + 1 font-lock-warning-face) + + ;; Warn about ==> instead of => + '("==+>" . font-lock-warning-face) + + ;; exclude casts from bare-word treatment (may contain spaces) + `(,(concat "(\\s-*\\(" php-types "\\)\\s-*)") + 1 font-lock-type-face) + + ;; PHP5: function declarations may contain classes as parameters type + `(,(concat "[(,]\\s-*\\(\\sw+\\)\\s-+&?\\$\\sw+\\>") + 1 font-lock-type-face) + + ;; Fontify variables and function calls + '("\\$\\(this\\|that\\)\\W" (1 font-lock-constant-face nil nil)) + `(,(concat "\\$\\(" php-superglobals "\\)\\W") + (1 font-lock-constant-face nil nil)) ;; $_GET & co + '("\\$\\(\\sw+\\)" (1 font-lock-variable-name-face)) ;; $variable + '("->\\(\\sw+\\)" (1 font-lock-variable-name-face t t)) ;; ->variable + '("->\\(\\sw+\\)\\s-*(" . (1 php-default-face t t)) ;; ->function_call + '("\\(\\sw+\\)::\\sw+\\s-*(?" . (1 font-lock-type-face)) ;; class::member + '("::\\(\\sw+\\>[^(]\\)" . (1 php-default-face)) ;; class::constant + '("\\<\\sw+\\s-*[[(]" . php-default-face) ;; word( or word[ + '("\\<[0-9]+" . php-default-face) ;; number (also matches word) + + ;; Warn on any words not already fontified + '("\\<\\sw+\\>" . font-lock-warning-face) + + )) + "Gauchy level highlighting for PHP mode.") + +(provide 'php-mode) + +;;; php-mode.el ends here diff --git a/emacs/nxhtml/related/readme.txt b/emacs/nxhtml/related/readme.txt new file mode 100644 index 0000000..465fbf6 --- /dev/null +++ b/emacs/nxhtml/related/readme.txt @@ -0,0 +1,7 @@ +This subdir (related/) contains files that are taken from different +places and are maybe modified to work with nXhtml. + +Please notice that major mode that are used with mumamo-mode must be a +bit more carefully written. One problem I have noticed is that some +major modes requuires that buffer-file-name is non-nil. That +assumption does not work when mumamo-mode is used! diff --git a/emacs/nxhtml/related/rhino.js b/emacs/nxhtml/related/rhino.js new file mode 100644 index 0000000..efc50f0 --- /dev/null +++ b/emacs/nxhtml/related/rhino.js @@ -0,0 +1,14 @@ +// Where you store your files +var project_folder = 'file:///c:/emacs/p/091105/EmacsW32/nxhtml/related/'; +// Browser environment wrapper over Rhino +load(project_folder + 'env.js'); +// For DOM constructing +window.location = project_folder + 'blank.html'; +var my_script = arguments[0]; +// If DOM ready +window.onload = function(){ + // Avoid recursive inclusion + if ("rhino_flymake.js" != my_script) { + load(my_script); + } +} diff --git a/emacs/nxhtml/related/smarty-mode.el b/emacs/nxhtml/related/smarty-mode.el new file mode 100644 index 0000000..ad003b5 --- /dev/null +++ b/emacs/nxhtml/related/smarty-mode.el @@ -0,0 +1,2753 @@ +;;; smarty-mode.el --- major mode for editing Smarty templates + +;; Author: Vincent DEBOUT <deboutv@free.fr> +;; Maintainer: Vincent DEBOUT <deboutv@free.fr> +;; Keywords: languages smarty templates +;; WWW: http://deboutv.free.fr/lisp/smarty/ + +;;; License + +;; 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;; Minor changes by Lennart Borgman + +(defconst smarty-version "0.0.5" + "Smarty Mode version number.") + +(defconst smarty-time-stamp "2007-11-01" + "Smarty Mode time stamp for last update.") + +(defconst smarty-is-xemacs (string-match "XEmacs" emacs-version) + "Non-nil if XEmacs is used.") + +(require 'font-lock) +(when (not smarty-is-xemacs) + (require 'cc-mode) + (require 'custom) + (require 'etags)) +(eval-when-compile + (require 'regexp-opt)) +;;(when smarty-is-xemacs + (require 'easymenu) + (require 'hippie-exp) +;;) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Customization +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;###autoload +(defgroup smarty nil + "Customizations for Smarty mode." + :prefix "smarty-" + :group 'languages) + +(defgroup smarty-mode nil + "Customizations for Smarty mode." + :group 'smarty) + +(defcustom smarty-electric-mode t + "*Non-nil enables electrification (automatic template generation). +If nil, template generators can still be invoked through key bindings and +menu. Is indicated in the modeline by \"/e\" after the mode name and can be +toggled by `\\[smarty-electric-mode]'." + :type 'boolean + :group 'smarty-mode) + +(defcustom smarty-stutter-mode t + "*Non-nil enables stuttering. +Is indicated in the modeline by \"/s\" after the mode name and can be toggled +by `\\[smarty-stutter-mode]'." + :type 'boolean + :group 'smarty-mode) + +(defgroup smarty-menu nil + "Customizations for menues." + :group 'smarty) + +(defcustom smarty-source-file-menu t + "*Non-nil means add a menu of all source files in current directory." + :type 'boolean + :group 'smarty-menu) + +(defgroup smarty-highlight nil + "Customizations for highlight." + :group 'smarty) + +(defcustom smarty-highlight-plugin-functions t + "*Non-nil means highlight the plugin functions in the buffer." + :type 'boolean + :group 'smarty-highlight) + +(defgroup smarty-template nil + "Customizations for templates." + :group 'smarty) + +(defgroup smarty-header nil + "Customizations for header template." + :group 'smarty-template) + +(defcustom smarty-file-header "" + "*String or file to insert as file header. +If the string specifies an existing file name, the contents of the file is +inserted, otherwise the string itself is inserted as file header. +Type `C-j' for newlines. +If the header contains RCS keywords, they may be written as <RCS>Keyword<RCS> +if the header needs to be version controlled. + +The following keywords for template generation are supported: + <filename> : replaced by the name of the buffer + <author> : replaced by the user name and email address + \(`user-full-name',`mail-host-address', `user-mail-address') + <login> : replaced by user login name (`user-login-name') + <company> : replaced by contents of option `smarty-company-name' + <date> : replaced by the current date + <year> : replaced by the current year + <copyright> : replaced by copyright string (`smarty-copyright-string') + <cursor> : final cursor position." + :type 'string + :group 'smarty-header) + +(defcustom smarty-file-footer "" + "*String or file to insert as file footer. +If the string specifies an existing file name, the contents of the file is +inserted, otherwise the string itself is inserted as file footer (i.e. at +the end of the file). +Type `C-j' for newlines. +The same keywords as in option `smarty-file-header' can be used." + :type 'string + :group 'smarty-header) + +(defcustom smarty-company-name "" + "*Name of company to insert in file header. +See option `smarty-file-header'." + :type 'string + :group 'smarty-header) + +(defcustom smarty-copyright-string "" + "*Copyright string to insert in file header. +Can be multi-line string (type `C-j' for newline) and contain other file +header keywords (see option `smarty-file-header')." + :type 'string + :group 'smarty-header) + +(defcustom smarty-date-format "%Y-%m-%d" + "*Specifies the date format to use in the header. +This string is passed as argument to the command `format-time-string'. +For more information on format strings, see the documentation for the +`format-time-string' command (C-h f `format-time-string')." + :type 'string + :group 'smarty-header) + +(defcustom smarty-modify-date-prefix-string "" + "*Prefix string of modification date in Smarty file header. +If actualization of the modification date is called (menu, +`\\[smarty-template-modify]'), this string is searched and the rest +of the line replaced by the current date." + :type 'string + :group 'smarty-header) + +(defcustom smarty-modify-date-on-saving nil + "*Non-nil means update the modification date when the buffer is saved. +Calls function `\\[smarty-template-modify]'). + +NOTE: Activate the new setting in a Smarty buffer by using the menu entry + \"Activate Options\"." + :type 'boolean + :group 'smarty-header) + +(defgroup smarty-misc nil + "Miscellaneous customizations." + :group 'smarty) + +(defcustom smarty-left-delimiter "{" + "Left escaping delimiter." + :type 'string + :group 'smarty-misc) + +(defcustom smarty-right-delimiter "}" + "Right escaping delimiter." + :type 'string + :group 'smarty-misc) + +(defcustom smarty-intelligent-tab t + "*Non-nil means `TAB' does indentation, word completion and tab insertion. +That is, if preceding character is part of a word then complete word, +else if not at beginning of line then insert tab, +else if last command was a `TAB' or `RET' then dedent one step, +else indent current line (i.e. `TAB' is bound to `smarty-electric-tab'). +If nil, TAB always indents current line (i.e. `TAB' is bound to +`indent-according-to-mode'). + +NOTE: Activate the new setting in a Smarty buffer by using the menu entry + \"Activate Options\"." + :type 'boolean + :group 'smarty-misc) + +(defcustom smarty-word-completion-in-minibuffer t + "*Non-nil enables word completion in minibuffer (for template prompts). + +NOTE: Activate the new setting by restarting Emacs." + :type 'boolean + :group 'smarty-misc) + +(defcustom smarty-word-completion-case-sensitive nil + "*Non-nil means word completion using `TAB' is case sensitive. +That is, `TAB' completes words that start with the same letters and case. +Otherwise, case is ignored." + :type 'boolean + :group 'smarty-misc) + +;; Functions + +(defun smarty-customize () + "Call the customize function with `smarty' as argument." + (interactive) + (customize-browse 'smarty)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Variables +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-menu-max-size 20 + "*Specifies the maximum size of a menu before splitting it into submenues.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Menu tools functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-menu-split (list title) + "Split menu LIST into several submenues, if number of +elements > `smarty-menu-max-size'." + (if (> (length list) smarty-menu-max-size) + (let ((remain list) + (result '()) + (sublist '()) + (menuno 1) + (i 0)) + (while remain + (setq sublist (cons (car remain) sublist)) + (setq remain (cdr remain)) + (setq i (+ i 1)) + (if (= i smarty-menu-max-size) + (progn + (setq result (cons (cons (format "%s %s" title menuno) + (nreverse sublist)) result)) + (setq i 0) + (setq menuno (+ menuno 1)) + (setq sublist '())))) + (and sublist + (setq result (cons (cons (format "%s %s" title menuno) + (nreverse sublist)) result))) + (nreverse result)) + list)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Source file menu +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-sources-menu nil) + +;; Create the source menu +(defun smarty-add-source-files-menu () + "Scan directory for all Smarty source files and generate menu. +The directory of the current source file is scanned." + (interactive) + (message "Scanning directory for source files ...") + (let ((newmap (current-local-map)) + (file-list (smarty-get-source-files)) + menu-list found) + ;; Create list for menu + (setq found nil) + (while file-list + (setq found t) + (setq menu-list (cons (vector (car file-list) + (list 'find-file (car file-list)) t) + menu-list)) + (setq file-list (cdr file-list))) + (setq menu-list (smarty-menu-split menu-list "Sources")) + (when found (setq menu-list (cons "--" menu-list))) + (setq menu-list (cons ["*Rescan*" smarty-add-source-files-menu t] menu-list)) + (setq menu-list (cons "Sources" menu-list)) + ;; Create menu + (easy-menu-add menu-list) + (easy-menu-define smarty-sources-menu newmap + "Smarty source files menu" menu-list)) + (message "")) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Smarty menu +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-create-mode-menu () + "Create Smarty Mode menu." + `("Smarty" + ("Templates" + ("Built-in Functions" + ["capture" smarty-template-capture t] + ["config_load" smarty-template-config-load t] + ["else" smarty-template-else t] + ["elseif" smarty-template-elseif t] + ["foreach" smarty-template-foreach t] + ["foreachelse" smarty-template-foreachelse t] + ["if" smarty-template-if t] + ["include" smarty-template-include t] + ["include_php" smarty-template-include-php t] + ["insert" smarty-template-insert t] + ["ldelim" smarty-template-ldelim t] + ["literal" smarty-template-literal t] + ["php" smarty-template-php t] + ["rdelim" smarty-template-rdelim t] + ["section" smarty-template-section t] + ["sectionelse" smarty-template-sectionelse t] + ["strip" smarty-template-strip t]) + ("Custom Functions" + ["assign" smarty-template-assign t] + ["counter" smarty-template-counter t] + ["cycle" smarty-template-cycle t] + ["debug" smarty-template-debug t] + ["eval" smarty-template-eval t] + ["fetch" smarty-template-fetch t] + ["html_checkboxes" smarty-template-html-checkboxes t] + ["html_image" smarty-template-html-image t] + ["html_options" smarty-template-html-options t] + ["html_radios" smarty-template-html-radios t] + ["html_select_date" smarty-template-html-select-date t] + ["html_select_time" smarty-template-html-select-time t] + ["html_table" smarty-template-html-table t] + ["mailto" smarty-template-mailto t] + ["math" smarty-template-math t] + ["popup" smarty-template-popup t] + ["popup_init" smarty-template-popup-init t] + ["textformat" smarty-template-textformat t]) + ("Variable Modifiers" + ["capitalize" smarty-template-capitalize t] + ["cat" smarty-template-cat t] + ["count_characters" smarty-template-count-characters t] + ["count_paragraphs" smarty-template-count-paragraphs t] + ["count_sentences" smarty-template-count-sentences t] + ["count_words" smarty-template-count-words t] + ["date_format" smarty-template-date-format t] + ["default" smarty-template-default t] + ["escape" smarty-template-escape t] + ["indent" smarty-template-indent t] + ["lower" smarty-template-lower t] + ["nl2br" smarty-template-nl2br t] + ["regex_replace" smarty-template-regex-replace t] + ["replace" smarty-template-replace t] + ["spacify" smarty-template-spacify t] + ["string_format" smarty-template-string-format t] + ["strip" smarty-template-vstrip t] + ["strip_tags" smarty-template-strip-tags t] + ["truncate" smarty-template-truncate t] + ["upper" smarty-template-upper t] + ["wordwrap" smarty-template-wordwrap t]) + ("Plugins (Functions)" + ("BlockRepeatPlugin" + ["repeat" smarty-template-repeat t] + ["str_repeat" smarty-template-str-repeat t]) + ("ClipCache" + ["clipcache" smarty-template-clipcache t] + ["include_clipcache" smarty-template-include-clipcache t]) + ("SmartyFormtool" + ["formtool_checkall" smarty-template-formtool-checkall t] + ["formtool_copy" smarty-template-formtool-copy t] + ["formtool_count_chars" smarty-template-formtool-count-chars t] + ["formtool_init" smarty-template-formtool-init t] + ["formtool_move" smarty-template-formtool-move t] + ["formtool_moveall" smarty-template-formtool-moveall t] + ["formtool_movedown" smarty-template-formtool-movedown t] + ["formtool_moveup" smarty-template-formtool-moveup t] + ["formtool_remove" smarty-template-formtool-remove t] + ["formtool_rename" smarty-template-formtool-rename t] + ["formtool_save" smarty-template-formtool-save t] + ["formtool_selectall" smarty-template-formtool-selectall t]) + ("SmartyPaginate" + ["paginate_first" smarty-template-paginate-first t] + ["paginate_last" smarty-template-paginate-last t] + ["paginate_middle" smarty-template-paginate-middle t] + ["paginate_next" smarty-template-paginate-next t] + ["paginate_prev" smarty-template-paginate-prev t]) + ("SmartyValidate" + ["validate" smarty-template-validate t])) + ("Plugins (Variable Modifiers)" + ("AlternativeDateModifierPlugin" + ["date_format2" smarty-template-date-formatto t]) + ("B2Smilies" + ["B2Smilies" smarty-template-btosmilies t]) + ("BBCodePlugin" + ["bbcode2html" smarty-template-bbcodetohtml t]) + ) + "--" + ["Insert Header" smarty-template-header t] + ["Insert Footer" smarty-template-footer t] + ["Insert Date" smarty-template-insert-date t] + ["Modify Date" smarty-template-modify t]) + "--" + ["Show Messages" smarty-show-messages :keys "C-c M-m"] + ["Smarty Mode Documentation" smarty-doc-mode :keys "C-c C-h"] + ["Version" smarty-version :keys "C-c C-v"] + "--" + ("Options" + ("Mode" + ["Electric Mode" + (progn (customize-set-variable 'smarty-electric-mode + (not smarty-electric-mode)) + (smarty-mode-line-update)) + :style toggle :selected smarty-electric-mode :keys "C-c C-m C-e"] + ["Stutter Mode" + (progn (customize-set-variable 'smarty-stutter-mode + (not smarty-stutter-mode)) + (smarty-mode-line-update)) + :style toggle :selected smarty-stutter-mode :keys "C-c C-m C-s"] + "--" + ["Customize Group..." (customize-group 'smarty-mode) t]) + ("Menu" + ["Source Menu" + (customize-set-variable 'smarty-source-file-menu + (not smarty-source-file-menu)) + :style toggle :selected smarty-source-file-menu] + "--" + ["Customize Group..." (customize-group 'smarty-menu) t]) + ("Highlight" + ["Highlight plugin functions" + (progn (customize-set-variable 'smarty-highlight-plugin-functions + (not smarty-highlight-plugin-functions))) + :style toggle :selected smarty-highlight-plugin-functions] + "--" + ["Customize Group..." (customize-group 'smarty-highlight) t]) + ("Template" + ("Header" + ["Header template..." + (customize-option 'smarty-file-header) t] + ["Footer template..." + (customize-option 'smarty-file-footer) t] + ["Company..." + (customize-option 'smarty-company-name) t] + ["Copyright..." + (customize-option 'smarty-copyright-string) t] + ["Date format..." + (customize-option 'smarty-date-format) t] + ["Modify date prefix..." + (customize-option 'smarty-modify-date-prefix-string) t] + ["Modify date on saving" + (customize-set-variable 'smarty-modify-date-on-saving + (not smarty-modify-date-on-saving)) + :style toggle :selected smarty-modify-date-on-saving] + "--" + ["Customize Group..." (customize-group 'smarty-header) t]) + "--" + ["Customize Group..." (customize-group 'smarty-template) t]) + ("Miscellaneous" + ["Left delimiter..." + (customize-option 'smarty-left-delimiter) t] + ["Right delimiter..." + (customize-option 'smarty-right-delimiter) t] + ["Use Intelligent Tab" + (progn (customize-set-variable 'smarty-intelligent-tab + (not smarty-intelligent-tab)) + (smarty-activate-customizations)) + :style toggle :selected smarty-intelligent-tab] + ["Word Completion in Minibuffer" + (progn (customize-set-variable 'smarty-word-completion-in-minibuffer + (not smarty-word-completion-in-minibuffer)) + (message "Activate new setting by saving options and restarting Emacs")) + :style toggle :selected smarty-word-completion-in-minibuffer] + ["Completion is case sensitive" + (customize-set-variable 'smarty-word-completion-case-sensitive + (not smarty-word-completion-case-sensitive)) + :style toggle :selected smarty-word-completion-case-sensitive] + "--" + ["Customize Group..." (customize-group 'smarty-misc) t]) + "--" + ["Save Options" customize-save-customized t] + ["Activate Options" smarty-activate-customizations t] + ["Browse Options..." smarty-customize t]))) + +(defvar smarty-mode-menu-list (smarty-create-mode-menu) + "Smarty Mode menu.") + +(defvar smarty-mode-map nil + "Keymap for Smarty Mode.") + +(defun smarty-update-mode-menu () + "Update Smarty Mode menu." + (interactive) + (easy-menu-remove smarty-mode-menu-list) + (setq smarty-mode-menu-list (smarty-create-mode-menu)) + (easy-menu-add smarty-mode-menu-list) + (easy-menu-define smarty-mode-menu smarty-mode-map + "Menu keymap for Smarty Mode." smarty-mode-menu-list)) + + + + +(defvar smarty-mode-hook nil) + +(defvar smarty-functions nil + "List of Smarty functions.") + +(defvar smarty-functions-regexp nil + "Regexp for Smarty functions.") + +(defconst smarty-01-functions + '("capture" "config_load" "foreach" "foreachelse" "include" + "include_php" "insert" "if" "elseif" "else" "ldelim" "rdelim" + "literal" "php" "section" "sectionelse" "strip" "assign" "counter" + "cycle" "debug" "eval" "fetch" "html_checkboxes" "html_image" + "html_options" "html_radios" "html_select_date" "html_select_time" + "html_table" "math" "mailto" "popup_init" "popup" "textformat") + "Smarty built-in & custom functions.") + +(defvar smarty-modifiers nil + "List of Smarty variable modifiers.") + +(defvar smarty-modifiers-regexp nil + "Regexp for Smarty variable modifiers.") + +(defconst smarty-01-modifiers + '("capitalize" "cat" "count_characters" "count_paragraphs" + "count_sentences" "count_words" "date_format" "default" + "escape" "indent" "lower" "nl2br" "regex_replace" "replace" + "spacify" "string_format" "strip" "strip_tags" "truncate" + "upper" "wordwrap") + "Smarty variable modifiers.") + +(defvar smarty-plugins-functions nil + "List of Smarty functions.") + +(defvar smarty-plugins-functions-regexp nil + "Regexp for Smarty functions.") + +(defconst smarty-01-plugins-functions + '("validate" "formtool_checkall" "formtool_copy" "formtool_count_chars" + "formtool_init" "formtool_move" "formtool_moveall" + "formtool_movedown" "formtool_moveup" "formtool_remove" + "formtool_rename" "formtool_save" "formtool_selectall" + "paginate_first" "paginate_last" "paginate_middle" + "paginate_next" "paginate_prev" "clipcache" "include_clipcache" + "repeat" "str_repeat") + "Smarty plugins functions.") + +(defvar smarty-plugins-modifiers nil + "List of Smarty variable modifiers.") + +(defvar smarty-plugins-modifiers-regexp nil + "Regexp for Smarty functions.") + +(defconst smarty-01-plugins-modifiers + '("B2Smilies" "bbcode2html" "date_format2") + "Smarty plugins modifiers.") + +(defconst smarty-constants + (eval-when-compile + (regexp-opt + '("TRUE" "FALSE" "NULL") t)) + "Smarty constants.") + + +;; Syntax table creation +(defvar smarty-mode-syntax-table nil + "Syntax table for smarty-mode.") + +(defvar smarty-mode-ext-syntax-table nil + "Syntax table extended by `_' used in `smarty-mode' buffers.") + +(defun smarty-create-syntax-table () + (if smarty-mode-syntax-table + () + (setq smarty-mode-syntax-table (make-syntax-table)) + + ;; Make | a punctuation character + (modify-syntax-entry ?| "." smarty-mode-syntax-table) + ;; Make " a punctuation character so highlighing works withing html strings + (modify-syntax-entry ?\" "." smarty-mode-syntax-table) + ;; define parentheses to match + (modify-syntax-entry ?\( "()" smarty-mode-syntax-table) + (modify-syntax-entry ?\) ")(" smarty-mode-syntax-table) + (modify-syntax-entry ?\[ "(]" smarty-mode-syntax-table) + (modify-syntax-entry ?\] ")[" smarty-mode-syntax-table) + (modify-syntax-entry ?\{ "(}" smarty-mode-syntax-table) + (modify-syntax-entry ?\} "){" smarty-mode-syntax-table) + ) + (set-syntax-table smarty-mode-syntax-table) + ;; extended syntax table including '_' (for simpler search regexps) + (setq smarty-mode-ext-syntax-table (copy-syntax-table smarty-mode-syntax-table)) + (modify-syntax-entry ?_ "w" smarty-mode-ext-syntax-table)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; File/directory manipulation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-directory-files (directory &optional full match) + "Call `directory-files' if DIRECTORY exists, otherwise generate error +message." + (if (not (file-directory-p directory)) + (smarty-warning-when-idle "No such directory: \"%s\"" directory) + (let ((dir (directory-files directory full match))) + (setq dir (delete "." dir)) + (setq dir (delete ".." dir)) + dir))) + +(defun smarty-get-source-files (&optional full directory) + "Get list of SMARTY source files in DIRECTORY or current directory." + (let ((mode-alist auto-mode-alist) + filename-regexp) + ;; create regular expressions for matching file names + (setq filename-regexp "\\`[^.].*\\(") + (while mode-alist + (when (eq (cdar mode-alist) 'smarty-mode) + (setq filename-regexp + (concat filename-regexp (caar mode-alist) "\\|"))) + (setq mode-alist (cdr mode-alist))) + (setq filename-regexp + (concat (substring filename-regexp 0 + (string-match "\\\\|$" filename-regexp)) "\\)")) + ;; find files + (smarty-directory-files + (or directory default-directory) full filename-regexp))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Messages reporting +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-warnings nil + "Warnings to tell the user during start up.") + +(defun smarty-run-when-idle (secs repeat function) + "Wait until idle, then run FUNCTION." + (if (fboundp 'start-itimer) + (start-itimer "smarty-mode" function secs repeat t) +; (run-with-idle-timer secs repeat function))) + ;; explicitely activate timer (necessary when Emacs is already idle) + (aset (run-with-idle-timer secs repeat function) 0 nil))) + +(defun smarty-warning-when-idle (&rest args) + "Wait until idle, then print out warning STRING and beep." + (save-match-data ;; runs in timer + (if noninteractive + (smarty-warning (apply 'format args) t) + (unless smarty-warnings + (smarty-run-when-idle .1 nil 'smarty-print-warnings)) + (setq smarty-warnings (cons (apply 'format args) smarty-warnings))))) + +(defun smarty-warning (string &optional nobeep) + "Print out warning STRING and beep." + (message (concat "WARNING: " string)) + (unless (or nobeep noninteractive) (beep))) + +(defun smarty-print-warnings () + "Print out messages in variable `smarty-warnings'." + (let ((no-warnings (length smarty-warnings))) + (setq smarty-warnings (nreverse smarty-warnings)) + (while smarty-warnings + (message (concat "WARNING: " (car smarty-warnings))) + (setq smarty-warnings (cdr smarty-warnings))) + (beep) + (when (> no-warnings 1) + (message "WARNING: See warnings in message buffer (type `C-c M-m').")))) + +(defun smarty-show-messages () + "Get *Messages* buffer to show recent messages." + (interactive) + (display-buffer " *Message-Log*")) + +(defun smarty-version () + "Echo the current version of Smarty Mode in the minibuffer." + (interactive) + (message "Smarty Mode %s (%s)" smarty-version smarty-time-stamp) + (smarty-keep-region-active)) + +;; active regions +(defun smarty-keep-region-active () + "Do whatever is necessary to keep the region active in XEmacs. +Ignore byte-compiler warnings you might see." + (and (boundp 'zmacs-region-stays) + (setq zmacs-region-stays t))) + +(defmacro smarty-prepare-search-1 (&rest body) + "Enable case insensitive search and switch to syntax table that includes '_', +then execute BODY, and finally restore the old environment. Used for +consistent searching." + `(let ((case-fold-search t) ; case insensitive search + (current-syntax-table (syntax-table)) + result + (restore-prog ; program to restore enviroment + '(progn + ;; restore syntax table + (set-syntax-table current-syntax-table)))) + ;; use extended syntax table + (set-syntax-table smarty-mode-ext-syntax-table) + ;; execute BODY safely + (setq result + (condition-case info + (progn ,@body) + (error (eval restore-prog) ; restore environment on error + (error (cadr info))))) ; pass error up + ;; restore environment + (eval restore-prog) + result)) + +(defmacro smarty-prepare-search-2 (&rest body) + "Enable case insensitive search, switch to syntax table that includes '_', +and remove `intangible' overlays, then execute BODY, and finally restore the +old environment. Used for consistent searching." + `(let ((case-fold-search t) ; case insensitive search + (current-syntax-table (syntax-table)) + result overlay-all-list overlay-intangible-list overlay + (restore-prog ; program to restore enviroment + '(progn + ;; restore syntax table + (set-syntax-table current-syntax-table) + ;; restore `intangible' overlays + (when (fboundp 'overlay-lists) + (while overlay-intangible-list + (overlay-put (car overlay-intangible-list) 'intangible t) + (setq overlay-intangible-list + (cdr overlay-intangible-list))))))) + ;; use extended syntax table + (set-syntax-table smarty-mode-ext-syntax-table) + ;; remove `intangible' overlays + (when (fboundp 'overlay-lists) + (setq overlay-all-list (overlay-lists)) + (setq overlay-all-list + (append (car overlay-all-list) (cdr overlay-all-list))) + (while overlay-all-list + (setq overlay (car overlay-all-list)) + (when (memq 'intangible (overlay-properties overlay)) + (setq overlay-intangible-list + (cons overlay overlay-intangible-list)) + (overlay-put overlay 'intangible nil)) + (setq overlay-all-list (cdr overlay-all-list)))) + ;; execute BODY safely + (setq result + (condition-case info + (progn ,@body) + (error (eval restore-prog) ; restore environment on error + (error (cadr info))))) ; pass error up + ;; restore environment + (eval restore-prog) + result)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Enabling/disabling + +(defun smarty-mode-line-update () + "Update the modeline string for Smarty major mode." + (setq mode-name (concat "Smarty" + (and (or smarty-electric-mode smarty-stutter-mode) "/") + (and smarty-electric-mode "e") + (and smarty-stutter-mode "s"))) + (force-mode-line-update t)) + +(defun smarty-electric-mode (arg) + "Toggle Smarty electric mode. +Turn on if ARG positive, turn off if ARG negative, toggle if ARG zero or nil." + (interactive "P") + (setq smarty-electric-mode + (cond ((or (not arg) (zerop arg)) (not smarty-electric-mode)) + ((> arg 0) t) (t nil))) + (smarty-mode-line-update)) + +(defun smarty-stutter-mode (arg) + "Toggle Smarty stuttering mode. +Turn on if ARG positive, turn off if ARG negative, toggle if ARG zero or nil." + (interactive "P") + (setq smarty-stutter-mode + (cond ((or (not arg) (zerop arg)) (not smarty-stutter-mode)) + ((> arg 0) t) (t nil))) + (smarty-mode-line-update)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Smarty code delimitation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-in-literal () + "Determine if point is in a Smarty literal." + (save-excursion + (let ((here (point)) + start state) + (beginning-of-line) + (setq start (point)) + (goto-char here) + (setq state (parse-partial-sexp start (point))) + (cond + ((nth 3 state) 'string) + ((nth 4 state) 'comment) + (t nil))))) + +(defun smarty-in-comment-p () + "Check if point is in a comment." + (let ((result nil) (here (point-marker)) found) + (save-excursion + (setq found (re-search-backward (regexp-quote (concat smarty-left-delimiter "*")) nil t)) + (when found + (setq result (re-search-forward (regexp-quote (concat "*" smarty-right-delimiter)) here t)) + (setq result (not result)))) + result)) + +(defun smarty-after-ldelim () + "Check that the previous character is the left delimiter." + (let ((here (point-marker)) ldelim-found ldelim-point) + (save-excursion + (setq ldelim-found (re-search-backward (regexp-quote smarty-left-delimiter) nil t)) + (re-search-forward (regexp-quote smarty-left-delimiter) here t) + (setq ldelim-point (point-marker)) + (goto-char here) + (if (and (= here ldelim-point) ldelim-found) + t + nil)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Words to expand +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-words-init () + "Initialize reserved words." + (setq smarty-functions smarty-01-functions) + (setq smarty-modifiers smarty-01-modifiers) + (setq smarty-plugins-functions smarty-01-plugins-functions) + (setq smarty-plugins-modifiers smarty-01-plugins-modifiers) + (setq smarty-functions-regexp (concat "\\<\\(" (regexp-opt smarty-functions) "\\)\\>")) + (setq smarty-modifiers-regexp (concat "\\<\\(" (regexp-opt smarty-modifiers) "\\)\\>")) + (setq smarty-plugins-functions-regexp (concat "\\<\\(" (regexp-opt smarty-plugins-functions) "\\)\\>")) + (setq smarty-plugins-modifiers-regexp (concat "\\<\\(" (regexp-opt smarty-plugins-modifiers) "\\)\\>")) + (smarty-abbrev-list-init)) + +(defvar smarty-abbrev-list nil + "Predefined abbreviations for Smarty.") + +(defun smarty-abbrev-list-init () + (setq smarty-abbrev-list + (append + (list nil) smarty-functions + (list nil) smarty-modifiers + (list nil) smarty-plugins-functions + (list nil) smarty-plugins-modifiers))) + +(defvar smarty-expand-upper-case nil) + +(defun smarty-try-expand-abbrev (old) + "Try expanding abbreviations from `smarty-abbrev-list'." + (unless old + (he-init-string (he-dabbrev-beg) (point)) + (setq he-expand-list + (let ((abbrev-list smarty-abbrev-list) + (sel-abbrev-list '())) + (while abbrev-list + ; (if (stringp (car abbrev-list)) + ; (insert (concat " " (car abbrev-list)))) + (when (or (not (stringp (car abbrev-list))) + (string-match + (concat "^" he-search-string) (car abbrev-list))) + (setq sel-abbrev-list + (cons (car abbrev-list) sel-abbrev-list))) + (setq abbrev-list (cdr abbrev-list))) + (nreverse sel-abbrev-list)))) + (while (and he-expand-list + (or (not (stringp (car he-expand-list))) + (he-string-member (car he-expand-list) he-tried-table t))) + (unless (stringp (car he-expand-list)) + (setq smarty-expand-upper-case (car he-expand-list))) + (setq he-expand-list (cdr he-expand-list))) + (if (null he-expand-list) + (progn (when old (he-reset-string)) + nil) + (he-substitute-string + (if smarty-expand-upper-case + (upcase (car he-expand-list)) + (car he-expand-list)) + t) + (setq he-expand-list (cdr he-expand-list)) + t)) + +;; initialize reserved words for Smarty Mode +(smarty-words-init) + +;; function for expanding abbrevs and dabbrevs +(defun smarty-expand-abbrev (arg)) +(fset 'smarty-expand-abbrev (make-hippie-expand-function + '(try-expand-dabbrev + try-expand-dabbrev-all-buffers + smarty-try-expand-abbrev))) + +;; function for expanding parenthesis +(defun smarty-expand-paren (arg)) +(fset 'smarty-expand-paren (make-hippie-expand-function + '(try-expand-list + try-expand-list-all-buffers))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Stuttering +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-end-comment-column 80) + +(defvar found) ;; silence compiler, dyn var + +(defun smarty-electric-tab (&optional prefix-arg) + "If preceding character is part of a word or a paren then hippie-expand, +else if right of non whitespace on line then insert tab, +else if last command was a tab or return then dedent one step or if a comment +toggle between normal indent and inline comment indent, +else indent `correctly'." + (interactive "*P") + (smarty-prepare-search-2 + (cond + ;; expand word + ((= (char-syntax (preceding-char)) ?w) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil) + (hippie-expand-only-buffers + (or (and (boundp 'hippie-expand-only-buffers) + hippie-expand-only-buffers) + '(smarty-mode)))) + (smarty-expand-abbrev prefix-arg))) + ;; expand parenthesis + ((or (= (preceding-char) ?\() (= (preceding-char) ?\))) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil)) + (smarty-expand-paren prefix-arg)))) + (setq this-command 'smarty-electric-tab))) + +(defun smarty-electric-space (count) + "Expand abbreviations and self-insert space(s)." + (interactive "p") + (let ((here (point-marker)) ldelim-found ldelim-point rdelim-found rdelim-point + delete-a) + (setq ldelim-found (re-search-backward (regexp-quote smarty-left-delimiter) nil t)) + (re-search-forward (regexp-quote smarty-left-delimiter) here t) + (setq ldelim-point (point-marker)) + (goto-char here) + (setq rdelim-found (re-search-backward (regexp-quote (concat " " smarty-right-delimiter)) nil t)) + (re-search-forward (regexp-quote (concat " " smarty-right-delimiter)) here t) + (setq rdelim-point (point-marker)) + (goto-char here) + (cond ((and (= here ldelim-point) ldelim-found) (insert (concat "ldelim" smarty-right-delimiter))) + ((and (= here rdelim-point) rdelim-found) + (re-search-backward (regexp-quote (concat " " smarty-right-delimiter)) nil t) + (delete-char 1) + (insert (concat " " smarty-left-delimiter "rdelim")) + (goto-char here)) + ((smarty-in-comment-p) + (self-insert-command count) + (cond ((>= (current-column) (+ 2 smarty-end-comment-column)) + (backward-char 1) + (skip-chars-backward "^ \t\n") + (indent-new-comment-line) + (skip-chars-forward "^ \t\n") + (forward-char 1)) + ((>= (current-column) smarty-end-comment-column) + (indent-new-comment-line)) + (t nil))) + ((or (and (>= (preceding-char) ?a) (<= (preceding-char) ?z)) + (and (>= (preceding-char) ?A) (<= (preceding-char) ?Z)) + (and (>= (preceding-char) ?0) (<= (preceding-char) ?9))) + (progn + (setq here (point-marker)) + (insert " ") + (setq delete-a t) + (if (re-search-backward "|" nil t) + (progn + (setq found (re-search-forward (regexp-quote "B2Smilies") here t)) + (if (and found (= here (point-marker))) + (replace-match "btosmilies") + (setq found (re-search-forward (regexp-quote "bbcode2html") here t)) + (if (and found (= here (point-marker))) + (replace-match "bbcodetohtml") + (setq found (re-search-forward (regexp-quote "date_format2") here t)) + (if (and found (= here (point-marker))) + (replace-match "date_formatto") + (goto-char here) + (setq delete-a nil) + (delete-char 1))))) + (goto-char here) + (setq delete-a nil) + (delete-char 1))) + (smarty-prepare-search-1 (expand-abbrev)) + (self-insert-command count) + (if (and delete-a (looking-at " ")) + (delete-char 1))) + (t (self-insert-command count))))) + +(defun smarty-electric-open-bracket (count) + "'(' --> '(', '((' --> '[', '[(' --> '{'" + (interactive "p") + (if (and smarty-stutter-mode (= count 1) (not (smarty-in-literal))) + (if (= (preceding-char) ?\() + (progn (delete-char -1) (insert-char ?\[ 1)) + (if (= (preceding-char) ?\[) + (progn (delete-char -1) (insert-char ?\{ 1)) + (insert-char ?\( 1))) + (self-insert-command count))) + +(defun smarty-electric-close-bracket (count) + "')' --> ')', '))' --> ']', '])' --> '}'" + (interactive "p") + (if (and smarty-stutter-mode (= count 1) (not (smarty-in-literal))) + (progn + (if (= (preceding-char) ?\)) + (progn (delete-char -1) (insert-char ?\] 1)) + (if (= (preceding-char) ?\]) + (progn (delete-char -1) (insert-char ?} 1)) + (insert-char ?\) 1))) + (blink-matching-open)) + (self-insert-command count))) + +(defun smarty-electric-star (count) + "After a left delimiter add a right delemiter to close the comment" + (interactive "p") + (let ((here (point-marker)) found) + (if (and smarty-stutter-mode (= count 1) (not (smarty-in-literal))) + (progn + (setq found (re-search-backward (regexp-quote smarty-left-delimiter) nil t)) + (re-search-forward (regexp-quote smarty-left-delimiter) here t) + (if (not (and (= here (point-marker)) found)) + (progn (goto-char here) + (self-insert-command count)) + (self-insert-command count) + (insert " ") + (setq here (point-marker)) + (insert " *") + (insert smarty-right-delimiter) + (goto-char here))) + (self-insert-command count)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Electrification +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst smarty-template-prompt-syntax "[^ =<>][^<>@.\n]*[^ =<>]" + "Syntax of prompt inserted by template generators.") + +(defvar smarty-template-invoked-by-hook nil + "Indicates whether a template has been invoked by a hook or by key or menu. +Used for undoing after template abortion.") + +(defun smarty-minibuffer-tab (&optional prefix-arg) + "If preceding character is part of a word or a paren then hippie-expand, +else insert tab (used for word completion in Smarty minibuffer)." + (interactive "P") + (cond + ;; expand word + ((= (char-syntax (preceding-char)) ?w) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil) + (hippie-expand-only-buffers + (or (and (boundp 'hippie-expand-only-buffers) + hippie-expand-only-buffers) + '(smarty-mode)))) + (smarty-expand-abbrev prefix-arg))) + ;; expand parenthesis + ((or (= (preceding-char) ?\() (= (preceding-char) ?\))) + (let ((case-fold-search (not smarty-word-completion-case-sensitive)) + (case-replace nil)) + (smarty-expand-paren prefix-arg))) + ;; insert tab + (t (insert-tab)))) + +;; correct different behavior of function `unread-command-events' in XEmacs +(defun smarty-character-to-event (arg)) +(defalias 'smarty-character-to-event + (if (fboundp 'character-to-event) 'character-to-event 'identity)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Abbrev ook bindings +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-mode-abbrev-table nil + "Abbrev table to use in `smarty-mode' buffers.") + +(defun smarty-mode-abbrev-table-init () + "Initialize `smarty-mode-abbrev-table'." + (when smarty-mode-abbrev-table (clear-abbrev-table smarty-mode-abbrev-table)) + (define-abbrev-table 'smarty-mode-abbrev-table + (append + '( + ("capture" "" smarty-template-capture-hook 0) + ("config_load" "" smarty-template-config-load-hook 0) + ("else" "" smarty-template-else-hook 0) + ("elseif" "" smarty-template-elseif-hook 0) + ("foreach" "" smarty-template-foreach-hook 0) + ("foreachelse" "" smarty-template-foreachelse-hook 0) + ("if" "" smarty-template-if-hook 0) + ("include" "" smarty-template-include-hook 0) + ("include_php" "" smarty-template-include-php-hook 0) + ("insert" "" smarty-template-insert-hook 0) + ("ldelim" "" smarty-template-ldelim-hook 0) + ("literal" "" smarty-template-literal-hook 0) + ("php" "" smarty-template-php-hook 0) + ("rdelim" "" smarty-template-rdelim-hook 0) + ("section" "" smarty-template-section-hook 0) + ("sectionelse" "" smarty-template-sectionelse-hook 0) + ("strip" "" smarty-template-strip-hook 0) + ("assign" "" smarty-template-assign-hook 0) + ("counter" "" smarty-template-counter-hook 0) + ("cycle" "" smarty-template-cycle-hook 0) + ("debug" "" smarty-template-debug-hook 0) + ("eval" "" smarty-template-eval-hook 0) + ("fetch" "" smarty-template-fetch-hook 0) + ("html_checkboxes" "" smarty-template-html-checkboxes-hook 0) + ("html_image" "" smarty-template-html-image-hook 0) + ("html_options" "" smarty-template-html-options-hook 0) + ("html_radios" "" smarty-template-html-radios-hook 0) + ("html_select_date" "" smarty-template-html-select-date-hook 0) + ("html_select_time" "" smarty-template-html-select-time-hook 0) + ("html_table" "" smarty-template-html-table-hook 0) + ("mailto" "" smarty-template-mailto-hook 0) + ("math" "" smarty-template-math-hook 0) + ("popup" "" smarty-template-popup-hook 0) + ("popup_init" "" smarty-template-popup-init-hook 0) + ("textformat" "" smarty-template-textformat-hook 0) + ("capitalize" "" smarty-template-capitalize-hook 0) + ("cat" "" smarty-template-cat-hook 0) + ("count_characters" "" smarty-template-count-characters-hook 0) + ("count_paragraphs" "" smarty-template-count-paragraphs-hook 0) + ("count_sentences" "" smarty-template-count-sentences-hook 0) + ("count_words" "" smarty-template-count-words-hook 0) + ("date_format" "" smarty-template-date-format-hook 0) + ("default" "" smarty-template-default-hook 0) + ("escape" "" smarty-template-escape-hook 0) + ("indent" "" smarty-template-indent-hook 0) + ("lower" "" smarty-template-lower-hook 0) + ("nl2br" "" smarty-template-nl2br-hook 0) + ("regex_replace" "" smarty-template-regex-replace-hook 0) + ("replace" "" smarty-template-replace-hook 0) + ("spacify" "" smarty-template-spacify-hook 0) + ("string_format" "" smarty-template-string-format-hook 0) + ("strip" "" smarty-template-vstrip-hook 0) + ("strip_tags" "" smarty-template-strip-tags-hook 0) + ("truncate" "" smarty-template-truncate-hook 0) + ("upper" "" smarty-template-upper-hook 0) + ("wordwrap" "" smarty-template-wordwrap-hook 0) + ("validate" "" smarty-template-validate-hook 0) + ("clipcache" "" smarty-template-clipcache-hook 0) + ("repeat" "" smarty-template-repeat-hook 0) + ("str_repeat" "" smarty-template-str-repeat-hook 0) + ("include_clipcache" "" smarty-template-include-clipcache-hook 0) + ("formtool_checkall" "" smarty-template-formtool-checkall-hook 0) + ("formtool_copy" "" smarty-template-formtool-copy-hook 0) + ("formtool_count_chars" "" smarty-template-formtool-count-chars-hook 0) + ("formtool_init" "" smarty-template-formtool-init-hook 0) + ("formtool_move" "" smarty-template-formtool-move-hook 0) + ("formtool_moveall" "" smarty-template-formtool-moveall-hook 0) + ("formtool_movedown" "" smarty-template-formtool-movedown-hook 0) + ("formtool_moveup" "" smarty-template-formtool-moveup-hook 0) + ("formtool_remove" "" smarty-template-formtool-remove-hook 0) + ("formtool_rename" "" smarty-template-formtool-rename-hook 0) + ("formtool_save" "" smarty-template-formtool-save-hook 0) + ("formtool_selectall" "" smarty-template-formtool-selectall-hook 0) + ("paginate_first" "" smarty-template-paginate-first-hook 0) + ("paginate_last" "" smarty-template-paginate-last-hook 0) + ("paginate_middle" "" smarty-template-paginate-middle-hook 0) + ("paginate_next" "" smarty-template-paginate-next-hook 0) + ("paginate_prev" "" smarty-template-paginate-prev-hook 0) + ("btosmilies" "" smarty-template-btosmilies-hook 0) + ("bbcodetohtml" "" smarty-template-bbcodetohtml-hook 0) + ("date_formatto" "" smarty-template-date-formatto-hook 0))))) + +;; initialize abbrev table for Smarty Mode +(smarty-mode-abbrev-table-init) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Abbrev hooks +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-hooked-abbrev (func) + "Do function, if syntax says abbrev is a keyword, invoked by hooked abbrev, +but not if inside a comment or quote)." + (if (or (smarty-in-literal) + (smarty-in-comment-p)) + (progn + (insert " ") + (unexpand-abbrev) + (delete-char -1)) + (if (not smarty-electric-mode) + (progn + (insert " ") + (unexpand-abbrev) + (backward-word 1) + (delete-char 1)) + (let ((invoke-char last-command-event) + (abbrev-mode -1) + (smarty-template-invoked-by-hook t)) + (let ((caught (catch 'abort + (funcall func)))) + (when (stringp caught) (message caught))) + (when (= invoke-char ?-) (setq abbrev-start-location (point))) + ;; delete CR which is still in event queue + (if (fboundp 'enqueue-eval-event) + (enqueue-eval-event 'delete-char -1) + (setq unread-command-events ; push back a delete char + (list (smarty-character-to-event ?\177)))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Fontification +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-font-lock-keywords-1 + (list + + ;; Fontify built-in functions + (cons + (concat (regexp-quote smarty-left-delimiter) "[/]*" smarty-functions-regexp) + '(1 font-lock-keyword-face)) + + (cons + (concat "\\<\\(" smarty-constants "\\)\\>") + 'font-lock-constant-face) + + (cons (concat "\\(" (regexp-quote (concat smarty-left-delimiter "*")) "\\(\\s-\\|\\w\\|\\s.\\|\\s_\\|\\s(\\|\\s)\\|\\s\\\\)*" (regexp-quote (concat "*" smarty-right-delimiter)) "\\)") + 'font-lock-comment-face) + + ) + "Subdued level highlighting for Smarty mode.") + +(defconst smarty-font-lock-keywords-2 + (append + smarty-font-lock-keywords-1 + (list + + ;; Fontify variable names (\\sw\\|\\s_\\) matches any word character + + ;; underscore + '("\\$\\(\\(?:\\sw\\|\\s_\\)+\\)" (1 font-lock-variable-name-face)) ; $variable + '("->\\(\\(?:\\sw\\|\\s_\\)+\\)" (1 font-lock-variable-name-face t t)) ; ->variable + '("\\.\\(\\(?:\\sw\\|\\s_\\)+\\)" (1 font-lock-variable-name-face t t)) ; .variable + '("->\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" (1 font-lock-function-name-face t t)) ; ->function_call + '("\\<\\(\\(?:\\sw\\|\\s_\\)+\\s-*\\)(" (1 font-lock-function-name-face)) ; word( + '("\\<\\(\\(?:\\sw\\|\\s_\\)+\\s-*\\)[[]" (1 font-lock-variable-name-face)) ; word[ + '("\\<[0-9]+" . 'default) ; number (also matches word) + + ;; Fontify strings + ;;'("\"\\([^\"]*\\)\"[^\"]+" (1 font-lock-string-face t t)) + )) + + "Medium level highlighting for Smarty mode.") + +(defconst smarty-font-lock-keywords-3 + (append + smarty-font-lock-keywords-2 + (list + ;; Fontify modifiers + (cons (concat "|\\(" smarty-modifiers-regexp "\\)[:|]+") '(1 font-lock-function-name-face)) + (cons (concat "|\\(" smarty-modifiers-regexp "\\)" (regexp-quote smarty-right-delimiter)) '(1 font-lock-function-name-face)) + + ;; Fontify config vars + (cons (concat (regexp-quote smarty-left-delimiter) "\\(#\\(?:\\sw\\|\\s_\\)+#\\)") '(1 font-lock-constant-face)))) + "Balls-out highlighting for Smarty mode.") + +(defconst smarty-font-lock-keywords-4 + (append + smarty-font-lock-keywords-3 + (list + ;; Fontify plugin functions + (cons + (concat (regexp-quote smarty-left-delimiter) "[/]*" smarty-plugins-functions-regexp) + '(1 font-lock-keyword-face)) + + (cons (concat "|\\(" smarty-plugins-modifiers-regexp "\\)[:|]+") '(1 font-lock-function-name-face)) + (cons (concat "|\\(" smarty-plugins-modifiers-regexp "\\)" (regexp-quote smarty-right-delimiter)) '(1 font-lock-function-name-face))))) + +(defvar smarty-font-lock-keywords smarty-font-lock-keywords-3 + "Default highlighting level for Smarty mode") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mode map +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar smarty-template-map nil + "Keymap for Smarty templates.") + +(defun smarty-template-map-init () + "Initialize `smarty-template-map'." + (setq smarty-template-map (make-sparse-keymap)) + ;; key bindings for Smarty templates + (define-key smarty-template-map "\C-ba" 'smarty-template-capture) + (define-key smarty-template-map "\C-bc" 'smarty-template-config-load) + (define-key smarty-template-map "\C-b\M-e" 'smarty-template-else) + (define-key smarty-template-map "\C-b\C-e" 'smarty-template-elseif) + (define-key smarty-template-map "\C-b\C-f" 'smarty-template-foreach) + (define-key smarty-template-map "\C-b\M-f" 'smarty-template-foreachelse) + (define-key smarty-template-map "\C-bf" 'smarty-template-if) + (define-key smarty-template-map "\C-b\C-i" 'smarty-template-include) + (define-key smarty-template-map "\C-b\M-i" 'smarty-template-include-php) + (define-key smarty-template-map "\C-bi" 'smarty-template-insert) + (define-key smarty-template-map "\C-bl" 'smarty-template-ldelim) + (define-key smarty-template-map "\C-b\C-l" 'smarty-template-literal) + (define-key smarty-template-map "\C-bp" 'smarty-template-php) + (define-key smarty-template-map "\C-br" 'smarty-template-rdelim) + (define-key smarty-template-map "\C-b\C-s" 'smarty-template-section) + (define-key smarty-template-map "\C-b\M-s" 'smarty-template-sectionelse) + (define-key smarty-template-map "\C-bs" 'smarty-template-strip) + (define-key smarty-template-map "\C-ca" 'smarty-template-assign) + (define-key smarty-template-map "\C-co" 'smarty-template-counter) + (define-key smarty-template-map "\C-cc" 'smarty-template-cycle) + (define-key smarty-template-map "\C-cd" 'smarty-template-debug) + (define-key smarty-template-map "\C-ce" 'smarty-template-eval) + (define-key smarty-template-map "\C-cf" 'smarty-template-fetch) + (define-key smarty-template-map "\C-c\C-hc" 'smarty-template-html-checkboxes) + (define-key smarty-template-map "\C-c\C-hi" 'smarty-template-html-image) + (define-key smarty-template-map "\C-c\C-ho" 'smarty-template-html-options) + (define-key smarty-template-map "\C-c\C-hr" 'smarty-template-html-radios) + (define-key smarty-template-map "\C-c\C-hd" 'smarty-template-html-select-date) + (define-key smarty-template-map "\C-c\C-hm" 'smarty-template-html-select-time) + (define-key smarty-template-map "\C-c\C-ht" 'smarty-template-html-table) + (define-key smarty-template-map "\C-ci" 'smarty-template-mailto) + (define-key smarty-template-map "\C-ch" 'smarty-template-math) + (define-key smarty-template-map "\C-c\C-p" 'smarty-template-popup) + (define-key smarty-template-map "\C-c\M-p" 'smarty-template-popup-init) + (define-key smarty-template-map "\C-ct" 'smarty-template-textformat) + (define-key smarty-template-map "\C-vp" 'smarty-template-capitalize) + (define-key smarty-template-map "\C-vc" 'smarty-template-cat) + (define-key smarty-template-map "\C-v\C-cc" 'smarty-template-count-characters) + (define-key smarty-template-map "\C-v\C-cp" 'smarty-template-count-paragraphs) + (define-key smarty-template-map "\C-v\C-cs" 'smarty-template-count-sentences) + (define-key smarty-template-map "\C-v\C-cw" 'smarty-template-count-words) + (define-key smarty-template-map "\C-vf" 'smarty-template-date-format) + (define-key smarty-template-map "\C-vd" 'smarty-template-default) + (define-key smarty-template-map "\C-ve" 'smarty-template-escape) + (define-key smarty-template-map "\C-vi" 'smarty-template-indent) + (define-key smarty-template-map "\C-vl" 'smarty-template-lower) + (define-key smarty-template-map "\C-vn" 'smarty-template-nl2br) + (define-key smarty-template-map "\C-vx" 'smarty-template-regex-replace) + (define-key smarty-template-map "\C-v\C-p" 'smarty-template-replace) + (define-key smarty-template-map "\C-vy" 'smarty-template-spacify) + (define-key smarty-template-map "\C-vs" 'smarty-template-string-format) + (define-key smarty-template-map "\C-v\C-s" 'smarty-template-vstrip) + (define-key smarty-template-map "\C-v\M-s" 'smarty-template-strip-tags) + (define-key smarty-template-map "\C-vt" 'smarty-template-truncate) + (define-key smarty-template-map "\C-vu" 'smarty-template-upper) + (define-key smarty-template-map "\C-vw" 'smarty-template-wordwrap) + (define-key smarty-template-map "\C-h" 'smarty-template-header) + (define-key smarty-template-map "\C-f" 'smarty-template-footer) + (define-key smarty-template-map "\C-di" 'smarty-template-insert-date) + (define-key smarty-template-map "\C-dm" 'smarty-template-modify)) + +;; initialize template map for Smarty Mode +(smarty-template-map-init) + +(defun smarty-mode-map-init () + "Initialize `smarty-mode-map'." + (setq smarty-mode-map (make-sparse-keymap)) + ;; template key bindings + (define-key smarty-mode-map "\C-c\C-t" smarty-template-map) + ;; mode specific key bindings + (define-key smarty-mode-map "\C-c\C-m\C-e" 'smarty-electric-mode) + (define-key smarty-mode-map "\C-c\C-m\C-s" 'smarty-stutter-mode) + (define-key smarty-mode-map "\C-c\C-s\C-u" 'smarty-add-source-files-menu) + (define-key smarty-mode-map "\C-c\M-m" 'smarty-show-messages) + (define-key smarty-mode-map "\C-c\C-h" 'smarty-doc-mode) + (define-key smarty-mode-map "\C-c\C-v" 'smarty-version) + ;; electric key bindings + (when smarty-intelligent-tab + (define-key smarty-mode-map "\t" 'smarty-electric-tab)) + (define-key smarty-mode-map " " 'smarty-electric-space) + (define-key smarty-mode-map "(" 'smarty-electric-open-bracket) + (define-key smarty-mode-map ")" 'smarty-electric-close-bracket) + (define-key smarty-mode-map "*" 'smarty-electric-star)) + +;; initialize mode map for Smarty Mode +(smarty-mode-map-init) + +(defvar smarty-minibuffer-local-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-map) + (when smarty-word-completion-in-minibuffer + (define-key map "\t" 'smarty-minibuffer-tab)) + map) + "Keymap for minibuffer used in Smarty Mode.") + +(mapcar + (function + (lambda (sym) + (put sym 'delete-selection t) ; for `delete-selection-mode' (Emacs) + (put sym 'pending-delete t))) ; for `pending-delete-mode' (XEmacs) + '(smarty-electric-space + smarty-electric-tab + smarty-electric-open-bracket + smarty-electric-close-bracket + smarty-electric-star)) + +;;;###autoload +(defun smarty-mode () + "Smarty Mode +*********** + +Smarty Mode is a GNU XEmacs major mode for editing Smarty templates. + +1 Introduction +************** + +Smarty-Mode is a mode allowing easy edit of Smarty templates: +highlight, templates, navigation into source files... + + + +Features (new features in bold) : + + * Completion + + * Customizable + + * Highlight + + * Menu + + * Stuttering + + * Templates + - Built-in Functions + + - User Functions + + - Variable Modifiers + + - Plugin (Functions) + * BlockRepeatPlugin + + * ClipCache + + * Smarty Formtool + + * Smarty Paginate + + * Smarty Validate + + - Plugin (Variable Modifiers) + * AlternativeDateModifierPlugin + + * B2Smilies + + * BBCodePlugin + + - Fonctions Non-Smarty + + + +This manual describes Smarty Mode version 0.0.5. + +2 Installation +************** + +2.1 Requirements +================ + +Smarty Mode is a XEmacs major mode that needs the following +software/packages: + + * XEmacs (http://www.xemacs.org/). + + * `font-lock' mode generaly installed with XEmacs. + + * `assoc' mode generaly installed with XEmacs. + + * `easymenu' mode generaly installed with XEmacs. + + * `hippie-exp' mode generaly installed with XEmacs. + +Before continuing, you must be sure to have all this packages +installed. + +2.2 Download +============ + +Two internet address to download Smarty Mode : + + * Principal: Smarty-Mode 0.0.5 + (http://deboutv.free.fr/lisp/smarty/download/smarty-0.0.5.tar.gz) + (http://deboutv.free.fr/lisp/smarty/) + + * Secondary: Smarty-Mode 0.0.5 + (http://www.morinie.fr/lisp/smarty/download/smarty-0.0.5.tar.gz) + (http://www.morinie.fr/lisp/smarty/) + + * Old releases: Smarty-Mode + (http://deboutv.free.fr/lisp/smarty/download.php) + (http://deboutv.free.fr/lisp/smarty/) + +2.3 Installation +================ + +2.3.1 Installation +------------------ + +To install Smarty Mode you need to choose an installation directory +\(for example `/usr/local/share/lisp' or `c:\lisp'). The administrator +must have the write rights on this directory. + +With your favorite unzip software, unzip the archive in the +installation directory. + +Example: + cd /usr/local/share/lisp + tar zxvf smarty-0.0.5.tar.gz +Now you have a `smarty' directory in the installation directory. This +directory contains 2 files `smarty-mode.el' and `smarty-mode.elc' and +another directory `docs' containing the documentation. + +You need to configure XEmacs. open you initialization file `init.el' +\(open the file or start XEmacs then choose the Options menu and Edit +Init File). Add the following lines (the installation directory in +this example is `/usr/local/share/lisp') : + + (setq load-path + (append (list \"/usr/local/share/lisp/\") load-path)) + (autoload 'smarty-mode \"smarty-mode\" \"Smarty Mode\" t) + +2.3.2 Update +------------ + +The update is easy. You need to unzip the archive in the installation +directory to remove the old release. + +Example: + cd /usr/local/share/lisp + rm -rf smarty + tar zxvf smarty-0.0.5.tar.gz + +2.4 Invoke Smarty-Mode +====================== + +You have two possibilities to invoke the Smarty Mode. + + - Manually: At each file opening you need to launch Smarty Mode + with the following command: + + `M-x smarty-mode' + + - Automatically: Add the following linesin your initialization + file `init.el' : + + (setq auto-mode-alist + (append + '((\"\\.tpl$\" . smarty-mode)) + auto-mode-alist)) + + +3 Customization +*************** + +This chapter describes the differents parameters and functions that +you can change to customize Smarty Mode. To do that, open a Smarty +file, click on the Smarty menu and choose Options then Browse +Options.... + +3.1 Parameters +============== + +3.1.1 Mode +---------- + +Smarty Mode has 2 modes allowing to simplify the writing of Smarty +templates. You can enable/disable each mode individually. + +`smarty-electric-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable automatic generation of template. + If `nil'; template generators can still be invoked through key + bindings and menu. Is indicated in the modeline by \"/e\" after + the mode name and can be toggled by `smarty-electric-mode'. + +`smarty-stutter-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable the stuttering. Is indicated in the + modeline by \"/s\" after the mode name and can be toggled by + `smarty-stutter-mode'. + +3.1.2 Menu +---------- + +Smarty Mode has also 1 menu that you can enable/disable. The menu +Sources is specific to each Smarty files opened. + +`smarty-source-file-menu' + Type: boolean + Default value: `t' + Description: If `t'; the Sources menu is enabled. This menu + contains the list of Smarty file located in the current + directory. The Sources menu scans the directory when a file is + opened. + +3.1.3 Menu +---------- + +`smarty-highlight-plugin-functions' + Type: boolean + Default value: `t' + Description: If `t'; the functions described in the smarty + plugins are highlighted. + +3.1.4 Templates +--------------- + +3.1.4.1 Header +.............. + +`smarty-file-header' + Type: string + Default value: `\"\"' + Description: String or file to insert as file header. If the + string specifies an existing file name the contents of the file + is inserted; otherwise the string itself is inserted as file + header. + Type `C-j' for newlines. + The follonwing keywords are supported: + <filename>: replaced by the file name. + <author>: replaced by the user name and email address. + <login>: replaced by `user-login-name'. + <company>: replaced by `smarty-company-name' content. + <date>: replaced by the current date. + <year>: replaced by the current year. + <copyright>: replaced by `smarty-copyright-string' content. + <cursor>: final cursor position. + +`smarty-file-footer' + Type: string + Default value: `\"\"' + Description: String or file to insert as file footer. See + `smarty-file-header' + +`smarty-company-name' + Type: string + Default value: `\"\"' + Description: Name of the company to insert in file header. + +`smarty-copyright-string' + Type: string + Default value: `\"\"' + Description: Coryright string to insert in file header. + +`smarty-date-format' + Type: string + Default value: `\"%Y-%m-%d\"' + Description: Date format. + +`smarty-modify-date-prefix-string' + Type: string + Default value: `\"\"' + Description: Prefix string of modification date in Smarty file + header. + +`smarty-modify-date-on-saving' + Type: bool + Default value: `nil' + Description: If `t'; update the modification date when the + buffer is saved. + +3.1.5 Miscellaneous +------------------- + +`smarty-left-delimiter' + Type: string + Default value: `\"\"' + Description: Left escaping delimiter for Smarty templates. + +`smarty-right-delimiter' + Type: string + Default value: `\"\"' + Description: Right escaping delimiter for Smarty templates. + +`smarty-intelligent-tab' + Type: bool + Default value: `t' + Description: If `t'; TAB does indentation; completion and insert + tabulations. If `nil'; TAB does only indentation. + +`smarty-word-completion-in-minibuffer' + Type: bool + Default value: `t' + Description: If `t'; enable completion in the minibuffer. + +`smarty-word-completion-case-sensitive' + Type: bool + Default value: `nil' + Description: If `t'; completion is case sensitive. + +3.2 Functions +============= + +3.2.1 Mode +---------- + +`smarty-electric-mode' + Menu: Smarty -> Options -> Mode -> Electric Mode + Keybinding: `C-c C-m C-e' + Description: This functions is used to enable/disable the + electric mode. + +`smarty-stutter-mode' + Menu: Smarty -> Options -> Mode -> Stutter Mode + Keybinding: `C-c C-m C-s' + Description: This function is used to enable/disable the stutter + mode. + +4 Menus +******* + +There are 2 menus: Smarty and Sources. All theses menus can be +accessed from the menubar or from the right click. This chapter +describes each menus. + +4.1 Smarty +========== + +This is the main menu of Smarty Mode. It allows an easy access to the +main features of the Smarty Mode: Templates (see *Note Templates::) +and Options (see *Note Customization::). + +This menu contains also 3 functions that are discussed in the next +part. + +4.1.1 Functions +--------------- + +`smarty-show-messages' + Menu: Smarty -> Show Messages + Keybinding: `C-c M-m' + Description: This function opens the *Messages* buffer to + display previous error messages. + +`smarty-doc-mode' + Menu: Smarty -> Smarty Mode Documentation + Keybinding: `C-c C-h' + Description: This function opens the *Help* buffer and prints in + it the Smarty Mode documentation. + +`smarty-version' + Menu: Smarty -> Version + Keybinding: `C-c C-v' + Description: This function displays in the minibuffer the + current Smarty Mode version with the timestamp. + +4.2 Sources +=========== + +The Sources menu shows the Smarty files in the current directory. If +you add or delete a file in the current directory, you need to +refresh the menu. + +4.2.1 Customization +------------------- + +`smarty-source-file-menu' + Type: boolean + Default value: `t' + Description: If `t'; the Sources menu is enabled. This menu + contains the list of Smarty file located in the current + directory. The Sources menu scans the directory when a file is + opened. + +4.2.2 Functions +--------------- + +`smarty-add-source-files-menu' + Menu: Sources -> *Rescan* + Keybinding: `C-c C-s C-u' + Description: This function is used to refresh the Sources menu. + +5 Stuttering +************ + +The stutter mode is a mode that affects a function to a key. For +example, when you use the `ENTER' key, the associated function will +create a new line and indent it. + +5.1 Customization +================= + +`smarty-stutter-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable the stuttering. Is indicated in the + modeline by \"/s\" after the mode name and can be toggled by + `smarty-stutter-mode'. + +5.2 Functions +============= + +`SPACE' + If in comment, indent the comment and add new line if necessary. + In other case, add a space. + +`(' + If the previous character is a `(', the `((' will be replaced by + `['. + If the previous character is a `[', the `[(' will be replaced by + `{'. + In other case, insert a `('. + +`)' + If the previous character is a `)', the `))' will be replaced by + `]'. + If the previous character is a `]', the `])' will be replaced by + `}'. + In other case, insert a `)'. + +6 Templates +*********** + +In the Smarty Mode, the Smarty functions (like if, while, for, fopen, +fclose) are predefined in functions called \"Templates\". + +Each template can be invoked by the function name or by using the +<SPACE> key after the Smarty function name in the buffer (Note, using +`M-<SPACE>' disable the template). + +A template can be aborted by using the `C-g' or by lefting empty the +tempate prompt (in the minibuffer). + +6.1 Customization +================= + +`smarty-electric-mode' + Type: boolean + Default value: `t' + Description: If `t'; enable automatic generation of template. + If `nil'; template generators can still be invoked through key + bindings and menu. Is indicated in the modeline by \"/e\" after + the mode name and can be toggled by `smarty-electric-mode'. + +For a complete description of the template customizable variables, +see *Note Cu01-Pa01-Template:: + +6.2 Functions +============= + +6.2.1 Smarty Functions +---------------------- + +For Smarty functions, see PDF or HTML documentation. + +6.2.2 Non-Smarty Functions +-------------------------- + +`smarty-template-header' + Menu: Smarty -> Templates -> Insert Header + Keybinding: `C-c C-t C-h' + Description: This function is used to insert a header in the + current buffer. + +`smarty-template-footer' + Menu: Smarty -> Templates -> Insert Footer + Keybinding: `C-c C-t C-f' + Description: This function is used to insert a footer in the + current buffer. + +`smarty-template-insert-date' + Menu: Smarty -> Templates -> Insert Date + Keybinding: `C-c C-t C-d i' + Description: This function is used to insert the date in the + current buffer. + +`smarty-template-modify' + Menu: Smarty -> Templates -> Modify Date + Keybinding: `C-c C-t C-d m' + Description: This function is used to modify the last + modification date in the current buffer. + +7 Bugs, Help +************ + + * To report bugs: Bugtracker + (http://bugtracker.morinie.fr/lisp/set_project.php?project_id=2) + + * To obtain help you can post on the dedicated forum: Forum + (http://forum.morinie.fr/lisp/) + +8 Key bindings +************** + +\\{smarty-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'smarty-mode) + (setq mode-name "Smarty") + + (smarty-create-syntax-table) + + ;; set maps and tables + (use-local-map smarty-mode-map) + (set-syntax-table smarty-mode-syntax-table) + (setq local-abbrev-table smarty-mode-abbrev-table) + + (set (make-local-variable 'comment-start) (concat smarty-left-delimiter "*")) + (set (make-local-variable 'comment-end) (concat "*" smarty-right-delimiter)) + (set (make-local-variable 'comment-multi-line) t) + (set (make-local-variable 'smarty-end-comment-column) 80) + + (make-local-variable 'font-lock-defaults) + (if smarty-highlight-plugin-functions + (setq smarty-font-lock-keywords smarty-font-lock-keywords-4) + (setq smarty-font-lock-keywords smarty-font-lock-keywords-3)) + (setq font-lock-defaults + '((smarty-font-lock-keywords) + nil ; Keywords only (i.e. no comment or string highlighting + t ; case fold + nil ; syntax-alist + nil ; syntax-begin + )) + + (setq font-lock-maximum-decoration t + case-fold-search t) + + ;; add source file menu + (if smarty-source-file-menu (smarty-add-source-files-menu)) + ;; add Smarty menu + (easy-menu-add smarty-mode-menu-list) + (easy-menu-define smarty-mode-menu smarty-mode-map + "Menu keymap for Smarty Mode." smarty-mode-menu-list) + + ;; (message "Smarty Mode %s.%s" smarty-version + ;; (if noninteractive "" " See menu for documentation and release notes.")) + (smarty-mode-line-update) + (run-hooks 'smarty-mode-hook)) + +(defun smarty-doc-mode () + "Display Smarty Mode documentation in *Help* buffer." + (interactive) + (with-output-to-temp-buffer + (if (fboundp 'help-buffer) (help-buffer) "*Help*") + (princ mode-name) + (princ " mode:\n") + (princ (documentation 'smarty-mode)) + (with-current-buffer standard-output + (help-mode)) + (print-help-return-message))) + +(defun smarty-activate-customizations () + "Activate all customizations on local variables." + (interactive) + (smarty-mode-map-init) + (use-local-map smarty-mode-map) + (set-syntax-table smarty-mode-syntax-table) + (smarty-update-mode-menu) + (run-hooks 'menu-bar-update-hook) + (smarty-mode-line-update)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Templates +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun smarty-template-field (prompt &optional follow-string optional + begin end is-string string-char default) + "Prompt for string and insert it in buffer with optional FOLLOW-STRING. +If OPTIONAL is nil, the prompt is left if an empty string is inserted. If +an empty string is inserted, return nil and call `smarty-template-undo' for +the region between BEGIN and END. IS-STRING indicates whether a string +with double-quotes is to be inserted. DEFAULT specifies a default string." + (let ((position (point)) + string) + (insert "<" prompt ">") + (if (not (> (length string-char) 0)) + (setq string-char "\"")) + (setq string + (condition-case () + (read-from-minibuffer (concat prompt ": ") + (or (and is-string (cons (concat string-char string-char) 1)) default) + smarty-minibuffer-local-map) + (quit (if (and optional begin end) + (progn (beep) "") + (keyboard-quit))))) + (when (or (not (equal string "")) optional) + (delete-region position (point))) + (when (and (equal string "") optional begin end) + (smarty-template-undo begin end) + (message "Template aborted")) + (unless (equal string "") + (insert string)) + (when (or (not (equal string "")) (not optional)) + (insert (or follow-string ""))) + (if (equal string "") nil string))) + +(defun smarty-template-undo (begin end) + "Undo aborted template by deleting region and unexpanding the keyword." + (cond (smarty-template-invoked-by-hook + (goto-char end) + (insert " ") + (delete-region begin end) + (unexpand-abbrev)) + (t (delete-region begin end)))) + +(defun smarty-template-generic-function (label close-label field mandatory-count &optional infinite special-field force-var) + "Generic function template 'label field1= field2=..." + (interactive) + (let ((start (point)) found here result-value elt continue field-count stop prompt) + (if smarty-template-invoked-by-hook + (setq found (smarty-after-ldelim)) + (insert smarty-left-delimiter) + (setq found t)) + (insert label) + (setq here (point-marker)) + (insert " ") + (when found + (setq elt field) + (setq continue t) + (setq field-count 0) + (setq stop nil) + (while (and elt continue) + (setq prompt (car elt)) + (when (not special-field) + (insert prompt "=")) + (setq result-value (smarty-template-field prompt nil t)) + (if (and (not result-value) + (< field-count mandatory-count)) + (progn (setq continue nil) + (delete-region start (point)) + (insert (concat label " ")) + (setq stop t)) + (if (not result-value) + (setq continue nil) + (setq here (point-marker)) + (insert " "))) + (setq field-count (+ 1 field-count)) + (setq elt (cdr elt))) + (when (and infinite (or continue force-var)) + (when (not continue) + (delete-region here (point)) + (insert " ")) + (setq continue t) + (while continue + (setq result-value (smarty-template-field "var_name" "=" t here)) + (if (not result-value) + (setq continue nil) + (setq continue (smarty-template-field "var_value" nil t here)) + (setq here (point-marker)) + (insert " ")))) + (when (not stop) + (delete-region here (point)) + (if (> 0 mandatory-count) + (delete-char -1)) + (insert smarty-right-delimiter) + (setq here (point-marker)) + (if close-label + (insert smarty-left-delimiter "/" label smarty-right-delimiter)) + (goto-char here))))) + +(defun smarty-template-generic-modifier (label field mandatory-count) + "Generic modifier template '|label:field1:field2..." + (interactive) + (let ((start (point)) found here result-value elt continue field-count stop prompt) + (setq found (re-search-backward (concat (regexp-quote smarty-left-delimiter) "\\$\\(\\sw\\|\\s.\\)+" (regexp-quote "|")) nil t)) + (if found + (progn + (setq found (re-search-forward (regexp-quote smarty-right-delimiter) start t)) + (if (not found) + (progn + (goto-char start) + (insert label) + (setq here (point-marker)) + (setq elt field) + (setq continue t) + (setq field-count 0) + (setq stop nil) + (while (and elt continue) + (setq prompt (car elt)) + (insert ":") + (setq result-value (smarty-template-field prompt nil t)) + (if (and (not result-value) + (< field-count mandatory-count)) + (progn (setq continue nil) + (delete-region start (point)) + (insert (concat label " ")) + (setq stop t)) + (if (not result-value) + (setq continue nil) + (setq here (point-marker)) + (insert ":"))) + (setq field-count (+ 1 field-count)) + (setq elt (cdr elt))) + (when (not stop) + (delete-region here (point)) + (if (not (or (looking-at smarty-right-delimiter) + (looking-at "|"))) + (insert smarty-right-delimiter)))) + (goto-char start) + (insert label " "))) + (goto-char start) + (insert label " ")))) + +(defun smarty-template-capture-hook () + (smarty-hooked-abbrev 'smarty-template-capture)) +(defun smarty-template-config-load-hook () + (smarty-hooked-abbrev 'smarty-template-config-load)) +(defun smarty-template-else-hook () + (smarty-hooked-abbrev 'smarty-template-else)) +(defun smarty-template-elseif-hook () + (smarty-hooked-abbrev 'smarty-template-elseif)) +(defun smarty-template-foreach-hook () + (smarty-hooked-abbrev 'smarty-template-foreach)) +(defun smarty-template-foreachelse-hook () + (smarty-hooked-abbrev 'smarty-template-foreachelse)) +(defun smarty-template-if-hook () + (smarty-hooked-abbrev 'smarty-template-if)) +(defun smarty-template-include-hook () + (smarty-hooked-abbrev 'smarty-template-include)) +(defun smarty-template-include-php-hook () + (smarty-hooked-abbrev 'smarty-template-include-php)) +(defun smarty-template-insert-hook () + (smarty-hooked-abbrev 'smarty-template-insert)) +(defun smarty-template-ldelim-hook () + (smarty-hooked-abbrev 'smarty-template-ldelim)) +(defun smarty-template-literal-hook () + (smarty-hooked-abbrev 'smarty-template-literal)) +(defun smarty-template-php-hook () + (smarty-hooked-abbrev 'smarty-template-php)) +(defun smarty-template-rdelim-hook () + (smarty-hooked-abbrev 'smarty-template-rdelim)) +(defun smarty-template-section-hook () + (smarty-hooked-abbrev 'smarty-template-section)) +(defun smarty-template-sectionelse-hook () + (smarty-hooked-abbrev 'smarty-template-sectionelse)) +(defun smarty-template-strip-hook () + (smarty-hooked-abbrev 'smarty-template-strip)) + +(defun smarty-template-assign-hook () + (smarty-hooked-abbrev 'smarty-template-assign)) +(defun smarty-template-counter-hook () + (smarty-hooked-abbrev 'smarty-template-counter)) +(defun smarty-template-cycle-hook () + (smarty-hooked-abbrev 'smarty-template-cycle)) +(defun smarty-template-debug-hook () + (smarty-hooked-abbrev 'smarty-template-debug)) +(defun smarty-template-eval-hook () + (smarty-hooked-abbrev 'smarty-template-eval)) +(defun smarty-template-fetch-hook () + (smarty-hooked-abbrev 'smarty-template-fetch)) +(defun smarty-template-html-checkboxes-hook () + (smarty-hooked-abbrev 'smarty-template-html-checkboxes)) +(defun smarty-template-html-image-hook () + (smarty-hooked-abbrev 'smarty-template-html-image)) +(defun smarty-template-html-options-hook () + (smarty-hooked-abbrev 'smarty-template-html-options)) +(defun smarty-template-html-radios-hook () + (smarty-hooked-abbrev 'smarty-template-html-radios)) +(defun smarty-template-html-select-date-hook () + (smarty-hooked-abbrev 'smarty-template-html-select-date)) +(defun smarty-template-html-select-time-hook () + (smarty-hooked-abbrev 'smarty-template-html-select-time)) +(defun smarty-template-html-table-hook () + (smarty-hooked-abbrev 'smarty-template-html-table)) +(defun smarty-template-mailto-hook () + (smarty-hooked-abbrev 'smarty-template-mailto)) +(defun smarty-template-math-hook () + (smarty-hooked-abbrev 'smarty-template-math)) +(defun smarty-template-popup-hook () + (smarty-hooked-abbrev 'smarty-template-popup)) +(defun smarty-template-popup-init-hook () + (smarty-hooked-abbrev 'smarty-template-popup-init)) +(defun smarty-template-textformat-hook () + (smarty-hooked-abbrev 'smarty-template-textformat)) + +(defun smarty-template-capitalize-hook () + (smarty-hooked-abbrev 'smarty-template-capitalize)) +(defun smarty-template-cat-hook () + (smarty-hooked-abbrev 'smarty-template-cat)) +(defun smarty-template-count-characters-hook () + (smarty-hooked-abbrev 'smarty-template-count-characters)) +(defun smarty-template-count-paragraphs-hook () + (smarty-hooked-abbrev 'smarty-template-count-paragraphs)) +(defun smarty-template-count-sentences-hook () + (smarty-hooked-abbrev 'smarty-template-count-sentences)) +(defun smarty-template-count-words-hook () + (smarty-hooked-abbrev 'smarty-template-count-words)) +(defun smarty-template-date-format-hook () + (smarty-hooked-abbrev 'smarty-template-date-format)) +(defun smarty-template-default-hook () + (smarty-hooked-abbrev 'smarty-template-default)) +(defun smarty-template-escape-hook () + (smarty-hooked-abbrev 'smarty-template-escape)) +(defun smarty-template-indent-hook () + (smarty-hooked-abbrev 'smarty-template-indent)) +(defun smarty-template-lower-hook () + (smarty-hooked-abbrev 'smarty-template-lower)) +(defun smarty-template-nl2br-hook () + (smarty-hooked-abbrev 'smarty-template-nl2br)) +(defun smarty-template-regex-replace-hook () + (smarty-hooked-abbrev 'smarty-template-regex-replace)) +(defun smarty-template-replace-hook () + (smarty-hooked-abbrev 'smarty-template-replace)) +(defun smarty-template-spacify-hook () + (smarty-hooked-abbrev 'smarty-template-spacify)) +(defun smarty-template-string-format-hook () + (smarty-hooked-abbrev 'smarty-template-string-format)) +(defun smarty-template-vstrip-hook () + (smarty-hooked-abbrev 'smarty-template-vstrip)) +(defun smarty-template-strip-tags-hook () + (smarty-hooked-abbrev 'smarty-template-strip-tags)) +(defun smarty-template-truncate-hook () + (smarty-hooked-abbrev 'smarty-template-truncate)) +(defun smarty-template-upper-hook () + (smarty-hooked-abbrev 'smarty-template-upper)) +(defun smarty-template-wordwrap-hook () + (smarty-hooked-abbrev 'smarty-template-wordwrap)) + +(defun smarty-template-validate-hook () + (smarty-hooked-abbrev 'smarty-template-validate)) +(defun smarty-template-clipcache-hook () + (smarty-hooked-abbrev 'smarty-template-clipcache)) +(defun smarty-template-include-clipcache-hook () + (smarty-hooked-abbrev 'smarty-template-include-clipcache)) +(defun smarty-template-formtool-checkall-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-checkall)) +(defun smarty-template-formtool-copy-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-copy)) +(defun smarty-template-formtool-count-chars-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-count-chars)) +(defun smarty-template-formtool-init-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-init)) +(defun smarty-template-formtool-move-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-move)) +(defun smarty-template-formtool-moveall-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-moveall)) +(defun smarty-template-formtool-movedown-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-movedown)) +(defun smarty-template-formtool-moveup-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-moveup)) +(defun smarty-template-formtool-remove-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-remove)) +(defun smarty-template-formtool-rename-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-rename)) +(defun smarty-template-formtool-save-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-save)) +(defun smarty-template-formtool-selectall-hook () + (smarty-hooked-abbrev 'smarty-template-formtool-selectall)) +(defun smarty-template-paginate-first-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-first)) +(defun smarty-template-paginate-last-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-last)) +(defun smarty-template-paginate-middle-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-middle)) +(defun smarty-template-paginate-next-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-next)) +(defun smarty-template-paginate-prev-hook () + (smarty-hooked-abbrev 'smarty-template-paginate-prev)) + +(defun smarty-template-btosmilies-hook () + (smarty-hooked-abbrev 'smarty-template-btosmilies)) +(defun smarty-template-bbcodetohtml-hook () + (smarty-hooked-abbrev 'smarty-template-bbcodetohtml)) +(defun smarty-template-date-formatto-hook () + (smarty-hooked-abbrev 'smarty-template-date-formatto)) + +(defun smarty-template-capture () + "Insert a capture statement." + (interactive) + (smarty-template-generic-function "capture" t '("name" "assign") 0)) + +(defun smarty-template-config-load () + "Insert a config_load statement." + (interactive) + (smarty-template-generic-function "config_load" nil '("file" "section" "scope" "global") 1)) + +(defun smarty-template-else () + "Insert a else statement." + (interactive) + (smarty-template-generic-function "else" nil '() 0)) + +(defun smarty-template-elseif () + "Insert a elseif statement." + (interactive) + (smarty-template-generic-function "elseif" nil '("condition") 1 nil t)) + +(defun smarty-template-foreach () + "Insert a foreach statement." + (interactive) + (smarty-template-generic-function "foreach" t '("from" "item" "key" "name") 2)) + +(defun smarty-template-foreachelse () + "Insert a foreachelse statement." + (interactive) + (smarty-template-generic-function "foreachelse" nil '() 0)) + +(defun smarty-template-if () + "Insert a if statement." + (interactive) + (smarty-template-generic-function "if" t '("condition") 1 nil t)) + +(defun smarty-template-include () + "Insert a include statement." + (interactive) + (smarty-template-generic-function "include" nil '("file" "assign") 1 t)) + +(defun smarty-template-include-php () + "Insert a include_php statement." + (interactive) + (smarty-template-generic-function "include_php" nil '("file" "once" "assign") 1)) + +(defun smarty-template-insert () + "Insert a insert statement." + (interactive) + (smarty-template-generic-function "insert" nil '("name" "assign" "script") 1 t)) + +(defun smarty-template-ldelim () + "Insert a ldelim statement." + (interactive) + (smarty-template-generic-function "ldelim" nil '() 0)) + +(defun smarty-template-literal () + "Insert a literal statement." + (interactive) + (smarty-template-generic-function "literal" t '() 0)) + +(defun smarty-template-php () + "Insert a php statement." + (interactive) + (smarty-template-generic-function "php" t '() 0)) + +(defun smarty-template-rdelim () + "Insert a rdelim statement." + (interactive) + (smarty-template-generic-function "rdelim" nil '() 0)) + +(defun smarty-template-section () + "Insert a section statement." + (interactive) + (smarty-template-generic-function "section" t '("name" "loop" "start" "step" "max" "show") 2)) + +(defun smarty-template-sectionelse () + "Insert a sectionelse statement." + (interactive) + (smarty-template-generic-function "sectionelse" nil '() 0)) + +(defun smarty-template-strip () + "Insert a strip statement." + (interactive) + (smarty-template-generic-function "strip" t '() 0)) + + +(defun smarty-template-assign () + "Insert a assign statement." + (interactive) + (smarty-template-generic-function "assign" nil '("var" "value") 2)) + +(defun smarty-template-counter () + "Insert a counter statement." + (interactive) + (smarty-template-generic-function "counter" nil '("name" "start" "skip" "direction" "print" "assign") 0)) + +(defun smarty-template-cycle () + "Insert a cycle statement." + (interactive) + (smarty-template-generic-function "cycle" nil '("values" "name" "print" "advance" "delimiter" "assign" "reset") 1)) + +(defun smarty-template-debug () + "Insert a debug statement." + (interactive) + (smarty-template-generic-function "debug" nil '("output") 0)) + +(defun smarty-template-eval () + "Insert a eval statement." + (interactive) + (smarty-template-generic-function "eval" nil '("var" "assign") 1)) + +(defun smarty-template-fetch () + "Insert a fetch statement." + (interactive) + (smarty-template-generic-function "fetch" nil '("file" "assign") 1)) + +(defun smarty-template-html-checkboxes () + "Insert a html_checkboxes statement." + (interactive) + (smarty-template-generic-function "html_checkboxes" nil '("name" "values" "output" "selected" "options" "separator" "assign" "labels") 0)) + +(defun smarty-template-html-image () + "Insert a html_image statement." + (interactive) + (smarty-template-generic-function "html_image" nil '("file" "height" "width" "basedir" "alt" "href" "path_prefix") 1)) + +(defun smarty-template-html-options () + "Insert a html_options statement." + (interactive) + (smarty-template-generic-function "html_options" nil '("name" "values" "output" "selected" "options") 0)) + +(defun smarty-template-html-radios () + "Insert a html_radios statement." + (interactive) + (smarty-template-generic-function "html_radios" nil '("name" "values" "output" "selected" "options" "separator" "assign") 0)) + +(defun smarty-template-html-select-date () + "Insert a html_select_date statement." + (interactive) + (smarty-template-generic-function "html_select_date" nil '("prefix" "time" "start_year" "end_year" "display_days" "display_months" "display_years" "month_format" "day_format" "day_value_format" "year_as_text" "reverse_years" "field_array" "day_size" "month_size" "year_size" "all_extra" "day_extra" "month_extra" "year_extra" "field_order" "field_separator" "month_value_format" "year_empty" "month_empty" "day_empty") 0)) + +(defun smarty-template-html-select-time () + "Insert a html_select_time statement." + (interactive) + (smarty-template-generic-function "html_select_time" nil '("prefix" "time" "display_hours" "display_minutes" "display_seconds" "display_meridian" "use_24_hours" "minute_interval" "second_interval" "field_array" "all_extra" "hour_extra" "minute_extra" "second_extra" "meridian_extra") 0)) + +(defun smarty-template-html-table () + "Insert a html_table statement." + (interactive) + (smarty-template-generic-function "html_table" nil '("loop" "cols" "rows" "inner" "caption" "table_attr" "th_attr" "tr_attr" "td_attr" "trailpad" "hdir" "vdir") 1)) + +(defun smarty-template-mailto () + "Insert a mailto statement." + (interactive) + (smarty-template-generic-function "mailto" nil '("address" "text" "encode" "cc" "bcc" "subject" "newsgroups" "followupto" "extra") 1)) + +(defun smarty-template-math () + "Insert a math statement." + (interactive) + (smarty-template-generic-function "math" nil '("equation" "format" "assign") 1 t nil t)) + +(defun smarty-template-popup () + "Insert a popup statement." + (interactive) + (smarty-template-generic-function "popup" nil '("text" "trigger" "sticky" "caption" "fgcolor" "bgcolor" "textcolor" "capcolor" "closecolor" "textfont" "captionfont" "closefont" "textsize" "captionsize" "closesize" "width" "height" "left" "right" "center" "above" "below" "border" "offsetx" "offsety" "fgbackground" "bgbackground" "closetext" "noclose" "status" "autostatus" "autostatuscap" "inarray" "caparray" "capicon" "snapx" "snapy" "fixx" "fixy" "background" "padx" "pady" "fullhtml" "frame" "function" "delay" "hauto" "vauto") 1)) + +(defun smarty-template-popup-init () + "Insert a popup_init statement." + (interactive) + (smarty-template-generic-function "popup_init" nil '("src") 1)) + +(defun smarty-template-textformat () + "Insert a textformat statement." + (interactive) + (smarty-template-generic-function "textformat" t '("style" "indent" "indent_first" "indent_char" "wrap" "wrap_char" "wrap_cut" "assign") 0)) + +(defun smarty-template-capitalize () + "Insert a capitalize statement." + (interactive) + (smarty-template-generic-modifier "capitalize" '("upcase_numeric") 0)) + +(defun smarty-template-cat () + "Insert a cat statement." + (interactive) + (smarty-template-generic-modifier "cat" '("value") 0)) + +(defun smarty-template-count-characters () + "Insert a count_characters statement." + (interactive) + (smarty-template-generic-modifier "count_characters" '("include_whitespace") 0)) + +(defun smarty-template-count-paragraphs () + "Insert a count_paragraphs statement." + (interactive) + (smarty-template-generic-modifier "count_paragraphs" '() 0)) + +(defun smarty-template-count-sentences () + "Insert a count_sentences statement." + (interactive) + (smarty-template-generic-modifier "count_sentences" '() 0)) + +(defun smarty-template-count-words () + "Insert a count_words statement." + (interactive) + (smarty-template-generic-modifier "count_words" '() 0)) + +(defun smarty-template-date-format () + "Insert a date_format statement." + (interactive) + (smarty-template-generic-modifier "date_format" '("format" "default") 0)) + +(defun smarty-template-default () + "Insert a default statement." + (interactive) + (smarty-template-generic-modifier "default" '("value") 0)) + +(defun smarty-template-escape () + "Insert a escape statement." + (interactive) + (smarty-template-generic-modifier "escape" '("html|htmlall|url|urlpathinfo|quotes|hex|hexentity|javascript|mail" "charset") 0)) + +(defun smarty-template-indent () + "Insert a indent statement." + (interactive) + (smarty-template-generic-modifier "indent" '("value" "character") 0)) + +(defun smarty-template-lower () + "Insert a lower statement." + (interactive) + (smarty-template-generic-modifier "lower" '() 0)) + +(defun smarty-template-nl2br () + "Insert a nl2br statement." + (interactive) + (smarty-template-generic-modifier "nl2br" '() 0)) + +(defun smarty-template-regex-replace () + "Insert a regex_replace statement." + (interactive) + (smarty-template-generic-modifier "regex_replace" '("regexp" "string_to_replace") 2)) + +(defun smarty-template-replace () + "Insert a replace statement." + (interactive) + (smarty-template-generic-modifier "replace" '("string" "string_to_replace_with") 2)) + +(defun smarty-template-spacify () + "Insert a spacify statement." + (interactive) + (smarty-template-generic-modifier "spacify" '("character") 0)) + +(defun smarty-template-string-format () + "Insert a string_format statement." + (interactive) + (smarty-template-generic-modifier "string_format" '("format") 1)) + +(defun smarty-template-vstrip () + "Insert a strip statement." + (interactive) + (smarty-template-generic-modifier "strip" '() 0)) + +(defun smarty-template-strip-tags () + "Insert a strip_tags statement." + (interactive) + (smarty-template-generic-modifier "strip_tags" '("replace_by_space") 0)) + +(defun smarty-template-truncate () + "Insert a truncate statement." + (interactive) + (smarty-template-generic-modifier "truncate" '("count" "text_to_replace" "character_boundary" "middle_string") 0)) + +(defun smarty-template-upper () + "Insert a upper statement." + (interactive) + (smarty-template-generic-modifier "upper" '() 0)) + +(defun smarty-template-wordwrap () + "Insert a wordwrap statement." + (interactive) + (smarty-template-generic-modifier "wordwrap" '("count" "string" "character_boundary") 0)) + + +(defun smarty-template-validate () + "Insert a validate statement." + (interactive) + (smarty-template-generic-function "validate" nil '("field" "criteria" "message" "form" "transform" "trim" "empty" "halt" "assign" "append" "page") 3)) + +(defun smarty-template-repeat () + "Insert a repeat statement." + (interactive) + (smarty-template-generic-function "repeat" nil '("count" "assign") 1)) + +(defun smarty-template-str_repeat () + "Insert a str_repeat statement." + (interactive) + (smarty-template-generic-function "str_repeat" nil '("string" "count" "assign") 2)) + +(defun smarty-template-clipcache () + "Insert a clipcache statement." + (interactive) + (smarty-template-generic-function "clipcache" nil '("id" "group" "ttl" "ldelim" "rdelim") 3)) + +(defun smarty-template-include-clipcache () + "Insert a include_clipcache statement." + (interactive) + (smarty-template-generic-function "include_clipcache" nil '("file" "cache_id" "cache_lifetime" "ldelim" "rdelim") 3)) + +(defun smarty-template-formtool-checkall () + "Insert a formtool_checkall statement." + (interactive) + (smarty-template-generic-function "formtool_checkall" nil '("name" "class" "style") 1)) + +(defun smarty-template-formtool-copy () + "Insert a formtool_copy statement." + (interactive) + (smarty-template-generic-function "formtool_copy" nil '("from" "to" "save" "button_text" "all" "counter" "class" "style") 3)) + +(defun smarty-template-formtool-count-chars () + "Insert a formtool_count_chars statement." + (interactive) + (smarty-template-generic-function "formtool_count_chars" nil '("name" "limit" "alert") 3)) + +(defun smarty-template-formtool-init () + "Insert a formtool_init statement." + (interactive) + (smarty-template-generic-function "formtool_init" nil '("src") 1)) + +(defun smarty-template-formtool-move () + "Insert a formtool_move statement." + (interactive) + (smarty-template-generic-function "formtool_move" nil '("from" "to" "save_from" "save_to" "all" "count_to" "count_from" "class" "style") 4)) + +(defun smarty-template-formtool-moveall () + "Insert a formtool_moveall statement." + (interactive) + (smarty-template-generic-function "formtool_moveall" nil '("from" "to" "save_from" "save_to" "all" "count_to" "count_from" "class" "style") 4)) + +(defun smarty-template-formtool-movedown () + "Insert a formtool_movedown statement." + (interactive) + (smarty-template-generic-function "formtool_movedown" nil '("save" "name" "class" "style") 2)) + +(defun smarty-template-formtool-moveup () + "Insert a formtool_moveup statement." + (interactive) + (smarty-template-generic-function "formtool_moveup" nil '("save" "name" "class" "style") 2)) + +(defun smarty-template-formtool-remove () + "Insert a formtool_remove statement." + (interactive) + (smarty-template-generic-function "formtool_remove" nil '("from" "save" "all" "counter" "class" "style") 2)) + +(defun smarty-template-formtool-rename () + "Insert a formtool_rename statement." + (interactive) + (smarty-template-generic-function "formtool_rename" nil '("name" "from" "save" "class" "style") 3)) + +(defun smarty-template-formtool-save () + "Insert a formtool_save statement." + (interactive) + (smarty-template-generic-function "formtool_save" nil '("from" "name" "save") 3)) + +(defun smarty-template-formtool-selectall () + "Insert a formtool_selectall statement." + (interactive) + (smarty-template-generic-function "formtool_selectall" nil '("name" "class" "style") 1)) + +(defun smarty-template-paginate-first () + "Insert a paginate_first statement." + (interactive) + (smarty-template-generic-function "paginate_first" nil '("id" "text") 0)) + +(defun smarty-template-paginate-last () + "Insert a paginate_last statement." + (interactive) + (smarty-template-generic-function "paginate_last" nil '("id" "text") 0)) + +(defun smarty-template-paginate-middle () + "Insert a paginate_middle statement." + (interactive) + (smarty-template-generic-function "paginate_middle" nil '("id" "format" "prefix" "page_limit" "link_prefix" "link_suffix") 0)) + +(defun smarty-template-paginate-next () + "Insert a paginate_next statement." + (interactive) + (smarty-template-generic-function "paginate_next" nil '("id" "text") 0)) + +(defun smarty-template-paginate-prev () + "Insert a paginate_prev statement." + (interactive) + (smarty-template-generic-function "paginate_prev" nil '("id" "text") 0)) + + +(defun smarty-template-btosmilies () + "Insert a B2Smilies statement." + (interactive) + (smarty-template-generic-modifier "B2Smilies" '() 0)) + +(defun smarty-template-bbcodetohtml () + "Insert a bbcode2html statement." + (interactive) + (smarty-template-generic-modifier "bbcode2html" '() 0)) + +(defun smarty-template-date-formatto () + "Insert a date_format2 statement." + (interactive) + (smarty-template-generic-modifier "date_format2" '("format" "default") 0)) + +;; + +(defun smarty-resolve-env-variable (string) + "Resolve environment variables in STRING." + (while (string-match "\\(.*\\)${?\\(\\(\\w\\|_\\)+\\)}?\\(.*\\)" string) + (setq string (concat (match-string 1 string) + (getenv (match-string 2 string)) + (match-string 4 string)))) + string) + +(defun smarty-insert-string-or-file (string) + "Insert STRING or file contents if STRING is an existing file name." + (unless (equal string "") + (let ((file-name + (progn (string-match "^\\([^\n]+\\)" string) + (smarty-resolve-env-variable (match-string 1 string))))) + (if (file-exists-p file-name) + (forward-char (cadr (insert-file-contents file-name))) + (insert string))))) + +(defun smarty-template-insert-date () + "Insert date in appropriate format." + (interactive) + (insert + (cond + ;; 'american, 'european, 'scientific kept for backward compatibility + ((eq smarty-date-format 'american) (format-time-string "%m/%d/%Y" nil)) + ((eq smarty-date-format 'european) (format-time-string "%d.%m.%Y" nil)) + ((eq smarty-date-format 'scientific) (format-time-string "%Y/%m/%d" nil)) + (t (format-time-string smarty-date-format nil))))) + +(defun smarty-template-header (&optional file-title) + "Insert a Smarty file header." + (interactive) + (unless (equal smarty-file-header "") + (let (pos) + (save-excursion + (smarty-insert-string-or-file smarty-file-header) + (setq pos (point-marker))) + (smarty-template-replace-header-keywords + (point-min-marker) pos file-title)))) + +(defun smarty-template-footer () + "Insert a Smarty file footer." + (interactive) + (unless (equal smarty-file-footer "") + (let (pos) + (save-excursion + (setq pos (point-marker)) + (smarty-insert-string-or-file smarty-file-footer) + (unless (= (preceding-char) ?\n) + (insert "\n"))) + (smarty-template-replace-header-keywords pos (point-max-marker))))) + +(defun smarty-template-replace-header-keywords (beg end &optional file-title is-model) + "Replace keywords in header and footer." + (let () + (smarty-prepare-search-2 + (save-excursion + (goto-char beg) + (while (search-forward "<filename>" end t) + (replace-match (buffer-name) t t)) + (goto-char beg) + (while (search-forward "<copyright>" end t) + (replace-match smarty-copyright-string t t)) + (goto-char beg) + (while (search-forward "<author>" end t) + (replace-match "" t t) + (insert (user-full-name)) + (when user-mail-address (insert " <" user-mail-address ">"))) + (goto-char beg) + (while (search-forward "<login>" end t) + (replace-match (user-login-name) t t)) + (goto-char beg) + (while (search-forward "<company>" end t) + (replace-match smarty-company-name t t)) + (goto-char beg) + ;; Replace <RCS> with $, so that RCS for the source is + ;; not over-enthusiastic with replacements + (while (search-forward "<RCS>" end t) + (replace-match "$" nil t)) + (goto-char beg) + (while (search-forward "<date>" end t) + (replace-match "" t t) + (smarty-template-insert-date)) + (goto-char beg) + (while (search-forward "<year>" end t) + (replace-match (format-time-string "%Y" nil) t t)) + (goto-char beg) + (let (string) + (while + (re-search-forward "<\\(\\(\\w\\|\\s_\\)*\\) string>" end t) + (setq string (read-string (concat (match-string 1) ": "))) + (replace-match string t t))) + (goto-char beg) + (when (and (not is-model) (search-forward "<cursor>" end t)) + (replace-match "" t t)))))) + +(provide 'smarty-mode) +;;; smarty-mode.el ends here diff --git a/emacs/nxhtml/related/tt-mode.el b/emacs/nxhtml/related/tt-mode.el new file mode 100644 index 0000000..cf01a47 --- /dev/null +++ b/emacs/nxhtml/related/tt-mode.el @@ -0,0 +1,124 @@ +;; tt-mode.el --- Emacs major mode for editing Template Toolkit files +;; +;; Copyright (c) 2002 Dave Cross, all rights reserved. +;; +;; This file may be distributed under the same terms as GNU Emacs. +;; +;; $Id: tt-mode.el 13 2008-01-27 09:35:16Z dave $ +;; +;; This file adds simple font highlighting of TT directives when you are +;; editing Template Toolkit files. +;; +;; I usually give these files an extension of .tt and in order to automatically +;; invoke this mode for these files, I have the following in my .emacs file. +;; +;; (setq load-path +;; (cons "/home/dave/xemacs" load-path)) +;; (autoload 'tt-mode "tt-mode") +;; (setq auto-mode-alist +;; (append '(("\\.tt$" . tt-mode)) auto-mode-alist )) +;; +;; Something similar may well work for you. +;; +;; Author: Dave Cross <dave@dave.org.uk> +;; +;; Modified by Lennart Borgman 2008-08-06 + +(require 'font-lock) + +(defvar tt-mode-hook nil + "List of functions to call when entering TT mode") + +(defvar tt-keywords + (concat "\\b\\(?:" + (regexp-opt (list "GET" "CALL" "SET" "DEFAULT" "INSERT" "INCLUDE" + "BLOCK" "END" "PROCESS" "WRAPPER" "IF" "UNLESS" + "ELSIF" "ELSE" "SWITCH" "CASE" "FOR" "FOREACH" + "WHILE" "FILTER" "USE" "MACRO" "PERL" "RAWPERL" + "TRY" "THROW" "CATCH" "FINAL" "LAST" "RETURN" + "STOP" "CLEAR" "META" "TAGS")) + "\\)\\b")) + +(defvar tt-font-lock-keywords + (list + ;; Fontify [& ... &] expressions + '("\\(\\[%[-+]?\\)\\(\\(.\\|\n\\)+?\\)\\([-+]?%\\]\\)" + (1 font-lock-string-face t) + (2 font-lock-variable-name-face t) + (4 font-lock-string-face t)) + ;; Look for keywords within those expressions + ;; + ;; Comment out whole directive tag + '("\\[%\\(#.*?\\)%\\]" + (1 font-lock-comment-face t)) + ;; Comments to end of line +;;; '("\\[%\\(?:.\\|\n\\)*\\(#.*\\)" +;;; (1 font-lock-comment-face t)) + '("\\[% *\\([a-z_0-9]*\\) *%\\]" + (1 font-lock-constant-face t)) + (list (concat + "\\(\\[%[-+]?\\|;\\)[ \n\t]*\\(" + tt-keywords + "\\)") + 2 font-lock-keyword-face t) + ) + "Expressions to font-lock in tt-mode.") + +;; (defvar tt-font-lock-keywords +;; ;; Since this is used in a multi major mode we +;; (list +;; ;; Fontify [& ... &] expressions +;; ;;; '("^\\([-+]?\\)\\(\\(.\\|\n\\)+?\\)\\([-+]?\\)$" +;; ;;; (1 font-lock-string-face t) +;; ;;; (2 font-lock-variable-name-face t) +;; ;;; (4 font-lock-string-face t)) +;; '("\\(#.*\\)$" +;; (1 font-lock-comment-face t)) +;; '("^ *\\([a-z_0-9]*\\) *$" +;; (1 font-lock-constant-face t)) +;; (list (concat +;; "^\\(?:[-+]?\\|;\\)[ \n\t]*\\(" +;; tt-keywords +;; "\\)") +;; ) +;; 1 font-lock-keyword-face t) +;; ) +;; "Expressions to font-lock in tt-mode.") + +(defvar tt-font-lock-defaults + '(tt-font-lock-keywords nil t)) + +(defun tt-mode-after-change (beg end pre-len) + ;; add/remove font-lock-multiline + ;; Fix-me: add variable for search lengths + (let* ((here (point)) + (beg-is-ml (get-text-property beg 'font-lock-multiline)) + tt-beg + tt-end + ) + (when beg-is-ml + (let ((beg-ok (not (previous-single-property-change + here 'font-lock-multiline + nil (- here 1)))) + ) + (when beg-ok + (goto-char beg) + (search-forward "%]" end t) + ) + (search-forward "[%" end t) + )) + (when tt-end + (remove-list-of-text-properties here tt-beg '(font-lock-multiline)) + (set-text-properties tt-beg tt-end '(font-lock-multiline t)))) + ) + + +;;;###autoload +(define-derived-mode tt-mode fundamental-mode "TT" + "Major mode for editing Template Toolkit files." + (set (make-local-variable 'font-lock-defaults) tt-font-lock-defaults) + (add-hook 'after-change-functions 'tt-mode-after-change nil t) + ) + +(provide 'tt-mode) +;; tt-mode.el ends here diff --git a/emacs/nxhtml/related/visual-basic-mode.el b/emacs/nxhtml/related/visual-basic-mode.el new file mode 100644 index 0000000..ca448a6 --- /dev/null +++ b/emacs/nxhtml/related/visual-basic-mode.el @@ -0,0 +1,1263 @@ +;;; visual-basic-mode.el +;; This is free software. + +;; A mode for editing Visual Basic programs. +;; Modified version of Fred White's visual-basic-mode.el + +;; Copyright (C) 1996 Fred White <fwhite@alum.mit.edu> +;; Copyright (C) 1998 Free Software Foundation, Inc. +;; (additions by Dave Love) +;; Copyright (C) 2008-2009 Free Software Foundation, Inc. +;; (additions by Randolph Fritz and Vincent Belaiche (VB1) ) + +;; Author: Fred White <fwhite@alum.mit.edu> +;; Adapted-by: Dave Love <d.love@dl.ac.uk> +;; : Kevin Whitefoot <kevin.whitefoot@nopow.abb.no> +;; : Randolph Fritz <rfritz@u.washington.edu> +;; : Vincent Belaiche (VB1) <vincentb1@users.sourceforge.net> +;; Version: 1.4.8 (2009-09-29) +;; Serial Version: %Id: 17% +;; Keywords: languages, basic, Evil + + +;; (Old) LCD Archive Entry: +;; basic-mode|Fred White|fwhite@alum.mit.edu| +;; A mode for editing Visual Basic programs.| +;; 18-Apr-96|1.0|~/modes/basic-mode.el.Z| + +;; This file is NOT part of GNU Emacs but the same permissions apply. +;; +;; 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, 675 Mass Ave, Cambridge, MA 02139, USA. +;; 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. + +;;; Commentary: + +;; Purpose of this package: +;; This is a mode for editing programs written in The World's Most +;; Successful Programming Language. It features automatic +;; indentation, font locking, keyword capitalization, and some minor +;; convenience functions. + +;; Installation instructions +;; Put visual-basic-mode.el somewhere in your path, compile it, and add +;; the following to your init file: + +;; (autoload 'visual-basic-mode "visual-basic-mode" "Visual Basic mode." t) +;; (setq auto-mode-alist (append '(("\\.\\(frm\\|bas\\|cls\\)$" . +;; visual-basic-mode)) auto-mode-alist)) +;; +;; If you are doing Rhino scripts, add: +;; (setq auto-mode-alist (append '(("\\.\\(frm\\|bas\\|cls\\|rvb\\)$" . +;; visual-basic-mode)) auto-mode-alist)) + +;; If you had visual-basic-mode already installed, you may need to call +;; visual-basic-upgrade-keyword-abbrev-table the first time that +;; visual-basic-mode is loaded. + +;; Of course, under Windows 3.1, you'll have to name this file +;; something shorter than visual-basic-mode.el + +;; Revisions: +;; 1.0 18-Apr-96 Initial version +;; 1.1 Accomodate emacs 19.29+ font-lock-defaults +;; Simon Marshall <Simon.Marshall@esrin.esa.it> +; 1.2 Rename to visual-basic-mode +;; 1.3 Fix some indentation bugs. +;; 1.3+ Changes by Dave Love: [No attempt at compatibility with +;; anything other than Emacs 20, sorry, but little attempt to +;; sanitize for Emacs 20 specifically.] +;; Change `_' syntax only for font-lock and imenu, not generally; +;; provide levels of font-locking in the current fashion; +;; font-lock case-insensitively; use regexp-opt with the font-lok +;; keywords; imenu support; `visual-basic-split-line', bound to +;; C-M-j; account for single-statement `if' in indentation; add +;; keyword "Global"; use local-write-file-hooks, not +;; write-file-hooks. +;; 1.4 September 1998 +;; 1.4 KJW Add begin..end, add extra keywords +;; Add customisation for single line if. Disallow by default. +;; Fix if regexp to require whitespace after if and require then. +;; Add more VB keywords. Make begin..end work as if..endif so +;; that forms are formatted correctly. +;; 1.4.1 KJW Merged Dave Love and KJW versions. +;; Added keywords suggested by Mickey Ferguson +;; <MFerguson@peinc.com> +;; Fixed imenu variable to find private variables and enums + +;; Changed syntax class of =, <, > to punctuation to allow dynamic +;; abbreviations to pick up only the word at point rather than the +;; whole expression. + +;; Fixed bug introduced by KJW adding suport for begin...end in +;; forms whereby a single end outdented. + +;; Partially fixed failure to recognise if statements with +;; continuations (still fails on 'single line' if with +;; continuation, ugh). +;; 1.4.2 RF added "class" and "null" keywords, "Rhino" script note. +;; 1.4.3 VB1 added +;; 1) function visual-basic-if-not-on-single-line to recognize single line +;; if statements, even when line is broken. variable +;; visual-basic-allow-single-line-if default set to t again. +;; 2) use of 'words in calling regexp-opt rather than concat \\< ...\\> +;; 3) new keywords Preserve and Explicit +;; 1.4.4 VB1 added function visual-basic-close-block +;; 1.4.5 VB1, (expand-abbrev) within (save-excusion...) +;; 1.4.6 VB1 correct visual-basic-close-block (single line If case) +;; 1.4.7 VB1 correct visual-basic-close-block (For/Next) +;; 1.4.8 VB1 correct visual-basic-close-block (Property, + add With /End With) +;; add command visual-basic-insert-item + +;; Lennart Borgman: +;; 2009-11-20 +;; - Added eval-and-compile to visual-basic-label-regexp. +;; +;; Notes: +;; Dave Love +;; BTW, here's a script for making tags tables that I (Dave Love) have +;; used with reasonable success. It assumes a hacked version of etags +;; with support for case-folded regexps. I think this is now in the +;; development version at <URL:ftp://fly.cnuce.cnr.it/pub/> and should +;; make it into Emacs after 20.4. + +;; #! /bin/sh + +;; # etags-vb: (so-called) Visual (so-called) Basic TAGS generation. +;; # Dave Love <d.love@dl.ac.uk>. Public domain. +;; # 1997-11-21 + +;; if [ $# -lt 1 ]; then +;; echo "Usage: `basename $0` [etags options] VBfile ... [etags options] " 1>&2 +;; exit 1 +;; fi + +;; if [ $1 = "--help" ] || [ $1 = "-h" ]; then +;; echo "Usage: `basename $0` [etags options] VBfile ... [etags options] + +;; " +;; etags --help +;; fi + +;; exec etags --lang=none -c '/\(global\|public\)[ \t]+\(\(const\|type\)[ \t]+\)*\([a-z_0-9]+\)/\4/' \ +;; -c '/public[ \t]+\(sub\|function\|class\)[ \t]+\([a-z_0-9]+\)/\2/' \ +;; "$@" + +;; End Notes Dave Love + + +;; Known bugs: +;; Doesn't know about ":" separated stmts + + + +;; todo: +;; fwd/back-compound-statement +;; completion over OCX methods and properties. +;; IDE integration +;; Change behaviour of ESC-q to recognise words used as paragraph +;; titles and prevent them being dragged into the previous +;; paragraph. +;; etc. + + +;;; Code: + +(provide 'visual-basic-mode) + +(defvar visual-basic-xemacs-p (string-match "XEmacs\\|Lucid" (emacs-version))) +(defvar visual-basic-winemacs-p (string-match "Win-Emacs" (emacs-version))) +(defvar visual-basic-win32-p (eq window-system 'w32)) + +;; Variables you may want to customize. +(defvar visual-basic-mode-indent 8 "*Default indentation per nesting level.") +(defvar visual-basic-fontify-p t "*Whether to fontify Basic buffers.") +(defvar visual-basic-capitalize-keywords-p t + "*Whether to capitalize BASIC keywords.") +(defvar visual-basic-wild-files "*.frm *.bas *.cls" + "*Wildcard pattern for BASIC source files.") +(defvar visual-basic-ide-pathname nil + "*The full pathname of your Visual Basic exe file, if any.") +;; VB +(defvar visual-basic-allow-single-line-if t + "*Whether to allow single line if") + + +(defvar visual-basic-defn-templates + (list "Public Sub ()\nEnd Sub\n\n" + "Public Function () As Variant\nEnd Function\n\n" + "Public Property Get ()\nEnd Property\n\n") + "*List of function templates though which visual-basic-new-sub cycles.") + +(defvar visual-basic-imenu-generic-expression + '((nil "^\\s-*\\(public\\|private\\)*\\s-+\\(declare\\s-+\\)*\\(sub\\|function\\)\\s-+\\(\\sw+\\>\\)" + 4) + ("Constants" + "^\\s-*\\(private\\|public\\|global\\)*\\s-*\\(const\\s-+\\)\\(\\sw+\\>\\s-*=\\s-*.+\\)$\\|'" + 3) + ("Variables" + "^\\(private\\|public\\|global\\|dim\\)+\\s-+\\(\\sw+\\>\\s-+as\\s-+\\sw+\\>\\)" + 2) + ("Types" "^\\(public\\s-+\\)*type\\s-+\\(\\sw+\\)" 2))) + + + +(defvar visual-basic-mode-syntax-table nil) +(if visual-basic-mode-syntax-table + () + (setq visual-basic-mode-syntax-table (make-syntax-table)) + (modify-syntax-entry ?\' "\<" visual-basic-mode-syntax-table) ; Comment starter + (modify-syntax-entry ?\n ">" visual-basic-mode-syntax-table) + (modify-syntax-entry ?\\ "w" visual-basic-mode-syntax-table) + (modify-syntax-entry ?\= "." visual-basic-mode-syntax-table) + (modify-syntax-entry ?\< "." visual-basic-mode-syntax-table) + (modify-syntax-entry ?\> "." visual-basic-mode-syntax-table)) ; Make =, etc., punctuation so that dynamic abbreviations work properly + + +(defvar visual-basic-mode-map nil) +(if visual-basic-mode-map + () + (setq visual-basic-mode-map (make-sparse-keymap)) + (define-key visual-basic-mode-map "\t" 'visual-basic-indent-line) + (define-key visual-basic-mode-map "\r" 'visual-basic-newline-and-indent) + (define-key visual-basic-mode-map "\M-\r" 'visual-basic-insert-item) + (define-key visual-basic-mode-map "\C-c\C-j" 'visual-basic-insert-item) + (define-key visual-basic-mode-map "\M-\C-a" 'visual-basic-beginning-of-defun) + (define-key visual-basic-mode-map "\M-\C-e" 'visual-basic-end-of-defun) + (define-key visual-basic-mode-map "\M-\C-h" 'visual-basic-mark-defun) + (define-key visual-basic-mode-map "\M-\C-\\" 'visual-basic-indent-region) + (define-key visual-basic-mode-map "\M-q" 'visual-basic-fill-or-indent) + (define-key visual-basic-mode-map "\M-\C-j" 'visual-basic-split-line) + (define-key visual-basic-mode-map "\C-c]" 'visual-basic-close-block) + (cond (visual-basic-winemacs-p + (define-key visual-basic-mode-map '(control C) 'visual-basic-start-ide)) + (visual-basic-win32-p + (define-key visual-basic-mode-map (read "[?\\S-\\C-c]") 'visual-basic-start-ide))) + (if visual-basic-xemacs-p + (progn + (define-key visual-basic-mode-map "\M-G" 'visual-basic-grep) + (define-key visual-basic-mode-map '(meta backspace) 'backward-kill-word) + (define-key visual-basic-mode-map '(control meta /) 'visual-basic-new-sub)))) + + +;; These abbrevs are valid only in a code context. +(defvar visual-basic-mode-abbrev-table nil) + +(defvar visual-basic-mode-hook ()) + + +;; Is there a way to case-fold all regexp matches? +;; Change KJW Add enum, , change matching from 0 or more to zero or one for public etc. +(eval-and-compile + (defconst visual-basic-defun-start-regexp + (concat + "^[ \t]*\\([Pp]ublic \\|[Pp]rivate \\|[Ss]tatic\\|[Ff]riend \\)?" + "\\([Ss]ub\\|[Ff]unction\\|[Pp]roperty +[GgSsLl]et\\|[Tt]ype\\|[Ee]num\\|[Cc]lass\\)" + "[ \t]+\\(\\w+\\)[ \t]*(?"))) + + +(defconst visual-basic-defun-end-regexp + "^[ \t]*[Ee]nd \\([Ss]ub\\|[Ff]unction\\|[Pp]roperty\\|[Tt]ype\\|[Ee]num\\|[Cc]lass\\)") + +(defconst visual-basic-dim-regexp + "^[ \t]*\\([Cc]onst\\|[Dd]im\\|[Pp]rivate\\|[Pp]ublic\\)\\_>" ) + + +;; Includes the compile-time #if variation. +;; KJW fixed if to require a whitespace so as to avoid matching, for +;; instance, iFileName and to require then. + +;; Two versions; one recognizes single line if just as though it were +;; a multi-line and the other does not. Modified again to remove the +;; requirement for then so as to allow it to match if statements that +;; have continuations -- VB1 further elaborated on this for single line +;; if statement to be recognized on broken lines. +;;(defconst visual-basic-if-regexp +;; "^[ \t]*#?[Ii]f[ \t]+.*[ \t]+[Tt]hen[ \t]*.*\\('\\|$\\)") +(defconst visual-basic-if-regexp + "^[ \t]*#?[Ii]f[ \t]+.*[ \t_]+") + +(defconst visual-basic-ifthen-regexp "^[ \t]*#?[Ii]f.+\\<[Tt]hen\\>\\s-\\S-+") + +(defconst visual-basic-else-regexp "^[ \t]*#?[Ee]lse\\([Ii]f\\)?") +(defconst visual-basic-endif-regexp "[ \t]*#?[Ee]nd[ \t]*[Ii]f") + +(defconst visual-basic-looked-at-continuation-regexp "_[ \t]*$") + +(defconst visual-basic-continuation-regexp + (concat "^.*" visual-basic-looked-at-continuation-regexp)) + +(eval-and-compile + (defconst visual-basic-label-regexp "^[ \t]*[a-zA-Z0-9_]+:$")) + +(defconst visual-basic-select-regexp "^[ \t]*[Ss]elect[ \t]+[Cc]ase") +(defconst visual-basic-case-regexp "^[ \t]*[Cc]ase") +(defconst visual-basic-select-end-regexp "^[ \t]*[Ee]nd[ \t]+[Ss]elect") + + +(defconst visual-basic-for-regexp "^[ \t]*[Ff]or\\b") +(defconst visual-basic-next-regexp "^[ \t]*[Nn]ext\\b") + +(defconst visual-basic-do-regexp "^[ \t]*[Dd]o\\b") +(defconst visual-basic-loop-regexp "^[ \t]*[Ll]oop\\b") + +(defconst visual-basic-while-regexp "^[ \t]*[Ww]hile\\b") +(defconst visual-basic-wend-regexp "^[ \t]*[Ww]end\\b") + +;; Added KJW Begin..end for forms +(defconst visual-basic-begin-regexp "^[ \t]*[Bb]egin)?") +;; This has created a bug. End on its own in code should not outdent. +;; How can we fix this? They are used in separate Lisp expressions so +;; add another one. +(defconst visual-basic-end-begin-regexp "^[ \t]*[Ee]nd") + +(defconst visual-basic-with-regexp "^[ \t]*[Ww]ith\\b") +(defconst visual-basic-end-with-regexp "^[ \t]*[Ee]nd[ \t]+[Ww]ith\\b") + +(defconst visual-basic-blank-regexp "^[ \t]*$") +(defconst visual-basic-comment-regexp "^[ \t]*\\s<.*$") + + +;; This is some approximation of the set of reserved words in Visual Basic. +(eval-and-compile + (defvar visual-basic-all-keywords + '("Add" "Aggregate" "And" "App" "AppActivate" "Application" "Array" "As" + "Asc" "AscB" "Atn" "Attribute" + "Beep" "Begin" "BeginTrans" "Boolean" "ByVal" "ByRef" + "CBool" "CByte" "CCur" + "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr" "CVErr" "CVar" "Call" + "Case" "ChDir" "ChDrive" "Character" "Choose" "Chr" "ChrB" "Class" + "ClassModule" "Clipboard" "Close" "Collection" "Column" "Columns" + "Command" "CommitTrans" "CompactDatabase" "Component" "Components" + "Const" "Container" "Containers" "Cos" "CreateDatabase" "CreateObject" + "CurDir" "Currency" + "DBEngine" "DDB" "Data" "Database" "Databases" + "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue" "Day" + "Debug" "Declare" "Deftype" "DeleteSetting" "Dim" "Dir" "Do" + "DoEvents" "Domain" + "Double" "Dynaset" "EOF" "Each" "Else" "Empty" "End" "EndProperty" + "Enum" "Environ" "Erase" "Err" "Error" "Exit" "Exp" "Explicit" "FV" "False" "Field" + "Fields" "FileAttr" "FileCopy" "FileDateTime" "FileLen" "Fix" "Font" "For" + "Form" "FormTemplate" "Format" "Forms" "FreeFile" "FreeLocks" "Friend" + "Function" + "Get" "GetAllSettings" "GetAttr" "GetObject" "GetSetting" "Global" "GoSub" + "GoTo" "Group" "Groups" "Hex" "Hour" "IIf" "IMEStatus" "IPmt" "IRR" + "If" "Implements" "InStr" "Input" "Int" "Integer" "Is" "IsArray" "IsDate" + "IsEmpty" "IsError" "IsMissing" "IsNull" "IsNumeric" "IsObject" "Kill" + "LBound" "LCase" "LOF" "LSet" "LTrim" "Left" "Len" "Let" "Like" "Line" + "Load" "LoadPicture" "LoadResData" "LoadResPicture" "LoadResString" "Loc" + "Lock" "Log" "Long" "Loop" "MDIForm" "MIRR" "Me" "MenuItems" + "MenuLine" "Mid" "Minute" "MkDir" "Month" "MsgBox" "NPV" "NPer" "Name" + "New" "Next" "Not" "Now" "Nothing" "Null" "Object" "Oct" "On" "Open" + "OpenDatabase" + "Operator" "Option" "Optional" + "Or" "PPmt" "PV" "Parameter" "Parameters" "Partition" + "Picture" "Pmt" "Preserve" "Print" "Printer" "Printers" "Private" + "ProjectTemplate" "Property" + "Properties" "Public" "Put" "QBColor" "QueryDef" "QueryDefs" + "RSet" "RTrim" "Randomize" "Rate" "ReDim" "Recordset" "Recordsets" + "RegisterDatabase" "Relation" "Relations" "Rem" "RepairDatabase" + "Reset" "Resume" "Return" "Right" "RmDir" "Rnd" "Rollback" "RowBuffer" + "SLN" "SYD" "SavePicture" "SaveSetting" "Screen" "Second" "Seek" + "SelBookmarks" "Select" "SelectedComponents" "SendKeys" "Set" + "SetAttr" "SetDataAccessOption" "SetDefaultWorkspace" "Sgn" "Shell" + "Sin" "Single" "Snapshot" "Space" "Spc" "Sqr" "Static" "Step" "Stop" "Str" + "StrComp" "StrConv" "String" "Sub" "SubMenu" "Switch" "Tab" "Table" + "TableDef" "TableDefs" "Tan" "Then" "Time" "TimeSerial" "TimeValue" + "Timer" "To" "Trim" "True" "Type" "TypeName" "UBound" "UCase" "Unload" + "Unlock" "Val" "Variant" "VarType" "Verb" "Weekday" "Wend" + "While" "Width" "With" "Workspace" "Workspaces" "Write" "Year"))) + +(defvar visual-basic-font-lock-keywords-1 + (eval-when-compile + (list + ;; Names of functions. + (list visual-basic-defun-start-regexp + '(1 font-lock-keyword-face nil t) + '(2 font-lock-keyword-face nil t) + '(3 font-lock-function-name-face)) + + ;; Statement labels + (cons visual-basic-label-regexp 'font-lock-keyword-face) + + ;; Case values + ;; String-valued cases get font-lock-string-face regardless. + (list "^[ \t]*case[ \t]+\\([^'\n]+\\)" 1 'font-lock-keyword-face t) + + ;; Any keywords you like. + (list (regexp-opt + '("Dim" "If" "Then" "Else" "ElseIf" "End If") 'words) + 1 'font-lock-keyword-face)))) + +(defvar visual-basic-font-lock-keywords-2 + (append visual-basic-font-lock-keywords-1 + (eval-when-compile + `((, (regexp-opt visual-basic-all-keywords 'words) + 1 font-lock-keyword-face))))) + +(defvar visual-basic-font-lock-keywords visual-basic-font-lock-keywords-1) + + +(put 'visual-basic-mode 'font-lock-keywords 'visual-basic-font-lock-keywords) + +;;;###autoload +(defun visual-basic-mode () + "A mode for editing Microsoft Visual Basic programs. +Features automatic indentation, font locking, keyword capitalization, +and some minor convenience functions. +Commands: +\\{visual-basic-mode-map}" + (interactive) + (kill-all-local-variables) + (use-local-map visual-basic-mode-map) + (setq major-mode 'visual-basic-mode) + (setq mode-name "Visual Basic") + (set-syntax-table visual-basic-mode-syntax-table) + + ;;; This does not work in multi major modes. + ;;(add-hook 'local-write-file-hooks 'visual-basic-untabify) + + (setq local-abbrev-table visual-basic-mode-abbrev-table) + (if visual-basic-capitalize-keywords-p + (progn + (make-local-variable 'pre-abbrev-expand-hook) + (add-hook 'pre-abbrev-expand-hook 'visual-basic-pre-abbrev-expand-hook) + (abbrev-mode 1))) + + (make-local-variable 'comment-start) + (setq comment-start "' ") + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "'+ *") + (make-local-variable 'comment-column) + (setq comment-column 40) + (make-local-variable 'comment-end) + (setq comment-end "") + + (make-local-variable 'indent-line-function) + (setq indent-line-function 'visual-basic-indent-line) + + (if visual-basic-fontify-p + (visual-basic-enable-font-lock)) + + (make-local-variable 'imenu-generic-expression) + (setq imenu-generic-expression visual-basic-imenu-generic-expression) + + (set (make-local-variable 'imenu-syntax-alist) `((,(string-to-char "_") . "w"))) + (set (make-local-variable 'imenu-case-fold-search) t) + + ;;(make-local-variable 'visual-basic-associated-files) + ;; doing this here means we need not check to see if it is bound later. + (add-hook 'find-file-hooks 'visual-basic-load-associated-files) + + (run-hooks 'visual-basic-mode-hook)) + + +(defun visual-basic-enable-font-lock () + ;; Emacs 19.29 requires a window-system else font-lock-mode errs out. + (cond ((or visual-basic-xemacs-p window-system) + + ;; In win-emacs this sets font-lock-keywords back to nil! + (if visual-basic-winemacs-p + (font-lock-mode 1)) + + ;; Accomodate emacs 19.29+ + ;; From: Simon Marshall <Simon.Marshall@esrin.esa.it> + (cond ((boundp 'font-lock-defaults) + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + `((visual-basic-font-lock-keywords + visual-basic-font-lock-keywords-1 + visual-basic-font-lock-keywords-2) + nil t ((,(string-to-char "_") . "w"))))) + (t + (make-local-variable 'font-lock-keywords) + (setq font-lock-keywords visual-basic-font-lock-keywords))) + + (if visual-basic-winemacs-p + (font-lock-fontify-buffer) + (font-lock-mode 1))))) + +;; KJW should add some odds and bobs here to cover "end if" one way +;; could be to create the abbreviations by removing whitespace then we +;; could put "end if", "end with" and so on in the keyword table +;; Another idea would be to make it intelligent enough to substitute +;; the correct end for the construct (with, select, if) +;; Is this what the abbrev table hook entry is for? +(defun visual-basic-construct-keyword-abbrev-table () + (if visual-basic-mode-abbrev-table + nil + (let ((words visual-basic-all-keywords) + (word nil) + (list nil)) + (while words + (setq word (car words) + words (cdr words)) + (setq list (cons (list (downcase word) word) list))) + + (define-abbrev-table 'visual-basic-mode-abbrev-table list)))) + +;; Would like to do this at compile-time. +(visual-basic-construct-keyword-abbrev-table) + + +(defun visual-basic-upgrade-keyword-abbrev-table () + "Use this in case of upgrading visual-basic-mode.el" + (interactive) + + (let ((words visual-basic-all-keywords) + (word nil) + (list nil)) + (while words + (setq word (car words) + words (cdr words)) + (setq list (cons (list (downcase word) word) list))) + (define-abbrev-table 'visual-basic-mode-abbrev-table list))) + + +(defun visual-basic-in-code-context-p () + (if (fboundp 'buffer-syntactic-context) ; XEmacs function. + (null (buffer-syntactic-context)) + ;; Attempt to simulate buffer-syntactic-context + ;; I don't know how reliable this is. + (let* ((beg (save-excursion + (beginning-of-line) + (point))) + (list + (parse-partial-sexp beg (point)))) + (and (null (nth 3 list)) ; inside string. + (null (nth 4 list)))))) ; inside comment + + +(defun visual-basic-pre-abbrev-expand-hook () + ;; Allow our abbrevs only in a code context. + (setq local-abbrev-table + (if (visual-basic-in-code-context-p) + visual-basic-mode-abbrev-table))) + + +(defun visual-basic-newline-and-indent (&optional count) + "Insert a newline, updating indentation." + (interactive) + (save-excursion + (expand-abbrev) + (visual-basic-indent-line)) + (call-interactively 'newline-and-indent)) + +(defun visual-basic-beginning-of-defun () + (interactive) + (re-search-backward visual-basic-defun-start-regexp)) + +(defun visual-basic-end-of-defun () + (interactive) + (re-search-forward visual-basic-defun-end-regexp)) + +(defun visual-basic-mark-defun () + (interactive) + (beginning-of-line) + (visual-basic-end-of-defun) + (set-mark (point)) + (visual-basic-beginning-of-defun) + (if visual-basic-xemacs-p + (zmacs-activate-region))) + +(defun visual-basic-indent-defun () + (interactive) + (save-excursion + (visual-basic-mark-defun) + (call-interactively 'visual-basic-indent-region))) + + +(defun visual-basic-fill-long-comment () + "Fills block of comment lines around point." + ;; Derived from code in ilisp-ext.el. + (interactive) + (save-excursion + (beginning-of-line) + (let ((comment-re "^[ \t]*\\s<+[ \t]*")) + (if (looking-at comment-re) + (let ((fill-prefix + (buffer-substring + (progn (beginning-of-line) (point)) + (match-end 0)))) + + (while (and (not (bobp)) + (looking-at visual-basic-comment-regexp)) + (forward-line -1)) + (if (not (bobp)) (forward-line 1)) + + (let ((start (point))) + + ;; Make all the line prefixes the same. + (while (and (not (eobp)) + (looking-at comment-re)) + (replace-match fill-prefix) + (forward-line 1)) + + (if (not (eobp)) + (beginning-of-line)) + + ;; Fill using fill-prefix + (fill-region-as-paragraph start (point)))))))) + + +(defun visual-basic-fill-or-indent () + "Fill long comment around point, if any, else indent current definition." + (interactive) + (cond ((save-excursion + (beginning-of-line) + (looking-at visual-basic-comment-regexp)) + (visual-basic-fill-long-comment)) + (t + (visual-basic-indent-defun)))) + + +(defun visual-basic-new-sub () + "Insert template for a new subroutine. Repeat to cycle through alternatives." + (interactive) + (beginning-of-line) + (let ((templates (cons visual-basic-blank-regexp + visual-basic-defn-templates)) + (tem nil) + (bound (point))) + (while templates + (setq tem (car templates) + templates (cdr templates)) + (cond ((looking-at tem) + (replace-match (or (car templates) + "")) + (setq templates nil)))) + + (search-backward "()" bound t))) + + +;; (defun visual-basic-untabify () +;; "Do not allow any tabs into the file." +;; (if (eq major-mode 'visual-basic-mode) +;; (untabify (point-min) (point-max))) +;; nil) + +(defun visual-basic-default-tag () + (if (and (not (bobp)) + (save-excursion + (backward-sexp) + (looking-at "\\w"))) + (backward-word 1)) + (let ((s (point)) + (e (save-excursion + (forward-sexp) + (point)))) + (buffer-substring s e))) + +(defun visual-basic-grep (tag) + "Search BASIC source files in current directory for TAG." + (interactive + (list (let* ((def (visual-basic-default-tag)) + (tag (read-string + (format "Grep for [%s]: " def)))) + (if (string= tag "") def tag)))) + (grep (format "grep -n %s %s" tag visual-basic-wild-files))) + + +;;; IDE Connection. + +(defun visual-basic-buffer-project-file () + "Return a guess as to the project file associated with the current buffer." + (car (directory-files (file-name-directory (buffer-file-name)) t "\\.vbp"))) + +(defun visual-basic-start-ide () + "Start Visual Basic (or your favorite IDE, (after Emacs, of course)) +on the first project file in the current directory. +Note: it's not a good idea to leave Visual Basic running while you +are editing in Emacs, since Visual Basic has no provision for reloading +changed files." + (interactive) + (let (file) + (cond ((null visual-basic-ide-pathname) + (error "No pathname set for Visual Basic. See visual-basic-ide-pathname")) + ((null (setq file (visual-basic-buffer-project-file))) + (error "No project file found")) + ((fboundp 'win-exec) + (iconify-emacs) + (win-exec visual-basic-ide-pathname 'win-show-normal file)) + ((fboundp 'start-process) + (iconify-frame (selected-frame)) + (start-process "*VisualBasic*" nil visual-basic-ide-pathname file)) + (t + (error "No way to spawn process!"))))) + + + +;;; Indentation-related stuff. + +(defun visual-basic-indent-region (start end) + "Perform visual-basic-indent-line on each line in region." + (interactive "r") + (save-excursion + (goto-char start) + (beginning-of-line) + (while (and (not (eobp)) + (< (point) end)) + (if (not (looking-at visual-basic-blank-regexp)) + (visual-basic-indent-line)) + (forward-line 1))) + + (cond ((fboundp 'zmacs-deactivate-region) + (zmacs-deactivate-region)) + ((fboundp 'deactivate-mark) + (deactivate-mark)))) + + + +(defun visual-basic-previous-line-of-code () + (if (not (bobp)) + (forward-line -1)) ; previous-line depends on goal column + (while (and (not (bobp)) + (or (looking-at visual-basic-blank-regexp) + (looking-at visual-basic-comment-regexp))) + (forward-line -1))) + + +(defun visual-basic-find-original-statement () + "If the current line is a continuation, move back to the original stmt." + (let ((here (point))) + (visual-basic-previous-line-of-code) + (while (and (not (bobp)) + (looking-at visual-basic-continuation-regexp)) + (setq here (point)) + (visual-basic-previous-line-of-code)) + (goto-char here))) + +(defun visual-find-matching-stmt (open-p close-p) + ;; Searching backwards + (let ((level 0)) + (while (and (>= level 0) (not (bobp))) + (visual-basic-previous-line-of-code) + (visual-basic-find-original-statement) + (cond ((funcall close-p) + (setq level (+ level 1))) + ((funcall open-p) + (setq level (- level 1))))))) + +(defun visual-basic-find-matching-stmt (open-regexp close-regexp) + (visual-find-matching-stmt + (lambda () (looking-at open-regexp)) + (lambda () (looking-at close-regexp)))) + +(defun visual-basic-get-complete-tail-of-line () + "Return the tail of the current statement line, starting at + point and going up to end of statement line. If you want the + complete statement line, you have to call functions + `visual-basic-find-original-statement' and then + `beginning-of-line' before" + (let* ((start-point (point)) + complete-line + (line-beg start-point) + line-end) + (while (null line-end) + (end-of-line) + (setq line-end (point)) + (if (search-backward "_" line-beg t) + (if (looking-at visual-basic-looked-at-continuation-regexp) + ;; folded line + (progn + (setq line-end (1- (point)) + complete-line (cons + (buffer-substring-no-properties + line-beg line-end) + complete-line) + line-end nil) + (beginning-of-line 2) + (setq line-beg (point))) + ;; _ found, but not a folded line (this is a syntax error) + (setq complete-line + (cons (buffer-substring-no-properties line-beg line-end) complete-line))) + ;; not a folded line + (setq complete-line + (cons (buffer-substring-no-properties line-beg line-end) + complete-line)))) + (mapconcat 'identity (nreverse complete-line) " "))) + +(defun visual-basic-if-not-on-single-line () + "Return non-`nil' when the If statement is not on a single statement +line, i.e. requires a matching End if. Note that a statement line may +be folded over several code lines." + (if (looking-at visual-basic-if-regexp) + (save-excursion + (beginning-of-line) + (let (p1 + p2 + ;; 1st reconstruct complete line + (complete-line (visual-basic-get-complete-tail-of-line)) ) + + ;; now complete line has been reconstructed, drop confusing elements + + ;; remove any VB string from complete line, as strings may disrupt : and ' detection + (while (and (setq p1 (string-match "\"" complete-line)) + (setq p2 (string-match "\"" complete-line (1+ p1)))) + (setq complete-line (concat (substring complete-line 0 p1) + (substring complete-line (1+ p2))))) + ;; now drop tailing comment if any + (when (setq p1 (string-match "'" complete-line)) + (setq complete-line (substring complete-line p1))) + ;; now drop 1st concatenated instruction is any + (when (setq p1 (string-match ":" complete-line)) + (setq complete-line (substring complete-line p1))) + ;; + (string-match "Then\\s-*$" complete-line))); end (save-excursion ...) + ;; else, not a basic if + nil)) + +(defun visual-basic-find-matching-if () + (visual-find-matching-stmt 'visual-basic-if-not-on-single-line + (lambda () (looking-at visual-basic-endif-regexp)))) + +(defun visual-basic-find-matching-select () + (visual-basic-find-matching-stmt visual-basic-select-regexp + visual-basic-select-end-regexp)) + +(defun visual-basic-find-matching-for () + (visual-basic-find-matching-stmt visual-basic-for-regexp + visual-basic-next-regexp)) + +(defun visual-basic-find-matching-do () + (visual-basic-find-matching-stmt visual-basic-do-regexp + visual-basic-loop-regexp)) + +(defun visual-basic-find-matching-while () + (visual-basic-find-matching-stmt visual-basic-while-regexp + visual-basic-wend-regexp)) + +(defun visual-basic-find-matching-with () + (visual-basic-find-matching-stmt visual-basic-with-regexp + visual-basic-end-with-regexp)) + +;;; If this fails it must return the indent of the line preceding the +;;; end not the first line because end without matching begin is a +;;; normal simple statement +(defun visual-basic-find-matching-begin () + (let ((original-point (point))) + (visual-basic-find-matching-stmt visual-basic-begin-regexp + visual-basic-end-begin-regexp) + (if (bobp) ;failed to find a matching begin so assume that it is + ;an end statement instead and use the indent of the + ;preceding line. + (progn (goto-char original-point) + (visual-basic-previous-line-of-code))))) + + +(defun visual-basic-calculate-indent () + (let ((original-point (point))) + (save-excursion + (beginning-of-line) + ;; Some cases depend only on where we are now. + (cond ((or (looking-at visual-basic-defun-start-regexp) + (looking-at visual-basic-label-regexp) + (looking-at visual-basic-defun-end-regexp)) + 0) + + ;; The outdenting stmts, which simply match their original. + ((or (looking-at visual-basic-else-regexp) + (looking-at visual-basic-endif-regexp)) + (visual-basic-find-matching-if) + (current-indentation)) + + ;; All the other matching pairs act alike. + ((looking-at visual-basic-next-regexp) ; for/next + (visual-basic-find-matching-for) + (current-indentation)) + + ((looking-at visual-basic-loop-regexp) ; do/loop + (visual-basic-find-matching-do) + (current-indentation)) + + ((looking-at visual-basic-wend-regexp) ; while/wend + (visual-basic-find-matching-while) + (current-indentation)) + + ((looking-at visual-basic-end-with-regexp) ; with/end with + (visual-basic-find-matching-with) + (current-indentation)) + + ((looking-at visual-basic-select-end-regexp) ; select case/end select + (visual-basic-find-matching-select) + (current-indentation)) + + ;; A case of a select is somewhat special. + ((looking-at visual-basic-case-regexp) + (visual-basic-find-matching-select) + (+ (current-indentation) visual-basic-mode-indent)) + + ;; Added KJW: Make sure that this comes after the cases + ;; for if..endif, end select because end-regexp will also + ;; match "end select" etc. + ((looking-at visual-basic-end-begin-regexp) ; begin/end + (visual-basic-find-matching-begin) + (current-indentation)) + + (t + ;; Other cases which depend on the previous line. + (visual-basic-previous-line-of-code) + + ;; Skip over label lines, which always have 0 indent. + (while (looking-at visual-basic-label-regexp) + (visual-basic-previous-line-of-code)) + + (cond + ((looking-at visual-basic-continuation-regexp) + (visual-basic-find-original-statement) + ;; Indent continuation line under matching open paren, + ;; or else one word in. + (let* ((orig-stmt (point)) + (matching-open-paren + (condition-case () + (save-excursion + (goto-char original-point) + (beginning-of-line) + (backward-up-list 1) + ;; Only if point is now w/in cont. block. + (if (<= orig-stmt (point)) + (current-column))) + (error nil)))) + (cond (matching-open-paren + (1+ matching-open-paren)) + (t + ;; Else, after first word on original line. + (back-to-indentation) + (forward-word 1) + (while (looking-at "[ \t]") + (forward-char 1)) + (current-column))))) + (t + (visual-basic-find-original-statement) + + (let ((indent (current-indentation))) + ;; All the various +indent regexps. + (cond ((looking-at visual-basic-defun-start-regexp) + (+ indent visual-basic-mode-indent)) + + ((or (visual-basic-if-not-on-single-line) + (and (looking-at visual-basic-else-regexp) + (not (and visual-basic-allow-single-line-if + (looking-at visual-basic-ifthen-regexp))))) + (+ indent visual-basic-mode-indent)) + + ((or (looking-at visual-basic-select-regexp) + (looking-at visual-basic-case-regexp)) + (+ indent visual-basic-mode-indent)) + + ((or (looking-at visual-basic-do-regexp) + (looking-at visual-basic-for-regexp) + (looking-at visual-basic-while-regexp) + (looking-at visual-basic-with-regexp) + (looking-at visual-basic-begin-regexp)) + (+ indent visual-basic-mode-indent)) + + (t + ;; By default, just copy indent from prev line. + indent)))))))))) + +(defun visual-basic-indent-to-column (col) + (let* ((bol (save-excursion + (beginning-of-line) + (point))) + (point-in-whitespace + (<= (point) (+ bol (current-indentation)))) + (blank-line-p + (save-excursion + (beginning-of-line) + (looking-at visual-basic-blank-regexp)))) + + (cond ((/= col (current-indentation)) + (save-excursion + (beginning-of-line) + (back-to-indentation) + (delete-region bol (point)) + (indent-to col)))) + + ;; If point was in the whitespace, move back-to-indentation. + (cond (blank-line-p + (end-of-line)) + (point-in-whitespace + (back-to-indentation))))) + + +(defun visual-basic-indent-line () + "Indent current line for BASIC." + (interactive) + (visual-basic-indent-to-column (visual-basic-calculate-indent))) + + +(defun visual-basic-split-line () + "Split line at point, adding continuation character or continuing a comment. +In Abbrev mode, any abbrev before point will be expanded." + (interactive) + (let ((pps-list (parse-partial-sexp (save-excursion + (beginning-of-line) + (point)) + (point)))) + ;; Dispatch on syntax at this position. + (cond ((equal t (nth 4 pps-list)) ; in comment + (indent-new-comment-line)) + ((equal t (nth 4 pps-list)) ; in string + (error "Can't break line inside a string")) + (t (just-one-space) ; leading space on next line + ; doesn't count, sigh + (insert "_") + (visual-basic-newline-and-indent))))) + +(defun visual-basic-detect-idom () + "Detects whether this is a VBA or VBS script. Returns symbol + `vba' if it is VBA, `nil' otherwise" + (let (ret) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (cond + ((looking-at "^[ \t]*Attribute\\s-+VB_Name\\s-+= ") (setq ret 'vba))) + )) + ret)) + +(defun visual-basic-close-block () + "Insert `End If' is current block is a `If Then ...', `End +With' if the block is a `With ...', etc..." + (interactive) + (let (end-statement end-indent) + (save-excursion + (save-match-data + (while + (unless (bobp) + (visual-basic-previous-line-of-code) + (visual-basic-find-original-statement) + (cond + ;; Cases where the current statement is a start-of-smthing statement + ((looking-at visual-basic-defun-start-regexp) + (let ((smt (match-string 2))) + (when (string-match "\\`Prop" smt) + (setq smt "Property")) + (setq end-statement (concat "End " smt) + end-indent 0)) + nil) + ((looking-at visual-basic-select-regexp) + (setq end-statement "End Select" + end-indent (current-indentation)) + nil) + ((looking-at visual-basic-with-regexp) + (setq end-statement "End With" + end-indent (current-indentation)) + nil) + ((looking-at visual-basic-case-regexp) + (setq end-statement "End Select" + end-indent (max 0 (- (current-indentation) visual-basic-mode-indent))) + nil) + ((looking-at visual-basic-begin-regexp) + (setq end-statement "End" + end-indent (current-indentation)) + nil) + ((or (visual-basic-if-not-on-single-line) + (looking-at visual-basic-else-regexp)) + (setq end-statement "End If" + end-indent (current-indentation)) + nil) + + ((looking-at visual-basic-do-regexp) + (setq end-statement "Loop" + end-indent (current-indentation)) + nil) + + ((looking-at visual-basic-for-regexp) + (goto-char (match-end 0)) + (setq end-statement "Next" + end-indent (current-indentation)) + (let ((vb-idom (visual-basic-detect-idom))) + (cond + ;; for VBA add the variable name after Next. + ((eq vb-idom 'vba) + (when (looking-at "\\s-+\\(Each\\s-+\\|\\)\\([^ \t\n\r]+\\)") + (setq end-statement (concat end-statement " " (match-string 2))))))) + nil) + ;; Cases where the current statement is an end-of-smthing statement + ((or (looking-at visual-basic-else-regexp) + (looking-at visual-basic-endif-regexp)) + (visual-basic-find-matching-if) + t) + ((looking-at visual-basic-next-regexp) ; for/next + (visual-basic-find-matching-for) + t) + ((looking-at visual-basic-loop-regexp) ; do/loop + (visual-basic-find-matching-do) + t) + ((looking-at visual-basic-wend-regexp) ; while/wend + (visual-basic-find-matching-while) + t) + ((looking-at visual-basic-end-with-regexp) ; with/end with + (visual-basic-find-matching-with) + t) + ((looking-at visual-basic-select-end-regexp) ; select case/end select + (visual-basic-find-matching-select) + t) + + + ;; default is to loop again back to previous line of code. + (t t)))))) + (when end-statement + (insert end-statement) + (visual-basic-indent-to-column end-indent)))) + +(defvar delta-split-to-cur-point) ;; Don't know what it is, just silence compiler + +(defun visual-basic-insert-item () + "Insert a new item in a block. + +This function is under developement, and for the time being only Dim items are handled. + +Interting an item means: + +* Add a `Case' or `Case Else' into a `Select ... End Select' + block. Pressing again toggles between `Case' and `Case + Else'. `Case Else' is possible only if there is not already a `Case Else'. + +* split a Dim declaration over several lines. + +* Add an `Else' or `ElseIf ... Then' into an `If ... Then ... End + If' block. Pressing again toggles between `Else' and `ElseIf + ... Then'. `Else' is possible only if therei s not already an + `Else'. +" + (interactive) + ;; possible cases are + ;; dim-split-before => split before variable name + ;; dim-split-after => split after type name if any + ;; if-with-else + ;; if-without-else + ;; select-with-else + ;; select-without-else + ;; not-itemizable + (let (item-case + item-ident + split-point + cur-point-mark + prefix + tentative-split-point + block-stack (cur-point (point)) previous-line-of-code) + (save-excursion + (save-match-data + (beginning-of-line) + (while + (progn + (visual-basic-find-original-statement) + (cond + ;; dim case + ;;-------------------------------------------------------------- + ((and (null previous-line-of-code) + (looking-at visual-basic-dim-regexp) + (null (save-match-data (looking-at visual-basic-defun-start-regexp)))) + (setq prefix (buffer-substring-no-properties + (point) + (goto-char (setq split-point (match-end 0))))) + (while + (progn + (if + (looking-at "\\s-*\\sw+\\s-*") + (progn + (goto-char (setq tentative-split-point (match-end 0))) + (if (>= tentative-split-point cur-point) + nil + (while (or + (looking-at "([^)\n]+)\\s-*") + (looking-at visual-basic-looked-at-continuation-regexp)) + (goto-char (setq tentative-split-point (match-end 0)))) + (when (looking-at "As\\s-+\\sw+\\s-*") + (goto-char (setq tentative-split-point (match-end 0)))) + (when (looking-at visual-basic-looked-at-continuation-regexp) + (beginning-of-line 2)) + (if (looking-at ",") + (goto-char (setq split-point (match-end 0))) + (setq split-point (point)) + nil))) + nil))) + (goto-char split-point) + (setq item-case (if (<= split-point cur-point) 'dim-split-before 'dim-split-after)) + (setq delta-split-to-cur-point (- split-point cur-point)) + (setq cur-point-mark (make-marker)) + (set-marker cur-point-mark cur-point) + (looking-at "\\s-*") + (setq delta-split-to-cur-point (- delta-split-to-cur-point + (- (match-end 0) (match-beginning 0)))) + (delete-region (point) (match-end 0)) + (when (looking-back ",") + (delete-region split-point (1- split-point))) + (insert "\n" prefix " ") + (setq cur-point (marker-position cur-point-mark)) + (set-marker cur-point-mark nil) + nil) + ;; next + ((looking-at visual-basic-next-regexp) + (push (list 'next) block-stack)) + ;; default + ;;-------------------------------------------------------------- + (t (if (bobp) + (setq item-case 'not-itemizable))) + ) + (when (null item-case) + (visual-basic-previous-line-of-code) + (setq previous-line-of-code t)) + (null item-case))))) + (cond + ((eq item-case 'dim-split-after) + (goto-char cur-point)) + ) + )) + +;;; Some experimental functions + +;;; Load associated files listed in the file local variables block +(defun visual-basic-load-associated-files () + "Load files that are useful to have around when editing the source of the file that has just been loaded. +The file must have a local variable that lists the files to be loaded. +If the file name is relative it is relative to the directory +containing the current buffer. If the file is already loaded nothing +happens, this prevents circular references causing trouble. After an +associated file is loaded its associated files list will be +processed." + (if (boundp 'visual-basic-associated-files) + (let ((files visual-basic-associated-files) + (file nil)) + (while files + (setq file (car files) + files (cdr files)) + (message "Load associated file: %s" file) + (visual-basic-load-file-ifnotloaded file default-directory))))) + + + +(defun visual-basic-load-file-ifnotloaded (file default-directory) + "Load file if not already loaded. +If file is relative then default-directory provides the path" + (let((file-absolute (expand-file-name file default-directory))) + (if (get-file-buffer file-absolute); don't do anything if the buffer is already loaded + () + (find-file-noselect file-absolute )))) + + + +;;; visual-basic-mode.el ends here + + +;External Links +;* [http://visualbasic.freetutes.com/ Visual Basic tutorials] + diff --git a/emacs/nxhtml/related/wikipedia-mode.el b/emacs/nxhtml/related/wikipedia-mode.el new file mode 100644 index 0000000..c219e19 --- /dev/null +++ b/emacs/nxhtml/related/wikipedia-mode.el @@ -0,0 +1,2296 @@ +;;; wikipedia-mode.el --- Mode for editing Wikipedia articles off-line +;; Copyright (C) 2003, 2004, 2006 Chong Yidong, Uwe Brauer + +;; Author: Chong Yidong <cyd at stupidchicken com> +;; Maintainer: Uwe Brauer <oub at mat.ucm.es> +;; Version: 0.51 +;; Keywords: wiki +;; $Id: wikipedia-mode.el,v 1.5 2006/05/30 15:16:45 oub Exp oub $ + + +;; This file is not part of GNU Emacs. + +;;{{{ GPL2 + +;; 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 of +;; the License, 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; if not, write to the Free +;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +;; MA 02111-1307 USA + +;;}}} + +;;; Commentary: + +;; This is `wikipedia-mode', a major mode for editing articles written +;; in the markup language used by Wikipedia, the free on-line +;; encyclopedia (http://www.wikipedia.org). It is intended to work +;; with GNU Emacs 21.x, and Xemacs 21.4.x. See below for details. + +;; wikipedia mode can be found also at: +;; http://en.wikipedia.org/wiki/Wikipedia:Wikipedia-mode.el + +;;{{{ INSTALLING WIKIPEDIA-MODE + +;; Installing wikipedia-mode +;; ========================= +;; +;; Save wikipedia-mode.el in a convenient directory, preferably in +;; your `load-path'. Add the following to your `user-init-file': +;; +;; (autoload 'wikipedia-mode +;; "wikipedia-mode.el" +;; "Major mode for editing documents in Wikipedia markup." t) +;; +;; If you did not save wikipedia-mode.el in your `load-path', you must +;; use the full pathname. On MS Windows, use forward slashes (/) +;; rather than back slashes (\) to indicate the directory, e.g.: +;; +;; (autoload 'wikipedia-mode +;; "C:/Documents and Settings/USERNAME/.emacs.d/Wikipedia-mode.el" +;; "Major mode for editing documents in Wikipedia markup." t) +;; +;; If you want to associate filenames ending in ".wiki" with +;; wikipedia-mode, add the following to your init file: +;; +;; (setq auto-mode-alist +;; (cons '("\\.wiki\\'" . wikipedia-mode) auto-mode-alist)) + +;;}}} + +;;{{{ REQUIREMENTS + +;; This is not a real requirements but I highly recommend to use +;; outline-magic written by Carsten Dominik. If you don't want to use it +;; you have to comment out the relevant reference to outline magic. +;; It can be found at +;; http://www.astro.uva.nl/~dominik/Tools/outline-magic.el + + + + +;;}}} + +;;{{{ RECOMMENDATIONS INSTALLING LONGLINES-MODE + +;; Installing longlines-mode +;; ========================= +;; +;; If you are using Emacs 22 or later longlines-mode is included so +;; please skip this section! +;; +;; Wikipedia articles don't use newline characters to break paragraphs +;; into lines, so each paragraph looks like a super-long line to +;; Emacs. To let Emacs handle "soft word wrapping", you need to +;; download a third-party package, longlines-mode. +;; +;; Download longlines.el, saving into your `load-path': +;; +;; http://www.emacswiki.org/elisp/longlines.el +;; +;; Add the following to your `user-init-file': +;; +;; (autoload 'longlines-mode "longlines.el" +;; "Minor mode for editing long lines." t) +;; +;; +;; WARNING: if you insert text from one file in wikipedia-mode to +;; another file in wikipedia-mode I strongly recommend, to turn +;; longlines-mode off, before the copying! + +;;}}} + +;;{{{ RECOMMENDATIONS INSTALLING PABBREV-MODE + +;; Installing pabbrev-mode +;; ========================= +;; +;; You may find pabbrev.el useful, which can be found at +;; http://www.russet.org.uk/download/emacs/pabbrev.el + + +;;}}} + +;;{{{ Xemacs or (GNU) Emacs + +;; Xemacs or (GNU) Emacs +;; ===================== +;; Usually that is a question of taste. However almost all wikipedia +;; articles nowadays use UTF8 coding, so the question which of the +;; Macsen to use, boils down to which degree UTF8 support is +;; implemented (no mule Xemacs is ruled out). While Xemacs has the +;; better font support, the UTF8 support still is not complete and +;; hence at the time being it is sad for the maintainer (a long time +;; Xemacs user) to recommend NOT to use Xemacs, even not 21.5.x, which +;; has a much better implemented UTF8 coding engine. That might +;; however change in the foreseeable future.... +;; WARNING: at least for me in Debian testing/unstable Emacs does not +;; ship all fonts necessary for a flawless editing of UTF8 files. For +;; example you can chose Greek input, write Greek text, but then when +;; you close and open the file again, the Greek symbol are not +;; displayed but you see empty blocks. The reason seems that emacs +;; chooses for the input fonts other fonts as for the display (don't +;; ask me). However for installing the (ugly) UTF8 compatible fonts +;; from ..... solved that problem. + + +;;}}} + +;;{{{ INSTALLING EE-HELPER or MOZEX + +;; Installing the helper programs. +;; ========================= +;; Helper Programs: MozEx and EE-HELPER. There are three possibilities +;; in order to use Emacs as an external editor +;; +;; (1) Firefox add-on It's All Text: Recommended. The elisp +;; library its-all-text.el makes it easier to use this. +;; +;; PROS: Easy to intall, supported. (You need to add Emacs +;; client as the editor.) Can be used for editing other +;; text fields with Emacs too. +;; +;; (2) EE-HELPER: This is perl script which will communicate with +;; the wikipedia server. However that sometimes be slow. + +;; PROS: if the editor supports UTF8, then ee-helper will +;; pass the coding flawlessly. +;; +;; CONTRA: the problem with this script is that it directly +;; communicates with the wikipedia site and does not +;; warn you about simultaneous editing. Use it with +;; care!!! Moreover section editing is not implemented. + +;; (3) MozEx: this is a Java-script which allows to communicate +;; Mozilla (or Firefox) directly with Emacs. + +;; PROS: After finishing editing you use the wikipedia +;; software to submit your changes and not the script, +;; so you are warned about possible conflicting editing. +;; +;; CONTRA: the official version does not support UTF8, +;; however there is now a new semi official version which +;; does support UTF8. + +;; Installing It's All Text +;; ======================== +;; +;; Go to the home page and follow the instructions there: +;; +;; https://addons.mozilla.org/en-US/firefox/addon/4125 +;; +;; Then open It's All Text preferences from the Firefox Add-ons page +;; and choose emacsclient as your editor (emacsclientw.exe on +;; Windows). + +;; Installing ee-helper +;; ==================== +;; +;; Download the perl script from +;; +;; http://meta.wikimedia.org/wiki/Help:External_editors +;; +;; and follow the instructions. configure the .ee-ini file. chance in +;; your personal wikipedia-mode-map account setting the editing +;; functions: activate the `external editor' option. + +;; Installing MozEx +;; ================ +;; +;; If your web browser is Mozilla or Firefox, take a look at the MozEx +;; extension, which allows you to call Emacs for editing text boxes: +;; +;; http://mozex.mozdev.org/development.html +;; +;; See also +;; +;; http://www.emacswiki.org/cgi-bin/wiki/FireFox +;; +;; If you mostly use MozEx to edit Wikipedia articles, it might be +;; worthwhile to tell Emacs to enter wikipedia-mode whenever it is +;; called by MozEx. Just add this to your `user-init-file': +;; +;; (add-to-list 'auto-mode-alist '("mozex.\\.*" . wikipedia-mode)) + +;; Recall: you have to click on edit (either edit article or edit +;; section), then use mouse3 (or shift f10), then select +;; mozex, then edit textarea: Edit-->mouse3-->mozex-->Edit +;; Textarea. After editing, you have to _click_ on the +;; text in the browser otherwise Mozilla will ignore your +;; typing. + +;;}}} + +;;{{{ NEWS + + +;; NEWS +;; ================================== +;; (1) Font setting has changed. +;; (2) Some makeup formats have been added: italics, bold, strong +;; emphasise, links. +;; (3) outline-cycle from Carsten Dominiks outline-magic has been +;; added. +;; (4) "Draft", "send" and "reply" (for discussion pages) +;; abilities 'based' on ideas of John Wigleys remember.el: see +;; the functions wikipedia-draft-* +;; RATIONALE: This comes handy in 2 situations +;; 1. You are editing articles which various authors (this I +;; think is the usual case), you then want not to submit +;; your edit immediately but want to copy it somewhere and +;; to continue later. You can use the following functions +;; for doing that: +;; wikipedia-draft-buffer \C-c\C-b +;; wikipedia-draft-region \C-c\C-r +;; then the buffer/region will be appended to the +;; wikipedia-draft-data-file (default is +;; "~/Wiki/discussions/draft.wiki", which you can visit via +;; wikipedia-draft-view-draft) and it will be +;; surrounded by the ^L marks in order to set a page. +;; moreover on top on that a section header == will be +;; inserted, which consists of the Word Draft, a subject +;; you are asked for and a date stamp. +;; +;; Another possibility consists in using the function +;; wikipedia-draft, bound to \C-c \C-m then a new buffer +;; will opened already in wikipedia mode. You edit and then +;; either can send the content of the buffer to the +;; wikipedia-draft-data-file in the same manner as +;; described above using the function +;; wikipedia-draft-buffer (bound to \C-c\C-k) +;; +;; BACK: In order to copy/send the content of temporary +;; buffer or of a page in the wikipedia-draft-data-file +;; back in to your wikipedia file, use the function +;; `wikipedia-send-to-mozex'. You +;; will be asked to which buffer to copy your text! +;; +;; +;; 2. You want to reply in a discussion page to a specific +;; contribution, you can use either the function +;; +;; \\[wikipedia-reply-at-point-simple] bound to [(meta shift r)] +;; which inserts a newline, a hline, and the signature of +;; the author. Or can use +;; \\[wikipedia-draft-reply] bound [(meta r)] +;; which does the same as wikipedia-reply-at-point-simple +;; but in a temporary draft buffer. +;; +;; BACK: In order to copy/send the content of that buffer +;; back in to your wikipedia file, use the function +;; \\[wikipedia-send-to-mozex] bound to "\C-c\C-c". You +;; will be asked to which buffer to copy your text! If +;; you want a copy to be send to your draft file, use +;; the variable wikipedia-draft-send-archive +;; + +;;}}} + +;;{{{ NEW FUNCTIONS AND VARIABLES + + +;; VERSION 0.4 +;;================== +;; NEW FUNCTIONS +;; ------------------ +;; wikipedia-insert-enumerate +;; wikipedia-insert-itemize +;; wikipedia-insert-strong-emphasis (renamed to wikipedia-insert-bold-italic) +;; wikipedia-insert-bold +;; wikipedia-insert-italics +;; wikipedia-insert-header +;; wikipedia-insert-link-wiki +;; wikipedia-turn-on-outline-minor-mode +;; wikipedia-insert-signature +;; wikipedia-insert-hline +;; wikipedia-unfill-paragraph-or-region +;; wikipedia-start-paragraph +;; wikipedia-hardlines +;; wikipedia-outline-magic-keys +;; wikipedia-enhance-indent +;; wikipedia-yank-prefix +;; wikipedia-simple-outline-promote +;; wikipedia-simple-outline-demote +;; wikipedia-next-long-line +;; wikipedia-unfill-paragraph +;; wikipedia-rename-buffer +;; wikipedia-draft +;; wikipedia-draft-buffer-desc +;; wikipedia-draft-append-to-file +;; wikipedia-draft-page +;; wikipedia-draft-region (&optional beg end) +;; wikipedia-draft-buffer +;; wikipedia-draft-clipboard +;; wikipedia-draft-mode +;; wikipedia-draft-view-draft +;; wikipedia-mark-section +;; wikipedia-activate-region +;; wikipedia-copy-page-to-register +;; wikipedia-insert-page-to-register +;; wikipedia-send-to-mozex (target-buffer) +;; wikipedia-reply-at-point-simple +;; wikipedia-draft-reply +;; wikipedia-insert-quotation-with-signature +;; wikipedia-insert-quotation + +;; NEW VARIABLES +;;--------------------- +;; wikipedia-enumerate-with-terminate-paragraph +;; wikipedia-draft-buffer "*Wikipedia-Draft*" +;; wikipedia-draft-mode-map +;; wikipedia-draft-mode-hook +;; wikipedia-draft-register ?R +;; wikipedia-draft-filter-functions +;; wikipedia-draft-handler-functions '(wikipedia-draft-append-to-file) +;; wikipedia-draft-data-file "~/Wiki/discussions/draft.wiki" +;; wikipedia-draft-leader-text "== " +;; wikipedia-draft-page ?S +;; wikipedia-draft-send-archive +;; wikipedia-reply-with-quote + + +;; VERSION 0.5 +;;==================================== +;; NEW FUNCTIONS +;; ------------------------------------ +;; wikipedia-insert-audio +;; wikipedia-insert-image +;; wikipedia-insert-link-www (renamed to wikipedia-insert-link-external) +;; wikipedia-insert-user +;; wikipedia-mark-signature +;; wikipedia-outline-cycle +;; wikipedia-reply-at-signature +;; wikipedia-terminate-paragraph-and-indent +;; wikipedia-yank-prefix + +;; NEW VARIABLES (defvar, defcustom, defconst) +;; ---------------------- +;; wikipedia-reply-with-hline +;; wikipedia-user-simplify-signature +;; wikipedia-english-or-german +;; wikipedia-draft-reply-register ?M +;; wikipedia-mode-version + +;; VERSION 0.51 +;;==================================== +;; +;; - Now requires Emacs 22 or higher. +;; - Cleaned the code in various ways. +;; - Removed wikipedia-english-or-german +;; - Removed some private stuff +;; - Simplified some key bindings. +;; - Changed some key bindings to those used in org-mode. +;; - Added wikipedia-lang etc +;; - Added support for templates +;; - Adjusted header end after inserting heading/promoting/demoting +;; - Removed some functions that are already supported by outline.el +;; - Changed wikipedia-mode menus +;; - Added support for bullets and numbering + +;;}}} + +;;{{{ TODO + +;; Todo +;; ---- + + +;; * Implement TeX highlighting in <math> environment +;; * Implement (La)TeX input syntax, following the ideas of CDlatex.el +;; * Make outline-cycle work correctly +;; * wikipedia-reply-at-point-simple should use regexp! + +;;}}} + + + +;;; Code: + +(require 'org) + +(defconst wikipedia-mode-version (concat "0." (substring "$Revision: 1.5 $" 13 14)) + "$Id: wikipedia-mode.el,v 1.5 2006/05/30 15:16:45 oub Exp oub $ + +Report bugs to: Uwe Brauer oub at mat.ucm.es") + +;;{{{ LANGS + +;; (defvar wikipedia-english-or-german t +;; "*Variable in order to set the english (t) or german (nil) environment.") + +(require 'tutorial) ;; for lang strings + +(defvar wikipedia-lang "English") + +(defvar wikipedia-langs-added nil) +;;(defconst xlang-strings nil) + +(unless wikipedia-langs-added + (defun add-lang-strings (lang new-strings) + (let ((lang-rec (assoc lang lang-strings))) + (if lang-rec + (dolist (str new-strings) + (nconc (cdr lang-rec) (list str))) + (setq lang-rec (cons lang new-strings)) + (add-to-list 'lang-strings lang-rec)))) + + (add-lang-strings "English" + '( + (wikip-username-prompt . "Name of user: ") + (wikip-image-mark . "[[Image:") + (wikip-media-mark . "[[Media:") + (wikip-utc . "(UTC)") + (wikip-user-mark . "[[User:") + )) + (add-lang-strings "Deutsch" + '( + (wikip-username-prompt . "Name des Benutzers: ") + (wikip-image-mark . "[[Bild:") + (wikip-media-mark . "[[Bild:") + (wikip-utc . "(CET)") + (wikip-user-mark . "[[Benutzer:") + )) + (setq wikipedia-langs-added t)) + +;;}}} + +;;{{{ TAGS + +(defvar wikipedia-simple-tags + '("b" "big" "blockquote" "br" "caption" "code" "center" "cite" "del" + "dfn" "dl" "em" "i" "ins" "kbd" "math" "nowiki" "ol" "pre" "samp" + "small" "strike" "strong" "sub" "sup" "tt" "u" "ul" "var") + "Tags that do not accept arguments.") + +(defvar wikipedia-complex-tags + '("a" "div" "font" "table" "td" "th" "tr") + "Tags that accept arguments.") + +(defvar wikipedia-url-protocols + '("ftp" "gopher" "http" "https" "mailto" "news") + "Valid protocols for URLs in Wikipedia articles.") + +;;}}} + +;;{{{ FACES + +(defvar font-wikipedia-sedate-face 'font-wikipedia-sedate-face + "Face to use for Wikipedia minor keywords.") + +(defvar font-wikipedia-italic-face 'font-wikipedia-italic-face + "Face to use for Wikipedia italics.") +(defvar font-wikipedia-bold-face 'font-wikipedia-bold-face + "Face to use for Wikipedia bolds.") +(defvar font-wikipedia-math-face 'font-wikipedia-math-face + "Face to use for Wikipedia math environments.") +(defvar font-wikipedia-string-face 'font-wikipedia-string-face + "Face to use for strings. This is set by Font Wikipedia.") +(defvar font-wikipedia-verbatim-face 'font-wikipedia-verbatim-face + "Face to use for text in verbatim macros or environments.") + + + + +(defface font-wikipedia-bold-face + (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold)) + ((assq :weight custom-face-attributes) '(:weight bold)) + (t '(:bold t))))) + `((((class grayscale) (background light)) + (:foreground "DimGray" ,@font)) + (((class grayscale) (background dark)) + (:foreground "LightGray" ,@font)) + (((class color) (background light)) + (:foreground "DarkOliveGreen" ,@font)) + (((class color) (background dark)) + (:foreground "OliveDrab" ,@font)) + (t (,@font)))) + "Face used to highlight text to be typeset in bold." + :group 'font-wikipedia-highlighting-faces) + +(defface font-wikipedia-italic-face + (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic)) + ((assq :slant custom-face-attributes) '(:slant italic)) + (t '(:italic t))))) + `((((class grayscale) (background light)) + (:foreground "DimGray" ,@font)) + (((class grayscale) (background dark)) + (:foreground "LightGray" ,@font)) + (((class color) (background light)) + (:foreground "DarkOliveGreen" ,@font)) + (((class color) (background dark)) + (:foreground "OliveDrab" ,@font)) + (t (,@font)))) + "Face used to highlight text to be typeset in italic." + :group 'font-wikipedia-highlighting-faces) + +(defface font-wikipedia-math-face + (let ((font (cond ((assq :inherit custom-face-attributes) + '(:inherit underline)) + (t '(:underline t))))) + `((((class grayscale) (background light)) + (:foreground "DimGray" ,@font)) + (((class grayscale) (background dark)) + (:foreground "LightGray" ,@font)) + (((class color) (background light)) + (:foreground "SaddleBrown")) + (((class color) (background dark)) + (:foreground "burlywood")) + (t (,@font)))) + "Face used to highlight math." + :group 'font-wikipedia-highlighting-faces) + +(defface font-wikipedia-sedate-face + '((((class grayscale) (background light)) (:foreground "DimGray")) + (((class grayscale) (background dark)) (:foreground "LightGray")) + (((class color) (background light)) (:foreground "DimGray")) + (((class color) (background dark)) (:foreground "LightGray")) +;;;(t (:underline t)) + ) + "Face used to highlight sedate stuff." + :group 'font-wikipedia-highlighting-faces) + +(defface font-wikipedia-string-face + (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit italic)) + ((assq :slant custom-face-attributes) '(:slant italic)) + (t '(:italic t))))) + `((((type tty) (class color)) + (:foreground "green")) + (((class grayscale) (background light)) + (:foreground "DimGray" ,@font)) + (((class grayscale) (background dark)) + (:foreground "LightGray" ,@font)) + (((class color) (background light)) + (:foreground "RosyBrown")) + (((class color) (background dark)) + (:foreground "LightSalmon")) + (t (,@font)))) + "Face used to highlight strings." + :group 'font-wikipedia-highlighting-faces) + +(defface font-wikipedia-warning-face + (let ((font (cond ((assq :inherit custom-face-attributes) '(:inherit bold)) + ((assq :weight custom-face-attributes) '(:weight bold)) + (t '(:bold t))))) + `((((class grayscale)(background light)) + (:foreground "DimGray" ,@font)) + (((class grayscale)(background dark)) + (:foreground "LightGray" ,@font)) + (((class color)(background light)) + (:foreground "red" ,@font)) + (((class color)(background dark)) + (:foreground "red" ,@font)) + (t (,@font)))) + "Face for important keywords." + :group 'font-wikipedia-highlighting-faces) + +(defface font-wikipedia-verbatim-face + (let ((font (if (and (assq :inherit custom-face-attributes) + (if (featurep 'xemacs) + (find-face 'fixed-pitch) + (facep 'fixed-pitch))) + '(:inherit fixed-pitch) + '(:family "courier")))) + `((((class grayscale) (background light)) + (:foreground "DimGray" ,@font)) + (((class grayscale) (background dark)) + (:foreground "LightGray" ,@font)) + (((class color) (background light)) + (:foreground "SaddleBrown" ,@font)) + (((class color) (background dark)) + (:foreground "burlywood" ,@font)) + (t (,@font)))) + "Face used to highlight TeX verbatim environments." + :group 'font-wikipedia-highlighting-faces) + + +(defvar wikipedia-font-lock-keywords + (list + + ;; Apostrophe-style text markup + (cons "''''\\([^']\\|[^']'\\)*?\\(''''\\|\n\n\\)" + 'font-lock-builtin-face) + (cons "'''\\([^']\\|[^']'\\)*?\\('''\\|\n\n\\)" + ; 'font-lock-builtin-face) + 'font-wikipedia-bold-face) + (cons "''\\([^']\\|[^']'\\)*?\\(''\\|\n\n\\)" + 'font-wikipedia-italic-face) + + ;; Headers and dividers + (list "^\\(==+\\)\\(.*\\)\\(\\1\\)" + '(1 font-lock-builtin-face) + ; '(2 wikipedia-header-face) + '(2 font-wikipedia-sedate-face) + '(3 font-lock-builtin-face)) + (cons "^-----*" 'font-lock-builtin-face) + + ;; Bare URLs and ISBNs + (cons (concat "\\(^\\| \\)" (regexp-opt wikipedia-url-protocols t) + "://[-A-Za-z0-9._\/~%+&#?!=()@]+") + 'font-lock-variable-name-face) + (cons "\\(^\\| \\)ISBN [-0-9A-Z]+" 'font-lock-variable-name-face) + + ;; Colon indentation, lists, definitions, and tables + (cons "^\\(:+\\|[*#]+\\||[}-]?\\|{|\\)" 'font-lock-builtin-face) + + (list "^\\(;\\)\\([^:\n]*\\)\\(:?\\)" + '(1 font-lock-builtin-face) + '(2 font-lock-keyword-face) + '(3 font-lock-builtin-face)) + + + + ;; Tags and comments + + (list (concat "\\(</?\\)" + (regexp-opt wikipedia-simple-tags t) "\\(>\\)") + '(1 font-lock-builtin-face t t) + '(2 font-lock-function-name-face t t) + '(3 font-lock-builtin-face t t)) + (list (concat "\\(</?\\)" + (regexp-opt wikipedia-complex-tags t) + "\\(\\(?: \\(?:[^\"'/><]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?\\)\\(>\\)") + '(1 font-lock-builtin-face t t) + '(2 font-lock-function-name-face t t) + '(3 font-lock-keyword-face t t) + '(4 font-lock-builtin-face t t)) + (cons (concat "<!-- \\([^->]\\|>\\|-\\([^-]\\|-[^>]\\)\\)*-->") + '(0 font-lock-comment-face t t)) + + + + ;; External Links + + (list (concat "\\(\\[\\)\\(\\(?:" + (regexp-opt wikipedia-url-protocols) + "\\)://[-A-Za-z0-9._\/~%-+&#?!=()@]+\\)\\(\\(?: [^]\n]*\\)?\\)\\(\\]\\)") + '(1 font-lock-builtin-face t t) + '(2 font-lock-variable-name-face t t) + '(3 font-lock-keyword-face t t) + '(4 font-lock-builtin-face t t)) + + + + + ;; Wiki links + '("\\(\\[\\[\\)\\([^]\n|]*\\)\\(|?\\)\\([^]\n]*\\)\\(\\]\\]\\)" + (1 font-lock-builtin-face t t) + (2 font-lock-variable-name-face t t) + (3 font-lock-builtin-face t t) + (4 font-lock-keyword-face t t) + (5 font-lock-builtin-face t t)) + + ;; Wiki variables + '("\\({{\\)\\(.+?\\)\\(}}\\)" + (1 font-lock-builtin-face t t) + (2 font-lock-variable-name-face t t) + (3 font-lock-builtin-face t t)) + + ;; Character entity references + (cons "&#?[a-zA-Z0-9]+;" '(0 font-lock-type-face t t)) + + ;; Preformatted text + (cons "^ .*$" '(0 font-lock-constant-face t t)) + + ;; Math environment (uniform highlight only, no TeX markup) + (list "<math>\\(\\(\n?.\\)*\\)</math>" + '(1 font-lock-keyword-face t t)))) + + ; ) + +;;}}} + +;;{{{ Menu and header stuff + +(defvar wikipedia-imenu-generic-expression + ;;(list '(nil "^==+ *\\(.*[^\n=]\\)==+" 1)) + (list '(nil "^=+ *\\(.*[^\n=]\\)=+" 1)) + "Imenu expression for `wikipedia-mode'. See `imenu-generic-expression'.") + +;; (defun wikipedia-next-header () +;; "Move point to the end of the next section header." +;; (interactive) +;; (let ((oldpoint (point))) +;; (end-of-line) +;; (if (re-search-forward "\\(^==+\\).*\\1" (point-max) t) +;; (beginning-of-line) +;; (goto-char oldpoint) +;; (message "No section headers after point.")))) + +;; (defun wikipedia-prev-header () +;; "Move point to the start of the previous section header." +;; (interactive) +;; (unless (re-search-backward "\\(^==+\\).*\\1" (point-min) t) +;; (message "No section headers before point."))) + +;;}}} + +;;{{{ Paragraph terminate and filling stuff (Chong) + +(defun wikipedia-terminate-paragraph () ;Version:1.58 + "New list item or paragraph. +In a list, start a new list item. In a paragraph, start a new +paragraph. + +If the current paragraph is colon indented, the new paragraph +will be indented in the same way." + (interactive) + (let (indent-chars) + (save-excursion + (beginning-of-line) + (while (cond ((looking-at "^$") nil) + ((looking-at "^\\(\\(?: \\|:+\\|[#*]+\\) *\\)") + (setq indent-chars (match-string 1)) nil) + ((eq (point) (point-min)) nil) + ((progn (forward-line -1) t))) + t)) + (newline) (if (not indent-chars) (newline) + (insert indent-chars)))) + +(defun wikipedia-terminate-paragraph-and-indent () + "New list item or paragraph, ignore *,#. +In a list, start a new list item. In a paragraph, start a new +paragraph but *,# will be ignored. + +If the current paragraph is colon ; indented, the new paragraph +will be indented in the same way." + (interactive) + (let (indent-chars) + (save-excursion + (beginning-of-line) + (while (cond ((looking-at "^$") nil) + ((looking-at "^\\(\\(?: \\|:+\\) *\\)") + (setq indent-chars (match-string 1)) nil) + ((eq (point) (point-min)) nil) + ((progn (forward-line -1) t))) + t)) + (newline) (if (not indent-chars) (newline) + (insert indent-chars)))) + + +(defun wikipedia-link-fill-nobreak-p () + "Function for `fill-nobreak-predicate'. +When filling, don't break the line for preformatted (fixed-width) +text or inside a Wiki link." + (save-excursion + (let ((pos (point))) + (or (eq (char-after (line-beginning-position)) ? ) + (if (re-search-backward "\\[\\[" (line-beginning-position) t) + ;; Break if the link is really really long. + ;; You often get this with captioned images. + (null (or (> (- pos (point)) fill-column) + (re-search-forward "\\]\\]" pos t)))))))) + +(defun wikipedia-fill-article () + "Fill the entire article." + (interactive) + (save-excursion + (fill-region (point-min) (point-max)))) + +(defun wikipedia-unfill-article () + "Unfill article. +Undo filling, deleting stand-alone newlines (newlines that do not +end paragraphs, list entries, etc.)" + (interactive) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward ".\\(\n\\)\\([^# *;:|!\n]\\|----\\)" nil t) + (replace-match " " nil nil nil 1))) + (message "Stand-alone newlines deleted")) + + +(defun wikipedia-unfill-paragraph-with-newline (&optional justifyp) + (interactive "P") + (let ((before (point))) ;Version:1.3 + (save-excursion + (forward-paragraph) + (or (bolp) (newline 1)) + (let ((end (point)) + (start (progn (backward-paragraph) (point)))) + (goto-char before) + (while (re-search-forward ".\\(\n\\)\\([^# *;:|!\n]\\|----\\)" nil t) + (replace-match " " nil nil nil 1)))))) + ; (message "Stand-alone newlines IN PARAGRAPH deleted")) + +(defun wikipedia-unfill-region () + "Unfill region. +Undo filling, deleting stand-alone newlines (newlines that do not +end paragraphs, list entries, etc.) see also the function +\\[wikipedia-unfill-paragraph-or-region] and the even simpler +function \\[wikipedia-unfill-paragraph-simple]." + (interactive) + (save-excursion + (narrow-to-region (point) (mark)) + (goto-char (point-min)) + (while (re-search-forward ".\\(\n\\)\\([^# *;:|!\n]\\|----\\)" nil t) + (replace-match " " nil nil nil 1))) + (message "Stand-alone newlines deleted") + (widen)) + +;;}}} + +;;{{{ Main function wikipedia mode (using define-derived mode) + +;;{{{ KEY SETTING +;; (defvar wikipedia-outline-map +;; (let ((map (make-sparse-keymap))) +;; (define-key map [(down)] 'outline-next-visible-heading) +;; (define-key map [(up)] 'outline-previous-visible-heading) +;; (define-key map "n" 'outline-next-visible-heading) +;; (define-key map "p" 'outline-previous-visible-heading) +;; (define-key map "f" 'outline-forward-same-level) +;; (define-key map "b" 'outline-backward-same-level) +;; (define-key map "u" 'outline-up-heading) +;; (define-key map "/" 'org-occur) +;; (define-key map "\C-c\C-n" 'outline-next-visible-heading) +;; (define-key map "\C-c\C-p" 'outline-previous-visible-heading) +;; (define-key map "\C-c\C-f" 'outline-forward-same-level) +;; (define-key map "\C-c\C-b" 'outline-backward-same-level) +;; (define-key map "\C-c\C-u" 'outline-up-heading) +;; map)) + + +(defvar wikipedia-mode-map + (let ((map (make-sparse-keymap))) + ;;(define-key map "\M-n" 'wikipedia-next-header) + (define-key map "\C-c\C-n" 'wikipedia-next-long-line) + ;; (define-key map "\M-p" 'wikipedia-prev-header) + ;; (define-key map [(meta down)] 'wikipedia-next-header) + ;; (define-key map [(meta up)] 'wikipedia-prev-header) + (define-key map "\C-j" 'wikipedia-terminate-paragraph) + ;;(define-key map "RET" 'wikipedia-newline) + (define-key map [(shift return)] 'wikipedia-newline) + + ;;(define-key mm [separator-format] '("--")) +;; (define-key mm [outline] +;; '("Toggle Outline Mode..." . outline-minor-mode)) + ;;(define-key mm [separator-edit-structure] '("--")) + + + ;; Use some mnemonic + ;;(define-key map "\C-c\C-q" 'wikipedia-unfill-article) + (define-key map "\C-c\M-qua" 'wikipedia-unfill-article) + ;;(define-key map "\C-c\M-q" 'wikipedia-fill-article) + (define-key map "\C-c\M-qfa" 'wikipedia-fill-article) + ;;(define-key map "\M-u" 'wikipedia-unfill-paragraph-or-region) + (define-key map "\C-c\M-qur" 'wikipedia-unfill-paragraph-or-region) + ;;(define-key map "\C-c\C-u" 'wikipedia-unfill-paragraph-simple) + (define-key map "\C-c\M-qup" 'wikipedia-unfill-paragraph-simple) + + (define-key map "\C-c\C-fs" 'wikipedia-insert-bold-italic) + (define-key map "\C-c\C-fb" 'wikipedia-insert-bold) ;Version:1.3 + (define-key map "\C-c\C-fi" 'wikipedia-insert-italics) + (define-key map "\C-c\C-fn" 'wikipedia-insert-nowiki) + + (define-key map "\C-c\C-ts" 'wikipedia-insert-signature) + (define-key map "\C-c\C-tt" 'wikipedia-insert-template) + (define-key map "\C-c\C-tu" 'wikipedia-insert-user) + ;;(define-key map "\C-c\C-fq" 'wikipedia-insert-quotation) + ;;(define-key map "\C-c\C-fh" 'wikipedia-insert-header) + (define-key map "\C-c\C-fr" 'wikipedia-insert-hline) ;Version:1.30 + (define-key map "\C-c\C-li" 'wikipedia-insert-link-wiki) + (define-key map "\C-c\C-le" 'wikipedia-insert-link-external) + + ;; Breaks key binding conventions: + ;;(define-key map [(meta f7)] 'wikipedia-draft) + ;;(define-key map [(meta f8)] 'wikipedia-reply-at-point-simple) + ;;(define-key map [(meta f9)] 'wikipedia-draft-view-draft) + + (define-key map "\C-c\C-r" 'wikipedia-reply-at-point-simple) + + ;; Breaks key binding conventions: + ;;(define-key map "\C-cr" 'wikipedia-draft-region) + + (define-key map [(meta r)] 'wikipedia-draft-reply) + (define-key map "\C-c\C-m" 'wikipedia-draft) ;Version:1.25 + (define-key map "\C-c\C-b" 'wikipedia-draft-region) + (define-key map "\C-c\C-d" 'wikipedia-draft-buffer) + (define-key map "\C-c\C-k" 'wikipedia-draft-buffer) + (define-key map "\C-c\C-p" 'wikipedia-draft-copy-page-to-register) ;Version:1.39 + ;; (define-key map "\C-c\C-c" 'wikipedia-draft-send-to-mozex) + (define-key map "\C-c\C-s" 'wikipedia-draft-yank-page-to-register) + + (define-key map [(control meta prior)] 'wikipedia-enhance-indent) + (define-key map [(control meta next)] 'wikipedia-yank-prefix) + (define-key map [(meta return)] 'wikipedia-insert-enumerate) + (define-key map [(meta control return)] 'wikipedia-insert-enumerate-nonewline) + ;; private setting + ;; This is bound to C-j by default: + ;;(define-key map [(shift return)] 'newline-and-indent) ;Version:1.24 + (define-key map "\C-\\" 'wikipedia-insert-itemize) ;Version:1.28 + (define-key map [(control return)] 'wikipedia-insert-itemize) + + ;; The next three breaks Emacs key binding conventions, are they really necessary? + ;;(define-key map "\C-ca" 'auto-capitalize-mode) + ;;(define-key map "\C-ci" 'set-input-method) + ;;(define-key map "\C-ct" 'toggle-input-method) ;Version:1.23 + + (define-key map [(shift tab)] 'org-shifttab) + (define-key map [backtab] 'org-shifttab) + (define-key map [tab] 'org-cycle) + + map)) + +(defvar wikipedia-org-menu nil) +;; From org.el: +(easy-menu-define wikipedia-org-menu wikipedia-mode-map "Wikipedia menu" + '("Wikipedia" + ("Show/Hide" + ["Cycle Visibility" org-cycle (or (bobp) (outline-on-heading-p))] + ["Cycle Global Visibility" org-shifttab] + ["Sparse Tree" org-occur t] + ["Reveal Context" org-reveal t] + ["Show All" show-all t] + "--" + ["Subtree to indirect buffer" org-tree-to-indirect-buffer t]) + "--" + ["New Heading" outline-insert-heading t] + ("Navigate Headings" + ["Up" outline-up-heading t] + ["Next" outline-next-visible-heading t] + ["Previous" outline-previous-visible-heading t] + ["Next Same Level" outline-forward-same-level t] + ["Previous Same Level" outline-backward-same-level t] + "--" + ["Jump" org-goto t]) + ("Edit Structure" + ["Move Subtree Up" outline-move-subtree-up] + ["Move Subtree Down" outline-move-subtree-down] + "--" + ["Copy Subtree" org-copy-special] + ["Cut Subtree" org-cut-special] + ["Paste Subtree" org-paste-special] + "--" + ["Promote Heading" wikipedia-simple-outline-promote] + ["Promote Subtree" outline-promote] + ["Demote Heading" wikipedia-simple-outline-demote] + ["Demote Subtree" outline-demote]) + ("Filling" + ["Unfill article" wikipedia-unfill-article] + ["Fill article" wikipedia-fill-article]) + "--" + ("Format" + ["Horizontal line" wikipedia-insert-hline] + "--" + ["Indent Paragraph" wikipedia-indent-paragraph] + ["Deindent Paragraph" wikipedia-deindent-paragraph] + "--" + ["Insert No Wiki Formatting" wikipedia-insert-nowiki] + ["Bold-Italic" wikipedia-insert-bold-italic] + ["Italic" wikipedia-insert-italics] + ["Bold" wikipedia-insert-bold] + "--" + ("Insert" + ("Templates" + ["Site Specific Template" wikipedia-insert-template] + ["Signature" wikipedia-insert-signature] + ) + ("Links" + ["External Link" wikipedia-insert-link-external] + ["Internal Wiki Link" wikipedia-insert-link-wiki] + ) + ("Bullets and numbering" + ["Bullet" wikipedia-insert-bullet] + ["Numbering" wikipedia-insert-numbering] + ) + )) + )) +;;}}} + + +;;;###autoload +;;{{{ Main function wikipedia-mode + +(define-derived-mode wikipedia-mode outline-mode "Wikipedia" + "Major mode for editing wikimedia style wikis. +Major mode for editing articles written in the markup language +used by Wikipedia, the free on-line +encyclopedia (see URL `http://www.wikipedia.org'). + +There are several ways to use wikipedia-mode: + +- You can simply cut and paste articles between Emacs and your + web browser's text box. +- If you are using Firefox you can use the It's All Text add-on + for Firefox. +- You can use MozEx, a Mozilla/Firefox web browser extension that + allows you to call Emacs from a text + box (see URL `http://mozex.mozdev.org/'). +- Another way is to use the PERL script ee-helper, which allows + you to up and download wiki texts. + +Wikipedia articles are usually unfilled: newline characters are not +used for breaking paragraphs into lines. Unfortunately, Emacs does not +handle word wrapping yet. As a workaround, wikipedia-mode turns on +longlines-mode automatically. In case something goes wrong, the +following commands may come in handy: + +\\[wikipedia-fill-article] fills the buffer. +\\[wikipedia-unfill-article] unfills the buffer. +Be warned that function can be dead slow, better use wikipedia-unfill-paragraph-or-region. +\\[wikipedia-unfill-paragraph-or-region] unfills the paragraph +\\[wikipedia-unfill-paragraph-simple] doehe same but simpler. + + + +The following commands put in markup structures. + +\\[wikipedia-insert-bold-italic] bold+italic +\\[wikipedia-insert-bold] bold text +\\[wikipedia-insert-italics] italics +\\[wikipedia-insert-nowiki] no wiki markup +\\[wikipedia-insert-link-wiki] inserts a link + +The following commands are also defined: +\\[wikipedia-insert-user] inserts user name +\\[wikipedia-insert-signature] inserts ~~~~ +\\[wikipedia-insert-enumerate] inserts enumerate type structures +\\[wikipedia-insert-itemize] inserts itemize type structures +\\[wikipedia-insert-hline] inserts a hline + +The draft functionality +\\[wikipedia-draft] +\\[wikipedia-draft-region] +\\[wikipedia-draft-view-draft] +\\[wikipedia-draft-page] +\\[wikipedia-draft-buffer] + +Replying and sending functionality +\\[wikipedia-reply-at-point-simple] +\\[wikipedia-draft-reply] + + +The register functionality +\\[wikipedia-copy-page-to-register] +\\[defun wikipedia-insert-page-to-register] + + +Some simple editing commands. +\\[wikipedia-enhance-indent] +\\[wikipedia-yank-prefix] +\\[wikipedia-unfill-paragraph-or-region] + + + +\\[wikipedia-terminate-paragraph] starts a new list item or paragraph in a context-aware manner." + + (set (make-local-variable 'adaptive-fill-regexp) "[ ]*") + (set (make-local-variable 'comment-start-skip) "\\(?:<!\\)?-- *") + (set (make-local-variable 'comment-end-skip) " *--\\([ \n]*>\\)?") + (set (make-local-variable 'comment-start) "<!-- ") + (set (make-local-variable 'comment-end) " -->") + (set (make-local-variable 'paragraph-start) + "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$") + (set (make-local-variable 'sentence-end-double-space) nil) + (set (make-local-variable 'font-lock-multiline) t) + (set (make-local-variable 'font-lock-defaults) + '(wikipedia-font-lock-keywords t nil nil nil)) + (set (make-local-variable 'fill-nobreak-predicate) + 'wikipedia-link-fill-nobreak-p) + (set (make-local-variable 'auto-fill-inhibit-regexp) "^[ *#:|;]") + + ;; Support for outline-minor-mode. No key conflicts, so we'll use + ;; the normal outline-mode prefix. + ;;(set (make-local-variable 'outline-regexp) "==+") + (set (make-local-variable 'outline-regexp) "=+") + ;;(set (make-local-variable 'outline-heading-end-regexp) "=+") ;; For betting fixing + ;; (set (make-local-variable 'outline-regexp) "=+") + ;; (set (make-local-variable 'outline-regexp) ":") + + ;; Fix-me: Why change this?? Should not the user do this globally instead? + ;;(set (make-local-variable 'outline-minor-mode-prefix) "\C-c\C-o") + + ;; Fix-mde For longlines-mode??: + (set (make-local-variable 'auto-fill-inhibit-regexp) "^[ *#:|;]") + + ;: From org.el: + ;; Get rid of Outline menus, they are not needed + ;; Need to do this here because define-derived-mode sets up + ;; the keymap so late. Still, it is a waste to call this each time + ;; we switch another buffer into org-mode. + (if (featurep 'xemacs) + (when (boundp 'outline-mode-menu-heading) + ;; Assume this is Greg's port, it used easymenu + (easy-menu-remove outline-mode-menu-heading) + (easy-menu-remove outline-mode-menu-show) + (easy-menu-remove outline-mode-menu-hide)) + (define-key wikipedia-mode-map [menu-bar headings] 'undefined) + (define-key wikipedia-mode-map [menu-bar hide] 'undefined) + (define-key wikipedia-mode-map [menu-bar show] 'undefined)) + + (easy-menu-add wikipedia-org-menu) + + ;; Turn on the Imenu automatically. +;; (when menu-bar-mode +;; (set (make-local-variable 'imenu-generic-expression) +;; wikipedia-imenu-generic-expression) +;; (imenu-add-to-menubar "TOC")) + + (modify-syntax-entry ?< "(>" wikipedia-mode-syntax-table) + (modify-syntax-entry ?> ")<" wikipedia-mode-syntax-table) + + ;;}}} + + ;;; This is the wrong way to do it, see add-hook: + ;; (make-local-variable 'change-major-mode-hook) + + ;; Check if our version of outline.el has the new header hooks: + (require 'outline) + (when (boundp 'outline-demote-hook) + (add-hook 'outline-demote-hook 'wikipedia-outline-insert-heading-f nil t) + (add-hook 'outline-promote-hook 'wikipedia-outline-insert-heading-f nil t) + (add-hook 'outline-insert-heading-hook 'wikipedia-outline-insert-heading-f nil t) + ) + ) + +(defun wikipedia-outline-insert-heading-f () + (insert " ") + (backward-char) + (wikipedia-adjust-header-end)) + +;; wikipedia-mode ends here +;;}}} + +;;{{{ longlines-mode + +(defun wikipedia-turn-on-longlines () ;Version:1.58 + "Turn on longlines-mode if it is defined." + (if (functionp 'longlines-mode) + (longlines-mode 1))) + +(defcustom wikipedia-use-longlines-mode nil + "Turn on longlines-mode' if non-nil. +Unfortunately there are some bugs in `longlines-mode' so turning +it on is an option currently." + :type 'boolean + :set (lambda (sym val) + (set-default sym val) + (if val + (add-hook 'wikipedia-mode-hook 'wikipedia-turn-on-longlines) + (remove-hook 'wikipedia-mode-hook 'wikipedia-turn-on-longlines))) + :group 'wikipedia) + +;;}}} + +;; New formating stuff for inserting simple formating structures such + +;;{{{ Insert makeup and templates + +(defvar wikipedia-enumerate-with-terminate-paragraph nil + "*Before insert enumerate/itemize do \\[wikipedia-terminate-paragraph].") + +(defun wikipedia-region-active-p () + (or (and (boundp 'zmacs-region-active-p) zmacs-region-active-p) + (and (boundp 'transient-mark-mode) transient-mark-mode mark-active))) + +(defun wikipedia-insert-around-region (before after) + (if (wikipedia-region-active-p) + (save-excursion + (let ((beginning (region-beginning)) + (end (region-end)) + (check (= (string-to-char before) ?'))) + ;; When we are inserting ' do not mix them: + (if (or (not check) + (not (memq ?' + (append (buffer-substring-no-properties + beginning end) nil)))) + (progn + (goto-char end) + (insert after) + (goto-char beginning) + (insert before)) + (message "Sorry, the region already contains the char '.") + ))) + (insert before) + (insert after) + (backward-char (length after)))) + +(defun wikipedia-insert-enumerate () + "Insert enumerated items. +Format depends on `wikipedia-enumerate-with-terminate-paragraph'. +Note however that `wikipedia-terminate-paragraph' does not work +very well will longlines-mode." + (interactive) + (if wikipedia-enumerate-with-terminate-paragraph + (progn + (wikipedia-terminate-paragraph) + (insert "#")) + (newline nil) + (insert ":#"))) + + + + + +(defun wikipedia-insert-itemize () + "Insert not enumerated items. +Format depends on `wikipedia-enumerate-with-terminate-paragraph'. +Note however that the `wikipedia-terminate-paragraph' does not +work very well will longlines-mode." + (interactive) + (if wikipedia-enumerate-with-terminate-paragraph + (progn + (wikipedia-terminate-paragraph) + (insert "*")) + (newline nil) + (insert ":*"))) + + +(defun wikipedia-insert-bold-italic () + "Insert strong emphasis. +Uses four apostrophes (e.g. ''''FOO''''.) When mark is active, surrounds region." + (interactive) + (wikipedia-insert-around-region "''''" "''''")) + + +(defun wikipedia-insert-bold () + "Insert bold. +Uses three apostrophes (e.g. '''FOO'''.) When mark is active, +surrounds region." + (interactive) + (wikipedia-insert-around-region "'''" "'''")) + + +(defun wikipedia-insert-italics () + "Insert italics. +Uses two apostrophes (e.g. ''FOO''.) When mark is active, +surrounds region." + (interactive) + (wikipedia-insert-around-region "''" "''")) + +(defun wikipedia-indent-paragraph () + (interactive) + (backward-paragraph) + ) +(defun wikipedia-deindent-paragraph () + (interactive) + ) +;;}}} +;;{{{ Templates + +;; http://en.wikipedia.org/wiki/Template:Quotation +;; http://en.wikipedia.org/wiki/Help:A_quick_guide_to_templates +(defvar wikipedia-site nil) +(make-variable-buffer-local 'wikipedia-site) +(defvar wikipedia-site-history nil) + +(defcustom wikipedia-templates nil + "Templates for different wikis." + :type '(repeat (list + (string :tag "Wiki site") + (repeat + (list + (string :tag "Template name") + (string :tag "Template code"))))) + :group 'wikipedia) + +(defun wikipedia-insert-template () + "Prompts for a template and inserts it." + (interactive) + (let* ((t-name-code (wikipedia-get-template)) + (t-name (car t-name-code)) + ;; Ask how to insert: + (choices '("Evaluate when page is created" + "Substitute when saving this source page" + "Show template when page is fetched" + "Insert template itself")) + (hist (copy-sequence choices)) + (default (car choices)) + (choice (completing-read + "How do you want to insert the template? " + choices + nil + t + default + (cons 'hist 1)))) +;; (lwarn 't :warning "t-name=%s" t-name) +;; (lwarn 't :warning "choice=%s" choice) +;; (lwarn 't :warning "0=%s" (nth 0 choices)) +;; (lwarn 't :warning "1=%s" (nth 1 choices)) +;; (lwarn 't :warning "2=%s" (nth 2 choices)) + (cond + ((string= choice (nth 0 choices)) + ;;(lwarn 't :warning "evaluate=>%s" (concat "{{" t-name "}}")) + (insert "{{" t-name "}}") + ) + ((string= choice (nth 1 choices)) + ;;(lwarn 't :warning "subst=>%s" (concat "{{subst:" t-name "}}")) + (insert "{{subst:" t-name "}}") + ) + ((string= choice (nth 2 choices)) + ;;(lwarn 't :warning "raw=>%s" (concat "{{msgnw:" t-name "}}")) + (insert "{{msgnw:" t-name "}}") + ) + ((string= choice (nth 3 choices)) + (insert (cdr t-name-code)) + )))) + +(defun wikipedia-get-template () + (let* ((sites (mapcar (lambda (t-sites) + (car t-sites)) + wikipedia-templates)) + (hist (copy-sequence sites)) + (default-site wikipedia-site) + (histpos (if (not default-site) + 1 + (catch 'pos + (let ((n 0)) + (dolist (elt sites) + (setq n (1+ n)) + (when (string= default-site elt) + (throw 'pos n))))))) + (site (if (= 1 (length sites)) + (car sites) + (completing-read "Wiki site: " + sites + nil + t + default-site + (cons 'hist histpos)))) + (s-t (assoc site wikipedia-templates)) + (templates (car (cdr s-t))) + (t-names (mapcar (lambda (t-for-site) + ;;(lwarn 't :warning "t-for-site=%s" t-for-site) + (car t-for-site)) + templates)) + (t-name (wikipedia-get-template-name site templates)) + (code (car (cdr (assoc t-name templates)))) + ) + (setq wikipedia-site site) +;; (lwarn 't :warning "site=%s" site) +;; (lwarn 't :warning "s-t=%s" s-t) +;; (lwarn 't :warning "templates=%s" templates) +;; (lwarn 't :warning "t-names=%s" t-names) +;; (lwarn 't :warning "t-name=%s" t-name) +;; (lwarn 't :warning "code=%s" code) + (cons t-name code))) + +(defun wikipedia-get-template-name (site templates) + "" + (let* ((prompt "Template: ") + (minibuffer-local-must-match-map (copy-keymap minibuffer-local-must-match-map)) + (hist (mapcar (lambda (elt) + (car elt)) + templates)) + (desc-fun (lambda () + (let ((s (minibuffer-contents-no-properties))) + (when (< 0 (length s)) + (wikipedia-describe-template s site templates))))) + (up-fun (lambda () (interactive) + (previous-history-element 1) + (funcall desc-fun))) + (down-fun (lambda () (interactive) + (next-history-element 1) + (funcall desc-fun))) + (default nil) + (histpos (if (not default) 1)) + (default-name (if default + default + (car (nth (1- histpos) templates)))) + (tpl-name nil) + ) + (define-key minibuffer-local-must-match-map [up] up-fun) + (define-key minibuffer-local-must-match-map [down] down-fun) + (save-window-excursion + (wikipedia-describe-template default-name site templates) + (setq tpl-name (completing-read prompt + templates + nil ; predicate + t ; require-match + default-name ;; initial-input + (cons 'hist histpos) ;; hist + ))) + (when (= 0 (length tpl-name)) + (error "No template name given")) + (let ((tpl (assoc tpl-name templates))) + (unless tpl + (error "There is no template named %s for site %s" tpl-name site)) + ;;(lwarn 't :warning "tpl=%s" tpl) + ) + tpl-name)) + +(defun wikipedia-describe-template (name site templates) + (let ((tpl-rec (assoc name templates))) + (with-output-to-temp-buffer (help-buffer) + (with-current-buffer (help-buffer) + (help-setup-xref (list #'wikipedia-describe-template name site templates) (interactive-p)) + (let ((inhibit-read-only t) + start end + here + (tpl (assoc name templates))) + ;;(insert (format "%S\n\n" family)) + (insert (format "%s - a wiki template for site %s" name site)) + (insert "\n\n") + (setq start (point)) + (insert (cadr tpl)) + (setq end (point)) + (with-no-warnings (print-help-return-message)) + ;;(put-text-property start end 'face 'highlight) + (goto-char start) + (setq here (point)) + (while (re-search-forward "\\(?:<onlyinclude>\\|</onlyinclude>\\|<noinclude>.*</noinclude>\\)" end t) + (put-text-property here (match-beginning 0) 'face 'highlight) + (setq here (point)) + ) + (put-text-property (point) end 'face 'highlight) + ))))) + +(defun wikipedia-insert-nowiki () + "Mark the region as 'nowiki'. +When mark is active, surrounds region." + (interactive) + (wikipedia-insert-around-region "<nowiki>" "</nowiki>")) + + + +(defun wikipedia-insert-user () + "Prompt for a user name, insert [[User:foo]]" + (interactive) + (let ((user (read-string (get-lang-string wikipedia-lang 'wikip-username-prompt))) + (user-mark (get-lang-string wikipedia-lang 'wikip-user-mark))) + (insert (concat user-mark user "|" user "]]")))) + +(defun wikipedia-insert-signature () ;Version:1.4 + "Insert \"~~~~\". +This will be shown as your user identity when showing the page." + (interactive) + (insert "~~~~")) + + + +(defun wikipedia-insert-reply-prefix () ;Version:1.60 + "Quotation box of the form {{Quotation}}{{}}. When mark is active, +surrounds region." + (interactive) + (beginning-of-line 1) + (search-forward "[[") + (backward-char 2) + (mark-sexp 1) + (copy-to-register wikipedia-draft-reply-register (region-beginning) (region-end) nil) + (end-of-line 1) + (wikipedia-terminate-paragraph) + (beginning-of-line 1) + (kill-line nil) + (insert "----") + (newline 1) + (yank) + (insert ":'''Re: ") + (insert-register wikipedia-draft-reply-register 1) + (insert "''' ") + (end-of-line 1)) + +;; (defun wikipedia-insert-header () +;; "Insert subheader via == (e.g. == FOO ==.)" +;; (interactive) +;; (unless (bolp) +;; (beginning-of-line)) +;; (insert "== ") +;; (end-of-line) +;; (insert " ==") +;; (backward-char 3)) + +(defvar wikipedia-link-wiki-history nil) + +(defun wikipedia-insert-link-wiki () + "Insert link via [[ (e.g. [[FOO]].) When mark is active, surround region." + (interactive) + (if (wikipedia-region-active-p) + (wikipedia-insert-around-region "[[" "]]") + (let* ((link (read-string "Wiki link: " nil wikipedia-link-wiki-history)) + (name (read-string "Name (optional): "))) + (insert "[[" link) + (when (< 0 (length name)) + (insert "|" name)) + (insert "]]")))) + +(defun wikipedia-insert-link-external () + "Insert link via [[ (e.g. [http://FOO].) When mark is active, surround region." + (interactive) + (if (wikipedia-region-active-p) + (wikipedia-insert-around-region "[" "]") + (let* ((choices '("Plain" "Footnote" "Named")) + (hist (copy-sequence choices)) + (style (completing-read + "Link style: " ; prompt + choices ; collection + nil ; predicate + t ; requite-match + "Plain" ; initial-input + (cons 'hist 1) ; hist + )) + (url (read-string "URL: ")) + name) + ;;(lwarn 't :warning "style=%s" style) + (cond + ((string= style "Plain") + (insert url)) + ((string= style "Footnote") + (insert "[" url "]")) + ((string= style "Named") + (let ((name (read-string "Link name: "))) + (insert "[" url) + (when (< 0 (length name)) + (insert " " name)) + (insert "]"))) + (t + (error "Internal error, bad style=%s" style)))))) + + +(defun wikipedia-insert-image () + "Insert link image, e.g. [[Image:FOO]]. +When mark is active, surround region." + (interactive) + (let ((img-mark (get-lang-string wikipedia-lang 'wikip-image-mark))) + (wikipedia-insert-around-region img-mark "]]"))) + +(defun wikipedia-insert-audio () + "Insert audio link, e.g. [[Media:FOO]]. +When mark is active, surround region." + (interactive) + (let ((aud-mark (get-lang-string wikipedia-lang 'wikip-audio-mark))) + (wikipedia-insert-around-region aud-mark "]]"))) + + + + +;; (defun wikipedia-turn-on-outline-minor-mode () +;; "Turn on outline minor mode." +;; ;;(interactive) +;; (outline-minor-mode nil)) + + + + + + +(defun wikipedia-insert-hline () ;Version:1.29 + "Insert \"----\" " + (interactive) + (end-of-line) + (insert hard-newline "----" hard-newline)) + +(defun wikipedia-newline (&optional arg) + "Insert newline and check for bullets and numbering." + (interactive "*P") + (let ((here (point)) + (line-type nil)) + (beginning-of-line) + (when (eq ?* (char-after)) + (setq line-type 'bullet)) + (when (eq ?# (char-after)) + (setq line-type 'numbered)) + (if (and line-type + (looking-at ".\\s-*$")) + (progn + (delete-region (match-beginning 0) (match-end 0)) + (newline arg)) + (goto-char here) + (newline arg) + (cond + ((eq line-type 'bullet) + (insert "* ")) + ((eq line-type 'numbered) + (insert "# ")))))) + +;;}}} + +;;{{{ bullets and numbering + +;; Fix-me: Seems like this and my newline stuff already was there ... ;-) +(defun wikipedia-insert-bullet () + "Insert a bullet." + (interactive) + (end-of-line) + (newline) + (insert "* ")) + +(defun wikipedia-insert-numbering () + "Insert numbering." + (interactive) + (end-of-line) + (newline) + (insert "# ")) + +;;}}} + +;;{{{ filling and longline + +(defun wikipedia-unfill-paragraph-or-region () ;Version:1.7 + "Unfill region. +This function does NOT explicitly search for \"soft newlines\" as +does wikipedia-unfill-region." + (interactive) + (when use-hard-newlines + ;; (backward-paragraph 1) + ;; (next-line 1) + (beginning-of-line 1) + (set-fill-prefix) + ;; Fix-me: The use of make-local-variable here looks incorrect, + ;; use lexical binding instead: +;; (set (make-local-variable 'use-hard-newlines) nil) +;; (set (make-local-variable 'sentence-end-double-space) t) +;; (set (make-local-variable 'paragraph-start) "[ ã \n]") + (let ((use-hard-newlines nil) + (sentence-end-double-space t) + (paragraph-start nil)) + (when (featurep 'xemacs) + (let ((fill-column (point-max))) + (fill-paragraph-or-region nil))) + (unless (featurep 'xemacs) + (let ((fill-column (point-max))) + (fill-paragraph nil))))) +;; (set (make-local-variable 'use-hard-newlines) t) +;; (set (make-local-variable 'sentence-end-double-space) nil) +;; (set (make-local-variable 'paragraph-start) "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$")) + (unless use-hard-newlines + ;; (backward-paragraph 1) + ;; (next-line 1) + (beginning-of-line 1) + (set-fill-prefix) +;; (set (make-local-variable 'sentence-end-double-space) t) +;; (set (make-local-variable 'paragraph-start) + (let ((sentence-end-double-space t) + (paragraph-start nil)) + (when (featurep 'xemacs) + (let ((fill-column (point-max))) + (fill-paragraph-or-region nil))) + (unless (featurep 'xemacs) + (let ((fill-column (point-max))) + (fill-paragraph nil)))) +;; (set (make-local-variable 'sentence-end-double-space) nil) +;; (set (make-local-variable 'paragraph-start) "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$") + )) + + + + +;; (defun wikipedia-start-paragraph () +;; (interactive) +;; (set (make-local-variable 'paragraph-start) +;; "\\*\\| \\|#\\|;\\|:\\||\\|!\\|$")) + +;; Use function use-hard-newlines instead: +;; (defun wikipedia-hardlines () +;; "Set use-hard-newlines to NIL." +;; (interactive) +;; (setq use-hard-newlines nil)) + +;; from emacs wiki +(defun wikipedia-next-long-line () + "Move forward to the next long line with column-width greater + than `fill-column'. + + TODO: When function reaches end of buffer, save-excursion to + starting point. + Generalise to make `previous-long-line'." + (interactive) + ;; global-variable: fill-column + (if (= (forward-line) 0) + (let ((line-length + (save-excursion + (end-of-line) + (current-column)))) + (if (<= line-length fill-column) + (wikipedia-next-long-line) + (message "Long line found"))) + ;; Stop, end of buffer reached. + (error "Long line not found"))) + + +(defun wikipedia-unfill-paragraph-simple () + "A very simple function for unfilling a paragraph." + (interactive) + (if (functionp 'filladapt-mode) + (filladapt-mode nil)) + (let ((fill-column (point-max))) + (fill-paragraph nil) + (if (functionp 'filladapt-mode) + (filladapt-mode nil)))) + +;;}}} + +;;{{{ outline and outline-magic stuff + +;;(add-hook 'wikipedia-mode-hook 'wikipedia-turn-on-outline-minor-mode) +;;(remove-hook 'wikipedia-mode-hook 'wikipedia-turn-on-outline-minor-mode) + +(defun wikipedia-outline-cycle () + (interactive) + (if (functionp 'outline-cycle) + (outline-cycle))) + +;; Fix-me: Unfortunately outline maybe does not take care of the +;; heading endings when promoting and demoting (I have submitted a bug +;; report for this and hooks will be added). To work around this we +;; defadvice outline-demote/promote: + +(require 'outline) +(unless (boundp 'outline-demote-hook) + + (defadvice outline-demote (after wikipedia-outline-demote-advice + (&optional which)) + "Adjust heading after demote." + (unless which + (wikipedia-adjust-header-end))) + + (defadvice outline-promote (after wikipedia-outline-promote-advice + (&optional which)) + "Adjust heading after promote." + (unless which + (wikipedia-adjust-header-end))) + + (defadvice outline-insert-heading (after wikipedia-outline-insert-heading-advice + ()) + "Adjust heading after insert new heading." + (wikipedia-adjust-header-end)) + + ) + +(defun wikipedia-adjust-header-end () + (when (eq major-mode 'wikipedia-mode) + (let ((here (point)) + (end-pos (line-end-position)) + bgn-mark + bgn-len + end-mark + end-len + ) + (beginning-of-line) + (when (looking-at outline-regexp) + (setq bgn-mark (match-string-no-properties 0)) + (setq bgn-len (length bgn-mark)) + (end-of-line) + (if (looking-back outline-regexp nil t) + (when (progn + (setq end-mark (match-string-no-properties 0)) + (setq end-len (length end-mark)) + (/= end-len bgn-len)) + (replace-match bgn-mark)) + (insert bgn-mark))) + ;;(lwarn 't :warning "bgn-len=%s, end-len=%s" bgn-len end-len) + (goto-char here)))) + + + +;;(add-hook 'outline-minor-mode-hook 'wikipedia-outline-magic-keys) +(add-hook 'wikipedia-mode-hook 'wikipedia-outline-magic-keys) + +(defun wikipedia-outline-magic-keys () + (interactive) + (unless (featurep 'xemacs) + (local-set-key [(shift iso-lefttab)] 'wikipedia-outline-cycle)) + (local-set-key [iso-left-tab] 'wikipedia-outline-cycle) + ;;(local-set-key [(meta left)] 'outline-promote) + (local-set-key [(meta shift left)] 'outline-promote) + ;;(local-set-key [(meta right)] 'outline-demote) + (local-set-key [(meta shift right)] 'outline-demote) + ;;(local-set-key [(control left)] 'wikipedia-simple-outline-promote) + (local-set-key [(meta left)] 'wikipedia-simple-outline-promote) + ;;(local-set-key [(control right)] 'wikipedia-simple-outline-demote) + (local-set-key [(meta right)] 'wikipedia-simple-outline-demote) + (local-set-key [(shift return)] 'newline-and-indent) + ;;(local-set-key [(control up)] 'outline-move-subtree-up) + (local-set-key [(meta shift up)] 'outline-move-subtree-up) + ;;(local-set-key [(control down)] 'outline-move-subtree-down)) + (local-set-key [(meta shift down)] 'outline-move-subtree-down)) + +(defun wikipedia-enhance-indent () ;Version:1.26 + (interactive) + (string-rectangle (region-beginning) (region-end) ":")) + +(defun wikipedia-yank-prefix () ;Version:1.26 + (interactive) + (string-rectangle (region-beginning) (region-end) ":")) + +;; modification for outline-magic + +(defun wikipedia-simple-outline-promote () + "Function simple deletes \"=\" and the end and the beginning of line, +does not promote the whole tree!" + (interactive) + (save-excursion + (progn + (beginning-of-line 1) + (search-forward "=") + (delete-char 1 nil) + (end-of-line 1) + (search-backward "=") + (delete-char 1 nil)))) + +(defun wikipedia-simple-outline-demote () + "Function simple adds \"=\" and the end and the beginning of line, +does not promote the whole tree!" + (interactive) + (save-excursion + (progn + (beginning-of-line 1) + (search-forward "=") + (insert "=") + (end-of-line 1) + (search-backward "=") + (insert "=")))) + + +(defun wikipedia-rename-buffer () ;Version:1.5 + "Make sure that the option UNIQUE is used." + (interactive) + (rename-buffer (read-string "Name of new buffer (unique): " ) 1)) + +;;}}} + +;;{{{ wikipedia drafts functionality: `stolen' from remember.el: + +(defgroup wikipedia-draft nil + "A mode to wikipedia-draft information." + :group 'data) + +;;; User Variables: + +(defcustom wikipedia-draft-mode-hook nil + "*Functions run upon entering wikipedia-draft-mode." + :type 'hook + :group 'wikipedia-draft) + +(defcustom wikipedia-draft-register ?R + "The register in which the window configuration is stored." + :type 'character + :group 'wikipedia-draft) + +(defcustom wikipedia-draft-filter-functions nil + "*Functions run to filter wikipedia-draft data. +All functions are run in the wikipedia-draft buffer." + :type 'hook + :group 'wikipedia-draft) + +(defcustom wikipedia-draft-handler-functions '(wikipedia-draft-append-to-file) + "*Functions run to process wikipedia-draft data. +Each function is called with the current buffer narrowed to what the +user wants wikipedia-drafted. +If any function returns non-nil, the data is assumed to have been +recorded somewhere by that function. " + :type 'hook + :group 'wikipedia-draft) + +(defcustom wikipedia-draft-data-file "~/Wiki/discussions/draft.wiki" + "*The file in which to store the wikipedia drafts." + :type 'file + :group 'wikipedia-draft) + +(defcustom wikipedia-draft-reply-register ?M + "The register in which the window configuration is stored." + :type 'character + :group 'wikipedia-draft) + +(defcustom wikipedia-draft-page ?S ;Version:1.37 + "The register in which the a page of the wiki draft file is stored." + :type 'character + :group 'wikipedia-draft) + + +(defcustom wikipedia-draft-leader-text "== " + "*The text used to begin each wikipedia-draft item." + :type 'string + :group 'wikipedia-draft) + + +;;; Internal Variables: + +(defvar wikipedia-draft-buffer "*Wikipedia-Draft*" + "The name of the wikipedia-draft (temporary) data entry buffer.") + +;;; User Functions: + +;;;###autoload +(defun wikipedia-draft () + "Open a temporary buffer in wikipedia mode for editing an + wikipedia draft, which an arbitrary piece of data. After + finishing the editing either use \\[wikipedia-draft-buffer] to + send the data into the wikipedia-draft-data-file, or send the + buffer using `wikipedia-draft-send-to-mozex' and insert it later + into a wikipedia article." + (interactive) + (window-configuration-to-register wikipedia-draft-register) + (let ((buf (get-buffer-create wikipedia-draft-buffer))) + (switch-to-buffer-other-window buf) + (wikipedia-mode) + (message " C-c C-k sends to draft file, C-c C-c sends to org buffer."))) + + + + + +(defsubst wikipedia-draft-time-to-seconds (time) + "Convert TIME to a floating point number." + (+ (* (car time) 65536.0) + (cadr time) + (/ (or (car (cdr (cdr time))) 0) 1000000.0))) + +(defsubst wikipedia-draft-mail-date (&optional rfc822-p) + "Return a simple date. Nothing fancy." + (if rfc822-p + (format-time-string "%a, %e %b %Y %T %z" (current-time)) + (format-time-string "%c" (current-time)))) + +(defun wikipedia-draft-buffer-desc () + "Using the first line of the current buffer, create a short description." + (buffer-substring (point-min) + (save-excursion + (goto-char (point-min)) + (end-of-line) + (if (> (- (point) (point-min)) 60) + (goto-char (+ (point-min) 60))) + (point)))) + + +;; Wikipedia-Drafting to plain files: + + +(defun wikipedia-draft-append-to-file () + "Add a header together with a subject to the text and add it to the +draft file. It might be better if longlines-mode is off." + (let ((text (buffer-string)) + (desc (wikipedia-draft-buffer-desc))) + (with-temp-buffer + (insert "\n\n") + (insert wikipedia-draft-leader-text) + (insert "Draft: ") ;Version:1.39 + (insert (read-string "Enter Subject: ")) + (insert " ") + (insert (current-time-string)) + (insert " ") + (insert wikipedia-draft-leader-text) + (insert "\n\n") ;Version:1.27 + (insert "") + (insert "\n\n") + (insert text) + (insert "\n") + (insert "") + (insert "\n") + (if (not (bolp)) + (insert "\n\n")) + (if (find-buffer-visiting wikipedia-draft-data-file) + (let ((wikipedia-draft-text (buffer-string))) + (set-buffer (get-file-buffer wikipedia-draft-data-file)) + (save-excursion + (goto-char (point-max)) + (insert "\n") + (insert wikipedia-draft-text) + (insert "\n") + (save-buffer))) + (append-to-file (point-min) (point-max) wikipedia-draft-data-file))))) + + +(setq wikipedia-draft-handler-functions 'wikipedia-draft-append-to-file) + + +(custom-add-option 'wikipedia-draft-handler-functions 'wikipedia-draft-append-to-file) + +;;;###autoload +(defun wikipedia-draft-page () ;Version:1.32 + (interactive) + (mark-page) + (copy-region-as-kill (region-beginning) (region-end)) + (wikipedia-draft) + (yank nil)) + + +(defun wikipedia-draft-region (&optional beg end) + "Wikipedia-Draft the data from BEG to END. +If called from within the wikipedia-draft buffer, BEG and END are ignored, +and the entire buffer will be wikipedia-drafted. If called from any other +buffer, that region, plus any context information specific to that +region, will be wikipedia-drafted." + (interactive) + (let ((b (or beg (min (point) (or (mark) (point-min))))) + (e (or end (max (point) (or (mark) (point-max)))))) + (save-restriction + (narrow-to-region b e) + (run-hook-with-args-until-success 'wikipedia-draft-handler-functions) + (when (equal wikipedia-draft-buffer (buffer-name)) + (kill-buffer (current-buffer)) + (jump-to-register wikipedia-draft-register))))) + +;; +;;;###autoload +(defun wikipedia-draft-buffer () + "Wikipedia-draft-buffer sends the contents of the current (temporary) +buffer to the wikipedia-draft-buffer, see the variable +wikipedia-draft-data-file." + (interactive) + (wikipedia-draft-region (point-min) (point-max))) + +(defun wikipedia-draft-clipboard () + "Wikipedia-Draft the contents of the current clipboard. +Most useful for wikipedia-drafting things from Netscape or other X Windows +application." + (interactive) + (with-temp-buffer + (insert (x-get-clipboard)) + (run-hook-with-args-until-success 'wikipedia-draft-handler-functions))) + +;;;###autoload + + +;;; Internal Functions: +(defvar wikipedia-draft-send-archive t ;Version:1.56 + "*Archive the reply.") + +(defvar wikipedia-draft-mode-map + (let ((m (make-sparse-keymap))) + (define-key m "\C-c\C-k" 'wikipedia-draft-buffer) + (define-key m "\C-c\C-d" 'wikipedia-draft-buffer) + m)) + +(defun wikipedia-draft-mode () + "Major mode for output from \\[wikipedia-draft]. +\\<wikipedia-draft-mode-map> This buffer is used to collect data that +you want wikipedia-draft. Just hit \\[wikipedia-draft-region] when +you're done entering, and it will go ahead and file the data for +latter retrieval, and possible indexing. +\\{wikipedia-draft-mode-map}" + (interactive) + (kill-all-local-variables) + (indented-text-mode) + (use-local-map wikipedia-draft-mode-map) + (setq major-mode 'wikipedia-draft-mode + mode-name "Wikipedia-Draft") + (run-hooks 'wikipedia-draft-mode-hook)) + + +(defun wikipedia-draft-view-draft () + (interactive) + "Simple shortcut to visit the file, which contains the wikipedia drafts." + (find-file wikipedia-draft-data-file)) + +;;}}} + +;;{{{ functions for marking regions + +(defun wikipedia-mark-section () ;Version:1.36 + "Set mark at end of current logical section, and point at top." + (interactive) + (re-search-forward (concat "== " "[a-z,A-z \t]*" + " ==")) + (re-search-backward "^") + (set-mark (point)) + (re-search-backward (concat "== " "[a-z,A-z \t]*" + " ")) + (wikipedia-activate-region)) + +(defun wikipedia-mark-signature () ;Version:1.36 + "Set mark at end of current logical section, and point at top." + (interactive) + (re-search-forward "]]") ;;[[ ]] + (re-search-backward "^") + (set-mark (point)) + (re-search-backward "[[") + (wikipedia-activate-region)) + +(when (featurep 'xemacs) + (fset 'wikipedia-activate-region (symbol-function 'zmacs-activate-region))) + +(unless (featurep 'xemacs) + (defun wikipedia-activate-region () + nil)) + +;;}}} + +;;{{{ `reply' and `send' functions + +(defun wikipedia-draft-copy-page-to-register () ;Version:1.47 + "Copy a page via the wikipedia-draft-register." + (interactive) + (save-excursion + (narrow-to-page nil) + (copy-to-register wikipedia-draft-page (point-min) (point-max) nil) + (message "draft page copied to wikipedia register wikipedia-draft-page.") + (widen))) + + ;aux function +(defun wikipedia-draft-yank-page-to-register () ;Version:1.50 + "Insert a page via the wikipedia-draft-register." + (interactive) + (insert-register wikipedia-draft-page nil)) + + + +(defun wikipedia-draft-send-to-mozex (target-buffer) ;Version:1.56 + "Copy the current page from the wikipedia draft file to + TARGET-BUFFER, this buffer is named something like mozex.textarea. +Check the variable wikipedia-draft-send-archive. If it is t, then +additionally the text will be archived in the draft.wiki file. Check +longlines-mode, it might be better if it is set off." + (interactive "bTarget buffer: ") + (let ((src-buf (current-buffer))) + (wikipedia-draft-copy-page-to-register) + (switch-to-buffer target-buffer) + (end-of-line 1) + (newline 1) + (wikipedia-draft-yank-page-to-register) + (message "The page has been sent (copied) to the mozex file!") + (switch-to-buffer "*Wikipedia-Draft*") + (when wikipedia-draft-send-archive ;Version:1.56 + (let ((text (buffer-string)) ;Version:1.59 + (desc (wikipedia-draft-buffer-desc))) + (with-temp-buffer + (insert "\n\n") + (insert wikipedia-draft-leader-text) + (insert-register wikipedia-draft-reply-register 1) + (insert " ") + (insert (current-time-string)) + (insert " ") + (insert wikipedia-draft-leader-text) + (insert "\n\n") + (insert "") + (insert "\n\n") + (insert text) + (insert "\n") + (insert "") + (insert "\n") + (if (not (bolp)) + (insert "\n\n")) + (if (find-buffer-visiting wikipedia-draft-data-file) + (let ((wikipedia-draft-text (buffer-string))) + (set-buffer (get-file-buffer wikipedia-draft-data-file)) + (save-excursion + (goto-char (point-max)) + (insert "\n") + (insert wikipedia-draft-text) + (insert "\n") + (save-buffer))) + (append-to-file (point-min) (point-max) wikipedia-draft-data-file))))) + (when (equal wikipedia-draft-buffer (buffer-name)) + (kill-buffer (current-buffer))) + (switch-to-buffer target-buffer))) + + +;;Apr_22_2006 +(defvar wikipedia-reply-with-hline nil + "*Whether to use a hline as a header seperator in the reply.") + +(defvar wikipedia-reply-with-quote nil ;Version:1.60 + "*Whether to use a quotation tempalate or not.") + +(defvar wikipedia-user-simplify-signature t + "*Simple varible in order to threat complicated signatures of users, which uses +fonts and other makeup.") + +(defun wikipedia-reply-at-signature () ;Version:1.40 + "Very simple function to add the reply prefix to the signature, +sorrounded by the boldface makeup. You have to set the point BEFORE +the signature, then the functions inserts the following +:'''Re: [[User:foo]]'''." + (interactive) + (beginning-of-line 1) + (search-forward "[[") + (mark-word 3) + (yank) + (end-of-line 1) + (wikipedia-terminate-paragraph) + (insert ":'''Re: ") + (insert "[[") + (yank) + (insert "]]") + (insert "'''")) + + + + +(defun wikipedia-draft-reply () ;Version:1.62 + "Open a temporary buffer in wikipedia mode for editing an wikipedia +draft, with an arbitrary piece of data. After finishing the editing +|]]:either use \"C-c C-k\" \\[wikipedia-draft-buffer] to send the data into +the wikipedia-draft-data-file, or send the buffer \"C-c\C-c\", +\\[wikipedia-draft-send-to-mozex] to the current wikipedia article via +mozex. Check the varibale wikipedia-draft-send-archive." + (interactive) + (wikipedia-reply-at-point-simple) + (beginning-of-line 1) + (kill-line nil) + (save-excursion + (window-configuration-to-register wikipedia-draft-register) + (let ((buf (get-buffer-create wikipedia-draft-buffer))) + (switch-to-buffer-other-window buf) + (wikipedia-mode) + (if (functionp 'pabbrev-mode) + (pabbrev-mode)) + (when (not wikipedia-reply-with-quote) + (when wikipedia-reply-with-hline + (insert "----") + (newline 1)) + (yank) + (end-of-line 1)) + (when wikipedia-reply-with-quote + (insert "{{Quotation|") + (yank) + (insert "'''Re: ") + (insert-register wikipedia-draft-reply-register 1) + (insert "''' |~~~~}}") + (backward-char 7)) + (message " C-c C-k sends to draft, C-c C-c sends to org buffer.")))) + +(defun wikipedia-reply-at-point-simple () ;Version:1.65 + "Reply to posts in discussion forums. +You have to put the region around the signature, then the +functions inserts the following +:'''Re: [[User:foo]]'''." + (interactive) + (beginning-of-line 1) + (search-forward (get-lang-string wikipedia-lang 'wikip-utc)) + (search-backward (get-lang-string wikipedia-lang 'wikip-user-mark)) + (when (not wikipedia-user-simplify-signature) + (mark-word 3)) + (when wikipedia-user-simplify-signature + (mark-word 2)) + (copy-to-register wikipedia-draft-reply-register (region-beginning) (region-end) nil) + (end-of-line 1) + (wikipedia-terminate-paragraph-and-indent) + (insert ":'''Re: ") + (insert-register wikipedia-draft-reply-register 1) + (when wikipedia-user-simplify-signature + (insert "|]]''' ")) + (when (not wikipedia-user-simplify-signature) + (insert "]]''' "))) + +;;}}} + +;;{{{ Optional private stuff: + +;; (defun wikipedia-insert-quotation-with-signature () ;Version:1.60 +;; "Insert quotation with signature. +;; When mark is active, surrounds region." +;; (interactive) +;; (wikipedia-insert-around-region "{{Quotation|" "}}{{~~~~}}")) + +;; (defun wikipedia-insert-quotation () ;Version:1.60 +;; "Insert quotation box. +;; When mark is active, surrounds region." +;; (interactive) +;; ;; Fix-me: This uses a template, is that really always available??? +;; (wikipedia-insert-around-region "{{Quotation|" "}}")) + +;; (define-key wikipedia-mode-map "\C-c\C-fv" 'wikipedia-insert-bible-verse-template) +;; +;; (defun wikipedia-insert-bible-verse-template () +;; "Insert a template for the quotation of bible verses." +;; (interactive) +;; (insert "({{niv|") +;; (let ((name (read-string "Name: "))) +;; (insert (concat name "|")) +;; (let ((verse (read-string "Verse: "))) +;; (insert (concat verse "|" name " " verse "}})"))))) + +;;}}} + +(provide 'wikipedia-mode) +;;; wikipedia-mode.el ends here. + + diff --git a/emacs/nxhtml/tests/angus77-setup-jde.el b/emacs/nxhtml/tests/angus77-setup-jde.el new file mode 100644 index 0000000..dd8f9ac --- /dev/null +++ b/emacs/nxhtml/tests/angus77-setup-jde.el @@ -0,0 +1,90 @@ +;;; angus77-setup-jde.el --- +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-20T16:57:35+0200 Wed +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +;; Question #42407 on nXhtml changed: +;; https://answers.launchpad.net/nxhtml/+question/42407 + +;; Angus77 posted a new comment: + +(eval-when-compile (require 'cl)) +(let ( + ;;(jde-lisp-dir "C:/jdee/jdee/trunk/jde/lisp/") + (jde-lisp-dir "C:/jdee/jdee/branches/phil_lord/dimitre_liotev_new_build/jde/lisp") + (cedet-root "c:/cedet/cedet/") + (elib-dir "C:/DL/emacs/elib-1.0") + ) + (assert (file-directory-p jde-lisp-dir) t) + ;;(add-to-list 'load-path (expand-file-name "~/elisp/jde-2.3.5.1/lisp")) + (add-to-list 'load-path jde-lisp-dir) + ;;(add-to-list 'load-path (expand-file-name "~/elisp/cedet-1.0pre4/semantic")) + (add-to-list 'load-path (expand-file-name "semantic" cedet-root)) + ;;(add-to-list 'load-path (expand-file-name "~/elisp/cedet-1.0pre4/speedbar")) + (add-to-list 'load-path (expand-file-name "speedbar" cedet-root)) + ;;(add-to-list 'load-path (expand-file-name "~/elisp/elib")) + (add-to-list 'load-path elib-dir) + ;;(add-to-list 'load-path (expand-file-name "~/elisp/cedet-1.0pre4/eieio")) + (add-to-list 'load-path (expand-file-name "eieio" cedet-root)) + ;;(add-to-list 'load-path (expand-file-name "~/elisp/cedet-1.0pre4/common")) + (add-to-list 'load-path (expand-file-name "common" cedet-root))) + +;; Initialize CEDET. +;;(load-file (expand-file-name "~/elisp/cedet-1.0pre4/common/cedet.el")) +(load-library "cedet.el") + +(setq defer-loading-jde t) + +(if defer-loading-jde + (progn + (autoload 'jde-mode "jde" "JDE mode." t) + (setq auto-mode-alist + (append + '(("\\.java\\'" . jde-mode)) + auto-mode-alist))) + (require 'jde)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; angus77-setup-jde.el ends here diff --git a/emacs/nxhtml/tests/emacstest-suites.el b/emacs/nxhtml/tests/emacstest-suites.el new file mode 100644 index 0000000..5953fac --- /dev/null +++ b/emacs/nxhtml/tests/emacstest-suites.el @@ -0,0 +1,102 @@ +;;; emacstest-suites.el --- Some unit tests for Emacs +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-09-21T22:34:11+0200 Sun +;; Version: +;; Last-Updated: 2008-09-22T00:36:11+0200 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `button', `cl', `debug', `ert', `ert2', `ewoc', `find-func', +;; `help-fns', `help-mode', `view'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Unit tests for some Emacs bug reports. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile + (let* ((this-file (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + (this-dir (file-name-directory this-file)) + (load-path (cons this-dir load-path))) + (require 'ert2))) + +(setq debug-on-error t) + +(defvar emacstest-bin + (file-name-directory (if load-file-name load-file-name buffer-file-name))) + +(pushnew emacstest-bin load-path) + + + +(defvar emacstest-files-root + (let* ((this-dir emacstest-bin) + (root (expand-file-name "inemacs/" this-dir))) + (unless (file-accessible-directory-p root) + (error (if (file-exists-p root) + "Can't read files in test directory %s" + "Can't find test directory %s") + root)) + root)) + +(let ((distr-in "c:/EmacsW32/nxhtml/tests/inemacs/")) + (when (file-directory-p distr-in) + (setq emacstest-files-root distr-in))) + +(defun emacstest-run () + "Run Emacs tests." + (interactive) + (setq message-log-max t) + (setq ert-test-files-root emacstest-files-root) + (let ((selector "emacs-")) + (if noninteractive + (ert-run-tests-batch selector) + (ert-kill-temp-test-buffers) + (ert-run-tests-interactively selector) + (other-window 1) + (ert-list-temp-test-buffers)))) + +(ert-deftest emacs-bug1013 () + "Emacs bug 1013. +See URL +`http://emacsbugs.donarmstrong.com/cgi-bin/bugreport.cgi?bug=1013'." + (ert-with-temp-buffer-include-file "bug1013.el" + (eval-buffer))) + +(provide 'emacstest-suites) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; emacstest-suites.el ends here diff --git a/emacs/nxhtml/tests/ert.el b/emacs/nxhtml/tests/ert.el new file mode 100644 index 0000000..491d79f --- /dev/null +++ b/emacs/nxhtml/tests/ert.el @@ -0,0 +1,2418 @@ +;;; ert.el --- Emacs Lisp Regression Testing + +;; Modified by Lennart Borgman 2008-07-13 to make all global symbols +;; use the "ert-" prefix. + +;; Copyright (C) 2007, 2008 Christian M. Ohler + +;; Author: Christian M. Ohler +;; Version: 0.2 +;; Keywords: lisp, tools + +;; This file is NOT part of 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 3 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, see `http://www.gnu.org/licenses/'. + +;;; Commentary: + +;; ERT is a tool for automated testing in Emacs Lisp. Its main +;; features are facilities for defining and running test cases and +;; reporting the results as well as for debugging test failures +;; interactively. +;; +;; The main entry points are `ert-deftest', which is similar to +;; `defun' but defines a test, and `ert-run-tests-interactively', +;; which runs tests and offers an interactive interface for inspecting +;; results and debugging. There is also `ert-run-tests-batch' for +;; non-interactive use. +;; +;; The body of `ert-deftest' forms resembles a function body, but the +;; additional operators `should', `should-not' and `should-error' are +;; available. `should' is similar to cl's `assert', but signals a +;; different error when its condition is violated that is caught and +;; processed by ERT. In addition, it analyzes its argument form and +;; records information that helps debugging (`assert' tries to do +;; something similar when its second argument SHOW-ARGS is true, but +;; `should' is more sophisticated). For information on `should-not' +;; and `should-error', see their docstrings. +;; +;; For example, +;; +;; ;; Define a test named `foo'. +;; (ert-deftest foo () +;; (ert-should (= (+ 1 2) 4))) +;; +;; ;; Run it. +;; (ert-run-tests-interactively 'foo) +;; +;; generates the following output (in addition to some statistics) in +;; the *ert* results buffer: +;; +;; F foo +;; (ert-test-failed +;; ((ert-should +;; (= +;; (+ 1 2) +;; 4)) +;; :form +;; (= 3 4) +;; :value nil)) +;; +;; This indicates that the test failed. The `should' form that failed +;; was (ert-should (= (+ 1 2) 4)), because its inner form, after +;; evaluation of its arguments, was the function call (= 3 4), which +;; returned nil. +;; +;; Obviously, this is a bug in the test case, not in the functions `+' +;; or `='. In the results buffer, with point on the test result, the +;; key "." can be used to jump to the definition of the test to modify +;; it to correct the bug. After evaluating the modified definition +;; and switching back to the results buffer, the key "r" will re-run +;; the test and show the new result. + + +;; Test selectors +;; +;; Functions like `ert-run-tests-interactively' accept a test +;; selector, which is a Lisp expression specifying a set of tests. +;; Each test name is a selector that refers to that test, the selector +;; `t' refers to all tests, and the selector `:failed' refers to all +;; tests that failed; but more complex selectors are available. Test +;; selector syntax is similar to cl's type specifier syntax. See the +;; docstring of `ert-select-tests' for details. + + +;; Comparison with other testing tools +;; +;; ERT allows test-driven development similar to *Unit frameworks for +;; other languages. However, two common *Unit features are notably +;; absent from ERT: fixtures and test suites. +;; +;; Fixtures, as used e.g. in SUnit or JUnit, have two main purposes: +;; Setting up (and tearing down) an environment for a set of test +;; cases, and making that environment accessible through object +;; attributes that can be used like local variables. +;; +;; While fixtures are a great syntactic simplification in other +;; languages, they are not very useful in Lisp, where higher-order +;; functions and `unwind-protect' are available. One way to implement +;; and use a fixture in ERT is +;; +;; (defun my-fixture (body) +;; (unwind-protect +;; (progn ...set up... +;; (funcall body)) +;; ...tear down...)) +;; +;; (ert-deftest my-test () +;; (my-fixture +;; (lambda () +;; ...test code...))) +;; +;; (Another way would be a `with-my-fixture' macro.) This solves the +;; set-up and tear-down part, and additionally allows any test case to +;; use any combination of fixtures, so it is more general than what +;; other tools typically allow. +;; +;; If the test case needs access to the environment the fixture sets +;; up, the fixture can be modified to pass arguments to the body. +;; +;; These are standard Lisp idioms. Special syntax for them could be +;; added easily enough, but would provide only a minor simplification. +;; +;; (Note that splitting set-up and tear-down into separate functions, +;; like *Unit tools usually do, makes it impossible to establish +;; dynamic `let' bindings as part of the fixture. So, blindly +;; imitating the way fixtures are implemented in other languages would +;; be counter-productive in Lisp.) +;; +;; +;; The purpose of test suites is to group related test cases together. +;; The most common use of this is to run just the tests for one +;; particular module. Since symbol prefixes are the usual way of +;; separating module namespaces in Emacs Lisp, test selectors already +;; solve this by allowing regexp matching on test names; e.g., the +;; selector "^ert-" selects ERT's self-tests. +;; +;; If test suites containing arbitrary sets of tests are found to be +;; desirable, it would be easy to add a `define-test-selector' +;; mechanism that introduces a new selector, defined in terms of +;; existing ones; e.g. +;; +;; ;; Note that `define-test-selector' does not exist yet. +;; (define-test-selector my-test-suite () `(member foo-test bar-test)) +;; +;; would define a test suite named `my-test-suite' consisting of +;; `foo-test' and `bar-test'. See also `deftype' in Common Lisp. + + +;; TODO: Add `skip' feature for tests that can't run in current environment. + + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'ewoc) +(require 'find-func) +(require 'debug) + +(defvar ert-debug-on-error nil + "Non-nil means enter debugger when a test fails or terminates with an error.") + + +;;; Defining and locating tests. + +;; The data structure that represents a test case. +(defstruct ert-test + (name nil) + (documentation nil) + (body (assert nil)) + (most-recent-result nil) + (expected-result-type 'ert-test-passed)) + +(defun ert-test-boundp (symbol) + "Return non-nil if SYMBOL names a test." + (and (get symbol 'ert-test) t)) + +(defun ert-get-test (symbol) + "If SYMBOL names a test, return that. Signal an error otherwise." + (assert (ert-test-boundp symbol) t) + (get symbol 'ert-test)) + +(defun ert-set-test (symbol doc definition) + "Make SYMBOL name the test DEFINITION, and return DEFINITION." + (when doc + (put symbol 'ert-test-documentation doc)) + (put symbol 'ert-test definition) + definition) + +(defun ert-make-test-unbound (symbol) + "Make SYMBOL name no test. Return SYMBOL." + (remprop symbol 'ert-test) + symbol) + +(defun ert-test-result-expected-p (test result) + "Return non-nil if RESULT matches the expected result type for TEST." + (typep result (ert-test-expected-result-type test))) + +(defvar ert-find-test-regexp + (concat "^\\s-*(ert-deftest" + find-function-space-re + "%s\\(\\s-\\|$\\)") + "The regexp the `find-function' mechanisms use for locating test definitions.") + +(eval-and-compile + (defun ert-parse-keys-and-body (docstr keys-and-body) + "Split KEYS-AND-BODY into keyword-and-value pairs and the remaining body. + +KEYS-AND-BODY should have the form of a property list, with the +exception that only keywords are permitted as keys and that the +tail -- the body -- is a list of forms that does not start with a +keyword. + +Returns a two-element list containing the keys-and-values plist +and the body." + (unless (stringp docstr) + (when docstr + (setq keys-and-body (cons docstr keys-and-body)) + (setq docstr nil))) + (let ((extracted-key-accu '()) + (remaining keys-and-body)) + (while (and (consp remaining) (keywordp (first remaining))) + (let ((keyword (pop remaining))) + (unless (consp remaining) + (error "Value expected after keyword %S in %S" + keyword keys-and-body)) + (when (assoc keyword extracted-key-accu) + (warn "Keyword %S appears more than once in %S" keyword + keys-and-body)) + (push (cons keyword (pop remaining)) extracted-key-accu))) + (setq extracted-key-accu (nreverse extracted-key-accu)) + (list (loop for (key . value) in extracted-key-accu + collect key + collect value) + docstr + remaining)))) + +(defvar ert-error-on-test-redefinition nil) + +;;;###autoload +(defmacro* ert-deftest (name () + &optional docstr + &body keys-and-body) + "Define NAME (a symbol) as a test. + +\(fn NAME () [:documentation DOCSTRING] [:expected-result TYPE] BODY...)" + ;; The :documentation would be unreadable. I have therefore added + ;; docstr that will look like documentation use to in Emacs. Maybe + ;; add function ert-describe-test? + (declare (indent 2) + (debug (&define :name test name sexp + [&optional [":documentation" stringp]] + [&optional [":expected-result" sexp]] + def-body))) + (destructuring-bind ((&key (expected-result nil expected-result-supplied-p) + (documentation nil documentation-supplied-p)) + doc + body) + (ert-parse-keys-and-body docstr keys-and-body) + `(progn + ;; Guard against missing/badly named tests: + (when (and ert-error-on-test-redefinition + (symbolp ',name) + (get ',name 'ert-test)) + (with-output-to-temp-buffer "*Ert Error*" + (with-current-buffer "*Ert Error*" + (insert "Test " + (format "%s" ',name) + " is already defined in " + (format "%s" (find-definition-noselect ',name 'ert-deftest)) + "\n\n" + "Tip: Use `ert-delete-all-tests' or `ert-delete-test' before redefining tests." + ))) + (if (y-or-n-p "Do you want to call ert-delete-all-tests and then continue? ") + ;; Fix-me: This does not work, why? + (ert-delete-all-tests) + (error "Test %s is already defined in %s" + ',name + (find-definition-noselect ',name 'ert-deftest)))) + (ert-set-test ',name + nil ;;doc + (make-ert-test + :name ',name + :body (lambda () ,@body) + ,@(when expected-result-supplied-p + `(:expected-result-type ,expected-result)) + ,@(when documentation-supplied-p + `(:documentation ,documentation)))) + ;; This hack allows `symbol-file' to associate `ert-deftest' + ;; forms with files, and therefore enables `find-function' to + ;; work with tests. However, it leads to warnings in + ;; `unload-feature', which doesn't know how to undefine tests + ;; and has no mechanism for extension. + (push '(ert-deftest . ,name) current-load-list) + ',name))) + +(defun ert-read-test-name (prompt &optional default-value history) + "Read the name of a test and return it as a symbol. +Prompt with PROMPT. By default, return DEFAULT-VALUE." + (when (symbolp default-value) (setq default-value (symbol-name default-value))) + (intern (completing-read prompt obarray #'ert-test-boundp + t nil history default-value nil))) + +(defun ert-find-test-other-window (test-name) + "Find, in another window, the definition of TEST-NAME." + (interactive (list (ert-read-test-name "Find test definition: "))) + (find-function-do-it test-name 'ert-deftest 'switch-to-buffer-other-window)) + +(defun ert-delete-test (test-name) + "An interactive interface to `ert-make-test-unbound'." + (interactive (list (let ((default (thing-at-point 'symbol))) + (when default + (set-text-properties 0 (length default) nil default) + (when (or (string= default "nil") (intern-soft default)) + (setq default (intern default))) + (unless (ert-test-boundp default) + (setq default nil))) + (completing-read (if (null default) + "Delete test: " + (format "Delete test (default %s): " + default)) + obarray #'ert-test-boundp + 'really-require-match + nil nil default nil)))) + (ert-make-test-unbound test-name)) + +(defun ert-delete-all-tests () + "Make all symbols in `obarray' name no test." + (interactive) + (when (interactive-p) + (unless (y-or-n-p "Delete all tests? ") + (error "Aborted"))) + (mapc #'ert-delete-test (mapcar #'ert-test-name (ert-select-tests t t))) + t) + + +(defun ert-make-end-marker (buffer must-exist) + "Return a marker to the end of buffer BUFFER. +BUFFER may be a string or a buffer. If BUFFER does not exist +return nil. + +The buffer must exist if MUST-EXIST is non-nil. + +See also: + `ert-end-of-messages' + `ert-end-of-warnings'" + (let ((buf (if must-exist + (get-buffer buffer) + (get-buffer-create buffer)))) + (when (and buf + (bufferp buf) + (buffer-live-p buf)) + (with-current-buffer buf + (save-restriction + (widen) + (point-max-marker)))))) + +(defun ert-end-of-messages () + "Return a marker to the end of *Messages* buffer." + (ert-make-end-marker "*Messages*" nil)) + +(defun ert-end-of-warnings () + "Return a marker to the end of *Warnings* buffer." + (ert-make-end-marker "*Warnings*" nil)) + +(defun ert-search-after (after regexp) + "Search after marker in AFTER for regular expression REGEXP. +Return a alist of position and matches. AFTER should have been +created with `ert-make-end-marker'. + +This is supposed to be used for messages and trace buffers. + +See also + `ert-get-messages'" + (let ((buf (marker-buffer after))) + (with-current-buffer buf + (let ((here (point)) + res) + (goto-char after) + (save-match-data + (while (re-search-forward regexp nil t) + (setq res (cons (match-data) res)))) + (goto-char here) + (reverse res))))) +;; fix-me: add a conventient way to look at the result of +;; `ert-search-after'. Probably this means adding something more to +;; the returned result. + +(defvar ert-messages-mark) +(defun ert-get-messages (regexp) + "Search *Messages* buffer for regular expression REGEXP. +This should be used within `ert-deftest'. Search begins where +the buffer ended when test started. + +See also: + `ert-get-warnings' + `ert-search-after'" + (ert-search-after ert-messages-mark regexp)) + +(defvar ert-warnings-mark) +(defun ert-get-warnings (regexp) + "Search *Warnings* buffer for regular expression REGEXP. +See `ert-get-messages' for more information." + (ert-search-after ert-warnings-mark regexp)) + + +;;; Test selectors. + +(defun ert-select-tests (selector universe) + "Select, from UNIVERSE, a set of tests according to SELECTOR. + +UNIVERSE should be a list of tests, or t, which refers to all +tests named by symbols in `obarray'. + +Returns the set of tests as a list. + +Valid selectors: + +nil -- Selects the empty set. +t -- Selects UNIVERSE. +:new -- Selects all tests that have not been run yet. +:failed, :passed, :error -- Select tests according to their most recent result. +:expected, :unexpected -- Select tests according to their most recent result. +a string -- Selects all tests that have a name that matches the string, a regexp. +a test -- Selects that test. +a symbol -- Selects the test that the symbol names, errors if none. +\(member TESTS...\) -- Selects TESTS, a list of tests or symbols naming tests. +\(eql TEST\) -- Selects TEST, a test or a symbol naming a test. +\(and SELECTORS...\) -- Selects the tests that match all SELECTORS. +\(or SELECTORS...\) -- Selects the tests that match any SELECTOR. +\(not SELECTOR\) -- Selects all tests that do not match SELECTOR. +\(satisfies PREDICATE\) -- Selects all tests that satisfy PREDICATE. + +Only selectors that require a superset of tests, such +as (satisfies ...), strings, :new, etc. make use of UNIVERSE. +Selectors that do not, such as \(member ...\), just return the +set implied by them without checking whether it is really +contained in UNIVERSE." + ;; This code needs to match the etypecase in + ;; `ert-insert-human-readable-selector'. + (etypecase selector + ((member nil) nil) + ((member t) (etypecase universe + (list universe) + ((member t) (ert-select-tests "" universe)))) + ((member :new) (ert-select-tests + `(satisfies ,(lambda (test) + (typep (ert-test-most-recent-result test) + 'null))) + universe)) + ((member :failed) (ert-select-tests + `(satisfies ,(lambda (test) + (typep (ert-test-most-recent-result test) + 'ert-test-failed))) + universe)) + ((member :passed) (ert-select-tests + `(satisfies ,(lambda (test) + (typep (ert-test-most-recent-result test) + 'ert-test-passed))) + universe)) + ((member :error) (ert-select-tests + `(satisfies ,(lambda (test) + (typep (ert-test-most-recent-result test) + 'ert-test-error))) + universe)) + ((member :expected) (ert-select-tests + `(satisfies + ,(lambda (test) + (ert-test-result-expected-p + test + (ert-test-most-recent-result test)))) + universe)) + ((member :unexpected) (ert-select-tests `(not :expected) universe)) + (string + (etypecase universe + ((member t) (mapcar #'ert-get-test + (apropos-internal selector #'ert-test-boundp))) + (list (remove-if-not (lambda (test) + (and (ert-test-name test) + (string-match selector (ert-test-name test)))) + universe)))) + (ert-test (list selector)) + (symbol + (assert (ert-test-boundp selector)) + (list (ert-get-test selector))) + (cons + (destructuring-bind (operator &rest operands) selector + (ecase operator + (member + (mapcar (lambda (purported-test) + (etypecase purported-test + (symbol (assert (ert-test-boundp purported-test)) + (ert-get-test purported-test)) + (ert-test purported-test))) + operands)) + (eql + (assert (eql (length operands) 1)) + (ert-select-tests `(member ,@operands) universe)) + (and + ;; Do these definitions of AND, NOT and OR satisfy de + ;; Morgan's rules? Should they? + (case (length operands) + (0 (ert-select-tests 't universe)) + (t (ert-select-tests `(and ,@(rest operands)) + (ert-select-tests (first operands) universe))))) + (not + (assert (eql (length operands) 1)) + (set-difference (ert-select-tests 't universe) + (ert-select-tests (first operands) universe))) + (or + (case (length operands) + (0 (ert-select-tests 'nil universe)) + (t (union (ert-select-tests (first operands) universe) + (ert-select-tests `(or ,@(rest operands)) universe))))) + (satisfies + (assert (eql (length operands) 1)) + (remove-if-not (first operands) (ert-select-tests 't universe)))))))) + +(defun ert-insert-human-readable-selector (selector) + "Insert a human-readable presentation of SELECTOR into the current buffer." + ;; This is needed to avoid printing the (huge) contents of the + ;; `backtrace' slot of the result objects in the + ;; `most-recent-result' slots of test case objects in (eql ...) or + ;; (member ...) selectors. + (labels ((rec (selector) + ;; This code needs to match the etypecase in `ert-select-tests'. + (etypecase selector + ((or (member nil t + :new :failed :passed :error + :expected :unexpected) + string + symbol) + selector) + (ert-test + (if (ert-test-name selector) + (make-symbol (format "<%S>" (ert-test-name selector))) + (make-symbol "<unnamed test>"))) + (cons + (destructuring-bind (operator &rest operands) selector + (ecase operator + ((member eql and not or) + `(,operator ,@(mapcar #'rec operands))) + (satisfies + selector))))))) + (insert (format "%S" (rec selector))))) + + +;;; Running tests. + +(put 'ert-test-failed 'error-conditions '(error ert-test-failed)) +(put 'ert-test-failed 'error-message "Test failed") + +(defun ert-pass () + "Terminate the current test and mark it passed. Does not return." + (throw 'ert-pass nil)) + +(defun ert-fail (data) + "Terminate the current test and mark it failed. Does not return. +DATA is displayed to the user and should state the reason of the failure." + (signal 'ert-test-failed (list data))) + +;; The data structures that represent the result of running a test. +(defstruct ert-test-result + (messages nil) + ) +(defstruct (ert-test-passed (:include ert-test-result))) +(defstruct (ert-test-result-with-condition (:include ert-test-result)) + (condition (assert nil)) + (backtrace (assert nil))) +(defstruct (ert-test-error (:include ert-test-result-with-condition))) +(defstruct (ert-test-quit (:include ert-test-result-with-condition))) +(defstruct (ert-test-failed (:include ert-test-result-with-condition))) +(defstruct (ert-test-aborted-with-non-local-exit (:include ert-test-result))) + + +(defun ert-record-backtrace () + "Record the current backtrace (as a list) and return it." + ;; Since the backtrace is stored in the result object, result + ;; objects must only be printed with appropriate limits + ;; (`print-level' and `print-length') in place. For interactive + ;; use, the cost of ensuring this possibly outweighs the advantage + ;; of storing the backtrace for + ;; `ert-results-pop-to-backtrace-for-test-at-point' given that we + ;; already have `ert-results-rerun-test-debugging-errors-at-point'. + ;; For batch use, however, printing the backtrace may be useful. + (loop + ;; 6 is the number of frames our own debugger adds (when + ;; compiled; more when interpreted). FIXME: Need to describe a + ;; procedure for determining this constant. + for i from 6 + for frame = (backtrace-frame i) + while frame + collect frame)) + +;; A container for the state of the execution of a single test and +;; environment data needed during its execution. +(defstruct ert-test-execution-info + (test (assert nil)) + (result (assert nil)) + ;; A thunk that may be called when RESULT has been set to its final + ;; value and test execution should be terminated. Should not + ;; return. + (exit-continuation (assert nil)) + ;; The binding of `debugger' outside of the execution of the test. + next-debugger + ;; The binding of `ert-debug-on-error' that is in effect for the + ;; execution of the current test. We store it to avoid being + ;; affected by any new bindings the test itself may establish. (I + ;; don't remember whether this feature is important.) + ert-debug-on-error) + +(defun ert-run-test-debugger (info debugger-args) + "The function that `debugger' is bound to during the execution of tests. + +Records failures and errors and either terminates the test +silently or calls the interactive debugger, as appropriate." + (destructuring-bind (first-debugger-arg &rest more-debugger-args) debugger-args + (ecase first-debugger-arg + ((lambda debug t exit nil) + (apply (ert-test-execution-info-next-debugger info) debugger-args)) + (error + (let* ((condition (first more-debugger-args)) + (type (case (car condition) + ((quit) 'quit) + ((ert-test-failed) 'failed) + (otherwise 'error))) + (backtrace (ert-record-backtrace))) + (setf (ert-test-execution-info-result info) + (ecase type + (quit + (make-ert-test-quit :condition condition + :backtrace backtrace)) + (failed + (make-ert-test-failed :condition condition + :backtrace backtrace)) + (error + (make-ert-test-error :condition condition + :backtrace backtrace)))) + ;; Work around Emacs' heuristic (in eval.c) for detecting + ;; errors in the debugger. + (incf num-nonmacro-input-events) + ;; FIXME: We should probably implement more fine-grained + ;; control a la non-t `debug-on-error' here. + (cond + ((ert-test-execution-info-ert-debug-on-error info) + (apply (ert-test-execution-info-next-debugger info) debugger-args)) + (t)) + (funcall (ert-test-execution-info-exit-continuation info))))))) + +(defun ert-run-test-internal (ert-test-execution-info) + (lexical-let ((info ert-test-execution-info)) + (setf (ert-test-execution-info-next-debugger info) debugger + (ert-test-execution-info-ert-debug-on-error info) ert-debug-on-error) + (catch 'ert-pass + ;; For now, each test gets its own temp buffer and its own + ;; window excursion, just to be safe. If this turns out to be + ;; too expensive, we can remove it. + (with-temp-buffer + (save-window-excursion + (let ((debugger (lambda (&rest debugger-args) + (ert-run-test-debugger info debugger-args))) + (debug-on-error t) + (debug-on-quit t) + ;; FIXME: Do we need to store the old binding of this + ;; and consider it in `ert-run-test-debugger'? + (debug-ignored-errors nil) + (ert-messages-mark (ert-end-of-messages)) + (ert-warnings-mark (ert-end-of-warnings))) + (funcall (ert-test-body (ert-test-execution-info-test info)))))) + (ert-pass)) + (setf (ert-test-execution-info-result info) (make-ert-test-passed))) + nil) + +(defun ert-make-marker-in-messages-buffer () + (with-current-buffer (get-buffer-create "*Messages*") + (set-marker (make-marker) (point-max)))) + +(defun ert-force-message-log-buffer-truncation () + (with-current-buffer (get-buffer-create "*Messages*") + ;; This is a reimplementation of this part of message_dolog() in xdisp.c: + ;; if (NATNUMP (Vmessage_log_max)) + ;; { + ;; scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, + ;; -XFASTINT (Vmessage_log_max) - 1, 0); + ;; del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0); + ;; } + (when (and (integerp message-log-max) (>= message-log-max 0)) + (let ((begin (point-min)) + (end (save-excursion + (goto-char (point-max)) + (forward-line (- message-log-max)) + (point)))) + (delete-region begin end))))) + +(defun ert-run-test (test) + "Run TEST. Return the result and store it in TEST's `most-recent-result' slot." + (setf (ert-test-most-recent-result test) nil) + (block error + (lexical-let* ((begin-marker (ert-make-marker-in-messages-buffer)) + (info (make-ert-test-execution-info + :test test + :result (make-ert-test-aborted-with-non-local-exit) + :exit-continuation (lambda () + (return-from error nil))))) + (unwind-protect + (let ((message-log-max t)) + (ert-run-test-internal info)) + (let ((result (ert-test-execution-info-result info))) + (setf (ert-test-result-messages result) + (with-current-buffer (get-buffer-create "*Messages*") + (buffer-substring begin-marker (point-max)))) + (ert-force-message-log-buffer-truncation) + (setf (ert-test-most-recent-result test) result))))) + (ert-test-most-recent-result test)) + + +;;; The `should' macros. + +(eval-and-compile + (defun ert-special-operator-p (thing) + "Return non-nil if THING is a symbol naming a special operator." + (and (symbolp thing) + (let ((definition (indirect-function thing t))) + (and (subrp definition) + (eql (cdr (subr-arity definition)) 'unevalled))))) + (defun ert-expand-should (whole form env inner-expander) + "Helper function for the `should' macro and its variants. + +Analyzes FORM and produces an expression that has the same +semantics under evaluation but records additional debugging +information. INNER-EXPANDER adds the actual checks specific to +the particular variant of `should'." + (let ((form (macroexpand form env))) + ;; It's sort of a wart that `inner-expander' can't influence the + ;; value the expansion returns. + (cond + ((atom form) + (funcall inner-expander form `(list ',whole :form ',form :value ,form))) + ((ert-special-operator-p (car form)) + (let ((value (gensym "value-"))) + `(let ((,value (make-symbol "ert-form-evaluation-aborted"))) + ,(funcall inner-expander + `(setq ,value ,form) + `(list ',whole :form ',form :value ,value)) + ,value))) + (t + (let ((fn-name (car form)) + (arg-forms (cdr form))) + (assert (or (symbolp fn-name) + (and (consp fn-name) + (eql (car fn-name) 'lambda) + (listp (cdr fn-name))))) + (let ((fn (gensym "fn-")) + (args (gensym "args-")) + (value (gensym "value-")) + (default-value (gensym "ert-form-evaluation-aborted-"))) + `(let ((,fn (function ,fn-name)) + (,args (list ,@arg-forms))) + (let ((,value ',default-value)) + ,(funcall inner-expander + `(setq ,value (apply ,fn ,args)) + `(nconc (list ',whole) + (list :form `(,,fn ,@,args)) + (unless (eql ,value ',default-value) + (list :value ,value)) + (let ((-explainer- + (and (symbolp ',fn-name) + (get ',fn-name + 'ert-explainer)))) + (when -explainer- + (list :explanation + (apply -explainer- ,args)))))) + ,value))))))))) + +(defmacro* ert-should (form &environment env) + "Evaluate FORM. If it returns nil, abort the current test as failed. + +Returns the value of FORM." + (ert-expand-should `(ert-should ,form) form env + (lambda (inner-form form-description-form) + `(unless ,inner-form + (ert-fail ,form-description-form))))) + +(defmacro* ert-should-not (form &environment env) + "Evaluate FORM. If it returns non-nil, abort the current test as failed. + +Returns nil." + (ert-expand-should `(ert-should-not ,form) form env + (lambda (inner-form form-description-form) + `(unless (not ,inner-form) + (ert-fail ,form-description-form))))) + +(defun ert-should-error-handle-error (form-description-fn + condition type exclude-subtypes test) + "Helper function for `should-error'. + +Determines whether CONDITION matches TYPE, EXCLUDE-SUBTYPES and +TEST, and aborts the current test as failed if it doesn't." + (let ((signalled-conditions (get (car condition) 'error-conditions)) + (handled-conditions (etypecase type + (list type) + (symbol (list type))))) + (assert signalled-conditions) + (unless (intersection signalled-conditions handled-conditions) + (ert-fail (append + (funcall form-description-fn) + (list + :condition condition + :fail-reason (concat "the error signalled did not" + " have the expected type"))))) + (when exclude-subtypes + (unless (member (car condition) handled-conditions) + (ert-fail (append + (funcall form-description-fn) + (list + :condition condition + :fail-reason (concat "the error signalled was a subtype" + " of the expected type")))))) + (unless (funcall test condition) + (ert-fail (append + (funcall form-description-fn) + (list + :condition condition + :fail-reason "the error signalled did not pass the test")))))) + +;; FIXME: The expansion will evaluate the keyword args (if any) in +;; nonstandard order. +(defmacro* ert-should-error (form &rest keys &key type exclude-subtypes test + &environment env) + "Evaluate FORM. Unless it signals an error, abort the current test as failed. + +The error signalled additionally needs to match TYPE and satisfy +TEST. TYPE should be a condition name or a list of condition +names. If EXCLUDE-SUBTYPES is nil, the error matches TYPE if one +of its condition names is an element of TYPE. If +EXCLUDE-SUBTYPES is non-nil, the error matches TYPE if it is an +element of TYPE. TEST should be a predicate." + ;; Returns a gensym named `ert-form-evaluation-aborted-XXX', but + ;; that's a wart, so let's not document it. + (unless type (setq type ''error)) + (unless test (setq test '(lambda (condition) t))) + (ert-expand-should + `(ert-should-error ,form ,@keys) + form env + (lambda (inner-form form-description-form) + (let ((errorp (gensym "errorp")) + (form-description-fn (gensym "form-description-fn-"))) + `(let ((,errorp nil) + (,form-description-fn (lambda () ,form-description-form))) + (condition-case -condition- + ,inner-form + ;; We can't use ,type here because we want to evaluate it. + (error + (setq ,errorp t) + (ert-should-error-handle-error ,form-description-fn + -condition- + ,type ,exclude-subtypes ,test) + ;; It would make sense to have the `should-error' form + ;; return the error in this case, but `ert-expand-should' + ;; doesn't allow that at the moment. + )) + (unless ,errorp + (ert-fail (append + (funcall ,form-description-fn) + (list + :fail-reason "did not signal an error"))))))))) + + +;;; Explanation of `should' failures. + +(defun ert-proper-list-p (x) + "Return non-nil if X is a proper list, nil otherwise." + (loop + for firstp = t then nil + for fast = x then (cddr fast) + for slow = x then (cdr slow) do + (when (null fast) (return t)) + (when (not (consp fast)) (return nil)) + (when (null (cdr fast)) (return t)) + (when (not (consp (cdr fast))) (return nil)) + (when (and (not firstp) (eq fast slow)) (return nil)))) + +(defun ert-explain-not-equal (a b) + "Return a programmer-readable explanation of why A and B are not `equal'. + +Returns nil if they are equal." + (if (not (equal (type-of a) (type-of b))) + `(different-types ,a ,b) + (etypecase a + (cons + (let ((a-proper-p (ert-proper-list-p a)) + (b-proper-p (ert-proper-list-p b))) + (if (not (eql (not a-proper-p) (not b-proper-p))) + `(one-list-proper-one-improper ,a ,b) + (if a-proper-p + (if (not (equal (length a) (length b))) + ;; This would be even more helpful if it showed + ;; something like what `set-difference' would + ;; return. + `(proper-lists-of-different-length ,a ,b) + (loop for i from 0 + for ai in a + for bi in b + for xi = (ert-explain-not-equal ai bi) + do (when xi (return `(list-elt ,i ,xi))))) + (let ((car-x (ert-explain-not-equal (car a) (car b)))) + (if car-x + `(car ,car-x) + (let ((cdr-x (ert-explain-not-equal (cdr a) (cdr b)))) + (if cdr-x + `(cdr ,cdr-x)) + nil))))))) + (array (if (not (equal (length a) (length b))) + `(arrays-of-different-length ,a ,b) + (loop for i from 0 + for ai across a + for bi across b + for xi = (ert-explain-not-equal ai bi) + do (when xi (return `(array-elt ,i ,xi)))))) + (atom (if (not (equal a b)) + `(different-atoms ,a ,b) + nil))))) +(put 'equal 'ert-explainer 'ert-explain-not-equal) + + +;;; Results display. + +;; The data structure that contains the set of tests being executed +;; during one particular test run, their results, the state of the +;; execution, and some statistics. +;; +;; The data about results and expected results of tests may seem +;; redundant here, since the test objects also carry such information. +;; However, the information in the test objects may be more recent, it +;; may correspond to a different test run. We need the information +;; that corresponds to this run in order to be able to update the +;; statistics correctly when a test is re-run interactively and has a +;; different result than before. +(defstruct ert-stats + (selector (assert nil)) + ;; The tests, in order. + (tests (assert nil) :type vector) + ;; A map of test names (or the test objects themselves for unnamed + ;; tests) to indices into the `tests' vector. + (test-map (assert nil) :type hash-table) + ;; The results of the tests during this run, in order. + (test-results (assert nil) :type vector) + ;; The expected result types of the tests, in order. + (test-results-expected (assert nil) :type vector) + (total (assert nil)) + (passed-expected 0) + (passed-unexpected 0) + (failed-expected 0) + (failed-unexpected 0) + (error-expected 0) + (error-unexpected 0) + (start-time (assert nil)) + (end-time nil) + (aborted-p nil) + (current-test nil)) + +;; An entry in the results buffer ewoc. There is one entry per test. +(defstruct ert-ewoc-entry + (test (assert nil)) + (result nil) + ;; If the result of this test was expected, its ewoc entry is hidden + ;; initially. + (hidden-p (assert nil)) + ;; An ewoc entry may be collapsed to hide details such as the error + ;; condition. + ;; + ;; I'm not sure the ability to expand and collapse entries is still + ;; a useful feature. + (expanded-p t) + ;; By default, the ewoc entry presents the error condition with + ;; certain limits on how much to print (`print-level', + ;; `print-length'). The user can interactively switch to a set of + ;; higher limits. + (extended-printer-limits-p nil)) + +;; Variables local to the results buffer. + +;; The ewoc. +(defvar ert-results-ewoc) +;; The stats object. +(defvar ert-results-stats) +;; A string with one character per test. Each character represents +;; the result of the corresponding test. The string is displayed near +;; the top of the buffer and serves as a progress bar. +(defvar ert-results-progress-bar-string) +;; The position where the progress bar button begins. +(defvar ert-results-progress-bar-button-begin) +;; The test result listener that updates the buffer when tests are run. +(defvar ert-results-listener) + +;; The same as `ert-results-stats', but dynamically bound. Used for +;; the mode line progress indicator. +(defvar ert-current-run-stats nil) + +(defun ert-format-time-iso8601 (time) + "Format TIME in the particular variant of ISO 8601 used for timestamps in ERT." + (format-time-string "%Y-%m-%d %T%z" time)) + +(defun ert-insert-test-name-button (test-name) + (insert-text-button (format "%S" test-name) + :type 'ert-test-name-button + 'ert-test-name test-name)) + +(defun ert-results-update-ewoc-hf (ewoc stats) + "Update the header and footer of EWOC to show certain information from STATS. + +Also sets `ert-results-progress-bar-button-begin'." + (let ((run-count (+ (ert-stats-passed-expected stats) + (ert-stats-passed-unexpected stats) + (ert-stats-failed-expected stats) + (ert-stats-failed-unexpected stats) + (ert-stats-error-expected stats) + (ert-stats-error-unexpected stats))) + (results-buffer (current-buffer))) + (ewoc-set-hf + ewoc + ;; header + (with-temp-buffer + (insert "Selector: ") + (ert-insert-human-readable-selector (ert-stats-selector stats)) + (insert "\n") + (insert + (format (concat "Passed: %s (%s unexpected)\n" + "Failed: %s (%s unexpected)\n" + "Error: %s (%s unexpected)\n" + "Total: %s/%s\n\n") + (+ (ert-stats-passed-expected stats) + (ert-stats-passed-unexpected stats)) + (ert-stats-passed-unexpected stats) + (+ (ert-stats-failed-expected stats) + (ert-stats-failed-unexpected stats)) + (ert-stats-failed-unexpected stats) + (+ (ert-stats-error-expected stats) + (ert-stats-error-unexpected stats)) + (ert-stats-error-unexpected stats) + run-count + (ert-stats-total stats))) + (insert + (format "Started at: %s\n" + (ert-format-time-iso8601 (ert-stats-start-time stats)))) + ;; FIXME: This is ugly. Need to properly define invariants of + ;; the `stats' data structure. + (let ((state (cond ((ert-stats-aborted-p stats) + 'aborted) + ((ert-stats-current-test stats) + 'running) + ((ert-stats-end-time stats) + 'finished) + (t + 'preparing)))) + (ecase state + (preparing + (insert "")) + (aborted + (cond ((ert-stats-current-test stats) + (insert "Aborted during test: ") + (ert-insert-test-name-button + (ert-test-name (ert-stats-current-test stats)))) + (t + (insert "Aborted.")))) + (running + (assert (ert-stats-current-test stats)) + (insert "Running test: ") + (ert-insert-test-name-button (ert-test-name + (ert-stats-current-test stats)))) + (finished + (assert (not (ert-stats-current-test stats))) + (insert "Finished."))) + (insert "\n") + (if (ert-stats-end-time stats) + (insert + (format "%s%s\n" + (if (ert-stats-aborted-p stats) + "Aborted at: " + "Finished at: ") + (ert-format-time-iso8601 (ert-stats-end-time stats)))) + (insert "\n")) + (insert "\n")) + (let ((progress-bar-string (with-current-buffer results-buffer + ert-results-progress-bar-string))) + (let ((progress-bar-button-begin + (insert-text-button (substring progress-bar-string 0 run-count) + :type 'ert-results-progress-bar-button))) + (with-current-buffer results-buffer + (set (make-local-variable 'ert-results-progress-bar-button-begin) + progress-bar-button-begin))) + (insert (substring progress-bar-string run-count))) + (insert "\n\n") + (buffer-string)) + ;; footer + ;; + ;; We actually want an empty footer, but that would trigger a bug + ;; in ewoc, sometimes clearing the entire buffer. + "\n"))) + +(defun ert-results-update-stats-display (ewoc stats) + "Update EWOC and the mode line to show data from STATS." + (ert-results-update-ewoc-hf ewoc stats) + (force-mode-line-update) + (redisplay t)) + +(defun ert-char-for-test-result (result expectedp) + "Return a character that represents the test result RESULT." + (let ((char + (etypecase result + (ert-test-passed ?.) + (ert-test-failed ?f) + (ert-test-error ?e) + (null ?-) + (ert-test-aborted-with-non-local-exit ?a)))) + (if expectedp + char + (upcase char)))) + +(defun ert-string-for-test-result (result expectedp) + "Return a string that represents the test result RESULT." + (etypecase result + (ert-test-passed "passed") + (ert-test-failed "failed") + (ert-test-error "error") + (null "unknown") + (ert-test-aborted-with-non-local-exit "aborted"))) + +(defun ert-tests-running-mode-line-indicator () + (let* ((stats ert-current-run-stats) + (tests-total (ert-stats-total stats)) + (tests-completed (+ (ert-stats-passed-expected stats) + (ert-stats-passed-unexpected stats) + (ert-stats-failed-expected stats) + (ert-stats-failed-unexpected stats) + (ert-stats-error-expected stats) + (ert-stats-error-unexpected stats)))) + (if (>= tests-completed tests-total) + (format " ERT(%s/%s,finished)" tests-completed tests-total) + (format " ERT(%s/%s):%s" + (1+ tests-completed) + tests-total + (if (null (ert-stats-current-test stats)) + "?" + (format "%S" + (ert-test-name (ert-stats-current-test stats)))))))) + +(defun ert-pp-with-indentation-and-newline (object) + "Pretty-print OBJECT, indenting it to the current column of point. +Ensures a final newline is inserted." + (let ((begin (point))) + (pp object (current-buffer)) + (unless (bolp) (insert "\n")) + (save-excursion + (goto-char begin) + (indent-sexp)))) + +(defun ert-print-test-for-ewoc (entry) + "The ewoc print function for ewoc test entries." + (let* ((test (ert-ewoc-entry-test entry)) + (result (ert-ewoc-entry-result entry)) + (hiddenp (ert-ewoc-entry-hidden-p entry)) + (expandedp (ert-ewoc-entry-expanded-p entry)) + (extended-printer-limits-p (ert-ewoc-entry-extended-printer-limits-p + entry))) + (cond (hiddenp) + (t + (insert-text-button (format "%c" + (ert-char-for-test-result + result + (ert-test-result-expected-p test + result))) + :type 'ert-results-expand-collapse-button) + (insert " ") + (ert-insert-test-name-button (ert-test-name test)) + (insert "\n") + (when (and expandedp (not (eql result 'nil))) + (etypecase result + (ert-test-passed + (insert " passed\n") + (insert "")) + (ert-test-result-with-condition + (insert " ") + (let ((print-escape-newlines t) + (print-level (if extended-printer-limits-p 10 5)) + (print-length (if extended-printer-limits-p 100 10))) + (let ((begin (point))) + (ert-pp-with-indentation-and-newline + (ert-test-result-with-condition-condition result)) + (save-restriction + (narrow-to-region begin (point)) + ;; Inhibit optimization in `debugger-make-xrefs' + ;; that sometimes inserts unrelated backtrace + ;; info into our buffer. + (let ((debugger-previous-backtrace nil)) + (debugger-make-xrefs)))))) + (ert-test-aborted-with-non-local-exit + (insert " aborted\n"))) + (insert "\n"))))) + nil) + +(defun ert-setup-results-buffer (stats listener buffer-name) + "Set up a test results buffer." + (unless buffer-name (setq buffer-name "*ert*")) + (let ((buffer (let ((default-major-mode 'fundamental-mode)) + (get-buffer-create buffer-name)))) + (with-current-buffer buffer + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-results-mode) + (set (make-local-variable 'ert-results-ewoc) + (ewoc-create 'ert-print-test-for-ewoc nil nil t)) + (set (make-local-variable 'ert-results-stats) stats) + (set (make-local-variable 'ert-results-progress-bar-string) + (make-string (ert-stats-total stats) + (ert-char-for-test-result nil t))) + (set (make-local-variable 'ert-results-listener) listener) + (ert-results-update-ewoc-hf ert-results-ewoc ert-results-stats) + (goto-char (1- (point-max))) + buffer)))) + +(defun ert-run-or-rerun-test (stats test listener) + "Run the single test TEST and record the result using STATS and LISTENER." + (let ((ert-current-run-stats stats) + (pos (ert-stats-test-index stats test)) + (results (ert-stats-test-results stats)) + (expected (ert-stats-test-results-expected stats))) + ;; Adjust stats to remove previous result. + (if (aref expected pos) + (etypecase (aref results pos) + (ert-test-passed (decf (ert-stats-passed-expected stats))) + (ert-test-failed (decf (ert-stats-failed-expected stats))) + (ert-test-error (decf (ert-stats-error-expected stats))) + (null) + (ert-test-aborted-with-non-local-exit)) + (etypecase (aref results pos) + (ert-test-passed (decf (ert-stats-passed-unexpected stats))) + (ert-test-failed (decf (ert-stats-failed-unexpected stats))) + (ert-test-error (decf (ert-stats-error-unexpected stats))) + (null) + (ert-test-aborted-with-non-local-exit))) + (setf (aref results pos) nil) + ;; Call listener after setting/before resetting + ;; (ert-stats-current-test stats); the listener might refresh the + ;; mode line display, and if the value is not set yet/any more + ;; during this refresh, the mode line will flicker unnecessarily. + (setf (ert-stats-current-test stats) test) + (funcall listener 'test-started stats test) + (setf (ert-test-most-recent-result test) nil) + (unwind-protect + (ert-run-test test) + (let* ((result (ert-test-most-recent-result test)) + (expectedp (typep result (ert-test-expected-result-type test)))) + ;; Adjust stats to add new result. + (if expectedp + (etypecase result + (ert-test-passed (incf (ert-stats-passed-expected stats))) + (ert-test-failed (incf (ert-stats-failed-expected stats))) + (ert-test-error (incf (ert-stats-error-expected stats))) + (null) + (ert-test-aborted-with-non-local-exit)) + (etypecase result + (ert-test-passed (incf (ert-stats-passed-unexpected stats))) + (ert-test-failed (incf (ert-stats-failed-unexpected stats))) + (ert-test-error (incf (ert-stats-error-unexpected stats))) + (null) + (ert-test-aborted-with-non-local-exit))) + (setf (aref results pos) result + (aref expected pos) expectedp) + (funcall listener 'test-ended stats test result)) + (setf (ert-stats-current-test stats) nil)))) + +(defun ert-run-tests (selector listener) + "Run the tests specified by SELECTOR, sending progress updates to LISTENER." + (let* ((tests (coerce (ert-select-tests selector t) 'vector)) + (map (let ((map (make-hash-table :size (length tests)))) + (loop for i from 0 + for test across tests + for key = (or (ert-test-name test) test) do + (assert (not (gethash key map))) + (setf (gethash key map) i)) + map)) + (stats (make-ert-stats :selector selector + :tests tests + :test-map map + :test-results (make-vector (length tests) nil) + :test-results-expected (make-vector + (length tests) nil) + :total (length tests) + :start-time (current-time)))) + (funcall listener 'run-started stats) + (let ((abortedp t)) + (let ((ert-current-run-stats stats)) + (force-mode-line-update) + (unwind-protect + (progn + (loop for test across tests do + (ert-run-or-rerun-test stats test listener)) + (setq abortedp nil)) + (setf (ert-stats-aborted-p stats) abortedp) + (setf (ert-stats-end-time stats) (current-time)) + (funcall listener 'run-ended stats abortedp))) + stats))) + +(defun ert-stats-test-index (stats test) + "Return the index of TEST in the run represented by STATS." + (gethash (or (ert-test-name test) test) (ert-stats-test-map stats))) + +(defvar ert-selector-history nil + "List of recent test selectors read from terminal.") + +;; Fix-me: return (regep (list of matches))? +;; Fix-me: Add prompt parameter? +(defun ert-read-test-selector () + "Read a regexp for test selection from minibuffer. +The user can use TAB to see which tests match." + (let* ((all-tests + (mapcar (lambda (rec) (format "%s" (elt rec 1))) + (ert-select-tests "" t)) + ;;'("ert-group1-1" "ert-group1-2" "ert-other") + ) + regexp + ret + (get-completions + (lambda () + (let* ((ret (save-match-data + (mapcar (lambda (alt) + (when (string-match regexp alt) + alt)) + all-tests)))) + (setq ret (delq nil ret)) + ret)))) + (setq all-tests (append all-tests + '(":new" + ":failed" ":passed" ":error" + ) + nil)) + (let ((mini-map (copy-keymap minibuffer-local-map))) + (define-key mini-map [?\t] + (lambda () (interactive) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list + (progn + (setq regexp (minibuffer-contents)) + (set-text-properties 0 (length regexp) nil regexp) + (funcall get-completions)))))) + (setq regexp + (let* ((sym-here (thing-at-point 'symbol)) + (test-here (when (and sym-here + (memq sym-here all-tests)) + sym-here)) + (default (if sym-here + (substring-no-properties sym-here) + (if ert-selector-history + (first ert-selector-history) + "t")))) + (read-from-minibuffer + (if (null default) + "Run tests, use TAB to see matches: " + (format "Run tests, use TAB to see matches (default %s): " + default)) + nil ;; initial-contents + mini-map ;; keymap + nil ;; read + 'ert-selector-history + default nil)))) + (setq ret regexp) + (when (string= "t" ret) + (setq ret t)) + ret)) + +;; Should OUTPUT-BUFFER-NAME and MESSAGE-FN really be arguments here? +;; They are needed only for our automated self-tests at the moment. +;; Or should there be some other mechanism? +;;;###autoload +(defun ert-run-tests-interactively (selector + &optional output-buffer-name message-fn) + "Run the tests specified by SELECTOR and display the results in a buffer." + (interactive +;;; (list (let ((default (if ert-selector-history +;;; (first ert-selector-history) +;;; "t"))) +;;; (read-from-minibuffer (if (null default) +;;; "Run tests: " +;;; (format "Run tests (default %s): " default)) +;;; ;;nil nil t 'ert-selector-history +;;; ;; +;;; ;; fix-me: seems like I am misunderstanding Christians intent here. +;;; nil nil nil 'ert-selector-history +;;; default nil)) +;;; nil nil)) + (list (ert-read-test-selector) + nil nil)) + (unless message-fn (setq message-fn 'message)) + (lexical-let ((output-buffer-name output-buffer-name) + buffer + listener + (message-fn message-fn)) + (setq listener + (lambda (event-type &rest event-args) + (ecase event-type + (run-started + (destructuring-bind (stats) event-args + (setq buffer (ert-setup-results-buffer stats + listener + output-buffer-name)) + (pop-to-buffer buffer))) + (run-ended + (destructuring-bind (stats abortedp) event-args + (funcall message-fn + "%sRan %s tests, %s results were as expected%s" + (if (not abortedp) + "" + "Aborted: ") + (ert-stats-total stats) + (+ (ert-stats-passed-expected stats) + (ert-stats-failed-expected stats) + (ert-stats-error-expected stats)) + (let ((unexpected + (+ (ert-stats-passed-unexpected stats) + (ert-stats-failed-unexpected stats) + (ert-stats-error-unexpected stats)))) + (if (zerop unexpected) + "" + (format ", %s unexpected" unexpected)))) + (ert-results-update-stats-display (with-current-buffer buffer + ert-results-ewoc) + stats))) + (test-started + (destructuring-bind (stats test) event-args + (with-current-buffer buffer + (let* ((ewoc ert-results-ewoc) + (pos (ert-stats-test-index stats test)) + (node (ewoc-nth ewoc pos))) + (unless node + ;; FIXME: How expensive is this assertion? + (assert (or (zerop pos) (ewoc-nth ewoc (1- pos))) + t) + (setq node (ewoc-enter-last + ewoc + (make-ert-ewoc-entry :test test + :hidden-p t)))) + (setf (ert-ewoc-entry-test (ewoc-data node)) test) + (setf (ert-ewoc-entry-result (ewoc-data node)) nil) + (aset ert-results-progress-bar-string pos + (ert-char-for-test-result nil t)) + (ert-results-update-stats-display ewoc stats) + (ewoc-invalidate ewoc node))))) + (test-ended + (destructuring-bind (stats test result) event-args + (with-current-buffer buffer + (let* ((ewoc ert-results-ewoc) + (pos (ert-stats-test-index stats test)) + (node (ewoc-nth ewoc pos))) + (setf (ert-ewoc-entry-result (ewoc-data node)) result) + (when (ert-ewoc-entry-hidden-p (ewoc-data node)) + (setf (ert-ewoc-entry-hidden-p (ewoc-data node)) + (ert-test-result-expected-p test result))) + (aset ert-results-progress-bar-string pos + (ert-char-for-test-result result + (ert-test-result-expected-p + test result))) + (ert-results-update-stats-display ewoc stats) + (ewoc-invalidate ewoc node)))))))) + (ert-run-tests + selector + listener))) + +(defvar ert-batch-backtrace-right-margin 70 + "*The maximum line length for printing backtraces in `ert-run-tests-batch'.") + +(defun ert-run-tests-batch (selector) + "Run the tests specified by SELECTOR, printing results to the terminal. + +Returns the stats object." + (ert-run-tests + selector + (lambda (event-type &rest event-args) + (ecase event-type + (run-started + (destructuring-bind (stats) event-args + (message "Running %s tests (%s)" + (length (ert-stats-tests stats)) + (ert-format-time-iso8601 (ert-stats-start-time stats))))) + (run-ended + (destructuring-bind (stats abortedp) event-args + (let ((unexpected (+ (ert-stats-passed-unexpected stats) + (ert-stats-failed-unexpected stats) + (ert-stats-error-unexpected stats)))) + (message "\n%sRan %s tests, %s results were as expected%s (%s)\n" + (if (not abortedp) + "" + "Aborted: ") + (ert-stats-total stats) + (+ (ert-stats-passed-expected stats) + (ert-stats-failed-expected stats) + (ert-stats-error-expected stats)) + (if (zerop unexpected) + "" + (format ", %s unexpected" unexpected)) + (ert-format-time-iso8601 (ert-stats-end-time stats))) + (unless (zerop unexpected) + (message "%s unexpected results:" unexpected) + (loop for test across (ert-stats-tests stats) + for result = (ert-test-most-recent-result test) do + (when (not (ert-test-result-expected-p test result)) + (message "%9s %S" + (ert-string-for-test-result result nil) + (ert-test-name test)))) + (message "%s" ""))))) + (test-started + ) + (test-ended + (destructuring-bind (stats test result) event-args + (etypecase result + (ert-test-passed) + (ert-test-result-with-condition + (message "Test %S backtrace:" (ert-test-name test)) + (with-temp-buffer + (ert-print-backtrace (ert-test-result-with-condition-backtrace result)) + (goto-char (point-min)) + (while (not (eobp)) + (let ((start (point)) + (end (progn (end-of-line) (point)))) + (setq end (min end + (+ start ert-batch-backtrace-right-margin))) + (message "%s" (buffer-substring-no-properties + start end))) + (forward-line 1))) + (with-temp-buffer + (insert " ") + (let ((print-escape-newlines t) + (print-level 5) + (print-length 10)) + (let ((begin (point))) + (ert-pp-with-indentation-and-newline + (ert-test-result-with-condition-condition result)))) + (goto-char (1- (point-max))) + (assert (looking-at "\n")) + (delete-char 1) + (message "Test %S condition:" (ert-test-name test)) + (message "%s" (buffer-string)))) + (ert-test-aborted-with-non-local-exit)) + (let* ((max (prin1-to-string (length (ert-stats-tests stats)))) + (format-string (concat "%9s %" + (prin1-to-string (length max)) + "s/" max " %S"))) + (message format-string + (ert-string-for-test-result result + (ert-test-result-expected-p + test result)) + (1+ (ert-stats-test-index stats test)) + (ert-test-name test))))))))) + + +;;; Commands and button actions for the results buffer. + +(define-derived-mode ert-results-mode fundamental-mode "ERT-Results" + "Major mode for viewing results of ERT test runs.") + +(loop for (key binding) in + '(("j" ert-results-jump-between-summary-and-result) + ("." ert-results-find-test-at-point-other-window) + ("r" ert-results-rerun-test-at-point) + ("d" ert-results-rerun-test-at-point-debugging-errors) + ("b" ert-results-pop-to-backtrace-for-test-at-point) + ("m" ert-results-pop-to-messages-for-test-at-point) + ("p" ert-results-toggle-printer-limits-for-test-at-point) + ("D" ert-delete-test) + ([?\t] forward-button) + ([backtab] backward-button) + ) + do + (define-key ert-results-mode-map key binding)) + +(define-button-type 'ert-results-progress-bar-button + 'action #'ert-results-progress-bar-button-action + 'help-echo "mouse-2, RET: Reveal test result") + +(define-button-type 'ert-test-name-button + 'action #'ert-test-name-button-action + 'help-echo "mouse-2, RET: Find test definition") + +(define-button-type 'ert-results-expand-collapse-button + 'action #'ert-results-expand-collapse-button-action + 'help-echo "mouse-2, RET: Expand/collapse test result") + +(defun ert-results-test-node-or-null-at-point () + "If point is on a valid ewoc node, return it; return nil otherwise. + +To be used in the ERT results buffer." + (let* ((ewoc ert-results-ewoc) + (node (ewoc-locate ewoc))) + ;; `ewoc-locate' will return an arbitrary node when point is on + ;; header or footer, or when all nodes are invisible. So we need + ;; to validate its return value here. + (if (and (>= (point) (ewoc-location node)) + (not (ert-ewoc-entry-hidden-p (ewoc-data node)))) + node + nil))) + +(defun ert-results-test-node-at-point () + "If point is on a valid ewoc node, return it; signal an error otherwise. + +To be used in the ERT results buffer." + (or (ert-results-test-node-or-null-at-point) + (error "No test at point"))) + +(defun ert-results-expand-collapse-button-action (button) + "Expand or collapse the test node BUTTON belongs to." + (let* ((ewoc ert-results-ewoc) + (node (save-excursion + (goto-char (ert-button-action-position)) + (ert-results-test-node-at-point))) + (entry (ewoc-data node))) + (setf (ert-ewoc-entry-expanded-p entry) + (not (ert-ewoc-entry-expanded-p entry))) + (ewoc-invalidate ewoc node))) + +(defun ert-results-find-test-at-point-other-window () + "Find the definition of the test at point in another window. + +To be used in the ERT results buffer." + (interactive) + (let* ((node (ert-results-test-node-at-point)) + (entry (ewoc-data node)) + (test (ert-ewoc-entry-test entry)) + (name (ert-test-name test))) + (ert-find-test-other-window name))) + +(defun ert-test-name-button-action (button) + "Find the definition of the test BUTTON belongs to, in another window." + (let ((name (button-get button 'ert-test-name))) + (ert-find-test-other-window name))) + +(defun ert-ewoc-position (ewoc node) + "Return the position of NODE in EWOC, or nil if NODE is not in EWOC." + (loop for i from 0 + for node-here = (ewoc-nth ewoc 0) then (ewoc-next ewoc node-here) + do (when (eql node node-here) + (return i)) + finally (return nil))) + +(defun ert-results-jump-between-summary-and-result () + "Jump back and forth between the test run summary and individual test results. + +From an ewoc node, jumps to the character that represents the +same test in the progress bar, and vice versa. + +To be used in the ERT results buffer." + ;; Maybe this command isn't actually needed much, but if it is, it + ;; seems like an indication that the UI design is not optimal. If + ;; jumping back and forth between a summary at the top of the buffer + ;; and the error log in the remainder of the buffer is useful, then + ;; the summary apparently needs to be easily accessible from the + ;; error log, and perhaps it would be better to have it in a + ;; separate buffer to keep it visible. + (interactive) + (let ((ewoc ert-results-ewoc) + (progress-bar-begin ert-results-progress-bar-button-begin)) + (cond ((ert-results-test-node-or-null-at-point) + (let* ((node (ert-results-test-node-at-point)) + (pos (ert-ewoc-position ewoc node))) + (goto-char (+ progress-bar-begin pos)))) + ((and (<= progress-bar-begin (point)) + (< (point) (button-end (button-at progress-bar-begin)))) + (let* ((node (ewoc-nth ewoc (- (point) progress-bar-begin))) + (entry (ewoc-data node))) + (when (ert-ewoc-entry-hidden-p entry) + (setf (ert-ewoc-entry-hidden-p entry) nil) + (ewoc-invalidate ewoc node)) + (ewoc-goto-node ewoc node))) + (t + (goto-char progress-bar-begin))))) + +(defun ert-button-action-position () + "The buffer position where the last button action was triggered." + (cond ((integerp last-command-event) + (point)) + ((eventp last-command-event) + (posn-point (event-start last-command-event))) + (t (assert nil)))) + +(defun ert-results-progress-bar-button-action (button) + "Find the ewoc node that represents the same test as the character clicked on." + (goto-char (ert-button-action-position)) + (ert-results-jump-between-summary-and-result)) + +(defun ert-results-rerun-test-at-point () + "Re-run the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((ewoc ert-results-ewoc) + (node (ert-results-test-node-at-point)) + (entry (ewoc-data node)) + (old-test (ert-ewoc-entry-test entry)) + (test-name (ert-test-name old-test)) + ;; FIXME: Write a test for this lookup. + (test (if test-name + (if (ert-test-boundp test-name) + (ert-get-test test-name) + (error "No such test: %S" test-name)) + old-test)) + (stats ert-results-stats) + (pos (gethash test (ert-stats-test-map stats))) + (progress-message (format "Running test %S" (ert-test-name test)))) + ;; Need to save and restore point manually here: When point is on + ;; the first visible ewoc entry while the header is updated, point + ;; moves to the top of the buffer. This is undesirable, and a + ;; simple `save-excursion' doesn't prevent it. + (let ((point (point))) + (unwind-protect + (unwind-protect + (progn + (message "%s..." progress-message) + (ert-run-or-rerun-test stats test + ert-results-listener)) + (ert-results-update-stats-display ewoc stats) + (message "%s...%s" + progress-message + (let ((result (ert-test-most-recent-result test))) + (ert-string-for-test-result + result (ert-test-result-expected-p test result))))) + (goto-char point))))) + +(defun ert-results-rerun-test-at-point-debugging-errors () + "Re-run the test at point with `ert-debug-on-error' bound to t. + +To be used in the ERT results buffer." + (interactive) + (let ((ert-debug-on-error t)) + (ert-results-rerun-test-at-point))) + +(defun ert-print-backtrace (backtrace) + "Format the backtrace BACKTRACE to the current buffer." + ;; This is essentially a reimplementation of Fbacktrace + ;; (src/eval.c), but for a saved backtrace, not the current one. + (let ((print-escape-newlines t) + (print-level 8) + (print-length 50)) + (dolist (frame backtrace) + (ecase (first frame) + ((nil) + ;; Special operator. + (destructuring-bind (special-operator &rest arg-forms) + (cdr frame) + (insert + (format " %S\n" (list* special-operator arg-forms))))) + ((t) + ;; Function call. + (destructuring-bind (fn &rest args) (cdr frame) + (insert (format " %S(" fn)) + (loop for firstp = t then nil + for arg in args do + (unless firstp + (insert " ")) + (insert (format "%S" arg))) + (insert ")\n"))))))) + +(defun ert-results-pop-to-backtrace-for-test-at-point () + "Display the backtrace for the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((node (ert-results-test-node-at-point)) + (entry (ewoc-data node)) + (test (ert-ewoc-entry-test entry)) + (result (ert-ewoc-entry-result entry))) + (etypecase result + (ert-test-passed (error "Test passed, no backtrace available")) + (ert-test-result-with-condition + (let ((backtrace (ert-test-result-with-condition-backtrace result)) + (buffer + (let ((default-major-mode 'fundamental-mode)) + (get-buffer-create "*ERT Backtrace*")))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (erase-buffer) + ;; Use unibyte because `debugger-setup-buffer' also does so. + (set-buffer-multibyte nil) + (setq truncate-lines t) + (ert-print-backtrace backtrace) + (debugger-make-xrefs) + (goto-char (point-min)))))))) + +(defun ert-results-pop-to-messages-for-test-at-point () + "Display the part of the *Messages* buffer generated during the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((node (ert-results-test-node-at-point)) + (entry (ewoc-data node)) + (test (ert-ewoc-entry-test entry)) + (result (ert-ewoc-entry-result entry))) + (let ((buffer + (let ((default-major-mode 'fundamental-mode)) + (get-buffer-create "*ERT Messages*")))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (erase-buffer) + (insert (ert-test-result-messages result)) + (goto-char (point-min)) + (insert "Messages for test `") + (ert-insert-test-name-button (ert-test-name test)) + (insert "':\n"))))) + +(defun ert-results-toggle-printer-limits-for-test-at-point () + "Toggle how much of the condition to print for the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((ewoc ert-results-ewoc) + (node (ert-results-test-node-at-point)) + (entry (ewoc-data node))) + (setf (ert-ewoc-entry-extended-printer-limits-p entry) + (not (ert-ewoc-entry-extended-printer-limits-p entry))) + (ewoc-invalidate ewoc node))) + +(defun ert-activate-font-lock-keywords () + (font-lock-add-keywords + nil + '(("(\\(\\<ert-deftest\\)\\>\\s *\\(\\sw+\\)?" + (1 font-lock-keyword-face nil t) + (2 font-lock-function-name-face nil t))))) + +(defun* ert-remove-from-list (list-var element &key key test) + "Remove ELEMENT from the value of LIST-VAR if present. + +This is an inverse of `add-to-list'." + (unless key (setq key #'identity)) + (unless test (setq test #'equal)) + (setf (symbol-value list-var) + (remove* element + (symbol-value list-var) + :key key + :test test))) + + +;;; Actions on load/unload. + +(add-to-list 'find-function-regexp-alist '(ert-deftest . ert-find-test-regexp)) +(add-to-list 'minor-mode-alist '(ert-current-run-stats + (:eval + (ert-tests-running-mode-line-indicator)))) +(add-to-list 'emacs-lisp-mode-hook 'ert-activate-font-lock-keywords) + +(defun ert-unload-function () + (ert-remove-from-list 'find-function-regexp-alist 'ert-deftest :key #'car) + (ert-remove-from-list 'minor-mode-alist 'ert-current-run-stats :key #'car) + (ert-remove-from-list 'emacs-lisp-mode-hook 'ert-activate-font-lock-keywords) + nil) + +(defvar ert-unload-hook '()) +(add-hook 'ert-unload-hook 'ert-unload-function) + + +;;; Self-tests. + +(ert-delete-all-tests) + +;; Test that test bodies are actually run. +(defvar ert-test-body-was-run) +(ert-deftest ert-test-body-runs () + (setq ert-test-body-was-run t)) + + +;; Test that nested test bodies run. +(ert-deftest ert-nested-test-body-runs () + (lexical-let ((was-run nil)) + (let ((test (make-ert-test :body (lambda () + (setq was-run t))))) + (assert (not was-run)) + (ert-run-test test) + (assert was-run)))) + + +;; Test that pass/fail works. +(ert-deftest ert-test-pass () + (let ((test (make-ert-test :body (lambda ())))) + (let ((result (ert-run-test test))) + (assert (typep result 'ert-test-passed))))) + +(ert-deftest ert-test-fail () + (let ((test (make-ert-test :body (lambda () (ert-fail "failure message"))))) + (let ((result (let ((ert-debug-on-error nil)) + (ert-run-test test)))) + (assert (typep result 'ert-test-failed) t) + (assert (equal (ert-test-result-with-condition-condition result) + '(ert-test-failed "failure message")) + t)))) + +(ert-deftest ert-test-fail-debug-with-condition-case () + (let ((test (make-ert-test :body (lambda () (ert-fail "failure message"))))) + (condition-case condition + (progn + (let ((ert-debug-on-error t)) + (ert-run-test test)) + (assert nil)) + ((error) + (assert (equal condition '(ert-test-failed "failure message")) t))))) + +(ert-deftest ert-test-fail-debug-with-debugger-1 () + (let ((test (make-ert-test :body (lambda () (ert-fail "failure message"))))) + (let ((debugger (lambda (&rest debugger-args) + (assert nil)))) + (let ((ert-debug-on-error nil)) + (ert-run-test test))))) + +(ert-deftest ert-test-fail-debug-with-debugger-2 () + (let ((test (make-ert-test :body (lambda () (ert-fail "failure message"))))) + (block nil + (let ((debugger (lambda (&rest debugger-args) + (return-from nil nil)))) + (let ((ert-debug-on-error t)) + (ert-run-test test)) + (assert nil))))) + +(ert-deftest ert-test-fail-debug-nested-with-debugger () + (let ((test (make-ert-test :body (lambda () + (let ((ert-debug-on-error t)) + (ert-fail "failure message")))))) + (let ((debugger (lambda (&rest debugger-args) + (assert nil nil "Assertion a")))) + (let ((ert-debug-on-error nil)) + (ert-run-test test)))) + (let ((test (make-ert-test :body (lambda () + (let ((ert-debug-on-error nil)) + (ert-fail "failure message")))))) + (block nil + (let ((debugger (lambda (&rest debugger-args) + (return-from nil nil)))) + (let ((ert-debug-on-error t)) + (ert-run-test test)) + (assert nil nil "Assertion b"))))) + +(ert-deftest ert-test-error () + (let ((test (make-ert-test :body (lambda () (error "error message"))))) + (let ((result (let ((ert-debug-on-error nil)) + (ert-run-test test)))) + (assert (typep result 'ert-test-error) t) + (assert (equal (ert-test-result-with-condition-condition result) + '(error "error message")) + t)))) + +(ert-deftest ert-test-error-debug () + (let ((test (make-ert-test :body (lambda () (error "error message"))))) + (condition-case condition + (progn + (let ((ert-debug-on-error t)) + (ert-run-test test)) + (assert nil)) + ((error) + (assert (equal condition '(error "error message")) t))))) + + +;; Test that `should' works. +(ert-deftest ert-test-should () + (let ((test (make-ert-test :body (lambda () (ert-should nil))))) + (let ((result (let ((ert-debug-on-error nil)) + (ert-run-test test)))) + (assert (typep result 'ert-test-failed) t) + (assert (equal (ert-test-result-with-condition-condition result) + '(ert-test-failed ((ert-should nil) :form nil :value nil))) + t))) + (let ((test (make-ert-test :body (lambda () (ert-should t))))) + (let ((result (ert-run-test test))) + (assert (typep result 'ert-test-passed) t)))) + +(ert-deftest ert-test-should-value () + (ert-should (eql (ert-should 'foo) 'foo)) + (ert-should (eql (ert-should 'bar) 'bar))) + +(ert-deftest ert-test-should-not () + (let ((test (make-ert-test :body (lambda () (ert-should-not t))))) + (let ((result (let ((ert-debug-on-error nil)) + (ert-run-test test)))) + (assert (typep result 'ert-test-failed) t) + (assert (equal (ert-test-result-with-condition-condition result) + '(ert-test-failed ((ert-should-not t) :form t :value t))) + t))) + (let ((test (make-ert-test :body (lambda () (ert-should-not nil))))) + (let ((result (ert-run-test test))) + (assert (typep result 'ert-test-passed))))) + + +(ert-deftest ert-test-should-error () + ;; No error. + (let ((test (make-ert-test :body (lambda () (ert-should-error (progn)))))) + (let ((result (let ((ert-debug-on-error nil)) + (ert-run-test test)))) + (ert-should (typep result 'ert-test-failed)) + (ert-should (equal (ert-test-result-with-condition-condition result) + '(ert-test-failed + ((ert-should-error (progn)) + :form (progn) + :value nil + :fail-reason "did not signal an error")))))) + ;; A simple error. + (let ((test (make-ert-test :body (lambda () (ert-should-error (error "foo")))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-passed)))) + ;; Error of unexpected type, no test. + (let ((test (make-ert-test :body (lambda () + (ert-should-error (error "foo") + :type 'singularity-error))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-failed)) + (ert-should (equal + (ert-test-result-with-condition-condition result) + '(ert-test-failed + ((ert-should-error (error "foo") :type 'singularity-error) + :form (error "foo") + :condition (error "foo") + :fail-reason + "the error signalled did not have the expected type")))))) + ;; Error of the expected type, no test. + (let ((test (make-ert-test :body (lambda () + (ert-should-error (signal 'singularity-error + nil) + :type 'singularity-error))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-passed)))) + ;; Error that fails the test, no type. + (let ((test (make-ert-test :body (lambda () + (ert-should-error + (error "foo") + :test (lambda (error) nil)))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-failed)) + (ert-should (equal (ert-test-result-with-condition-condition result) + '(ert-test-failed + ((ert-should-error (error "foo") :test (lambda (error) nil)) + :form (error "foo") + :condition (error "foo") + :fail-reason + "the error signalled did not pass the test")))))) + ;; Error that passes the test, no type. + (let ((test (make-ert-test :body (lambda () + (ert-should-error (error "foo") + :test (lambda (error) t)))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-passed)))) + ;; Error that has the expected type but fails the test. + (let ((test (make-ert-test :body (lambda () + (ert-should-error + (signal 'singularity-error nil) + :type 'singularity-error + :test (lambda (error) nil)))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-failed)) + (ert-should (equal (ert-test-result-with-condition-condition result) + '(ert-test-failed + ((ert-should-error (signal 'singularity-error nil) + :type 'singularity-error + :test (lambda (error) nil)) + :form (signal singularity-error nil) + :condition (singularity-error) + :fail-reason + "the error signalled did not pass the test")))))) + ;; Error that has the expected type and passes the test. + (let ((test (make-ert-test :body (lambda () + (ert-should-error + (signal 'singularity-error nil) + :type 'singularity-error + :test (lambda (error) t)))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-passed)))) + ) + +(ert-deftest ert-test-should-error-subtypes () + (let ((test (make-ert-test + :body (lambda () + (ert-should-error (signal 'singularity-error nil) + :type 'singularity-error + :exclude-subtypes t))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-passed)))) + (let ((test (make-ert-test + :body (lambda () + (ert-should-error (signal 'arith-error nil) + :type 'singularity-error))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-failed)) + (ert-should (equal + (ert-test-result-with-condition-condition result) + '(ert-test-failed + ((ert-should-error (signal 'arith-error nil) + :type 'singularity-error) + :form (signal arith-error nil) + :condition (arith-error) + :fail-reason + "the error signalled did not have the expected type")))))) + (let ((test (make-ert-test + :body (lambda () + (ert-should-error (signal 'arith-error nil) + :type 'singularity-error + :exclude-subtypes t))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-failed)) + (ert-should (equal + (ert-test-result-with-condition-condition result) + '(ert-test-failed + ((ert-should-error (signal 'arith-error nil) + :type 'singularity-error + :exclude-subtypes t) + :form (signal arith-error nil) + :condition (arith-error) + :fail-reason + "the error signalled did not have the expected type")))))) + (let ((test (make-ert-test + :body (lambda () + (ert-should-error (signal 'singularity-error nil) + :type 'arith-error + :exclude-subtypes t))))) + (let ((result (ert-run-test test))) + (ert-should (typep result 'ert-test-failed)) + (ert-should (equal + (ert-test-result-with-condition-condition result) + '(ert-test-failed + ((ert-should-error (signal 'singularity-error nil) + :type 'arith-error + :exclude-subtypes t) + :form (signal singularity-error nil) + :condition (singularity-error) + :fail-reason + "the error signalled was a subtype of the expected type")))))) + ) + +;; Test that `should' errors contain the information we expect them to. +(defmacro ert-test-my-list (&rest args) + `(list ,@args)) + +(ert-deftest ert-test-should-failure-debugging () + (loop for (body expected-condition) in + `((,(lambda () (let ((x nil)) (ert-should x))) + (ert-test-failed ((ert-should x) :form x :value nil))) + (,(lambda () (let ((x t)) (ert-should-not x))) + (ert-test-failed ((ert-should-not x) :form x :value t))) + (,(lambda () (let ((x t)) (ert-should (not x)))) + (ert-test-failed ((ert-should (not x)) :form (not t) :value nil))) + (,(lambda () (let ((x nil)) (ert-should-not (not x)))) + (ert-test-failed ((ert-should-not (not x)) :form (not nil) :value t))) + (,(lambda () (let ((x t) (y nil)) (ert-should-not (ert-test-my-list x y)))) + (ert-test-failed + ((ert-should-not (ert-test-my-list x y)) + :form (list t nil) + :value (t nil)))) + (,(lambda () (let ((x t)) (ert-should (error "foo")))) + (error "foo"))) + do + (let ((test (make-ert-test :body body))) + (condition-case actual-condition + (progn + (let ((ert-debug-on-error t)) + (ert-run-test test)) + (assert nil)) + ((error) + (ert-should (equal actual-condition expected-condition))))))) + +(ert-deftest ert-test-messages () + (let* ((message-string "Test message") + (messages-buffer (get-buffer-create "*Messages*")) + (test (make-ert-test :body (lambda () (message "%s" message-string))))) + (with-current-buffer messages-buffer + (let ((result (ert-run-test test))) + (ert-should (equal (concat message-string "\n") + (ert-test-result-messages result))))))) + +(defun ert-call-with-temporary-messages-buffer (thunk) + (lexical-let ((new-buffer-name (generate-new-buffer-name + "*Messages* orig buffer"))) + (unwind-protect + (progn + (with-current-buffer (get-buffer-create "*Messages*") + (rename-buffer new-buffer-name)) + (get-buffer-create "*Messages*") + (funcall thunk)) + (kill-buffer "*Messages*") + (with-current-buffer new-buffer-name + (rename-buffer "*Messages*"))))) + +(ert-deftest ert-test-messages-on-log-truncation () + (let ((test (make-ert-test + :body (lambda () + ;; Emacs would combine messages if we + ;; generate the same message multiple + ;; times. + (message "a") + (message "b") + (message "c") + (message "d"))))) + (let (result) + (ert-call-with-temporary-messages-buffer + (lambda () + (let ((message-log-max 2)) + (setq result (ert-run-test test))) + (ert-should (equal (with-current-buffer "*Messages*" + (buffer-string)) + "c\nd\n")))) + (ert-should (equal (ert-test-result-messages result) "a\nb\nc\nd\n"))))) + +;; Test `ert-select-tests'. +(ert-deftest ert-test-select-regexp () + (ert-should (equal (ert-select-tests "^ert-test-select-regexp$" t) + (list (ert-get-test 'ert-test-select-regexp))))) + +(ert-deftest ert-test-test-boundp () + (ert-should (ert-test-boundp 'ert-test-test-boundp)) + (ert-should-not (ert-test-boundp (make-symbol "ert-not-a-test")))) + +(ert-deftest ert-test-select-member () + (ert-should (equal (ert-select-tests '(member ert-test-select-member) t) + (list (ert-get-test 'ert-test-select-member))))) + +(ert-deftest ert-test-select-test () + (ert-should (equal (ert-select-tests (ert-get-test 'ert-test-select-test) t) + (list (ert-get-test 'ert-test-select-test))))) + +(ert-deftest ert-test-select-symbol () + (ert-should (equal (ert-select-tests 'ert-test-select-symbol t) + (list (ert-get-test 'ert-test-select-symbol))))) + +(ert-deftest ert-test-select-and () + (let ((test (make-ert-test + :name nil + :body nil + :most-recent-result (make-ert-test-failed + :condition nil + :backtrace nil)))) + (ert-should (equal (ert-select-tests `(and (member ,test) :failed) t) + (list test))))) + + +;; Test utility functions. +(ert-deftest ert-proper-list-p () + (ert-should (ert-proper-list-p '())) + (ert-should (ert-proper-list-p '(1))) + (ert-should (ert-proper-list-p '(1 2))) + (ert-should (ert-proper-list-p '(1 2 3))) + (ert-should (ert-proper-list-p '(1 2 3 4))) + (ert-should (not (ert-proper-list-p 'a))) + (ert-should (not (ert-proper-list-p '(1 . a)))) + (ert-should (not (ert-proper-list-p '(1 2 . a)))) + (ert-should (not (ert-proper-list-p '(1 2 3 . a)))) + (ert-should (not (ert-proper-list-p '(1 2 3 4 . a)))) + (let ((a (list 1))) + (setf (cdr (last a)) a) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2))) + (setf (cdr (last a)) a) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2 3))) + (setf (cdr (last a)) a) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2 3 4))) + (setf (cdr (last a)) a) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2))) + (setf (cdr (last a)) (cdr a)) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2 3))) + (setf (cdr (last a)) (cdr a)) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2 3 4))) + (setf (cdr (last a)) (cdr a)) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2 3))) + (setf (cdr (last a)) (cddr a)) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2 3 4))) + (setf (cdr (last a)) (cddr a)) + (ert-should (not (ert-proper-list-p a)))) + (let ((a (list 1 2 3 4))) + (setf (cdr (last a)) (cdddr a)) + (ert-should (not (ert-proper-list-p a))))) + +(ert-deftest ert-parse-keys-and-body () + (ert-should (equal (ert-parse-keys-and-body "doc" '(foo)) + '(nil "doc" (foo)))) + (ert-should (equal (ert-parse-keys-and-body "doc" '(:bar foo)) + '((:bar foo) "doc" nil))) + (ert-should (equal (ert-parse-keys-and-body nil '(:bar foo)) + '((:bar foo) nil nil))) + (ert-should (equal (ert-parse-keys-and-body "doc" '(:bar foo)) + '((:bar foo) "doc" nil))) + (ert-should (equal (ert-parse-keys-and-body nil '(:bar foo a (b))) + '((:bar foo) nil (a (b))))) + (ert-should (equal (ert-parse-keys-and-body nil '(:bar foo :a (b))) + '((:bar foo :a (b)) nil nil))) + (ert-should (equal (ert-parse-keys-and-body nil '(bar foo :a (b))) + '(nil nil (bar foo :a (b))))) + (ert-should-error (ert-parse-keys-and-body nil '(:bar foo :a)))) + + + +;; Test `ert-run-tests'. +(ert-deftest ert-test-run-tests () + (let ((passing-test (make-ert-test :name 'passing-test + :body (lambda () (ert-pass)))) + (failing-test (make-ert-test :name 'failing-test + :body (lambda () (ert-fail + "failure message")))) + ) + (let ((ert-debug-on-error nil)) + (let* ((buffer-name (generate-new-buffer-name " *ert-test-run-tests*")) + (messages nil) + (mock-message-fn + (lambda (format-string &rest args) + (push (apply #'format format-string args) messages)))) + (save-window-excursion + (unwind-protect + (let ((case-fold-search nil)) + (ert-run-tests-interactively + `(member ,passing-test ,failing-test) buffer-name + mock-message-fn) + (ert-should (equal messages `(,(concat + "Ran 2 tests, 1 results were " + "as expected, 1 unexpected")))) + (with-current-buffer buffer-name + (goto-char (point-min)) + (ert-should (equal + (buffer-substring (point-min) + (save-excursion + (forward-line 5) + (point))) + (concat + "Selector: (member <passing-test> <failing-test>)\n" + "Passed: 1 (0 unexpected)\n" + "Failed: 1 (1 unexpected)\n" + "Error: 0 (0 unexpected)\n" + "Total: 2/2\n"))))) + (when (get-buffer buffer-name) + (kill-buffer buffer-name)))))))) + +(ert-deftest ert-test-special-operator-p () + (ert-should (ert-special-operator-p 'if)) + (ert-should-not (ert-special-operator-p 'car)) + (ert-should-not (ert-special-operator-p 'ert-special-operator-p)) + (let ((b (gensym))) + (ert-should-not (ert-special-operator-p b)) + (fset b 'if) + (ert-should (ert-special-operator-p b)))) + +;; This test attempts to demonstrate that there is no way to force +;; immediate truncation of the *Messages* buffer from Lisp (and hence +;; justifies the existence of +;; `ert-force-message-log-buffer-truncation'): The only way that came +;; to my mind was (message ""), which doesn't have the desired effect. +(ert-deftest ert-test-builtin-message-log-flushing () + (ert-call-with-temporary-messages-buffer + (lambda () + (with-current-buffer "*Messages*" + (let ((message-log-max 2)) + (let ((message-log-max t)) + (loop for i below 4 do + (message "%s" i)) + (ert-should (eql (count-lines (point-min) (point-max)) 4))) + (ert-should (eql (count-lines (point-min) (point-max)) 4)) + (message "") + (ert-should (eql (count-lines (point-min) (point-max)) 4)) + (message "Test message") + (ert-should (eql (count-lines (point-min) (point-max)) 2))))))) + +(ert-deftest ert-test-force-message-log-buffer-truncation () + (labels ((body () + (loop for i below 5 do + (message "%s" i))) + (c (x) + (ert-call-with-temporary-messages-buffer + (lambda () + (let ((message-log-max x)) + (body)) + (with-current-buffer "*Messages*" + (buffer-string))))) + (lisp (x) + (ert-call-with-temporary-messages-buffer + (lambda () + (let ((message-log-max t)) + (body)) + (let ((message-log-max x)) + (ert-force-message-log-buffer-truncation)) + (with-current-buffer "*Messages*" + (buffer-string)))))) + (loop for x in '(0 1 2 3 4 5 6 t) do + (ert-should (equal (c x) (lisp x)))))) + +(defun ert-run-self-tests () + ;; Run tests and make sure they actually ran. + (let ((window-configuration (current-window-configuration))) + (let ((ert-test-body-was-run nil)) + ;; The buffer name chosen here should not compete with the default + ;; results buffer name for completion in `switch-to-buffer'. + (let ((stats (ert-run-tests-interactively "^ert-" " *ert self-tests*"))) + (assert ert-test-body-was-run) + (when (zerop (+ (ert-stats-passed-unexpected stats) + (ert-stats-failed-unexpected stats) + (ert-stats-error-unexpected stats))) + ;; Hide results window only when everything went well. + (set-window-configuration window-configuration)))))) + +(provide 'ert) + +;;; ert.el ends here diff --git a/emacs/nxhtml/tests/ert2.el b/emacs/nxhtml/tests/ert2.el new file mode 100644 index 0000000..1fe971c --- /dev/null +++ b/emacs/nxhtml/tests/ert2.el @@ -0,0 +1,268 @@ +;;; ert2.el --- Additions to ert.el +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-09-02T11:46:03+0200 Tue +;; Version: +;; Last-Updated: 2009-01-06 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; Cannot open load file: ert2. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile + (let* ((this-file (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + (this-dir (file-name-directory this-file)) + (load-path (cons this-dir load-path))) + (require 'ert))) + +(let* ((this-dir + (file-name-directory (if load-file-name load-file-name buffer-file-name))) + ;;(load-path (copy-list load-path))) + (load-path (copy-sequence load-path))) + (add-to-list 'load-path this-dir) + (require 'ert)) + + +(defvar ert-temp-test-buffer-test nil) +(make-variable-buffer-local 'ert-temp-test-buffer-test) +(put 'ert-temp-test-buffer-test 'permanent-local t) + +(defvar ert-temp-test-buffer-file nil) +(make-variable-buffer-local 'ert-temp-test-buffer-file) +(put 'ert-temp-test-buffer-file 'permanent-local t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Test buffers + +(defvar ert-failed-tests-temp-buffers nil) + +(defvar ert-list-failed-buffers-name "*Ert Failed Test Buffers*") + +(defun ert-kill-temp-test-buffers () + "Delete test buffers from unsuccessful tests." + (interactive) + (let ((failed (get-buffer ert-list-failed-buffers-name))) + (when failed (kill-buffer failed))) + (dolist (buf ert-failed-tests-temp-buffers) + (when (buffer-live-p buf) + (kill-buffer buf))) + (setq ert-failed-tests-temp-buffers nil)) + +(defun ert-list-temp-test-buffers () + "List test buffers from unsuccessful tests." + (interactive) + (setq ert-failed-tests-temp-buffers + (delq nil + (mapcar (lambda (buf) + (when (buffer-live-p buf) + buf)) + ert-failed-tests-temp-buffers))) + (let ((ert-buffer (get-buffer "*ert*")) + (buffers ert-failed-tests-temp-buffers)) + (when ert-buffer (setq buffers (cons ert-buffer buffers))) + (switch-to-buffer + (let ((Buffer-menu-buffer+size-width 40)) + (list-buffers-noselect nil buffers))) + (rename-buffer ert-list-failed-buffers-name t)) + (unless ert-failed-tests-temp-buffers + (message "No test buffers from unsuccessful tests"))) + +(defvar ert-temp-test-buffer-minor-mode-map + (let ((map (make-sparse-keymap))) + ;; Add menu bar entries for test buffer and test function + (define-key map [(control ?c) ?? ?t] 'ert-temp-test-buffer-go-test) + (define-key map [(control ?c) ?? ?f] 'ert-temp-test-buffer-go-file) + map)) +(defun ert-temp-test-buffer-go-test () + (interactive) + (ert-find-test-other-window ert-temp-test-buffer-test)) +(defun ert-temp-test-buffer-go-file () + (interactive) + (find-file-other-window ert-temp-test-buffer-file)) + +(define-minor-mode ert-temp-test-buffer-minor-mode + "Helpers for those buffers ..." + ) +(put 'ert-temp-test-buffer-minor-mode 'permanent-local t) + +;; Fix-me: doc +(defvar ert-test-files-root nil) +(defun ert-get-test-file-name (file-name) + (unless ert-test-files-root + (error "Please set ert-test-files-root for your tests")) + (unless (file-directory-p ert-test-files-root) + (error "Can't find directory %s" ert-test-files-root)) + (expand-file-name file-name ert-test-files-root)) + +(defmacro* ert-with-temp-buffer-include-file (file-name-form &body body) + "Insert FILE-NAME-FORM in a temporary buffer and eval BODY. +If success then delete the temporary buffer, otherwise keep it. + +To access these temporary test buffers use +- `ert-list-temp-test-buffers': list them +- `ert-kill-temp-test-buffers': delete them" + (declare (indent 1) (debug t)) + (let ((file-name (make-symbol "file-name-"))) + `(let* ((,file-name (ert-get-test-file-name ,file-name-form)) + (mode-line-buffer-identification (list (propertize "%b" 'face 'highlight))) + ;; Give the buffer a name that allows us to switch to it + ;; quickly when debugging a failure. + (temp-buf + (generate-new-buffer + (format "%s" (ert-this-test))))) + (unless (file-readable-p ,file-name) + (if (file-exists-p ,file-name) + (error "Can't read %s" ,file-name) + (error "Can't find %s" ,file-name))) + (message "Testing with file %s" ,file-name) + (setq ert-failed-tests-temp-buffers (cons temp-buf ert-failed-tests-temp-buffers)) + (with-current-buffer temp-buf + (ert-temp-test-buffer-minor-mode 1) + (setq ert-temp-test-buffer-file ,file-name) + (setq ert-temp-test-buffer-test (ert-this-test)) + ;; Avoid global font lock + (let ((font-lock-global-modes nil)) + ;; Turn off font lock in buffer + (font-lock-mode -1) + (when (> emacs-major-version 22) + (assert (not font-lock-mode) t "%s %s" "in ert-with-temp-buffer-include-file")) + (insert-file-contents ,file-name) + (save-window-excursion + ;; Switch to buffer so it will show immediately when + ;; debugging a failure. + (switch-to-buffer-other-window (current-buffer)) + ,@body) + ;; Fix-me: move to success list? + (kill-buffer temp-buf)))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Simulate commands + +(defvar ert-simulate-command-delay nil) + +(defvar ert-simulate-command-post-hook nil + "Normal hook to be run at end of `ert-simulate-command'.") + +;; Fix-me: use this in all tests where applicable. +(defun ert-simulate-command (command run-idle-timers) + ;; Fix-me: run-idle-timers - use seconds + ;; Fix-me: add unread-events + "Simulate calling command COMMAND as in Emacs command loop. +If RUN-IDLE-TIMERS is non-nil then run the idle timers after +calling everything involved with the command. + +COMMAND should be a list where the car is the command symbol and +the rest are arguments to the command. + +NOTE: Since the command is not called by `call-interactively' +test for `called-interactively' in the command will fail. + +Return the value of calling the command, ie + + (apply (car COMMAND) (cdr COMMAND)). + +Run the hook `ert-simulate-command-post-hook' at the very end." + + (message "command=%s" command) + (ert-should (listp command)) + (ert-should (commandp (car command))) + (ert-should (not unread-command-events)) + (let (return-value + (font-lock-mode t)) + ;; For the order of things here see command_loop_1 in keyboard.c + ;; + ;; The command loop will reset the command related variables so + ;; there is no reason to let bind them. They are set here however + ;; to be able to test several commands in a row and how they + ;; affect each other. + (setq deactivate-mark nil) + (setq this-original-command (car command)) + ;; remap through active keymaps + (setq this-command (or (command-remapping this-original-command) + this-original-command)) + (run-hooks 'pre-command-hook) + (setq return-value (apply (car command) (cdr command))) ;; <----- + (message "post-command-hook=%s" post-command-hook) + (run-hooks 'post-command-hook) + (when deferred-action-list + (run-hooks 'deferred_action_function)) + (setq real-last-command (car command)) + (setq last-repeatable-command real-last-command) + (setq last-command this-command) + (when (and deactivate-mark transient-mark-mode) (deactivate-mark)) + ;;(message "ert-simulate-command.before idle-timers, point=%s" (point)) + (when run-idle-timers + ;;(dolist (timer (copy-list timer-idle-list)) + (dolist (timer (copy-sequence timer-idle-list)) + (timer-event-handler timer) + ;;(message " after timer=%s, point=%s" timer (point)) + ) + (redisplay t)) + ;;(message "ert-simulate-command.after idle-timers, point=%s" (point)) + (when ert-simulate-command-delay + ;; Show user + ;;(message "After M-x %s" command) + (let ((old-buffer-name (buffer-name))) + (rename-buffer (propertize (format "After M-x %s" (car command)) + 'face 'highlight) + t) + (sit-for ert-simulate-command-delay) + (rename-buffer old-buffer-name))) + (ert-should (not unread-command-events)) + (run-hooks 'ert-simulate-command-post-hook) + return-value)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Misc + +(defun ert-this-test () + "Return current `ert-deftest' function." + (elt test 1)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Self tests + +(provide 'ert2) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ert2.el ends here diff --git a/emacs/nxhtml/tests/hfy-test.el b/emacs/nxhtml/tests/hfy-test.el new file mode 100644 index 0000000..4592d7b --- /dev/null +++ b/emacs/nxhtml/tests/hfy-test.el @@ -0,0 +1,102 @@ +;;; hfy-test.el --- Test for htmlfontify + hfyview +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-10-17 Fri +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: +(require 'winsav) +(require 'emacsw32 nil t) +(require 'grep) + +(defun hfy-test-setup-frame () + (find-library "htmlfontify") + (occur "hfy-tmpfont-stack") + (unless grep-template (grep-compute-defaults)) + (lgrep "hfy-tmpfont-stack" "*.el" ".") + (list-faces-display) + (list-colors-display) + (describe-function 'describe-function) + (delete-other-windows) + + (split-window-vertically) + (split-window-vertically) + (balance-windows) + (split-window-vertically) + (balance-windows) + (split-window-vertically) + (balance-windows) + + ;;(winsav-upper-left-window) + (frame-first-window) + (split-window-horizontally) + ;;(winsav-upper-left-window) + (frame-first-window) + (switch-to-buffer "*scratch*") + + (select-window (next-window)) + (switch-to-buffer "*Help*") + + (select-window (next-window)) + (switch-to-buffer "*Faces*") + (split-window-horizontally) + + (select-window (next-window)) + (switch-to-buffer "*Colors*") + + (select-window (next-window)) + (when (fboundp 'emacsw32-show-custstart) + (emacsw32-show-custstart)) + + (select-window (next-window)) + (info) + + (select-window (next-window)) + (split-window-horizontally) + (switch-to-buffer "*grep*") + + (select-window (next-window)) + (switch-to-buffer "*Occur*") + ) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; hfy-test.el ends here diff --git a/emacs/nxhtml/tests/in/3-heights.html b/emacs/nxhtml/tests/in/3-heights.html new file mode 100644 index 0000000..339b5c2 --- /dev/null +++ b/emacs/nxhtml/tests/in/3-heights.html @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>patika</title> +<meta name="generator" content="emacs 23.0.60.1; htmlfontify 0.20" /> +<style type="text/css"><!-- +body { font-family: Courier New; font-stretch: normal; font-weight: 500; font-style: normal; color: #f5deb3; background: #2f4f4f; font-size: 10pt; text-decoration: none; } +span.default { font-family: Courier New; font-stretch: normal; font-weight: 500; font-style: normal; color: #f5deb3; background: #2f4f4f; font-size: 10pt; text-decoration: none; } +span.default a { font-family: Courier New; font-stretch: normal; font-weight: 500; font-style: normal; color: #f5deb3; background: #2f4f4f; font-size: 10pt; text-decoration: underline; } +span.default-0004 { text-decoration: none; } +span.default-0004 a { text-decoration: underline; } +span.default-0002 { text-decoration: none; } +span.default-0002 a { text-decoration: underline; } + --></style> + + </head> + <body> + + <script type="text/javascript"> + // <![CDATA[ + +function getObj(name) { + if (document.getElementById) { + this.obj = document.getElementById(name); + this.style = document.getElementById(name).style; + } +} +function hfy_toggle_display(name) { + var x = new getObj("hfy_invis_" + name); + var flag = x.style.display == 'inline'; + x.style.display = (flag) ? 'none' : 'inline' +} + + // ]]> + </script> + +<pre>ajsha a<span class="default-0002">hsahs</span>jha<span class="default-0004">j sah</span>sja </pre> + + </body> +</html> diff --git a/emacs/nxhtml/tests/in/400415-index.phtml b/emacs/nxhtml/tests/in/400415-index.phtml new file mode 100644 index 0000000..de950e7 --- /dev/null +++ b/emacs/nxhtml/tests/in/400415-index.phtml @@ -0,0 +1,43 @@ +<h2>CLEO Memorandum Assignment #1. What's Next?</h2> +<table cellpadding="0" cellspacing="0"> + <thead> + <tr> + <th class="first author">Activity</th> +<!-- <th class="time">Progress</th> --> + </tr> + </thead> + + <tbody> + <?php + $AM = $this->activity_model; + foreach ($this->focus_transitions as $tran => $satisfied) { + $props = $AM->getTransitionProps($tran); + $url_params = $props['url_params']; + $link_text = $props['link_text']; + if (null !== $url_params and null !== $link_text) { + // TODO Add $sat class to <td>, style accordingly. + ?> + <tr> + <td class="first author"><a href="<?= + $this->url($url_params) ?>"><?= $link_text ?></a></td> +<!-- <td><?= + // TODO $props['allotted'] + $satisfied ? '✔' : ' ' + ?></td> --> + </tr> + <?php }} ?> + </tbody> +</table> +<!-- +<?php +print_r($this->acts); +print_r($this->states); +print_r($this->payload); +print_r($this->activity_model); +?> +--> +<?php +$foo = <<<MY_FOO +I am a heredoc +MY_FOO; +?> diff --git a/emacs/nxhtml/tests/in/asp.asp b/emacs/nxhtml/tests/in/asp.asp new file mode 100644 index 0000000..a557cb6 --- /dev/null +++ b/emacs/nxhtml/tests/in/asp.asp @@ -0,0 +1,40 @@ + +<%@LANGUAGE="VBScript"%> + +<SCRIPT LANGUAGE="JavaScript" RUNAT="Server"> +function JSGreeting() + { + return "Greetings from a JavaScript Function"; + } +</SCRIPT> + +<SCRIPT LANGUAGE="VBScript" RUNAT="Server"> +Function VBGreeting() + VBGreeting="Greetings from a VBScript Function" +End Function + +Function toDollars(x) + toDollars=FormatCurrency(x) +End Function +</SCRIPT> + +<% +var a = 2; +var b = 2; +var c = add(a,b) +c += " (Two numbers are added by JavaScript, " +c += "and then formatted into currency by VBScript.)" + +function add(x,y) + { + result = x + y; + result = toDollars(result); + return result; + } + +Response.Write("<HTML>\r") +Response.Write(JSGreeting() + "<BR>\r") +Response.Write(VBGreeting() + "<BR>\r") +Response.Write(c + " <BR>\r") +Response.Write("</HTML>\r") +%> diff --git a/emacs/nxhtml/tests/in/bastien-test.mm b/emacs/nxhtml/tests/in/bastien-test.mm new file mode 100644 index 0000000..1494a62 --- /dev/null +++ b/emacs/nxhtml/tests/in/bastien-test.mm @@ -0,0 +1,38 @@ +<map version="0.9.0"> +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> +<node BACKGROUND_COLOR="#00bfff" CREATED="1248161883687" ID="ID_4621171" MODIFIED="1248162997000" TEXT="test.org"> +<richcontent TYPE="NOTE"><html> + <head> + + </head> + <body> + <p> + --org-mode: WHOLE FILE + </p> + </body> +</html> +</richcontent> +<node CREATED="1248161883687" MODIFIED="1248161883687" POSITION="left" TEXT="Bonjour"> +<node CREATED="1248161883687" MODIFIED="1248161883687" TEXT="Ceci est un test"> +<node BACKGROUND_COLOR="#eeee00" CREATED="1248161883687" MODIFIED="1248161883687" STYLE="bubble"> +<richcontent TYPE="NODE"><html> +<head> +<style type="text/css"> +<!-- +p { margin-top: 0 } +--> +</style> +</head> +<body> +<p><br/> lkxjdflkdsz _lskfdsdf_ alskdjf<br/></p> +</body> +</html></richcontent> +<richcontent TYPE="NOTE"><html><head/><body><p>-- This is more about "Ceci est un test" --</p></body></html></richcontent> +</node> +</node> +</node> +<node CREATED="1248161883687" HGAP="-88" ID="ID_901848166" MODIFIED="1248162974171" POSITION="right" TEXT="Rebonjour" VSHIFT="76"> +<node CREATED="1248161883687" HGAP="85" ID="ID_1570634894" MODIFIED="1248162978203" TEXT="Ceci est un autre test" VSHIFT="-109"/> +</node> +</node> +</map> diff --git a/emacs/nxhtml/tests/in/bigfile-stringerr-64000.html b/emacs/nxhtml/tests/in/bigfile-stringerr-64000.html new file mode 100644 index 0000000..e42ab6e --- /dev/null +++ b/emacs/nxhtml/tests/in/bigfile-stringerr-64000.html @@ -0,0 +1,1850 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>News and Notes about nXhtml</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> +<style type="text/css"> +#nxhtml-home a { + /* Image */ + display: block; + background: transparent url("img/getitbuttons.png") 0 0 no-repeat; + overflow: hidden; + width: 200px; + xheight: 35px; + /* Text placement and size, etc */ + text-align: center; + padding-top: 11px; + font-size: 12px; + padding-bottom: 9px; + text-decoration: none; + white-space: nowrap; + margin: 0; + border: none; +} +#nxhtml-home a:hover { + background-position: 0 -35px; + color: yellow; +} + +</style> + </head> + <body> + <div id="container"> + + <div id="rgtcol"> + <p id="nxhtml-home"><a href="nxhtml.html">To nXhtml main page</a></p> + + <h1>News and Notes about nXhtml</h1> + + <dl> + + <dt id="hadron-bugs" style="margin-top:1em;">Thanks for testing!</dt> + <dd> + <p> + I want to thanks the testers (who have been many now), + especially to my first testers Hadron Quark and Eric + Lilja, for helping me by testing and pointing out bugs + and weaknesses, most of them related to editing of PHP. + </p> + <p> + Without testers all kind of problems I just can't + imagine myself would still be there in nXhtml. For + example Hadron told me once that he got the error + <i>(wrong-type-argument stringp nil)</i>. Eh, I replied, are + you sure. Yes he was. I tried the same file as him. No + error. + </p> + <p> + The error happened during fontification so the error + message above was all we had. A real black box for + me. Or perhaps black magic? After much confusion and + some hard work we finally found out what it was and I + implemented a better way to catch such errors. If Hadron + would have given up the problem would still have been + there. Some problems are just impossible to solve + without good cooperation. So, again, thanks Hadron. + </p> + <p> + BTW, I will perhaps add some even better way to Emacs to + catch these errors so other can benefit from our + insights too, but that requires some time and effort + which I can't afford right now. + </p> + </dd> + + <dt id="state-of-the-art" style="margin-top:1em; + background-color: #66cd5c; + background-color: #96cd5c; + padding: 0.5em; + ">The State of the Art</dt> + <dd style="background-color: #f9e529; padding: 0.5em"> + <p> + I wrote earlier that I thought that there were two parts + in nXhtml, nxhtml-mode and mumamo with a bit different + degree of maturity. I believe that is not that valid + any more. To my delight the second part, mumamo is now + also quite stable (from version 1.27). + </p> + </dd> + + <dt id="magic-problems" style="margin-top:1em;">Magic major mode selection</dt> + <dd> + <p> + Sometimes the major mode that Emacs opens a file in is + not what you expect. This can happen with files like PHP + files. The reason might be that magic-mode-alist have + choosen a mode based on the content of the file. The way + this is done does not take files with mixes a mix of for + example XHTML and PHP into account. + </p> + <p> + You may try setting magic-mode-alist to nil if this is a + problem for you. + </p> + <p> + <em> + This is now no longer necessary since the introduction + of magic-fallback-mode-alist in CVS Emacs on 2007-05-16. + (If you have an Emacs newer than that, of course.) + </em> + </p> + </dd> + + <dt id="underline-bug" style="margin-top:1em;">Long Red Underlines</dt> + <dd> + <p> + Because of a bug in Emacs 22.1 you can sometimes (at the + end of a line) get long red lines instead of just a + single underlined character. Many users (me included) + find this quite a bit disturbing. I have therefore added + a command to quickly hide/show the underlines. This is + on <em>C-c C-w</em>. + </p> + <p> + This is particular useful for example in the case where + you edit a PHP file and are bound to get a lot of XHTML + validation errors. + </p> + </dd> + + <dt id="php-attribute-values" style="margin-top:1em;">Attribute values computed by PHP</dt> + <dd> + <p> + If you want to have attribute values computed by PHP + here is a way how to structure that to avoid breaking + completion and validation in the XHTML part unnessecary: + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="<?php foo("bar");?>"/> + </p> + <p> + Unfortunately that still breaks XHTML validation since + < is not allowed in strings. In the long run I + believe the XML validator has to be broken up so that it + avoids parsing the string here (in PHP files). + </p> + <p> + For now I have implemented a workaround. + If you are using constructs like those above then turn on <em>nxhtml-strval-mode</em>. + This will temporarily replace the above with + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="«?php foo("bar");?»"/> + </p> + <p> + However on the screen you will still see the original + string and when writing to file the correct characters + will be used. + </p> + </dd> + + <dt id="pi-note" style="margin-top:1em;">A note for PHP and its cousins</dt> + <dd> + <p> + The rules for a process instruction in XML, like <?php + ... ?> says that the text can contain any text except + <em>?></em>. So if you want to output that string + from PHP then break it up so it does not look as ?> in + the source file. + </p> + <p> + It might be good to break up the beginning part of the + process instructions too. And please note that to use + XHTML validation or completion you should avoid using + < in strings, since it is not allowed there. + </p> + </dd> + +<!-- <dt id="pi-note" style="margin-top:1em;">Perl Mode slow with Mumamo Mode</dt> --> +<!-- <dd> --> +<!-- <p> --> +<!-- Perl mode used with MuMaMo mode sometimes makes the --> +<!-- fontification slow for big files. I do not know the --> +<!-- reason, but I am trying to find a solution for this. If --> +<!-- you encounter this problem, just turn off mumamo-mode in --> +<!-- that buffer. --> +<!-- </p> --> +<!-- </dd> --> + + <dt id="tab-width-problems" style="margin-top:1em;">Tab width</dt> + <dd> + <p> + Do you have <em>tab-width</em> to something different than 8 + (the default)? Then please change this to 8. I have got + reports of problem with indentation when it is not 8. + </p> + </dd> + + <dt id="mmm-compat" style="margin-top:1em;">Why the chunks are not compatible with mmm</dt> + <dd> + <p> + Some people have asked why the way to specify chunks in + mumamo-mode is not compatible with the old mmm-mode. The + answer is that I was not sure that the way used in + mmm-mode for specifying the chunks was flexible enough. + </p> + <p> + And I am sure that even the way used in mumamo-mode is + not good enough for all cases, but I let it be the way + it is until I have a better understanding of the + problem. Suggestions and comments are welcome! + </p> + </dd> + + </dl> + + <h1 id="change-history">nXhtml Changes</h1> + + <div> + <a href="#v0.89">v0.89</a> + <a href="#v0.90">v0.90</a> + <a href="#v0.91">v0.91</a> + <a href="#v0.92">v0.92</a> + <a href="#v0.93">v0.93</a> + <a href="#v0.94">v0.94</a> + <a href="#v0.95">v0.95</a> + <a href="#v0.96">v0.96</a> + <a href="#v0.97">v0.97</a> + <a href="#v0.98">v0.98</a> + <a href="#v0.99">v0.99</a> + <a href="#v1.00">v1.00</a> + <a href="#v1.01">v1.01</a> + <a href="#v1.02">v1.02</a> + <a href="#v1.03">v1.03</a> + <a href="#v1.04">v1.04</a> + <a href="#v1.10">v1.10</a> + <a href="#v1.11">v1.11</a> + <a href="#v1.12">v1.12</a> + <a href="#v1.13">v1.13</a> + <a href="#v1.14">v1.14</a> + <a href="#v1.15">v1.15</a> + <a href="#v1.16">v1.16</a> + <a href="#v1.17">v1.17</a> + <a href="#v1.18">v1.18</a> + <a href="#v1.19">v1.19</a> + <a href="#v1.20">v1.20</a> + <a href="#v1.21">v1.21</a> + <a href="#v1.22">v1.22</a> + <a href="#v1.23">v1.23</a> + <a href="#v1.24">v1.24</a> + <a href="#v1.25">v1.25</a> + <a href="#v1.26">v1.26</a> + <a href="#v1.27">v1.27</a> + <a href="#v1.28">v1.28</a> + <a href="#v1.29">v1.29</a> + <a href="#v1.30">v1.30</a> + <a href="#v1.31">v1.31</a> + <a href="#v1.32">v1.32</a> + <a href="#v1.33">v1.33</a> + <a href="#v1.34">v1.34</a> + <a href="#v1.35">v1.35</a> + <a href="#v1.36">v1.36</a> + <a href="#v1.37">v1.37</a> + <a href="#v1.38">v1.38</a> + <a href="#v1.39">v1.39</a> + </div> + + <dl> + <dt id="v0.89">0.89</dt> + <dd> + <ul> + <li> + Corrected autostart for nXhtml when not used together with EmacsW32. + </li> + </ul> + </dd> + <dt id="v0.90">0.90</dt> + <dd> + <ul> + <li> + Improved display of XML path. + </li> + <li> + Discontinued xmple-mode. + </li> + <li> + New major modes nxhtml-part-mode/nxml-part-mode replaces + minor mode xmlpe-mode. (While moving the code to + nxhtml-part.el I also fixed a bug in Xmple minor mode that + made Emacs take 99% of the CPU.) + </li> + </ul> + </dd> + <dt id="v0.91">0.91</dt> + <dd> + <ul> + <li> + Fixed some calls to perl which prevented uploading of + a site of you did not have perl in the same location + as me. + </li> + <li> + Glued together things so that editing PHP files works + as I intended. (This means that Emacs switches between + php-mode and nxhtml-part-mode automatically when + moving point. And that you can use completion.) + </li> + <li> + Starting working on the documentation for nXhtml. + New layout to the documentation files. + Examples with images. + </li> + </ul> + </dd> + <dt id="v0.92">0.92</dt> + <dd> + <ul> + <li> + Fixes to make the switching between php and xhtml + style editing work better. + </li> + </ul> + </dd> + <dt id="v0.93">0.93</dt> + <dd> + <ul> + <li> + Better error handling when switching to editing + embedded JavaScript and CSS. + </li> + <li> + Removed PHP spec from embedded switching since they + interfered with the automatic switching between php + and xhtml. + </li> + <li> + Gives an error message if web host is not defined in + site when trying to use View Uploaded File and + cousins. + </li> + <li> + Gives a ready message when finished uploading a single + file. + </li> + <li> + When using Mode Switching at <? ... ?> mode + switching could occur in wrong buffer. Fixed together + with some other buffer problems. + </li> + </ul> + </dd> + <dt id="v0.94">0.94</dt> + <dd> + <ul> + <li> + Add http://www.w3.org/ to the help sites for CSS. + </li> + <li> + Included a CSS mode. + </li> + <li> + Added a menu entry for bug reporting. + </li> + <li> + Renamed menu bar entry from XHTML to nXhtml for clarity. + (But nXml menu bar entry is still called XML.) + </li> + <li> + Added work around for globalized minor modes in the + cases of MLinks, XML Path and mode switching at <? ... ?>. + </li> + </ul> + </dd> + <dt id="v0.95">0.95</dt> + <dd> + <ul> + <li> + Added workaround for the problem with the first + keyboard key after automatically switching of mode at + <? ... ?>. + </li> + </ul> + </dd> + <dt id="v0.96">0.96</dt> + <dd> + <ul> + <li> + Added support for multiple major modes with mumamo.el. + </li> + <li> + More conventient handling of links. They can now be + opened in the same window, 'other window' or in a new + frame. + </li> + </ul> + </dd> + <dt id="v0.97">0.97</dt> + <dd> + <ul> + <li> + Schema was not setup after starting new page so + completion did not work. Fixed. + </li> + <li> + Added http://xhtml.com/ to help sites for XHTML. + </li> + <li> + Added the concept of <em>fictive XML validation + headers</em>. These are just text parsed by the nXml + validation parser to get a start state before starting + parsing a buffer. This allows the use of the nXml + completion in buffers where there are no XML header. + Such a header is often lacking for example in PHP code + since the XHTML header is often generated dynamically. + </li> + <li> + Because of the change above <em>nxhtml-part-mode</em> + is no longer needed and is therefore declared + obsolete. + </li> + <li> + Corrected a bug in mlinks.el that prevented opening an + HTML link in a other window or a new frame. + </li> + <li> + Added support for JSP, eRuby and some support for perl + in mumamo.el. + </li> + </ul> + </dd> + <dt id="v0.98">0.98</dt> + <dd> + <ul> + <li> + Mumamo was not found when nXhtml was installed with + just the zip file. Corrected. (nXhtml is also + installed when you install EmacsW32.) + </li> + <li> + Enhancement to mumamo error handling when a bad mode + specifier for an embedded mode is found. + </li> + <li> + Introduced a bug for empty XHTML documents in + 0.97. Corrected. + </li> + <li> + Corrected a bug for chunks 1 character long. + </li> + <li> + There is what I consider is a bug in Emacs 22.1 in the + handling of global minor mode that are not distributed + with Emacs. If they are turned on by customization, + but loaded after Emacs have loaded the customizations + (usually in .emacs) then they are not turned on + correctly. Added work-around for this. + </li> + <li> + <em>Fictive XHTML Validation Header</em>: + <ul> + <li> + <em>Fictive XHTML Validation Header</em> state was not saved when moving between chunks. Fixed. + </li> + <li> + Tried to make the concept of <em>Fictive XHTML Validation Header</em> + more clear. Added this visually to the buffer. + </li> + <li> + <em>Fictive XHTML Validation Headers</em> can now be turned on + automatically based on file name. + </li> + </ul> + </li> + <li> + <em>nXhtml menu:</em> + <ul> + <li> + Reorganized the nXhtml menu. + </li> + <li> + Added <em>customization</em> groups for help libraries to nXhtml. + </li> + <li> + Added an entry for customization of nXhtml to the menus. + </li> + <li> + Added <em>Tidy</em> to the menus again. + </li> + </ul> + </li> + <li> + Corrected bug in <em>XML Path</em> (nxml-where) for single tags. + Other small fixes to nxhtml-where. + </li> + <li> + Documentation enhancements. + Added <em>The Quick Guide</em>. + </li> + </ul> + </dd> + <dt id="v0.99">0.99</dt> + <dd> + <ul> + <li> + Fixed a serious bug in the cooperation between nxhtml-mode and mumamo-mode. + </li> + <li> + Turn on mumamo-mode by file name (mumamo-global-mode). + </li> + <li> + Fictive XHTML Validation Header: + <ul> + <li> + The Fictive XHTML Validation Header state were not saved when changing major mode in MuMaMo. Corrected. + </li> + <li> + Added more alternatives to the Fictive XHTML Validation Header list. + This should make it easier to use completion with for example PHP. + </li> + <li> + Added default value for the Fictive XHTML Validation Header. + </li> + <li> + Tried to make the use of Fictive XHTML Validation Header more automatic and therefore useful. + Also tried to make it play better with setting schema file. + (There is no need normally to set schema file by hand.) + </li> + <li> + To turn this on by default customize nxhtml-global-validation-header-mode. + </li> + </ul> + </li> + <li> + Possible to hide validation warnings without turning + on validation (which would make completion in the + XHTML part impossible). + </li> + <li> + Some fixes to php-mode: + <ul> + <li>Using the character # for comments now works for most cases.</li> + <li>Now uses the fontification faces in a more standard way which calms down the look.</li> + <li>Initialization bug fixes.</li> + <li>Renamed php-mode-user-hook to php-mode-hook to follow standard.</li> + </ul> + </li> + <li> + Indentation fixes: + <ul> + <li> + Various corrections to indentation in mumamo. + </li> + <li> + Added the possibility to use TAB to indent regions + (indent-region-mode). + </li> + <li> + Warn about bad indentation in mixed PHP/HTML code + when using php-mode only. + </li> + </ul> + </li> + <li> + Fontification now fontifies all text first in main + major mode and thereafter applies submodes. (This + avoids some problems with around a submode chunk.) + </li> + <li> + Reorganized the nXhtml menu: + <ul> + <li> + There is now a minor mode for the nXhtml + menu. This makes it possible to easier use common + features when in buffers not in nxhtml-mode. + </li> + <li> + The nXhtml menu does not disappear when moving + into a chunk where the major mode is not + nxhtml-mode. The changes also makes it easy to + access uploading functions functions etc from + other modes than nxhtml-mode since the + <em>nXhtml</em> may also be shown in them. + </li> + <li> + The nXhtml menu can be turned on globally by default. + Customize nxhtml-menu-mode for that. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.00">1.00</dt> + <dd> + <ul> + <li> + Reached version number 1.00 - which you maybe believe + means the bugs should be gone? Sorry, it is just that + I ran out of version numbers. However it looks like + much fewer bugs at least. + </li> + <li> + Fixed problems mostly related to global turn on of different features in nXhtml. + </li> + <li> + Small fixes to indentation. + <ul> + <li> + nxhtml-mode could get confused by php tags. + </li> + <li> + nxhtml-mode did not indent <!DOCTYPE in a sensible way. + </li> + <li> + Electric keys now works in embedded php when using mumamo-mode. + </li> + </ul> + </li> + <li> + Tidy was very misbehaving since the output buffer was + not erased between different files. But I have got no + bug reports on this. + </li> + <li> + Fixed a bug in validation that should up when using muamo-mode. + </li> + <li> + Fixed bug in <script ...> and <style ...> chunk dividing. + </li> + <li> + Added support for OpenLaszlo. + </li> + <li> + Corrections to mlinks-mode (visible mostly as links in + XHTML buffers): + <ul> + <li> + Links disappeared when a new file was + opened. Corrected. + </li> + <li> + Links were not correctly updated at changes in the + buffer when mumamo-mode was used. Fixed. + </li> + </ul> + </li> + <li> + The welcome message for nXhtml could be shown too + early sometimes when loading, before nXhtml actually + knew if it should be shown or not. Tried to fix it. + </li> + </ul> + </dd> + <dt id="v1.01">1.01</dt> + <dd> + <ul> + <li> + Reported wrong version number for nXhtml in the menus. Fixed. + </li> + <li> + <em>If you use the zip file to install nXhtml please + notice that it has now a top level nxml.</em> Sorry for not + having zipped it like that before! + </li> + <li> + The url links in <em>Welcome to nXhtml</em> was a bit + incorrect and did not work on all OS:es. Fixed. + </li> + <li> + Added customization of popup completion to the 'nxhtml + customization group so they are easier to find. + </li> + <li> + MuMaMo + <ul> + <li> + Struggled a bit with the load sequences of the elisp + libraries used by nXhtml when using MuMaMo. + </li> + <li> + Tried to get the global turn on of mumam-mode to work + in all cases. + </li> + <li> + The screen was blinking when changing overlays after + changes in the buffer. Tried to fix this. + </li> + <li> + Minor fixes do syntax highlighting, like taking care of single ':s. + </li> + <li> + Fixes to the support for JSP and eRuby. + </li> + <li> + Made the support for perl here documents a bit better. + Large perl documents are however still quite slow when + using mumamo-mode. I do not know the reason yet. + </li> + <li> + Refontification could miss some parts when buffer + changes caused chunk division changes. Complex, + tried to fix it, but I am a bit unsure that it + always works. + </li> + <li> + Cleaned up mumamo.el a bit. + </li> + <li> + Rewrote mumamo-test.el and functions called from it in + mumamo.el a bit to make tracebacks from errors more + useful. Changed keybindings in mumamo-test.el from + global to a minor mode <em>mumamo-test-mode</em>. + Renamed mumamo-notest.el to mumamo-test.el. Added it + to the zipped distribution of nXhtml. + </li> + </ul> + </li> + <li> + Fixed a bug related to links and buffer changes. + </li> + </ul> + </dd> + <dt id="v1.02">1.02</dt> + <dd> + <ul> + <li> + Fixed a refontification bug that occured after changes. + </li> + </ul> + </dd> + <dt id="v1.03">1.03</dt> + <dd> + <ul> + <li> + Added the possibility to call GIMP. + </li> + <li> + Reworked the messages for fontification errors to try + to catch an error that shows up sometimes. Tried to + avoid disturbing normal use in spite of that error. + </li> + <li> + Reverted to using a short delay before switching major + mode when moving between buffers. + </li> + </ul> + </dd> + <dt id="v1.04">1.04</dt> + <dd id="v1.04-dd"> + <ul> + <li> + Enhanced the documentation for nXhtml. Starting from + <i>C-h f nxhtml-mode</i> it should now be easier to + get an overview. + </li> + <li> + Bug fixes etc: + <ul id="v1.04-bugs"> + <li> + Completion on an empty page gave a faulty frameset page. Fixed. + </li> + <li> + Insert end tag did not work with a fictive + validation header. Fixed. + </li> + <li> + Insert end tag when all preceding tags where + closed gave a strange error message. Fixed. + </li> + <li> + Changed some key bindings to comply with + <i>(info "(elisp) Key Binding Conventions")</i> + </li> + <li> + Completion in empty buffers with a completion + header did not work. Fixed. + </li> + <li id="mumamo-bugs"> + Multiple major modes: + <ul> + <li> + Fixed a bug that prevented mumamo-global-mode from + beeing turned on in a file opened in + fundamental-mode. + </li> + <li> + Better error tracing for some functions, + including the call of major mode functions. + </li> + <li> + Position was garbled when a ;-char was inserted in php-mode chunk. Fixed. + </li> + <li> + A bad check for if mlinks-mode where available was fixed. + </li> + <li> + Some bugs concerning turning off mumamo-mode was fixed. + </li> + <li> + Fixed a bug in <i>perl here doc</i> chunks. Suddenly the + problem with slowness when using mumamo-mode in + perl buffers seems gone. (Note quite sure, but I + can't see any problems now.) + </li> + <li> + Fixed a bug in mumamo-mode when current buffer was + switched before the major mode had been set from + the current chunk. + </li> + <li> + Fixed a long standing bug in php fontification of + strings and comments. + </li> + <li> + Fixed a bug where <i>sgml-xml-mode</i> was not defined. + </li> + <li> + Fixed a bug related to get-text-property which + gives an error when buffer is narrowed. + </li> + <li> + Tried to refontify things outside of a narrowed part. Fixed. + </li> + <li> + Too little where refontified after changes. I hope I have fixed this. + </li> + </ul> + </li> + <li> + Fictive XHTML Validation Header: + <ul id="v1.04-fic-bugs"> + <li> + View File did not work correctly when a fictive + XHTML validation header was used. Corrected. + </li> + <li> + Fictive XHTML validation headers are no longer + turned on by default in any buffers. + </li> + </ul> + </li> + <li> + Indentation: + <ul> + <li> + Tried to fix a problem when using + newline-and-indent. When this was in a mode + derived from C the indentation sometimes became 0. + </li> + <li> + Speeded up the indentation of regions a bit when + using <i>mumamo-mode</i>. + </li> + <li> + Indentation: TAB now only indents a region if it + is visibly marked (see transient-mark-mode and + cua-mode). + </li> + <li> + Simplified the indentation code. + </li> + </ul> + </li> + <li> + Fixed a problem where string fontification got out + of phase so that wrong parts of buffer could be + fontified as a string. + </li> + <li> + Added a workaround for <a + href="#php-attribute-values">Attribute values + computed by PHP</a> + </li> + <li> + Added .nosearch to subdirectories with no elisp files. + </li> + <li> + Fixed incorrect checks for mlinks-mode in menu building. + </li> + <li> + File extensions where used in a case sensitive way + in some places. Fixed. + </li> + <li> + appmenu: Worked only in html files. Fixed. + </li> + <li> + html-site: Fixed the error <em>Error + (html-site-current): Can't find site: + your-site-name</em>. + </li> + <li> + Fixed a problem with longlines-mode in the support + for Firefox add-on It's All Text. (Note however + that there are some bugs in longlines-mode + itself.) Rewrote the support to be more + general. It is now in the file as-external.el, see + this file. + </li> + <li> + Fixed an encoding problem in + <i>tidy-buffer</i>. Output from tidy was not read + using the same coding system as tidy was using. + </li> + <li> + Fixed some problems with face definitions, possibly bugs (not sure). + </li> + <li> + Made the fontification faster when using mumamo-mode. + (It is still slower than single mode fontification of course.) + </li> + <li> + nxml-where.el: Made it aware of mumamo.el. + </li> + </ul> + </li> + <li> + Menu changes: + <ul> + <li> + Completion menu: Renamed to <i>Completion and + Validation</i> menu and reorganized a little bit to + make it more clear. + </li> + <li> + Renamed <i>view</i> to <i>browse</i> since this is + the normal emacs name for showing files in a web + browser. Also made corresponding changes to + function names. Put back the possibility to view + only the region in a web browser. + </li> + </ul> + </li> + <li> + Uploading: + <ul> + <li> + Added remote dired to the menus. + </li> + <li> + Fixed problems with file names starting with ~. + </li> + <li> + Fixed more problems with file names with spaces. + </li> + </ul> + </li> + <li> + nxml-where: + <ul> + <li> + nxml-where now uses a timeout for more smooth performance. + </li> + <li> + nxml-where can now recognizes both id and name attribute. + </li> + <li> + Hyphens are now accepted in tag names. + </li> + </ul> + </li> + <li> + Ruby + <ul> + <li> + Multiple major mode turned on by default for .rhtml files when this mode is global. + </li> + <li> + Multiple major mode is no longer turned on when rub-mode is turned on. + </li> + </ul> + </li> + <li> + Added support for switching major mode dependent on if + Emacs was called as an external editor. This makes it + possible for example to switch to relevant major and + minor modes when Firefox add-on It's All Text. + </li> + <li> + Added the possibility to easily view the output of scripts on the server (if they require no parameters). + You can now do that from the nXhtml menu. + Previously only html files on the server could be viewed that way. + Image files can also be viewed this way. + </li> + <li> + Filling: + <ul> + <li> + Added functions for unfilling. + </li> + <li> + Added keybindings and menu entries for longlines-mode, fill-paragraph and unfill-paragraph. + </li> + </ul> + </li> + <li> + Quoting: + Added HTML quoting of & and < in text areas. Bound to C-c C-q. + </li> + <li> + Images: + <ul> + <li> + Added image-mode to those that are encompassed by + nxhtml-global-minor-mode so that images can be + uploaded more easily. + </li> + <li> + Added <em>edit with GIMP</em> and <em>upload</em> to the popup menu for links. + This avoids the need to load the linked files in Emacs first. + </li> + </ul> + </li> + <li> + Added <em>nxml-untag-element</em>. + </li> + <li> + Added a modified version of wikipedia-mode.el. Seems likely to be useful if you are doing web editing. + </li> + <li> + Added html-imenu.el + </li> + <li> + MuMaMo: + <ul> + <li> + Removed the lighter <i>"MuMaMo"</i> for + mumamo-mode. Instead the active major mode now has + <b>"/m"</b> appended to mode-name (that is what you see + in the mode line). + </li> + <li> + The normal way to turn on <i>mumamo-mode</i> has + changed. There are now functions that you can use + in <i>auto-mode-alist</i> to directly set up the + buffer for mumamo-mode. The available functions + are in the + variable <i>mumamo-defined-turn-on-functions</i>. + <p> + You are not supposed to call mumamo-mode + yourself any more and mumamo-global-mode is + gone. So is also mumamo-chunk-family-by-mode and + mumamo-filenames-list. The functionality those + gave are all replaced by the new functions for + turning on mumamo mode. + </p> + </li> + <li> + Added support for buffer local values in + hooks. This is necessary for example to support + minor modes that are meant to be buffer local but + not major mode specific. Instructions for authors + of this kind of minor modes are in the file + mumamo.el. + </li> + <li> + Added support for Django. + </li> + <li> + Added support for Embperl. + </li> + <li> + Added support for PHP Smarty. The <i>{literal} + ... {/literal}</i> construct is not supported. + This mean that you can not use <style ..> or <script ..>. + </li> + <li> + Added support for imenu for the main major mode. + Turned on this by default in nxhtml-mode. + </li> + <li> + Made the temporary replacement of the + attr="<?php ... ?>" a bit better. They are + now more visible and also still mumamo chunks + during the temporary replacement. + </li> + <li> + Added support for <i>flymake-mode</i>. + Maybe add support for checking chunks? + </li> + <li> + Printing: Added htmlfontify.el and + hfyview.el. These makes if possible to print a + buffer fontified with <i>mumamo-mode</i> on in + colors (through your web browser). There is an + example of the capabilities of htmlfontify <a + href="htmlfontify-example.html">here</a> (made + with a little function in hfyview.el). + </li> + </ul> + </li> + <li> + PHP: + <ul> + <li> + Did a first merge with Aaron Hawleys fixes for php-mode.el. + </li> + </ul> + </li> + <li> + CSS: Upgraded to Stefan's latest css-mode.el. + </li> + <li> + Fictive XHTML Validation Headers: Changed the way they + are turned on. They may now be turned on when + mumamo-mode is turned on. + </li> + <li> + Some users want to use their own patched version of + nXml. Next version of Emacs will come with + nXml. Therefore, the loading routine for nXhtml now + checks if nXml is is already loaded. Thanks to Eric + Lilja for testing this. Eric also made me aware of + that if nXhtml was placed in the site-lisp directory + tree then things did not work as I expected. I think I + have corrected that by placing a <i>.nosearch</i> file + at the top of the nxml tree in nXhtml. + </li> + <li> + Restructured the directories. Moved some files out of + the <i>nxhtml</i> subdir. Some of them went into the + <i>util</i> subdir (those are written by me) and some + to the new subdir <i>related</i> (those that are + inherited from others, maybe changed by me - most + often to work with mumamo-mode). + </li> + <li> + Changed all licenses to be GNU GPL. + </li> + <li> + Additions to tidy support: It is now possible to use + the tidy support to tidy the XHTML part of php etc. + (Thanks to Hadron for this suggestion.) + </li> + <li> + Added <i>winsize.el</i> which allows interactive resizing of + windows. Also added <i>winsav.el</i> which adds the + capability to rotate window configurations and also to + save window configuration to file. + </li> + <li> + Made nXhtml work with CVS Emacs 23.0.50.1. + </li> + <li> + Added freemind.el to the parcel. After all FreeMind + supports web publishing too so why not have the Emacs + support here ... + </li> + </ul> + </dd> + <dt id="v1.10">1.10</dt> + <dd id="v1.10-dd"> + Just jumped the version number for the new release of + nXhtml. There are really significant changes in this + release, not only minor bug fixes. + </dd> + <dt id="v1.11">1.11</dt> + <dd id="v1.11-dd"> + Minor bug fixes to completion. Added fictive validation + header to completion alternatives when buffer is empty and + mumamo is used. + </dd> + <dt id="v1.12">1.12</dt> + <dd id="v1.12-dd"> + <ul> + <li> + Fixed a bug in image link insertion in nxhtml-mode, thanks Niels Giesen! + </li> + <li> + Restructured, reordered and documented mumamo.el. It is now two + separate files, mumamo.el and mumamo-fun.el. + </li> + <li> + Added move by chunk to the nXhtml menu. + </li> + </ul> + </dd> + <dt id="v1.13">1.13</dt> + <dd id="v1.13-dd"> + <ul> + <li> + Better handling of the case when no validation header + is needed and the user tries to turn it on. + </li> + <li> + Added .phtml as php file. + </li> + </ul> + </dd> + <dt id="v1.14">1.14</dt> + <dd id="v1.14-dd"> + <ul> + <li> + Completion of links in XHTML was broken. Fixed, thanks + to Niels Giesen. + </li> + </ul> + </dd> + <dt id="v1.15">1.15</dt> + <dd id="v1.15-dd"> + <ul> + <li> + Added `mumamo-map' keymap. + </li> + <li> + Added a keymap to all multi major modes. + </li> + <li> + Some more refinement to fictive validation headers. + </li> + </ul> + </dd> + <dt id="v1.16">1.16</dt> + <dd id="v1.16-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Changes to indentation: + <ul> + <li> + Removed indent-region-mode since that + functionality is now in indent-for-tab-command in + Emacs 22. + </li> + <li> + Removed some code that checked if indentation was 0. + </li> + <li> + Added indent-for-tab-command to mumamo-map. + </li> + </ul> + </li> + <li> + Reordering and renaming: + <ul> + <li> + Reordered and move some functions in mumamo.el et al. + Added new file nxhtml-mumamo.el. + </li> + <li> + Renamed <i>define-mumamo-turn-on</i> to + <i>define-mumamo-multi-major-mode</i>. + </li> + <li> + Removed the ending <i>-turn-on</i> from the + functions defined by the macro above. + </li> + <li> + Introduced <i>multi major mode</i> as a name for + the functions defined by the macro above. Those + works in many respects like major mode functions, + but they support multiple major modes in a buffer. + </li> + </ul> + </li> + <li> + Added support for noweb as multiple major mode. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.17">1.17</dt> + <dd id="v1.17-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Added support for flyspell. + </li> + </ul> + </li> + <li> + Bug fixes to the version of find-recursive.el that + ships with nXhtml. Thanks to Cezar Halmagean. + </li> + <li> + Added tabkey2.el which tries to make it easy to use + the Tab key for completion. (You must load it and turn + on tabkey2-mode to use it.) + </li> + <li> + Folding: + <ul> + <li> + Added <i>nxhtml-heading-element-name-regexp</i> as + default for nxml style folding. + </li> + <li> + Some changes to fold-dwim.el. + </li> + </ul> + </li> + <li> + AppMenu: + <ul> + <li> + Simplified: Removed the possibility to + automatically show minor and major mode menus. + There is now only one list, <i>appmenu-alist</i>. + </li> + <li> + Added menu item <i>At Current Point</i> for + bindings found in character and overlay keymaps at + point. Those you always forget. + </li> + </ul> + </li> + <li> + Physical line: + <ul> + <li> + Added physical-line.el to nXhtml. + </li> + <li> + Added new functions to move to beginning and end + of line to ourcomments-util.el that supports + physical-line.el. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.18">1.18</dt> + <dd id="v1.18-dd"> + <ul> + <li> + Better Tab completion in tabkey2.el. + </li> + </ul> + </dd> + <dt id="v1.19">1.19</dt> + <dd id="v1.19-dd"> + <ul> + <li> + Even better Tab completion in tabkey2.el. + </li> + </ul> + </dd> + <dt id="v1.20">1.20</dt> + <dd id="v1.20-dd"> + <ul> + <li> + Once again even better Tab completion in tabkey2.el. + </li> + <li> + Fixed bug in hiding of validation errors (they could + disappear totally). + </li> + <li> + Cleaned up menus in nXhtml. + </li> + </ul> + </dd> + <dt id="v1.21">1.21</dt> + <dd id="v1.21-dd"> + <ul> + <li> + Added a bit support for dired (upload, browse, browse + remote). + </li> + <li> + Fixed some strange menu problems (i hope). + </li> + </ul> + </dd> + <dt id="v1.22">1.22</dt> + <dd id="v1.22-dd"> + <ul> + <li> + Bug fix. + </li> + </ul> + </dd> + <dt id="v1.23">1.23</dt> + <dd id="v1.23-dd"> + <ul> + <li> + Bug fix. + </li> + </ul> + </dd> + <dt id="v1.24">1.24</dt> + <dd id="v1.24-dd"> + <ul> + <li> + Tried again to make hexcolor-mode more readable. + </li> + <li> + Mumamo: + <ul> + <li> + Added support for <i>hi-lock-mode</i>. At present + it might however be very puzzling. The hilight + added by hi-lock-mode may be hidden by the + overlays used by mumamo. Tip: you can always use + the face <span + style="font-size:1.5em;">hi-black-hb</span>. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.25">1.25</dt> + <dd id="v1.25-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Handle hi-lock-mode in a more general way + using <i>font-lock-mode-hook</i>. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.26">1.26</dt> + <dd id="v1.26-dd"> + <ul> + <li> + nxhtml-mode: + <ul> + <li> + Removed the indent line patch for nxml-mode. + </li> + <li> + Better test for empty page during completion. + </li> + </ul> + </li> + <li> + tabkey2-mode: + <ul> + <li> + A lot of improvements. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.27">1.27</dt> + <dd id="v1.27-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Worked with bugs in mumamo.el that was due to bad + handling of syntax-ppss et el. Looks like most of + them are fixed. + </li> + <li> + Fixed documentation and reordered code in mumamo.el + and mumamo-fun.el. + </li> + <li> + Changed javascript.el indentation to make it work with + mumamo.el. + </li> + <li> + Introduced the function + <i>mumamo-make-variable-buffer-permanent</i> as an aid for + minor mode authors. + </li> + <li> + Fixed quite a few indentation bugs. + There was one bug that could make Emacs loop after indentation. + </li> + </ul> + </li> + <li> + nxml-where, mlinks + <ul> + <li> + Fixed bugs with left over idle timers when buffer had + been killed (nxml-where.el, mlinks.el). + </li> + </ul> + </li> + <li> + html-site + <ul> + <li> + Fixed a bug in html-site when comparing file + names. File names where not made unique before + comparision. + </li> + </ul> + </li> + <li> + Tabkey2 + <ul> + <li> + Fixed tabkey2 bugs. + </li> + </ul> + </li> + <li> + freemind.el + <ul> + <li> + Fixed a problem in freemind-to-org-mode that + caused the error "wrong-type-argument string: nil" + in string-match("\\(?:^--org-mode: WHOLE FILE$\\)" + nil). + </li> + </ul> + </li> + <li> + Made nXhtml menu available in sub-chunks. + </li> + <li> + Included a slightly changed version of Steve Yegge's + js2.el + js2-fl-mode.el from 2008-04-24 with support for + jit-lock-mode. This support has some flaws and maybe + js2 is not ready for use, I am not sure. However if you want + to use this instead of Karl Landströms javascript-mode + then please customize <i>mumamo-major-modes</i>. + </li> + </ul> + </dd> + <dt id="v1.28">1.28</dt> + <dd id="v1.28-dd"> + <ul> + <li> + New version with mostly minor bug fixes from 1.27. + Unfortunately I put out 1.27 a bit too early. + Please upgrade. + </li> + </ul> + </dd> + <dt id="v1.29">1.29</dt> + <dd id="v1.29-dd"> + <ul> + <li> + MuMaMo: + <ul> + <li> + Fixed a bug causing emacs to loop when <?> + was encountered in an html style buffer. + </li> + <li> + Fixed some problems with <? and ?> in + strings in html style buffers. + </li> + <li> + Tried to avoid chunk dividers in strings and comments. (There are still some bugs there.) + </li> + <li> + Fixed an error that prevented byte compiling nxhtml-mumamo.el. + (Thanks Christoph Conrad.) + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.30">1.30</dt> + <dd id="v1.30-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Added support to handle specific rng + schemacs. With the help of this Genshi and MJT + templating languages are now handled. + </li> + <li> + Let the rng schema file name survive mumamo major + mode changes. + </li> + <li> + Added support for to let nxml-mode skip chunks it + can not parse. (This requires a patch to + rng-valid.el too which is not included, but which + I hope can go into Emacs soon.) + </li> + <li> + Chunk dividers can now be a part on their own. (Ie + there will be no parsing or syntax highlighting of + them by the chunk major mode. This is optional and + specified for each chunk types.) + </li> + <li> + Added support for Genshi and MJT. These multi + major modes support completion and error checking + in the XML/XHTML part according to their DTD + (which has some additions to the XHTML DTD). + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.31">1.31</dt> + <dd id="v1.31-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Fixed a bug that caused multi major modes to loop sometimes. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.32">1.32</dt> + <dd id="v1.32-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Fixed a bug in syntax-ppss advice. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.33">1.33</dt> + <dd id="v1.33-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Fixed another bug in syntax-ppss advice. + </li> + <li> + Added support for <i>fill-forward-paragraph-function</i>. + </li> + <li> + Made <i>longlines-mode</i> survive major mode changes in mumamo buffers. + </li> + <li> + Fixed a bug that made Emacs loop when it found + <??> in for example nxhtml-mumamo. + </li> + <li> + Made it usable with Emacs 22 again. + </li> + <li> + Moved some changes from rng-valid.el to + mumamo.el. This makes it possible to let nxml-mode + (and derivates) jump over parts when parsing the + buffer even if not using the patched version of + Emacs+EmacsW32. + </li> + </ul> + </li> + <li> + nxhtml: + <ul> + <li> + Added command to add CSS rollover images. + </li> + </ul> + </li> + <li> + mlinks: + <ul> + <li> + Tried to fix the error <i>invalid-read-syntax "] + in a list"</i> when loading <i>mlinks.el</i> + reported by some Asian users. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.34">1.34</dt> + <dd id="v1.34-dd"> + <ul> + <li> + <span style="font-size: 1.2em; color: red ()" + >Changed top directory name from nxml to nxhtml</span> + <p> + This will of course case some problems if you do not + notice it when you upgrade nXhtml. If you are using + EmacsW32 and upgrade nXhtml you should change the + file <i>emacsw32.el</i>. + </p> + <p> + The reason for this change is that nXml will soon + normally not be part of nXhtml so keeping the old + top directory name would be confusing. + </p> + </li> + <li> + Added a test suite. See the file <i>nxml/tests/test-Q.el</i>. + </li> + <li> + Mumamo: + <ul> + <li> + Fixed indentation when the whole line is a sub chunk. + </li> + <li> + Tried a bit more to stop nxml from parsing non-xml + mode chunks. Because of this php support was + changed a bit (for the better I hope). + </li> + </ul> + </li> + <li> + GIMP: + <ul> + <li> + Registry value location for GIMP had changed. + </li> + </ul> + </li> + <li> + nXhtml: + <ul> + <li> + Added support for + <a href="http://hyperstruct.net/projects/mozlab">MozLab</a>. If + you install MozLab in Firefox then you can + directly use it from javascript mode without any + additional setup. + </li> + <li> + Added <a href="http://www.oak.homeunix.org/~marcel/blog/articles/2008/07/18/nested-imenu-for-php">php-imenu.el</a>. + </li> + <li> + Fixed a bug where I inadvertently + added <i>../../lisp</i> to load-path. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.35">1.35</dt> + <dd id="v1.35-dd"> + <ul> + <li> + Fixed a small bug in sex-mode.el. + </li> + </ul> + </dd> + <dt id="v1.36">1.36</dt> + <dd id="v1.36-dd"> + <ul> + <li> + Added the function <i>emacs-Q-nxhtml</i> for easier + testing. It does the equivalent of <i>emacs -Q --load + PATH-TO/nxhtml/autostart.el</i>. + </li> + <li> + MuMaMo: + <ul> + <li> + Forgot to return php-mode in php short tags. Fixed. + </li> + <li> + Borders where not correctly calculated with php short tags. Fixed. + </li> + <li> + Subchunks not parseable by nxml-mode where marked as parseable. Fixed. + </li> + <li> + Debug messages from mumamo where not silenced. + </li> + <li> + Forgot font-lock-syntactic-keywords. This showed up in + bad fontification for strings sometimes. Fixed. + </li> + <li> + To fontify keywords font-lock-syntactically-fontified + must be set in each chunk. Fixed. + </li> + <li> + Find a way to at least temporarily work around the + problem with the last "e; char in + syntax="e;..."e; that could be seen in + large XHTML files, for example this file. The + drawback with the work around is that it bypasses + the cache for syntax-ppss, but this happens only + in multi major mode buffers and I notice no + performance problems here. + </li> + <li> + Fixed a number of problems with the defadvice for the syntax functions. + (I am afraid there are more left.) + </li> + <li> + Took a new grab on the indentation problems. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.37">1.37</dt> + <dd id="v1.37-dd"> + <ul> + <li> + The command <i>emacs-Q-nxhtml</i> and cousins did not + work on all platform. Tried to fix it. + </li> + <li> + Got a report that editing Django was to slow. Tried to fix this. + </li> + <li> + Added a test to the unit test suite that test + scrolling and jumping. + </li> + </ul> + </dd> + <dt id="v1.38">1.38</dt> + <dd id="v1.38-dd"> + <ul> + <li> + Added a workaround that removes validation error marking in non-xhtml chunks. + </li> + </ul> + </dd> + <dt id="v1.39">1.39</dt> + <dd id="v1.39-dd"> + <ul> + <li> + Multi major modes where not allowed in defcustoms + nxhtml-magic-mode-alist and + nxhtml-auto-mode-alist. Fixed. + </li> + <li> + Added tests for the use of the lists above. + </li> + <li> + Fixed some bugs that could make a buffer became + modified during mumamo fontification actions. + </li> + </ul> + </dd> + </dl> + </div> + </div> + + <hr class="footer"/> + <p class="footer"> + Copyright © <!-- this year -->2008<!-- end this year --> OurComments.org + -- + Latest update <!-- today -->2008-06-28<!-- end today --> + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/blorgit.rb b/emacs/nxhtml/tests/in/blorgit.rb new file mode 100644 index 0000000..5ec40e5 --- /dev/null +++ b/emacs/nxhtml/tests/in/blorgit.rb @@ -0,0 +1,313 @@ +# blorgit --- blogging with org-mode +require 'rubygems' +require 'sinatra' +require 'backend/rewrite_content_disposition' +require 'yaml' +$global_config ||= YAML.load(File.read(File.join(File.dirname(__FILE__), 'blorgit.yml'))) +$blogs_dir ||= File.expand_path($global_config[:blogs_dir]) +$url_prefix ||= $global_config[:url_prefix] +require 'backend/init.rb' + +# Configuration (http://sinatra.rubyforge.org/book.html#configuration) +#-------------------------------------------------------------------------------- +use RewriteContentDisposition, {"org" => "attachment"} +set(:public, $blogs_dir) +enable(:static) +set(:app_file, __FILE__) +set(:haml, { :format => :html5, :attr_wrapper => '"' }) +set(:url_prefix, $url_prefix) +use_in_file_templates! +mime(:org, 'text/org') + +# Routes (http://sinatra.rubyforge.org/book.html#routes) +#-------------------------------------------------------------------------------- +get('/') do + if config['index'] + redirect(path_for(config['index'])) + else + "It seems you haven't yet configured a blogs directory. Try"+ + " running <tt>rake new</tt> from the root. of your blorgit directory" + end +end + +post(/^\/.search/) do + @query = params[:query] + @results = Blog.search(params[:query]) + haml :results +end + +get(/^\/\.edit\/(.*)?$/) do + pass unless config['editable'] + path, format = split_format(params[:captures].first) + if @blog = Blog.find(path) + @title = @blog.title + @files = (Blog.files(path) or []) + haml :edit + else + "Nothing here to edit." + end +end + +get(/^\/(.*)?$/) do + path, format = split_format(params[:captures].first) + @files = (Blog.files(path) or []) + @blog = Blog.find(path) + if @blog or File.directory?(Blog.expand(path)) + if format == 'html' + @title = @blog ? @blog.title : path + haml :blog + elsif @blog + content_type(format) + attachment extension(@blog.path, format) + @blog.send("to_#{format}") + else + pass + end + elsif config['editable'] and extension(path, 'org').match(Blog.location_regexp) + pass if path.match(/^\./) + protected! + @path = path + haml :confirm_create + else + "Can't create a new page at #{path}" + end +end + +post(/^\/(.*)?$/) do + path, format = split_format(params[:captures].first) + @blog = Blog.find(path) + if params[:comment] + pass unless (@blog and config['commentable']) + return "Sorry, review your math..." unless params[:checkout] == params[:captca] + @blog.add_comment(Comment.build(2, params[:title], params[:author], params[:body])) + @blog.save + redirect(path_for(@blog)) + elsif config['editable'] + protected! + if @blog and params[:edit] + @blog.body = params[:body] + @blog.change_log = params[:change_log] if params[:change_log] + @blog.save + redirect(path_for(@blog)) + elsif extension(path, 'org').match(Blog.location_regexp) + @blog = Blog.new(:path => extension(path, 'org'), + :body => "# -*- mode: org -*-\n#+TITLE: #{File.basename(path)}\n#+OPTIONS: toc:nil ^:nil\n\n") + @blog.save + redirect(path_for(@blog)) + elsif path.match(/^\./) + pass + else + "Can't create a new page at #{path}" + end + else + pass + end +end + +# Helpers (http://sinatra.rubyforge.org/book.html#helpers) +#-------------------------------------------------------------------------------- +helpers do + def config + $local_config_file ||= File.join($blogs_dir, '.blorgit.yml') + $local_config ||= $global_config[:config].merge(File.exists?($local_config_file) ? YAML.load(File.read($local_config_file)) : {}) + config_file = File.join(File.dirname(File.join($blogs_dir, (params[:captures] ? params[:captures].first : ''))), '.blorgit.yml') + $local_config.merge((File.exists?(config_file)) ? YAML.load(File.read(config_file)) : {}) + end + + def split_format(url) url.match(/(.+)\.(.+)/) ? [$1, $2] : [url, 'html'] end + + def path_for(path, opts ={}) + path = (path.class == Blog ? path.path : path) + File.join(options.url_prefix, extension(path, (opts[:format] or nil))) + end + + def show(blog, options={}) haml("%a{ :href => '#{path_for(blog)}' } #{blog.title}", :layout => false) end + + def comment(blog, parent_comment) end + + def extension(path, format = nil) (path.match(/^(.+)\..+$/) ? $1 : path)+(format ? "."+format : '') end + + def time_ago(from_time) + distance_in_minutes = (((Time.now - from_time.to_time).abs)/60).round + case distance_in_minutes + when 0..1 then 'about a minute' + when 2..44 then "#{distance_in_minutes} minutes" + when 45..89 then 'about 1 hour' + when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours" + when 1440..2879 then '1 day' + when 2880..43199 then "#{(distance_in_minutes / 1440).round} days" + when 43200..86399 then 'about 1 month' + when 86400..525599 then "#{(distance_in_minutes / 43200).round} months" + when 525600..1051199 then 'about 1 year' + else "over #{(distance_in_minutes / 525600).round} years" + end + end + + # from http://www.sinatrarb.com/faq.html#auth + def protected! + response['WWW-Authenticate'] = %(Basic realm="username and password required") and \ + throw(:halt, [401, "Not authorized\n"]) and \ + return unless ((not config['auth']) or authorized?) + end + + def authorized? + @auth ||= Rack::Auth::Basic::Request.new(request.env) + @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == config['auth'] + end + +end + +# HAML Templates (http://haml.hamptoncatlin.com/) +#-------------------------------------------------------------------------------- +__END__ +@@ layout +!!! +%html + %head + %meta{'http-equiv' => "content-type", :content => "text/html;charset=UTF-8"} + :javascript + function toggle(item) { + el = document.getElementById(item); + if(el.style.display == "none") { document.getElementById(item).style.display = "block" } + else { document.getElementById(item).style.display = "none" } + } + - if config['favicon'] + %link{:rel => "icon", :type => "image/x-icon", :href => path_for(config['favicon'], :format => 'ico')} + %link{:rel => "stylesheet", :type => "text/css", :href => path_for(config['style'], :format => 'css')} + %title= "#{config['title']}: #{@title}" + %body + #container + #titlebar= render(:haml, :titlebar, :layout => false) + #insides + #sidebar= render(:haml, :sidebar, :locals => { :files => @files }, :layout => false) + #contents= yield + +@@ titlebar +#title_pre +#title + %a{ :href => path_for(''), :title => 'home' }= config['title'] +#title_post +#search= haml :search, :layout => false +- if @blog + #actions + %ul + - if config['editable'] + %li + %a{ :href => path_for(File.join(".edit", @blog.path)), :title => "edit #{@title}" } edit + %li + %a{ :href => path_for(@blog, :format => 'org'), :title => 'download as org-mode' } .org + %li + %a{ :href => path_for(@blog, :format => 'tex'), :title => 'download as LaTeX' } .tex + %li + %a{ :href => path_for(@blog, :format => 'pdf'), :title => 'download as PDF' } .pdf +#title_separator + +@@ sidebar +- if (config['recent'] and (config['recent'] > 0)) + #recent= haml :recent, :layout => false +- if (config['dir_list'] and @files) + #dir= haml :dir, :locals => { :files => files }, :layout => false + +@@ search +%form{ :action => path_for('.search'), :method => :post, :id => :search } + %ul + %li + %input{ :id => :query, :name => :query, :type => :text, :size => 12 } + %li + %input{ :id => :search, :name => :search, :value => :search, :type => :submit } + +@@ recent +%label Recent +%ul + - Blog.all.sort_by(&:ctime).reverse[(0..(config['recent'] - 1))].each do |blog| + %li + %a{ :href => path_for(blog)}= blog.title + +@@ dir +%label Directory +%ul + - files.each do |file| + %li + %a{ :href => path_for(file) + (File.directory?(Blog.expand(file)) ? "/" : "") }= File.basename(file) + +@@ results +#results_list + %h1 + Search Results for + %em= "/" + @query + "/" + %ul + - @results.sort_by{ |b,h| -h }.each do |blog, hits| + %li + %a{ :href => path_for(blog) }= blog.name + = "(#{hits})" + +@@ edit +%h1= "Edit #{@title}" +%form{ :action => path_for(@blog), :method => :post, :id => :comment_form } + %textarea{ :id => :body, :name => :body, :rows => 28, :cols => 82 }= @blog.body + %br + Change log: + %input{ :id => :change_log, :name => :change_log, :type => :text } + %input{ :id => :submit, :name => :edit, :value => :update, :type => :submit } + %a{ :href => path_for(@blog) } Cancel + +@@ blog +- if @blog + #blog_body= @blog.to_html + - if (config['commentable'] and (not @blog.commentable == 'disabled')) + #comments= render(:haml, :comments, :locals => {:comments => @blog.comments, :commentable => @blog.commentable}, :layout => false) +- else + #dir= haml :dir, :locals => { :files => @files }, :layout => false + +@@ comments +#existing_commment + %label= "Comments (#{comments.size})" + %ul + - comments.each do |comment| + %li + %ul + %li + %label title + = comment.title + %li + %label author + = comment.author + %li + %label date + = time_ago(comment.date) + " ago" + %li + %label comment + %div= Blog.string_to_html(comment.body) +- unless commentable == 'closed' + #new_comment + %label{ :onclick => "toggle('comment_form');"} Post a new Comment + %form{ :action => path_for(@blog), :method => :post, :id => :comment_form, :style => 'display:none' } + - equation = "#{rand(10)} #{['+', '*', '-'].sort_by{rand}.first} #{rand(10)}" + %ul + %li + %label name + %input{ :id => :author, :name => :author, :type => :text } + %li + %label title + %input{ :id => :title, :name => :title, :type => :text, :size => 36 } + %li + %label comment + %textarea{ :id => :body, :name => :body, :rows => 8, :cols => 68 } + %li + %input{ :id => :checkout, :name => :checkout, :type => :hidden, :value => eval(equation) } + %span + %p to protect against spam, please answer the following + = equation + " = " + %input{ :id => :captca, :name => :captca, :type => :text, :size => 4 } + %li + %input{ :id => :submit, :name => :comment, :value => :comment, :type => :submit } + +@@ confirm_create +%form{ :action => path_for(@path), :method => 'post', :id => 'creation_form'} + %label + Create a new page at + %em= @path + ? + %input{ :id => 'submit', :name => 'submit', :value => 'create', :type => 'submit' } + %a{ :href => path_for('/') } cancel + diff --git a/emacs/nxhtml/tests/in/bug-080609.html b/emacs/nxhtml/tests/in/bug-080609.html new file mode 100644 index 0000000..708a00a --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-080609.html @@ -0,0 +1,9 @@ +<html> + <head> + <script> + function x () { return 1 > 0; } + </script> + </head> + <body class="foo"> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/bug-1908494.php b/emacs/nxhtml/tests/in/bug-1908494.php new file mode 100644 index 0000000..778fb61 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-1908494.php @@ -0,0 +1,6 @@ +<?php + +$parent_id = 5; +var_dump($parent_id); + +?> diff --git a/emacs/nxhtml/tests/in/bug-2010-02-17-delgado.mm b/emacs/nxhtml/tests/in/bug-2010-02-17-delgado.mm new file mode 100644 index 0000000..990d000 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-2010-02-17-delgado.mm @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<map version="0.9.0"> +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> +<node text="Title"> +<node text="Node 1"> +</node><!-- a --> +<node text="Node 2"> +</node><!-- b --> +</node><!-- c cl=3, bl=1, odd=t --> +</map> diff --git a/emacs/nxhtml/tests/in/bug-2010-02-17-delgado.org b/emacs/nxhtml/tests/in/bug-2010-02-17-delgado.org new file mode 100644 index 0000000..5b9c3d5 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-2010-02-17-delgado.org @@ -0,0 +1,3 @@ +* Title +*** Node 1 +*** Node 2 diff --git a/emacs/nxhtml/tests/in/bug-290364.php b/emacs/nxhtml/tests/in/bug-290364.php new file mode 100644 index 0000000..190b230 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-290364.php @@ -0,0 +1,66 @@ +<?php +include 'HTML/QuickForm.php'; + +echo '<script type="text/javascript" src="library/javascript/prototype.js" language="javascript"></script>'; +echo '<script type="text/javascript" src="library/javascript/scriptaculous.js" language="javascript"></script>'; +echo '<script type="text/javascript" src="library/cropper/cropper.js" language="javascript"></script>'; + + + +echo ' <img src="test.jpg" alt="Test image" id="testImage" width="500" height="333" />'; + +echo ' <script type="text/javascript" language="javascript">'; + +echo ' function onEndCrop( coords, dimensions ) {'; +// echo ' $( "x1" ).value = coords.x1;'; +// echo ' $( "y1" ).value = coords.y1;'; +// echo ' $( "x2" ).value = coords.x2;'; +// echo ' $( "y2" ).value = coords.y2;'; +// echo ' $( "width" ).value = dimensions.width;'; +// echo ' $( "height" ).value = dimensions.height;'; +// echo 'console.log(coords.x1);'; +// echo 'console.log(coords.x2);'; +// echo ' style = clip:rect( + coords.x1 + "px " + coords.y1 + "px " + coords.x2 + "px " + coords.y2 + "px)\n"'; +?> +style = "clip:rect(0px 130px 130px 0px)"; +$("hidden_0").value = new Array (coords.x1, coords.x2, coords.y1, coords.y2); +$("testImage").writeAttribute("style=" style); +} +function js_init () { + Event.observe( "button_0", "click", function() { } ); + // $("file_0").writeAttribute("src", "") + + new Cropper.Img("testImage", {minWidth: 220,previewWrap: "previewWrap", onEndCrop: onEndCrop }); +} + + + +Event.observe( window, "load", function() { + js_init (); + } ); +?> +echo ' </script>'; + +echo '<h1> Cropper votre image v0.1</h1>'; + +$label = 'file_default'; + +$form = new HTML_QuickForm ('cropper_form', "", "img-cropped.php", '', 'enctype=multipart/form-data'); + +$form->addElement ('file', 'file_0', $label); +$form->addElement ('hidden', 'hidden_0'); +$form->addElement ('button', 'button_0'); +$form->updateElementAttr(array('button_0'), array ('id' => 'button_0')); +$form->addElement ('submit', 'submit_0', 'Envoyer!'); +$form->updateElementAttr(array('file_0'), array ('id' => 'file_0')); +$form->updateElementAttr(array('hidden_0'), array ('id' => 'hidden_0')); +echo $form->toHtml (); + +if (isset ($_POST['file_0'])): +$image = $_POST['file_0']; +tmpfile ($image); +echo $_POST['file_0']; +endif; +echo sys_get_temp_dir (); +var_dump ($_POST); +?> \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug-300946-index.html b/emacs/nxhtml/tests/in/bug-300946-index.html new file mode 100644 index 0000000..a90814a --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-300946-index.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> + +<head> +<meta http-equiv="expires" content="Monday, February 2nd, 2004 7:51:17pm"> +<title>The ACSys Group Home Page</title> +</head> + <frameset rows="113,*" framespacing="0" frameborder="0"> + + <frame name="logo" target="logo" src="logo.htm" marginwidth="4" marginheight="0"> + + <frameset cols="17%,*" framespacing="0" frameborder="0"> + <frame name="menu" target="content" src="menu.htm" marginwidth="4" marginheight="0"> + <frame name="content" target="_self" src="mission.htm" marginwidth="0" marginheight="0"> + </frameset> + + <noframes> + <body> + <p>This page uses frames, but your browser doesn't support them.</p> + </body> + </noframes> + + </frameset> +</html> diff --git a/emacs/nxhtml/tests/in/bug-311640-index.html b/emacs/nxhtml/tests/in/bug-311640-index.html new file mode 100644 index 0000000..64bb09b --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-311640-index.html @@ -0,0 +1,24 @@ +<script type="text/javascript"> + // Set this to the URL you used to fetch recommendations, whether you + // fetched them on the client or the server. + var request_url = '%(json_url)s'; + + // This function is used track click-throughs by fetching a web + // beacon.n + function trackClickThrough(elem) { + var img = new Image(); + img.src = '%(beacon_url)s' + + '?request_url=' + escape(request_url) + + '&click_through_url=' + escape(elem.href); + return true; + } +</script> + +<p> + <!-- + Imagine this is one of the recommendations that was returned. + Just add an onclick handler that calls trackClickThrough. + --> + <a href="http://www.google.com" + onclick="return trackClickThrough(this);">Click me!</a> +</p> diff --git a/emacs/nxhtml/tests/in/bug-311641.php b/emacs/nxhtml/tests/in/bug-311641.php new file mode 100644 index 0000000..96109ba --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-311641.php @@ -0,0 +1,7 @@ +<? + +try { +} catch (PDOException $e) { + } + +?> \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug-373106-flipbook.html b/emacs/nxhtml/tests/in/bug-373106-flipbook.html new file mode 100644 index 0000000..658d391 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-373106-flipbook.html @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> + <head> + <title>Flipbook (draft)</title> + <style type="text/css"> + body { + background-color: black; + color: white; + } + + .ui-effects-transfer { + border: 2px dotted gray; + } + </style> + <script type="text/javascript" src="jquery.js"></script> + <script type="text/javascript" src="jquery-ui.js"></script> + <script type="text/javascript" src="jquery.event.special.gesture.js"></script> + <script type="text/javascript" src="jquery.gestureable.js"></script> + <script type="text/javascript"> + /* Code to do some fancy book-like effects + */ + + /* a closure-based class */ + var ImageManager = function (images) { + var self = this; + var currentPage = 0; + + self.getCurrentPages = function () { + return [images[currentPage], + images[currentPage+1]]; + }; + + self.turnNext = function () { + currentPage += 2; + return self.getCurrentPages(); + }; + + self.turnPrevious = function () { + currentPage -= 2; + return self.getCurrentPages(); + }; + }; + + function style_element(element) { + element.css('background-color', 'black'); + element.css('width', '900px'); + element.css('height', '650px'); + element.css('border', '2px dashed white'); + } + + function small_gesture(event) { + /* called in mousedown of small images */ + var container = $(event.target).closest('div'); + var manager = container.data('manager'); + var large = $(event.target). + attr('src'). + replace(/small/, 'large'); + + switch (event.gesture) { + case 'U': + case 'D': + container.data('left').hide(); + container.data('right').hide(); + container.data('spacer').hide(); + container.data('zoomed').attr('src', large).show('clip'); + break; + case 'L': + var images = manager.turnPrevious(); + container.data('left').attr('src', images[0] + '_small.jpg'); + container.data('right').attr('src', images[1] + '_small.jpg'); + break; + case 'R': + var images = manager.turnNext(); + container.data('left').attr('src', images[0] + '_small.jpg'); + container.data('right').attr('src', images[1] + '_small.jpg'); + break; + } + } + + function large_gesture(event) { + var container = $(event.target).closest('div'); + switch (event.gesture) { + case 'U': + case 'D': + $(event.target).hide(); + container.data('spacer').show(); + container.data('left').show(); + container.data('right').show(); + } + } + + function disable_scroll(event) { + /* Simply disables the dragging of elements */ + return false; + } + + function flipbook(element, images) { + var manager = new ImageManager(images); + element.data('manager', manager); + + // apply the style + style_element(element); + + // create a spacer div and attach it + var spacer = $('<div class="spacer"></div>'); + spacer.css('height', '162px'); + element.data('spacer', spacer); + element.append(spacer); + + var zoomed = $('<img />'); + zoomed.gestureable(); + zoomed.mouseup(large_gesture). + mousedown(disable_scroll). + hide(); + + element.data('zoomed', zoomed); + element.append(zoomed); + + // create the images + var currentImages = manager.getCurrentPages(); + var left = $('<img src="' + currentImages[0] + '_small.jpg" />'); + var right = $('<img src="' + currentImages[1] + '_small.jpg" />'); + element.data('left', left); + element.data('right', right); + + $([left, right]).each(function (key, value) { + // enable gestures + value.gestureable(); + value.mouseup(small_gesture); + value.mousedown(disable_scroll); + // add to the display + element.append(value); + }); + } + + $(document).ready(function () { + flipbook($('#flipbook'), + ['image_01', 'image_02', 'image_03', 'image_04', + 'image_05', 'image_06', 'image_07', 'image_08', + 'image_09', 'image_10', 'image_11', 'image_12', + 'image_13', 'image_14', 'image_15']); + }); + </script> + </head> + <body> + <div id="flipbook"></div> + <p>Usage: gesture left/right to change images, up/down to zoom in/out</p> + <p>The flipbook uses a number of libs:</p> + <p> + <ul> + <li>jQuery</li> + <li>jQuery UI</li> + <li>jQuery Special Event Gestures</li> + </ul> + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/bug-381191-dh-test.el b/emacs/nxhtml/tests/in/bug-381191-dh-test.el new file mode 100644 index 0000000..d960a10 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-381191-dh-test.el @@ -0,0 +1,23 @@ +;; 3. Add a new c-indentation-style: + +(defconst drupal + '((c-basic-offset . 2) + (c-offsets-alist . ((arglist-close . c-lineup-close-paren) + (case-label . +) + (arglist-intro . +) + (arglist-cont-nonempty . c-lineup-math)))) + "My Drupal Programming style") + +(c-add-style "drupal" drupal) + +;; 4. Open file test.php, attached. + +;; 5. Run `c-set-style' and select "drupal" + +;; 6. Select the whole buffer and press "C-M-\" (or any other indentation command, +;; for that matter) and watch as the array elements are lined up with "array(", +;; whereas they should be indented by 2. + +;; 7. Run M-x php-mode and c-set-style to drupal + +;; 8. Try indenting again to see that indentation now works properly. diff --git a/emacs/nxhtml/tests/in/bug-381191-dh-test.php b/emacs/nxhtml/tests/in/bug-381191-dh-test.php new file mode 100644 index 0000000..c9e450c --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-381191-dh-test.php @@ -0,0 +1,6 @@ +<?php +$a = array( + 'foo' => 'bar', + 'gaz' => 'gazonk', +); +?> \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug-johan-2010-02-12.rhtml b/emacs/nxhtml/tests/in/bug-johan-2010-02-12.rhtml new file mode 100644 index 0000000..758a4b0 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-johan-2010-02-12.rhtml @@ -0,0 +1,22 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta content="text/html;charset=utf-8" http-equiv="Content-Type" /> + <link rel="icon" href="/favicon.ico" /> + + <%= include_stylesheets :blueprint, :application, :media => 'all' %> +<!--[if lt IE 8]> + <%= include_stylesheets :ie, :media => 'all' %> + <![endif]--> +<%= include_javascripts :mootools, :application %> + </head> + <body> + <div id="container"> + <%= render :partial => "layouts/application/header" %> +<%= render :partial => "layouts/application/menu" %> + <%= render :partial => "layouts/application/search_bar" %> +<%= render :partial => "layouts/application/contents" %> + <%= render :partial => "layouts/application/footer" %> +</div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/bug-johan-2010-02-16.html.haml b/emacs/nxhtml/tests/in/bug-johan-2010-02-16.html.haml new file mode 100644 index 0000000..4184a32 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-johan-2010-02-16.html.haml @@ -0,0 +1,34 @@ +!!! Strict +%html + %head + %title= t("site.title") + %meta{"http-equiv" => "Content-Type", :content => "text/html;charset=utf-8"} + = javascript_include_merged :mootools, :application + = stylesheet_link_merged :application + /[if lt IE 8] + = stylesheet_link_merged :ie + + %body + = render :partial => "shared/fork" + #container + #logo + = link_to image_tag("logo.png"), root_url + + = render :partial => "shared/user_panel" + = render :partial => "shared/menu" + + #body + #contents + = render :partial => "shared/flash", :object => flash + + .padder + #search_results + + = yield + + #sidebar + .padder + = render :partial => "shared/sidebar" + + #footer + %p= t("site.copyright") diff --git a/emacs/nxhtml/tests/in/bug-johan-2010-02-17-2.erb b/emacs/nxhtml/tests/in/bug-johan-2010-02-17-2.erb new file mode 100644 index 0000000..67411a9 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-johan-2010-02-17-2.erb @@ -0,0 +1,14 @@ + +<% semantic_form_for @user_session do |form| %> +<%= form.error_messages :header_tag => :h3 %> +<%#= authlogic_facebook_login_button %> + +<% form.inputs do %> +<%= form.input :email %> +<%= form.input :password %> +<% end %> + +<% form.buttons do %> +<%= form.commit_button %> +<% end %> +<% end %> diff --git a/emacs/nxhtml/tests/in/bug-johan-2010-02-17.erb b/emacs/nxhtml/tests/in/bug-johan-2010-02-17.erb new file mode 100644 index 0000000..ebb5094 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug-johan-2010-02-17.erb @@ -0,0 +1,4 @@ +<% collection.each do |item| %> +<%= item.method %> +<% end %> + diff --git a/emacs/nxhtml/tests/in/bug261792.ghtml b/emacs/nxhtml/tests/in/bug261792.ghtml new file mode 100644 index 0000000..faec7f9 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug261792.ghtml @@ -0,0 +1,7 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + xmlns:xi="http://www.w3.org/2001/XInclude" + lang="en"> + <xi:include href="../layout.html" /> + <head> diff --git a/emacs/nxhtml/tests/in/bug271497.el b/emacs/nxhtml/tests/in/bug271497.el new file mode 100644 index 0000000..7abe02e --- /dev/null +++ b/emacs/nxhtml/tests/in/bug271497.el @@ -0,0 +1,14 @@ +;;; bug271497.el --- For bug report 271497 at Launchpad +(require 'ada-mode) +(require 'mumamo) + +(eval-and-compile + (defun mumamo-chunk-embjava (pos min max) + "Find JAVA_ON ... JAVA_OFF, return range and java-mode." + (mumamo-quick-static-chunk pos min max "JAVA_ON" "JAVA_OFF" nil 'java-mode nil)) + ) + +(define-mumamo-multi-major-mode bug271497-mumamo + "docstring" + ("ADA Mode" ada-mode + (mumamo-chunk-embjava))) diff --git a/emacs/nxhtml/tests/in/bug271497.txt b/emacs/nxhtml/tests/in/bug271497.txt new file mode 100644 index 0000000..7e4e8e5 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug271497.txt @@ -0,0 +1,7 @@ +This is supposed to be ada code + +JAVA_ON +and this is supposed to be java code +JAVA_OFF + +This is also supposed to be ada code diff --git a/emacs/nxhtml/tests/in/bug272871.php b/emacs/nxhtml/tests/in/bug272871.php new file mode 100644 index 0000000..c205383 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug272871.php @@ -0,0 +1,7 @@ +<?php +function a() +{ + b($a, $b); + c($b, $c); +} +?> \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug290364-messages.txt b/emacs/nxhtml/tests/in/bug290364-messages.txt new file mode 100644 index 0000000..4aaae9a --- /dev/null +++ b/emacs/nxhtml/tests/in/bug290364-messages.txt @@ -0,0 +1,97 @@ +("/usr/bin/emacs22-gtk") +Loading 00debian-vars... +No /etc/mailname. Reverting to default... +Loading 00debian-vars...done +Loading /etc/emacs/site-start.d/20apel.el (source)...done +Loading /etc/emacs/site-start.d/50cedet-common.el (source)... +Loading advice...done +Loading /etc/emacs/site-start.d/50cedet-common.el (source)...done +Loading /etc/emacs/site-start.d/50css-mode.el (source)...done +Loading /etc/emacs/site-start.d/50devhelp.el (source)...done +Loading /etc/emacs/site-start.d/50dictionaries-common.el (source)... +Loading debian-ispell... +Loading /var/cache/dictionaries-common/emacsen-ispell-default.el (source)...done +Loading debian-ispell...done +Loading /var/cache/dictionaries-common/emacsen-ispell-dicts.el (source)...done +Loading /etc/emacs/site-start.d/50dictionaries-common.el (source)...done +Loading /etc/emacs/site-start.d/50eieio.el (source)...done +Loading /etc/emacs/site-start.d/50eldav.el (source)...done +Loading /etc/emacs/site-start.d/50elserv.el (source)...done +Loading /etc/emacs/site-start.d/50emacs-extra.el (source)...done +Loading /etc/emacs/site-start.d/50emacs-goodies-el.el (source)...done +Loading /etc/emacs/site-start.d/50erc.el (source)... +Loading erc-auto...done +Loading /etc/emacs/site-start.d/50erc.el (source)...done +Loading /etc/emacs/site-start.d/50flim.el (source)...done +Loading /etc/emacs/site-start.d/50gettext.el (source)...done +Loading /etc/emacs/site-start.d/50html-helper-mode.el (source)...done +Loading /etc/emacs/site-start.d/50mmm-mode.el (source)...done +Loading /etc/emacs/site-start.d/50php-elisp.el (source)...done +Loading /etc/emacs/site-start.d/50php-mode.el (source)...done +Loading /etc/emacs22/site-start.d/50psgml-init.el (source)...done +Loading /etc/emacs/site-start.d/50psvn.el (source)...done +Loading /etc/emacs/site-start.d/50tramp.el (source)...done +Loading /etc/emacs/site-start.d/50w3m-el.el (source)...done +Loading /etc/emacs/site-start.d/51ede.el (source)...done +Loading /etc/emacs/site-start.d/51speedbar.el (source)...done +Loading /etc/emacs/site-start.d/52semantic.el (source)...done +Loading /etc/emacs/site-start.d/53cedet-contrib.el (source)...done +Loading /etc/emacs/site-start.d/53cogre.el (source)...done +Loading /etc/emacs/site-start.d/55ecb.el (source)... +"/usr/share/emacs22/site-lisp/cedet-common/" added to `load-path' +Setting up cedet...done +Setting up cogre...done +Setting up ede... +Loading ede... +Loading ede-speedbar...done +Loading ede...done +Setting up ede...done +Setting up eieio...done +Setting up semantic... +Loading derived...done +Setting up semantic...done +Setting up speedbar...done +Setting up cedet-contrib...done +Loading /etc/emacs/site-start.d/55ecb.el (source)...done +Loading /etc/emacs22/site-start.d/60nxml-mode.el (source)... +Loading /usr/share/emacs22/site-lisp/nxml-mode/rng-auto.el (source)...done +Loading /etc/emacs22/site-start.d/60nxml-mode.el (source)...done +Loading /etc/emacs/site-start.d/60wysihtml-el.el (source)...done +Loading /home/guillaume/elisp/nxhtml/autostart.el (source)... +Nxml/Nxhtml Autostart.el loading ... +Loading edmacro...done +Loading easy-mmode...done +Loading /home/guillaume/elisp/nxhtml/nxhtml-loaddefs.el (source)...done +Loading /home/guillaume/elisp/nxhtml/etc/schema/schema-path-patch.el (source)...done +xhtml-loader.rnc was ok +(No changes need to be saved) +Loading /home/guillaume/elisp/nxhtml/nxhtml/nxhtml-autoload.el (source)... +Loading /home/guillaume/elisp/nxhtml/util/majmodpri.el (source)...done +majmodpri-sort-lists running ... +Loading /home/guillaume/elisp/nxhtml/nxhtml/nxhtml-autoload.el (source)...done +Loading /home/guillaume/elisp/nxhtml/autostart.el (source)...done +Loading /home/guillaume/elisp/nxhtml/nxhtml/nxhtml.el (source)... +html-site-current (information): No current site set +Loading /home/guillaume/elisp/nxhtml/nxhtml/nxhtml.el (source)...done +Loading nxml-uchnm...done +Loading rng-nxml...done +Loading rng-cmpct...done +Loading rng-xsd...done +Using vacuous schema +Loading /home/guillaume/elisp/nxhtml/nxhtml/nxhtml-menu.el (source)...done +Loading /home/guillaume/elisp/nxhtml/util/mlinks.el (source)...done +Loading imenu...done +Loading /home/guillaume/elisp/nxhtml/nxhtml/nxhtml-mumamo.el (source)... +Loading byte-opt...done +Loading /home/guillaume/elisp/nxhtml/nxhtml/nxhtml-mumamo.el (source)...done +Showing all blocks ... done +Loading semantic-html...done +Loading /home/guillaume/elisp/geben/geben.el (source)...done +ispell.el is already loaded +Using vacuous schema [4 times] +Loading semantic-el...done +let: Wrong type argument: stringp, nil [2 times] +Making completion list... +Loading eieio-opt...done +Making completion list... +let: Wrong type argument: stringp, nil \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug354363-index.php b/emacs/nxhtml/tests/in/bug354363-index.php new file mode 100644 index 0000000..3644f5d --- /dev/null +++ b/emacs/nxhtml/tests/in/bug354363-index.php @@ -0,0 +1,38 @@ +<?php + define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application/')); +set_include_path( + APPLICATION_PATH . '/../library' + . PATH_SEPARATOR . get_include_path() + ); + +if(true){ + echo 'test'; + } +else + { + + } + +require_once "Zend/Loader.php"; +Zend_Loader::registerAutoload(); + +try +{ + require '../application/bootstrap.php'; + } +catch(Exception $exception) +{ + echo '<html><body><center>' + . 'An exception occured while bootstrapping the application.'; + if(defined('APPLICATION_ENVIRONMENT') + && APPLICATION_ENVIRONMENT != 'production' + ) { + echo '<br /><br />' . $exception->getMessage() . '<br />' + . '<div align="left">Stack Trace:' + . '<pre>' . $exception->getTraceAsString() . '</pre></div>'; + } + echo '</center><body></html>'; + exit(1); + } + +Zend_Controller_Front::getInstance()->dispatch(); diff --git a/emacs/nxhtml/tests/in/bug354363-test.php b/emacs/nxhtml/tests/in/bug354363-test.php new file mode 100644 index 0000000..10e2c0d --- /dev/null +++ b/emacs/nxhtml/tests/in/bug354363-test.php @@ -0,0 +1,3 @@ +<?php +echo 'test'; +?> diff --git a/emacs/nxhtml/tests/in/bug369800-load-history.txt b/emacs/nxhtml/tests/in/bug369800-load-history.txt new file mode 100644 index 0000000..aad863d --- /dev/null +++ b/emacs/nxhtml/tests/in/bug369800-load-history.txt @@ -0,0 +1,9483 @@ +load-history is a variable defined in `C source code'. +Its value is shown below. + +Documentation: +Alist mapping file names to symbols and features. +Each alist element is a list that starts with a file name, +except for one element (optional) that starts with nil and describes +definitions evaluated from buffers not visiting files. + +The file name is absolute and is the true file name (i.e. it doesn't +contain symbolic links) of the loaded file. + +The remaining elements of each list are symbols defined as variables +and cons cells of the form `(provide . FEATURE)', `(require . FEATURE)', +`(defun . FUNCTION)', `(autoload . SYMBOL)', `(defface . SYMBOL)' +and `(t . SYMBOL)'. An element `(t . SYMBOL)' precedes an entry +`(defun . FUNCTION)', and means that SYMBOL was an autoload before +this file redefined it as a function. + +During preloading, the file name recorded is relative to the main Lisp +directory. These file names are converted to absolute at startup. + +Value: +(("/home/hobbes/nxhtml/autostart.el" nxhtml-install-dir + (defun . nxhtml-custom-autoload) + (defun . nxhtml-list-loaded-features) + (provide . nxhtml-autostart)) + ("/home/hobbes/nxhtml/nxhtml/nxhtml-autoload.el" + (require . majmodpri) + (require . moz) + (defun . javascript-moz-setup) + nxhtml-src-dir + (provide . nxhtml-autoload)) + ("/home/hobbes/nxhtml/related/moz.el" + (require . comint) + (require . cc-cmds) + moz-minor-mode-map moz-minor-mode + (t . moz-minor-mode) + (defun . moz-minor-mode) + (defun . run-mozilla) + moz-repl-name moz-input-separator moz-repl-host moz-repl-port moz-temporary-file + (defun . moz-temporary-file) + (defun . moz-send-region) + (defun . moz-send-defun) + (defun . moz-send-defun-and-go) + (defun . moz-save-buffer-and-send) + inferior-moz-buffer + (defun . inferior-moz-insert-moz-repl) + inferior-moz-mode-map inferior-moz-mode-map inferior-moz-mode-syntax-table inferior-moz-mode-abbrev-table inferior-moz-mode-abbrev-table + (t . inferior-moz-mode) + (defun . inferior-moz-mode) + (defun . inferior-moz-track-repl-name) + (defun . inferior-moz-self-insert-or-repl-name) + (defun . inferior-moz-input-sender) + (defun . inferior-moz-switch-to-mozilla) + (defun . inferior-moz-process) + (defun . inferior-moz-start-process) + (provide . moz)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/cc-cmds.elc" + (require . cc-defs) + (require . cc-vars) + (require . cc-engine) + c-fix-backslashes + (defun . c-indent-line) + (defun . c-newline-and-indent) + (defun . c-show-syntactic-information) + (defun . c-syntactic-information-on-region) + (defun . c-update-modeline) + (defun . c-toggle-syntactic-indentation) + (defun . c-toggle-auto-newline) + (defun . c-toggle-auto-state) + (defun . c-toggle-hungry-state) + (defun . c-toggle-auto-hungry-state) + (defun . c-toggle-electric-state) + (defun . c-electric-backspace) + (defun . c-hungry-delete-backwards) + (defun . c-hungry-backspace) + (defun . c-electric-delete-forward) + (defun . c-hungry-delete-forward) + (defun . c-electric-delete) + (defun . c-hungry-delete) + (defun . c-electric-pound) + (defun . c-point-syntax) + (defun . c-brace-newlines) + (defun . c-try-one-liner) + (defun . c-electric-brace) + (defun . c-electric-slash) + (defun . c-electric-star) + (defun . c-electric-semi&comma) + (defun . c-electric-colon) + (defun . c-electric-lt-gt) + (defun . c-electric-paren) + (defun . c-electric-continued-statement) + (defun . c-forward-into-nomenclature) + (defun . c-backward-into-nomenclature) + (defun . c-scope-operator) + (defun . c-in-function-trailer-p) + (defun . c-where-wrt-brace-construct) + (defun . c-backward-to-nth-BOF-{) + (defun . c-beginning-of-defun) + (defun . c-forward-to-nth-EOF-}) + (defun . c-end-of-defun) + (defun . c-defun-name) + (defun . c-declaration-limits) + (defun . c-mark-function) + (defun . c-cpp-define-name) + (defun . c-in-comment-line-prefix-p) + (defun . c-narrow-to-comment-innards) + (defun . c-beginning-of-sentence-in-comment) + (defun . c-end-of-sentence-in-comment) + (defun . c-beginning-of-sentence-in-string) + (defun . c-end-of-sentence-in-string) + (defun . c-ascertain-preceding-literal) + (defun . c-ascertain-following-literal) + (defun . c-after-statement-terminator-p) + (defun . c-back-over-illiterals) + (defun . c-forward-over-illiterals) + (defun . c-one-line-string-p) + (defun . c-beginning-of-statement) + (defun . c-end-of-statement) + (defun . c-calc-comment-indent) + (defun . c-comment-indent) + (defun . c-outline-level) + (defun . c-up-conditional) + (defun . c-up-conditional-with-else) + (defun . c-down-conditional) + (defun . c-down-conditional-with-else) + (defun . c-backward-conditional) + (defun . c-forward-conditional) + (defun . c-indent-command) + (defun . c-indent-exp) + (defun . c-indent-defun) + (defun . c-indent-region) + (defun . c-fn-region-is-active-p) + (defun . c-indent-line-or-region) + c-progress-info + (defun . c-progress-init) + (defun . c-progress-update) + (defun . c-progress-fini) + (defun . c-backslash-region) + (defun . c-append-backslashes-forward) + (defun . c-delete-backslashes-forward) + c-auto-fill-prefix c-lit-limits c-lit-type + (defun . c-guess-fill-prefix) + (defun . c-mask-paragraph) + (defun . c-fill-paragraph) + (defun . c-do-auto-fill) + (defun . c-indent-new-comment-line) + (defun . c-comment-line-break-function) + (defun . c-context-line-break) + (defun . c-context-open-line) + (provide . cc-cmds)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/cc-engine.elc" + (require . cc-defs) + (require . cc-vars) + (defun . c-declare-lang-variables) + c++-template-syntax-table c-identifier-syntax-modifications c-identifier-syntax-table c-get-state-before-change-function c-before-font-lock-function c-symbol-start c-symbol-key c-nonsymbol-chars c-opt-identifier-concat-key c-identifier-start c-identifier-key c-string-escaped-newlines c-multiline-string-start-char c-opt-cpp-prefix c-anchored-cpp-prefix c-opt-cpp-start c-opt-cpp-macro-define-start c-opt-cpp-macro-define-id c-overloadable-operators-regexp c-opt-op-identifier-prefix c-nonsymbol-token-regexp c-assignment-op-regexp c-<>-multichar-token-regexp c-<-op-cont-regexp c->-op-cont-regexp c-stmt-delim-chars c-stmt-delim-chars-with-comma c-line-comment-starter c-comment-start-regexp c-block-comment-start-regexp c-literal-start-regexp c-doc-comment-start-regexp c-syntactic-ws-start c-syntactic-ws-end c-syntactic-eol c-at-vsemi-p-fn c-vsemi-status-unknown-p-fn c-paragraph-start c-paragraph-separate c-primitive-type-key c-type-prefix-key c-opt-type-modifier-key c-opt-type-component-key c-class-key c-brace-list-key c-other-decl-block-key c-other-decl-block-key-in-symbols-alist c-decl-hangon-key c-prefix-spec-kwds-re c-specifier-key c-not-decl-init-keywords c-opt-block-decls-with-vars-key c-colon-type-list-re c-opt-<>-sexp-key c-block-stmt-1-key c-block-stmt-2-key c-opt-block-stmt-key c-simple-stmt-key c-paren-stmt-key c-opt-asm-stmt-key c-case-kwds-regexp c-label-kwds-regexp c-opt-inexpr-brace-list-key c-decl-block-key c-opt-bitfield-key c-keywords-regexp c-keywords-obarray c-regular-keywords-regexp c-primary-expr-regexp c-decl-prefix-re c-decl-start-re c-decl-prefix-or-start-re c-cast-parens c-block-prefix-charset c-type-decl-prefix-key c-type-decl-suffix-key c-after-suffixed-type-decl-key c-after-suffixed-type-maybe-decl-key c-opt-type-concat-key c-opt-type-suffix-key c-known-type-key c-special-brace-lists c-recognize-knr-p c-recognize-typeless-decls c-recognize-<>-arglists c-recognize-paren-inits c-recognize-paren-inexpr-blocks c-opt-<>-arglist-start c-opt-<>-arglist-start-in-paren c-opt-postfix-decl-spec-key c-recognize-colon-labels c-label-prefix-re c-nonlabel-token-key c-opt-extra-label-key c-opt-friend-key c-opt-method-key c-type-decl-end-used c-hungry-delete-key c-electric-flag c-auto-newline + (defun . c-calculate-state) + c-in-literal-cache c-macro-start + (defun . c-query-and-set-macro-start) + (defun . c-query-macro-start) + (defun . c-beginning-of-macro) + (defun . c-end-of-macro) + (defun . c-forward-over-cpp-define-id) + (defun . c-forward-to-cpp-define-body) + (defun . c-syntactic-content) + (defun . c-shift-line-indentation) + (defun . c-keyword-sym) + (defun . c-keyword-member) + c-string-syntax c-string-syntax c-string-limit-regexp c-string-limit-regexp c-ws*-string-limit-regexp c-ws*-string-limit-regexp c-parsing-error + (defun . c-echo-parsing-error) + c-literal-faces + (defun . c-put-c-type-property) + (defun . c-clear-c-type-property) + (defun . c-debug-add-face) + (defun . c-debug-remove-face) + (defun . c-bos-push-state) + (defun . c-bos-pop-state) + (defun . c-bos-pop-state-and-retry) + (defun . c-bos-save-pos) + (defun . c-bos-restore-pos) + (defun . c-bos-save-error-info) + (defun . c-bos-report-error) + (defun . c-beginning-of-statement-1) + (defun . c-crosses-statement-barrier-p) + (defun . c-at-statement-start-p) + (defun . c-at-expression-start-p) + (defun . c-forward-single-comment) + (defun . c-forward-comments) + (defun . c-backward-single-comment) + (defun . c-backward-comments) + (defun . c-debug-sws-msg) + (defun . c-put-is-sws) + (defun . c-put-in-sws) + (defun . c-remove-is-sws) + (defun . c-remove-in-sws) + (defun . c-remove-is-and-in-sws) + (defun . c-invalidate-sws-region-after) + (defun . c-forward-sws) + (defun . c-backward-sws) + (defun . c-partial-ws-p) + c-state-cache c-state-cache-start c-state-cache-good-pos + (defun . c-invalidate-state-cache) + (defun . c-get-fallback-start-pos) + (defun . c-parse-state) + c-debug-parse-state + (defun . c-debug-parse-state) + (defun . c-toggle-parse-state-debug) + (defun . c-whack-state-before) + (defun . c-whack-state-after) + (defun . c-most-enclosing-brace) + (defun . c-least-enclosing-brace) + (defun . c-safe-position) + (defun . c-beginning-of-syntax) + (defun . c-on-identifier) + (defun . c-simple-skip-symbol-backward) + (defun . c-beginning-of-current-token) + (defun . c-end-of-current-token) + c-jump-syntax-balanced c-jump-syntax-balanced c-jump-syntax-unbalanced c-jump-syntax-unbalanced + (defun . c-forward-token-2) + (defun . c-backward-token-2) + (defun . c-forward-token-1) + (defun . c-backward-token-1) + (defun . c-syntactic-re-search-forward) + (defun . c-syntactic-skip-backward) + (defun . c-slow-in-literal) + (defun . c-fast-in-literal) + (defun . c-in-literal) + (defun . c-literal-limits) + (defun . c-literal-limits-fast) + (defun . c-collect-line-comments) + (defun . c-literal-type) + c-find-decl-syntactic-pos c-find-decl-match-pos + (defun . c-invalidate-find-decl-cache) + (defun . c-debug-put-decl-spot-faces) + (defun . c-debug-remove-decl-spot-faces) + (defun . c-find-decl-prefix-search) + (defun . c-find-decl-spots) + c-found-types + (defun . c-clear-found-types) + (defun . c-add-type) + (defun . c-unfind-type) + (defun . c-check-type) + (defun . c-list-found-types) + (defun . c-trim-found-types) + (defun . c-after-change-check-<>-operators) + c-promote-possible-types c-parse-and-markup-<>-arglists c-restricted-<>-arglists c-record-type-identifiers c-record-ref-identifiers c-last-identifier-range + (defun . c-record-type-id) + (defun . c-record-ref-id) + c-record-found-types + (defun . c-forward-keyword-prefixed-id) + (defun . c-forward-id-comma-list) + (defun . c-forward-keyword-clause) + (defun . c-forward-<>-arglist) + (defun . c-forward-<>-arglist-recur) + (defun . c-backward-<>-arglist) + (defun . c-forward-name) + (defun . c-forward-type) + (defun . c-fdoc-shift-type-backward) + (defun . c-forward-decl-or-cast-1) + (defun . c-forward-label) + (defun . c-forward-objc-directive) + (defun . c-beginning-of-inheritance-list) + (defun . c-in-method-def-p) + (defun . c-in-gcc-asm-p) + (defun . c-at-toplevel-p) + (defun . c-just-after-func-arglist-p) + (defun . c-in-knr-argdecl) + (defun . c-skip-conditional) + (defun . c-after-conditional) + (defun . c-after-special-operator-id) + (defun . c-backward-to-block-anchor) + (defun . c-backward-to-decl-anchor) + (defun . c-search-decl-header-end) + (defun . c-beginning-of-decl-1) + (defun . c-end-of-decl-1) + (defun . c-looking-at-decl-block) + (defun . c-search-uplist-for-classkey) + (defun . c-inside-bracelist-p) + (defun . c-looking-at-special-brace-list) + (defun . c-looking-at-bos) + (defun . c-looking-at-inexpr-block) + (defun . c-looking-at-inexpr-block-backward) + c-auto-newline-analysis + (defun . c-brace-anchor-point) + (defun . c-add-syntax) + (defun . c-append-syntax) + (defun . c-add-stmt-syntax) + (defun . c-add-class-syntax) + (defun . c-guess-continued-construct) + (t . c-guess-basic-syntax) + (defun . c-guess-basic-syntax) + (defun . c-evaluate-offset) + (defun . c-calc-offset) + (defun . c-get-offset) + (defun . c-get-syntactic-indentation) + (provide . cc-engine)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/cc-vars.elc" + (require . cc-defs) + (defun . c-constant-symbol) + c-style-variables c-fallback-style + (defun . c-set-stylevar-fallback) + (defun . defcustom-c-stylevar) + (defun . c-valid-offset) + c-strict-syntax-p c-echo-syntactic-information-p c-report-syntactic-errors c-basic-offset c-tab-always-indent c-insert-tab-function c-syntactic-indentation c-syntactic-indentation-in-macros c-comment-only-line-offset c-indent-comment-alist c-indent-comments-syntactically-p c-block-comment-prefix c-comment-prefix-regexp c-doc-comment-style c-ignore-auto-fill c-cleanup-list c-hanging-braces-alist c-max-one-liner-length c-hanging-colons-alist c-hanging-semi&comma-criteria c-backslash-column c-backslash-max-column c-auto-align-backslashes c-backspace-function c-delete-function c-require-final-newline c-electric-pound-behavior c-special-indent-hook c-label-minimum-indentation c-progress-interval c-objc-method-arg-min-delta-to-bracket c-objc-method-arg-unfinished-offset c-objc-method-parameter-offset c-default-style c-offsets-alist c-inside-block-syms c-inside-block-syms c-style-variables-are-local-p c-mode-hook c++-mode-hook objc-mode-hook java-mode-hook idl-mode-hook pike-mode-hook awk-mode-hook c-mode-common-hook c-initialization-hook c-enable-xemacs-performance-kludge-p c-old-style-variable-behavior + (defun . c-make-font-lock-extra-types-blurb) + c-font-lock-extra-types c++-font-lock-extra-types objc-font-lock-extra-types java-font-lock-extra-types idl-font-lock-extra-types pike-font-lock-extra-types c-file-style c-file-offsets c-indentation-style c-current-comment-prefix c-string-par-start c-string-par-separate c-sentence-end-with-esc-eol + (provide . cc-vars)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/cc-defs.elc" + (require . regexp-opt) + c-version c-version-sym c-version-sym c-buffer-is-cc-mode c-inside-eval-when-compile + (defun . cc-eval-when-compile) + (defun . c-point) + (defun . c-region-is-active-p) + (defun . c-set-region-active) + (defun . c-delete-and-extract-region) + (defun . c-safe) + (defun . c-int-to-char) + (defun . c-sentence-end) + (defun . c-default-value-sentence-end) + (defun . c-save-buffer-state) + (defun . c-tentative-buffer-changes) + (defun . c-tnt-chng-record-state) + (defun . c-tnt-chng-cleanup) + (defun . c-forward-syntactic-ws) + (defun . c-backward-syntactic-ws) + (defun . c-forward-sexp) + (defun . c-backward-sexp) + (defun . c-safe-scan-lists) + (defun . c-go-list-forward) + (defun . c-go-list-backward) + (defun . c-up-list-forward) + (defun . c-up-list-backward) + (defun . c-down-list-forward) + (defun . c-down-list-backward) + (defun . c-go-up-list-forward) + (defun . c-go-up-list-backward) + (defun . c-go-down-list-forward) + (defun . c-go-down-list-backward) + (defun . c-beginning-of-defun-1) + (defun . c-at-vsemi-p) + (defun . c-vsemi-status-unknown-p) + (defun . c-benign-error) + (defun . c-with-syntax-table) + (defun . c-skip-ws-forward) + (defun . c-skip-ws-backward) + c-langs-are-parametric + (defun . c-major-mode-is) + c-use-extents c-use-extents + (defun . c-put-char-property-fun) + (defun . c-put-char-property) + (defun . c-get-char-property) + (defun . c-clear-char-property-fun) + (defun . c-clear-char-property) + (defun . c-clear-char-properties) + (defun . c-clear-char-property-with-value-function) + (defun . c-clear-char-property-with-value) + (defun . c-put-overlay) + (defun . c-delete-overlay) + (defun . c-end-of-defun-1) + c-<-as-paren-syntax c-<-as-paren-syntax + (defun . c-mark-<-as-paren) + c->-as-paren-syntax c->-as-paren-syntax + (defun . c-mark->-as-paren) + (defun . c-intersect-lists) + (defun . c-lookup-lists) + (defun . c-langelem-sym) + (defun . c-langelem-pos) + (defun . c-langelem-col) + (defun . c-langelem-2nd-pos) + (defun . c-keep-region-active) + (defun . c-mode-symbol) + (defun . c-mode-var) + (defun . c-got-face-at) + (defun . c-face-name-p) + (defun . c-concat-separated) + (defun . c-make-keywords-re) + (defun . c-make-bare-char-alt) + (defun . c-regexp-opt) + (defun . c-regexp-opt-depth) + c-emacs-features c-alpha c-alpha c-alnum c-alnum c-digit c-digit c-upper c-upper c-lower c-lower + (defun . c-add-language) + c-lang-constants c-lang-const-expansion + (defun . c-get-current-file) + (defun . c-lang-defconst-eval-immediately) + (defun . c-lang-defconst) + (defun . c-define-lang-constant) + (defun . c-lang-const) + c-lang-constants-under-evaluation + (defun . c-get-lang-constant) + (defun . c-find-assignment-for-mode) + (defun . c-lang-major-mode-is) + (provide . cc-defs)) + ("/home/hobbes/nxhtml/util/majmodpri.el" majmodpri:version majmodpri-idle-sort-timer + (defun . majmodpri-cancel-idle-sort) + (defun . majmodpri-start-idle-sort) + (defun . majmodpri-sort-lists-in-timer) + majmodpri-schwarzian-ordnum + (defun . majmodpri-schwarzian-in) + (defun . majmodpri-schwarzian-out) + majmodpri-no-nxml + (defun . majmodpri-priority) + (defun . majmodpri-compare-auto-modes) + (defun . majmodpri-sort-auto-mode-alist) + (defun . majmodpri-sort-magic-list) + (t . majmodpri-sort-lists) + (defun . majmodpri-sort-lists) + (t . majmodpri-apply) + (defun . majmodpri-apply) + (defun . majmodpri-sort-apply-to-current) + (t . majmodpri-apply-priorities) + (defun . majmodpri-apply-priorities) + majmodpri-mode-priorities majmodpri-lists-to-sort majmodpri-sort-after-load + (provide . majmodpri)) + ("/home/hobbes/nxhtml/etc/schema/schema-path-patch.el" rncpp-this-dir + (defun . rncpp-get-nxml-schema-dir) + (defun . rncpp-patch-xhtml-loader)) + ("/home/hobbes/nxhtml/nxhtml/nxhtml-menu.el" nxhtml-menu:version + (require . cl) + (require . cus-edit) + (require . dired) + (require . gimp) + (require . html-site) + (require . nxhtml-mode) + (require . css-color) + (require . flymake) + (require . flymake-php) + (require . flymake-js) + (require . udev-ecb) + (require . udev-cedet) + (require . udev-rinari) + (defun . nxhtml-nxhtml-in-buffer) + (defun . nxhtml-nxml-in-buffer) + (defun . nxhtml-html-in-buffer) + (defun . nxhtml-nxml-html-in-buffer) + (defun . nxhtml-this-file-can-have-toc) + (defun . nxhtml-buffer-possibly-local-viewable) + (defun . nxhtml-buffer-possibly-remote-viewable) + (defun . nxhtml-insert-menu-dynamically) + (defun . nxhtml-menu-image-file) + (defun . nxhtml-gimp-can-edit) + (t . nxhtml-edit-with-gimp) + (defun . nxhtml-edit-with-gimp) + (t . nxhtml-browse-file) + (defun . nxhtml-browse-file) + (t . nxhtml-browse-region) + (defun . nxhtml-browse-region) + nxhtml-browseable-buffer-file + (defun . nxhtml-save-browseable-temp-file) + nxhtml-minor-mode-menu-map nxhtml-minor-mode-map nxhtml-minor-mode + (defun . nxhtml-minor-mode) + nxhtml-minor-mode-modes + (defun . nxhtml-maybe-turn-on-minor-mode) + nxhtml-minor-mode-major-mode nxhtml-global-minor-mode + (t . nxhtml-global-minor-mode) + (defun . nxhtml-global-minor-mode) + nxhtml-global-minor-mode-buffers + (defun . nxhtml-global-minor-mode-enable-in-buffers) + (defun . nxhtml-global-minor-mode-check-buffers) + (defun . nxhtml-global-minor-mode-cmhh) + (defun . nxhtml-docfile) + (defun . nxhtml-docfile-url) + (defun . nxhtml-overview) + (defun . nxhtml-tutorials) + (defun . nxhtml-custom-valfaced) + (defun . nxhtml-custom-insert-nxhtml-row) + (defun . nxhtml-custom-h1) + (defun . widget-button-notify) + (defun . widget-insert-link) + (defun . widget-insert-button) + (defun . nxhtml-custom-url-link) + (defun . nxhtml-custom-describe-defun) + (defun . custom-set-and-prepare-save) + (defun . nxhtml-welcome) + nxhtml-skip-welcome + (defun . nxhtml-skip-welcome) + (defun . nxhtml-say-welcome-unless-skip) + (provide . nxhtml-menu)) + ("/home/hobbes/nxhtml/util/udev-rinari.el" udev-rinari:version + (require . udev) + udev-rinari-dir udev-rinari-load-rinari udev-rinari-steps udev-rinari-update-buffer + (defun . udev-rinari-buffer-name) + (defun . udev-rinari-check-conflicts) + (defun . udev-rinari-setup-when-finished) + (t . udev-rinari-update) + (defun . udev-rinari-update) + udev-rinari-fetch-buffer + (defun . udev-rinari-fetch) + udev-rinari-diff-file udev-rinari-fetch-diff-buffer + (defun . udev-rinari-fetch-diff) + (defun . udev-rinari-check-diff) + (provide . udev-rinari)) + ("/home/hobbes/nxhtml/util/udev-cedet.el" udev-cedet:version + (require . udev) + udev-cedet-dir + (defun . udev-cedet-load-cedet) + udev-cedet-load-cedet udev-cedet-steps + (defun . udev-cedet-buffer-name) + udev-cedet-update-buffer + (defun . udev-cedet-setup-when-finished) + (t . udev-cedet-update) + (defun . udev-cedet-update) + (defun . udev-cedet-fetch) + (defun . udev-cedet-cvs-dir) + (defun . udev-cedet-fetch-diff) + (defun . udev-cedet-check-diff) + (defun . udev-cedet-install-add-debug) + (defun . udev-cedet-install) + (provide . udev-cedet)) + ("/home/hobbes/nxhtml/util/udev-ecb.el" udev-ecb:version + (require . udev) + udev-ecb-dir + (defun . udev-ecb-load-ecb) + udev-ecb-load-ecb udev-ecb-steps + (defun . udev-ecb-buffer-name) + udev-ecb-update-buffer + (defun . udev-ecb-check-cedet) + (defun . udev-ecb-setup-when-finished) + (t . udev-ecb-update) + (defun . udev-ecb-update) + (defun . udev-ecb-fetch) + (defun . udev-ecb-cvs-dir) + (defun . udev-ecb-fetch-diff) + (defun . udev-ecb-check-diff) + (defun . udev-ecb-install) + (provide . udev-ecb)) + ("/home/hobbes/nxhtml/util/udev.el" udev:version + (require . cl) + (require . cus-edit) + udev-log-buffer udev-is-log-buffer + (defun . udev-check-is-log-buffer) + udev-this-chain udev-last-error + (defun . udev-set-last-error) + (defun . udev-chain) + (defun . udev-this-step) + (defun . udev-goto-next-step) + (defun . udev-num-steps) + (defun . udev-step-num) + (defun . udev-finish-function) + udev-control-mode-map udev-control-mode-map udev-control-mode-syntax-table udev-control-mode-abbrev-table udev-control-mode-abbrev-table + (defun . udev-control-mode) + (defun . udev-call-first-step) + udev-step-keymap + (defun . udev-step-at-point) + (defun . udev-rerun-this-step) + (defun . udev-continue-from-this-step) + (defun . udev-goto-this-step-source) + (defun . udev-call-this-step) + (defun . udev-call-next-step) + udev-orig-sentinel + (defun . udev-compilation-sentinel) + (defun . udev-set-compilation-end-message) + udev-continue-on-error-function + (defun . udev-buffer-name) + udev-this-dir + (defun . udev-batch-compile) + (defun . udev-fetch-cvs-diff) + (defun . udev-cvs-diff-continue) + (defun . udev-check-cvs-diff) + (defun . udev-send-buffer-process) + (provide . udev)) + ("/home/hobbes/nxhtml/related/flymake-js.el" + (require . flymake) + flymake-allowed-js-file-name-masks flymake-js-err-line-pattern-re flymake-js-rhino-jar flymake-js-rhino-js flymake-js-engine + (defun . flymake-js-init) + (defun . flymake-js-load) + flymake-js-has-engine + (defun . flymake-js-has-engine) + (defun . flymake-js-turn-on) + flymake-js-on + (provide . flymake-js)) + ("/home/hobbes/nxhtml/related/flymake-php.el" + (require . flymake) + flymake-allowed-php-file-name-masks flymake-php-err-line-pattern-re + (defun . flymake-php-init) + flymake-php-has-engine + (defun . flymake-php-has-engine) + (defun . flymake-php-turn-on) + flymake-php-on + (defun . flymake-php-load) + (provide . flymake-php)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/flymake.elc" flymake-is-running flymake-timer flymake-last-change-time flymake-check-start-time flymake-check-was-interrupted flymake-err-info flymake-new-err-info + (defun . flymake-makehash) + (defun . flymake-float-time) + (defun . flymake-replace-regexp-in-string) + (defun . flymake-split-string) + (defun . flymake-get-temp-dir) + (defun . flymake-line-beginning-position) + (defun . flymake-line-end-position) + (defun . flymake-posn-at-point-as-event) + (defun . flymake-popup-menu) + (defun . flymake-make-emacs-menu) + flymake-log-level + (defun . flymake-log) + (defun . flymake-ins-after) + (defun . flymake-set-at) + flymake-processes flymake-output-residual flymake-allowed-file-name-masks + (defun . flymake-get-file-name-mode-and-masks) + (defun . flymake-can-syntax-check-file) + (defun . flymake-get-init-function) + (defun . flymake-get-cleanup-function) + (defun . flymake-get-real-file-name-function) + flymake-find-buildfile-cache + (defun . flymake-get-buildfile-from-cache) + (defun . flymake-add-buildfile-to-cache) + (defun . flymake-clear-buildfile-cache) + (defun . flymake-find-buildfile) + (defun . flymake-fix-file-name) + (defun . flymake-same-files) + flymake-master-file-dirs flymake-master-file-count-limit + (defun . flymake-find-possible-master-files) + (defun . flymake-master-file-compare) + flymake-check-file-limit + (defun . flymake-check-patch-master-file-buffer) + (defun . flymake-replace-region) + (defun . flymake-read-file-to-temp-buffer) + (defun . flymake-copy-buffer-to-temp-buffer) + (defun . flymake-check-include) + (defun . flymake-find-buffer-for-file) + (defun . flymake-create-master-file) + (defun . flymake-save-buffer-in-file) + (defun . flymake-save-string-to-file) + (defun . flymake-read-file-to-string) + (defun . flymake-process-filter) + (defun . flymake-process-sentinel) + (defun . flymake-post-syntax-check) + (defun . flymake-parse-output-and-residual) + (defun . flymake-parse-residual) + (defun . flymake-er-make-er) + (defun . flymake-er-get-line) + (defun . flymake-er-get-line-err-info-list) + (defun . flymake-ler-file) + (defun . flymake-ler-line) + (defun . flymake-ler-type) + (defun . flymake-ler-text) + (defun . flymake-ler-full-file) + (defun . flymake-ler-p) + (defun . copy-flymake-ler) + (defun . flymake-ler-make-ler) + (defun . flymake-ler-set-file) + (defun . flymake-ler-set-full-file) + (defun . flymake-ler-set-line) + (defun . flymake-get-line-err-count) + (defun . flymake-get-err-count) + (defun . flymake-fix-line-numbers) + (defun . flymake-highlight-err-lines) + (defun . flymake-overlay-p) + (defun . flymake-make-overlay) + (defun . flymake-delete-own-overlays) + (defun . flymake-region-has-flymake-overlays) + (defface . flymake-errline) + (defface . flymake-warnline) + (defun . flymake-highlight-line) + (defun . flymake-parse-err-lines) + (defun . flymake-split-output) + (defun . flymake-reformat-err-line-patterns-from-compile-el) + (require . compile) + flymake-err-line-patterns + (defun . flymake-parse-line) + (defun . flymake-find-err-info) + (defun . flymake-line-err-info-is-less-or-equal) + (defun . flymake-add-line-err-info) + (defun . flymake-add-err-info) + (defun . flymake-get-project-include-dirs-imp) + flymake-get-project-include-dirs-function + (defun . flymake-get-project-include-dirs) + (defun . flymake-get-system-include-dirs) + flymake-project-include-dirs-cache + (defun . flymake-get-project-include-dirs-from-cache) + (defun . flymake-add-project-include-dirs-to-cache) + (defun . flymake-clear-project-include-dirs-cache) + (defun . flymake-get-include-dirs) + (defun . flymake-safe-delete-file) + (defun . flymake-safe-delete-directory) + flymake-compilation-prevents-syntax-check + (defun . flymake-start-syntax-check) + (defun . flymake-start-syntax-check-process) + (defun . flymake-kill-process) + (defun . flymake-stop-all-syntax-checks) + (defun . flymake-compilation-is-running) + (defun . flymake-compile) + flymake-no-changes-timeout + (defun . flymake-on-timer-event) + (defun . flymake-current-line-no) + (defun . flymake-count-lines) + (defun . flymake-display-err-menu-for-current-line) + (defun . flymake-make-err-menu-data) + (defun . flymake-goto-file-and-line) + flymake-mode-line flymake-mode-line-e-w flymake-mode-line-status + (defun . flymake-report-status) + (defun . flymake-display-warning) + flymake-gui-warnings-enabled + (defun . flymake-report-fatal-status) + flymake-start-syntax-check-on-find-file flymake-mode + (t . flymake-mode) + (defun . flymake-mode) + (t . flymake-mode-on) + (defun . flymake-mode-on) + (t . flymake-mode-off) + (defun . flymake-mode-off) + flymake-start-syntax-check-on-newline + (defun . flymake-after-change-function) + (defun . flymake-after-save-hook) + (defun . flymake-kill-buffer-hook) + (defun . flymake-find-file-hook) + (defun . flymake-get-first-err-line-no) + (defun . flymake-get-last-err-line-no) + (defun . flymake-get-next-err-line-no) + (defun . flymake-get-prev-err-line-no) + (defun . flymake-skip-whitespace) + (defun . flymake-goto-line) + (defun . flymake-goto-next-error) + (defun . flymake-goto-prev-error) + (defun . flymake-patch-err-text) + (defun . flymake-create-temp-inplace) + (defun . flymake-create-temp-with-folder-structure) + (defun . flymake-delete-temp-directory) + flymake-temp-source-file-name flymake-master-file-name flymake-temp-master-file-name flymake-base-dir + (defun . flymake-init-create-temp-buffer-copy) + (defun . flymake-simple-cleanup) + (defun . flymake-get-real-file-name) + (defun . flymake-get-full-patched-file-name) + (defun . flymake-get-full-nonpatched-file-name) + (defun . flymake-init-find-buildfile-dir) + (defun . flymake-init-create-temp-source-and-master-buffer-copy) + (defun . flymake-master-cleanup) + (defun . flymake-get-syntax-check-program-args) + (defun . flymake-get-make-cmdline) + (defun . flymake-get-ant-cmdline) + (defun . flymake-simple-make-init-impl) + (defun . flymake-simple-make-init) + (defun . flymake-master-make-init) + (defun . flymake-find-make-buildfile) + (defun . flymake-master-make-header-init) + (defun . flymake-simple-make-java-init) + (defun . flymake-simple-ant-java-init) + (defun . flymake-simple-java-cleanup) + (defun . flymake-perl-init) + (defun . flymake-php-init) + (defun . flymake-get-tex-args) + (defun . flymake-simple-tex-init) + (defun . flymake-master-tex-init) + (defun . flymake-get-include-dirs-dot) + (defun . flymake-xml-init) + (provide . flymake)) + ("/home/hobbes/nxhtml/util/css-color.el" css-color:version + (require . cl) + (defun . css-color-turn-on-in-buffer) + css-color-mode-major-mode css-color-global-mode + (t . css-color-global-mode) + (defun . css-color-global-mode) + css-color-global-mode-buffers + (defun . css-color-global-mode-enable-in-buffers) + (defun . css-color-global-mode-check-buffers) + (defun . css-color-global-mode-cmhh) + css-color-hex-chars css-color-hex-re css-color-hsl-re css-color-rgb-re css-color-html-colors css-color-html-re css-color-color-re css-color-keywords css-color-mode + (t . css-color-mode) + (defun . css-color-mode) + (defun . css-color-font-lock-hook-fun) + css-color-map css-color-generic-map + (defun . css-color-pal-lumsig) + (defun . css-color-foreground-color) + (defun . css-color-normalize-hue) + (defun . css-color-within-bounds) + (defun . css-color-hex-to-rgb) + (defun . css-color-hex-to-hsv) + (defun . css-color-rgb-to-hex) + (defun . css-color-rgb-to-hsv) + (defun . css-color-rgb-to-hsl) + (defun . css-color-hsv-to-hsl) + (defun . css-color-hsv-to-hex) + (defun . css-color-hsv-to-rgb) + (defun . css-color-hsv-to-prop-hexstring) + (defun . css-color-hsl-to-rgb-fractions) + (defun . css-color-hsl-to-rgb) + (defun . css-color-hsl-to-hex) + (defun . css-color-hue-to-rgb) + (defun . css-color-parse-hsl) + (defun . css-color-inchue) + (defun . css-color-incsat) + (defun . css-color-incval) + (defun . css-color-hexval-beginning) + (defun . css-color-replcolor-at-p) + (defun . css-color-get-color-at-point) + (defun . css-color-adj-hue-at-p) + (defun . css-color-adj-saturation-at-p) + (defun . css-color-adj-value-at-p) + (defun . css-color-what-channel) + (defun . css-color-adjust-hex-at-p) + (defun . css-color-up) + (defun . css-color-down) + (defun . css-color-hue-up) + (defun . css-color-hue-down) + (defun . css-color-saturation-up) + (defun . css-color-saturation-down) + (defun . css-color-value-up) + (defun . css-color-value-down) + (defun . css-color-num-up) + (defun . css-color-num-down) + (defun . css-color-beginning-of-color) + (defun . css-color-end-of-color) + (defun . css-color-color-info) + css-color-type-circle + (defun . css-color-next-type) + (defun . css-color-cycle-type) + (defun . css-color-string-hex-to-hsl) + (defun . css-color-string-hsl-to-rgb) + (defun . css-color-string-rgb-to-name) + (defun . css-color-string-name-to-hex) + (defun . css-color-string-rgb-to-hex) + (defun . css-color-string-hsl-to-hex) + (defun . css-color-next-channel) + (defun . css-color-hexify-anystring) + (defun . css-color-toggle-percentage) + css-color-fg-history css-color-bg-history + (defun . css-color-test) + (defun . css-color-run-tests) + (provide . css-color)) + ("/home/hobbes/nxhtml/nxhtml/nxhtml-mode.el" + (require . mumamo) + (require . cl) + (require . appmenu-fold) + (require . fold-dwim) + (require . typesetter) + (require . button) + (require . loadhist) + (require . nxml-mode) + (require . rngalt) + (require . url-parse) + (require . url-expand) + (require . popcmp) + (require . html-imenu) + (require . tidy-xhtml) + (require . html-quote) + (defun . nxhtml-version) + (defun . nxhtml-setup-for-fold-dwim) + (defun . nxhtml-outline-level) + (defun . nxhtml-hs-forward-element) + nxhtml-use-imenu nxhtml-default-encoding + (defun . nxhtml-insert-empty-frames-page) + (defun . nxhtml-insert-empty-page) + (defun . nxhtml-empty-page-completion) + nxhtml-mode-hook + (defun . nxhtml-help) + nxhtml-current-validation-header tidy-menu-symbol + (defun . tidy-menu-symbol) + (defun . nxhtml-change-mode) + nxhtml-heading-element-name-regexp nxhtml-mode-map nxhtml-mode-syntax-table nxhtml-mode-abbrev-table nxhtml-mode-abbrev-table + (t . nxhtml-mode) + (defun . nxhtml-mode) + (defun . nxhtml-quote-html) + nxhtml-single-tags + (defun . nxthml-is-single-tag) + nxhtml-help-attribute-name nxhtml-help-attribute-name-tag nxhtml-help-tag + (t . nxhtml-short-tag-help) + (defun . nxhtml-short-tag-help) + nxhtml-no-single-tags nxhtml-no-end-tags nxhtml-predicate-error + (defun . nxhtml-find-ids) + (defun . nxhtml-read-url) + (defun . nxhtml-read-url-type) + nxhtml-read-url-history nxhtml-read-web-url-history nxhtml-read-mail-url-history nxhtml-in-xml-attribute-value-regex + (defun . nxhtml-mailto-predicate) + nxhtml-image-completion-pattern + (defun . nxhtml-image-url-predicate) + nxhtml-css-completion-pattern + (defun . nxhtml-css-url-predicate) + nxhtml-script-completion-pattern + (defun . nxhtml-script-url-predicate) + (defun . nxhtml-coding-systems-complete) + nxhtml-in-proc-instr-back-regex nxhtml-in-proc-instr-forw-regex rngalt-in-pre-attribute-value-regex + (defun . nxhtml-check-where) + nxhtml-tag-sets nxhtml-attr-sets + (defun . nxhtml-complete-last-try) + (defun . nxhtml-img-tag-do-also) + (defun . nxhtml-redisplay-complete) + (defun . nxhtml-read-from-minibuffer) + (defun . nxhtml-meta-tag-do-also) + (defun . nxhtml-style-tag-do-also) + (defun . nxhtml-script-tag-do-also) + (defun . nxhtml-link-tag-do-also) + (defun . nxhtml-input-tag-do-also) + (defun . nxhtml-do-also-value) + (defun . nxhtml-form-tag-do-also) + nxhtml-complete-tag-do-also + (defun . nxhtml-complete-tag-do-also) + (defun . nxhtml-turn-onoff-tag-do-also) + nxhtml-tag-do-also + (defun . nxhtml-tag-do-also-toggle) + (defun . nxhtml-check-tag-do-also) + nxhtml-validation-header-mode + (t . nxhtml-validation-header-mode) + (defun . nxhtml-validation-header-mode) + (defun . nxhtml-can-insert-page-here) + (defun . nxhtml-complete-first-try) + (defun . nxhtml-completing-read-tag) + (defun . nxhtml-add-required-to-attr-set) + (defun . nxhtml-get-tag-specific-attr-help) + nxhtml-in-start-tag-regex + (defun . nxhtml-completing-read-attribute-name) + (defun . nxhtml-completing-read-attribute-value) + (defun . nxhtml-read-link-type) + (defun . nxhtml-read-link-media) + (defun . nxhtml-read-link-rel) + (defun . nxhtml-read-meta-name) + (defun . nxhtml-read-meta-content) + (defun . nxhtml-read-meta-scheme) + (defun . nxhtml-read-meta-http-equiv) + nxhtml-validation-headers nxhtml-default-validation-header + (defun . nxhtml-must-have-validation-headers) + nxhtml-set-validation-header-hist nxhtml-guess-validation-header-alist + (defun . nxhtml-guess-validation-header) + (defun . nxhtml-open-dir-saved-validation-headers) + (defun . nxhtml-get-saved-validation-header) + (defun . nxhtml-remove-saved-validation-header) + (defun . nxhtml-save-validation-header) + (defun . nxhtml-update-saved-validation-header) + (defun . nxhtml-get-default-validation-header) + (defun . nxhtml-set-validation-header) + (defun . nxhtml-apply-validation-header) + (defun . nxhtml-update-validation-header) + (defun . nxhtml-vhm-change-major) + (defun . nxhtml-recheck-validation-header) + (defun . nxhtml-validation-header-empty) + (defun . nxhtml-turn-on-validation-header-mode) + (defun . nxhtml-vhm-mumamo-change-major) + (defun . nxhtml-vhm-mumamo-after-change-major) + nxhtml-validation-headers-check nxhtml-validation-header-mumamo-modes + (defun . nxhtml-add-validation-header-if-mumamo) + nxhtml-validation-header-if-mumamo + (defun . nxhtml-validation-header-if-mumamo-toggle) + (defun . nxhtml-warnings-are-visible) + nxhtml-old-rng-error-face + (defun . nxhtml-toggle-visible-warnings) + nxml-untag-select + (defun . nxml-untag-element) + (defun . nxhtml-rollover-insert-2v) + (provide . nxhtml-mode)) + ("/home/hobbes/nxhtml/nxhtml/html-quote.el" html-quote-html + (defun . html-quote-html-char) + (defun . html-quote-html-string) + (provide . html-quote)) + ("/home/hobbes/nxhtml/nxhtml/tidy-xhtml.el" tidy-xhtml:version + (require . cl) + (require . ediff) + (require . mumamo) + (require . html-site) + (require . easymenu) + (require . compile) + (require . cus-edit) + (require . help-mode) + (defun . tidy-xemacs-p) + (defun . tidy-windows-p) + (defun . tidy-x-event-function) + (defun . tidy-x-event-object) + (defun . tidy-x-find-menu-item) + (defun . tidy-x-get-popup-menu-response) + (defun . tidy-x-make-event) + (defun . tidy-x-misc-user-event-p) + tidy-warnings tidy-errors tidy-message tidy-batch-last-file tidy-default-config-file tidy-config-file-parsed tidy-config-file tidy-shell-program tidy-temp-directory tidy-menu-lock tidy-menu-x-position tidy-debug + (defun . tidy-toggle-debug) + tidy-options-alist + (defun . tidy-build-options-alist) + tidy-xhtml-values + (defun . tidy-xhtml-options-ok) + (defun . tidy-show-xhtml-options) + (defun . tidy-set-xhtml-options) + current-menubar + (defun . tidy-menu-position) + (defun . tidy-menu-lock) + (defun . tidy-menu-lookup) + tidy-menu tidy-menu-position tidy-menu-state + (defun . tidy-menu-position) + (defun . tidy-menu-lock) + (defun . tidy-menu-lookup) + (defun . tidy-set) + (defun . tidy-boolean-entry) + (defun . tidy-list-entry) + (defun . tidy-set-string) + (defun . tidy-set-integer) + (defun . tidy-string-entry) + (defun . tidy-integer-entry) + (defun . tidy-exe-found) + tidy-top-menu tidy-newline-menu tidy-doctype-menu tidy-emacs-encoding-lbl + (defun . tidy-create-encoding-menu) + tidy-output-encoding-menu tidy-menu-symbol + (t . tidy-build-menu) + (defun . tidy-build-menu) + (defun . event-point) + (defun . tidy-describe-this-option-mouse) + (defun . tidy-describe-this-option) + (defun . tidy-quit-describe-options) + (defun . tidy-current-line) + (defun . tidy-describe-options) + (defun . tidy-parse-config-file) + (defun . tidy-save-settings) + tidy-markup + (defun . tidy-set-buffer-unmodified) + tidy-encodings-mime-charset-list + (defun . tidy-get-buffer-encoding) + (defun . tidy-get-tidy-encoding) + (defun . tidy-temp-config-file) + tidy-output-buf-name tidy-tidied-buffer + (defun . tidy-check-is-tidied) + tidy-control-buffer-name + (defun . tidy-buffer) + (defun . tidy-after-ediff) + (defun . tidy-ediff-buffers) + (defun . tidy-remove-ctrl-m) + tidy-html-files-re + (defun . tidy-is-html-file) + (defun . tidy-contains) + tidy-tree-files + (defun . tidy-tree-next) + (defun . tidy-tree) + (defun . tidy-html-site) + (defun . tidy-batch-sentinel) + (defun . tidy-batch-output-filter) + (defun . tidy-batch) + (defun . wab-compilation-button-at) + (defun . wab-click) + wab-errors-supress + (defun . wab-fb-errmsg) + (defun . wab-fb-helper) + wab-button-list + (defun . wab-fb) + (defun . wab-backward) + (defun . wab-forward) + wab-compilation-mode-map wab-compilation-mode-syntax-table wab-compilation-mode-abbrev-table wab-compilation-mode-abbrev-table + (defun . wab-compilation-mode) + tidy-menu-mode-map tidy-menu-mode + (defun . tidy-menu-mode) + (provide . tidy-xhtml)) + ("/usr/share/emacs/23.0.93/lisp/ediff.elc" ediff-version ediff-date + (provide . ediff) + (require . ediff-init) + (require . ediff-mult) + ediff-use-last-dir ediff-last-dir-A ediff-last-dir-B ediff-last-dir-C ediff-last-dir-ancestor ediff-last-merge-autostore-dir + (defun . ediff-set-read-only-in-buf-A) + (defun . ediff-get-default-file-name) + (t . ediff-files) + (defun . ediff-files) + (t . ediff-files3) + (defun . ediff-files3) + (defun . ediff3) + (defun . ediff-find-file) + (defun . ediff-files-internal) + (defun . ediff) + (t . ediff-backup) + (defun . ediff-backup) + (t . ediff-buffers) + (defun . ediff-buffers) + (defun . ebuffers) + (t . ediff-buffers3) + (defun . ediff-buffers3) + (defun . ebuffers3) + (defun . ediff-buffers-internal) + (defun . ediff-get-default-directory-name) + (t . ediff-directories) + (defun . ediff-directories) + (defun . edirs) + (t . ediff-directory-revisions) + (defun . ediff-directory-revisions) + (defun . edir-revisions) + (t . ediff-directories3) + (defun . ediff-directories3) + (defun . edirs3) + (t . ediff-merge-directories) + (defun . ediff-merge-directories) + (defun . edirs-merge) + (t . ediff-merge-directories-with-ancestor) + (defun . ediff-merge-directories-with-ancestor) + (t . ediff-merge-directory-revisions) + (defun . ediff-merge-directory-revisions) + (defun . edir-merge-revisions) + (t . ediff-merge-directory-revisions-with-ancestor) + (defun . ediff-merge-directory-revisions-with-ancestor) + (defun . edir-merge-revisions-with-ancestor) + (defun . edirs-merge-with-ancestor) + (defun . ediff-directories-internal) + (defun . ediff-directory-revisions-internal) + (t . ediff-windows-wordwise) + (defun . ediff-windows-wordwise) + (t . ediff-windows-linewise) + (defun . ediff-windows-linewise) + (defun . ediff-windows) + (t . ediff-regions-wordwise) + (defun . ediff-regions-wordwise) + (t . ediff-regions-linewise) + (defun . ediff-regions-linewise) + (defun . ediff-regions-internal) + (defun . ediff-merge) + (defun . ediff-merge-on-startup) + (t . ediff-merge-files) + (defun . ediff-merge-files) + (t . ediff-merge-files-with-ancestor) + (defun . ediff-merge-files-with-ancestor) + (defun . ediff-merge-with-ancestor) + (t . ediff-merge-buffers) + (defun . ediff-merge-buffers) + (t . ediff-merge-buffers-with-ancestor) + (defun . ediff-merge-buffers-with-ancestor) + (t . ediff-merge-revisions) + (defun . ediff-merge-revisions) + (t . ediff-merge-revisions-with-ancestor) + (defun . ediff-merge-revisions-with-ancestor) + (t . ediff-patch-file) + (defun . ediff-patch-file) + (t . ediff-patch-buffer) + (defun . ediff-patch-buffer) + (defun . epatch) + (defun . epatch-buffer) + (t . ediff-revision) + (defun . ediff-revision) + (defun . erevision) + (defun . ediff-load-version-control) + (t . ediff-version) + (defun . ediff-version) + (t . ediff-documentation) + (defun . ediff-documentation) + (require . ediff-util)) + ("/usr/share/emacs/23.0.93/lisp/ediff-util.elc" + (provide . ediff-util) + ediff-after-quit-hook-internal + (require . ediff-init) + (require . ediff-help) + (require . ediff-mult) + (require . ediff-wind) + (require . ediff-diff) + (require . ediff-merg) + (defun . ediff-mode) + ediff-mode-map + (defun . ediff-set-keys) + (defun . ediff-reload-keymap) + (defun . ediff-setup-keymap) + (defun . ediff-setup) + (defun . ediff-setup-control-buffer) + (defun . ediff-arrange-autosave-in-merge-jobs) + (defun . ediff-update-diffs) + (defun . ediff-revert-buffers-then-recompute-diffs) + (defun . ediff-recenter) + (defun . ediff-recenter-one-window) + (defun . ediff-recenter-ancestor) + (defun . ediff-toggle-split) + (defun . ediff-toggle-hilit) + (defun . ediff-toggle-autorefine) + (defun . ediff-show-ancestor) + (defun . ediff-make-or-kill-fine-diffs) + (defun . ediff-toggle-help) + (defun . ediff-toggle-read-only) + (defun . ediff-maybe-checkout) + (defun . ediff-file-checked-out-p) + (defun . ediff-file-checked-in-p) + (defun . ediff-file-compressed-p) + (defun . ediff-swap-buffers) + (defun . ediff-toggle-wide-display) + (t . ediff-toggle-multiframe) + (defun . ediff-toggle-multiframe) + (t . ediff-toggle-use-toolbar) + (defun . ediff-toggle-use-toolbar) + (defun . ediff-kill-bottom-toolbar) + (defun . ediff-make-bottom-toolbar) + (defun . ediff-toggle-show-clashes-only) + (defun . ediff-toggle-skip-changed-regions) + (defun . ediff-toggle-narrow-region) + (defun . ediff-visible-region) + (defun . ediff-operate-on-windows) + (defun . ediff-scroll-vertically) + (defun . ediff-scroll-horizontally) + (defun . ediff-position-region) + (defun . ediff-get-lines-to-region-end) + (defun . ediff-get-lines-to-region-start) + (defun . ediff-get-region-size-coefficient) + (defun . ediff-next-difference) + (defun . ediff-previous-difference) + (defun . ediff-jump-to-difference) + (defun . ediff-jump-to-difference-at-point) + (defun . ediff-diff-at-point) + (defun . ediff-diff-to-diff) + (defun . ediff-copy-A-to-B) + (defun . ediff-copy-B-to-A) + (defun . ediff-copy-A-to-C) + (defun . ediff-copy-B-to-C) + (defun . ediff-copy-C-to-B) + (defun . ediff-copy-C-to-A) + (defun . ediff-copy-diff) + (defun . ediff-save-diff-region) + (defun . ediff-test-save-region) + (defun . ediff-pop-diff) + (defun . ediff-restore-diff) + (defun . ediff-restore-diff-in-merge-buffer) + (defun . ediff-toggle-regexp-match) + (defun . ediff-toggle-skip-similar) + (defun . ediff-focus-on-regexp-matches) + (defun . ediff-hide-regexp-matches) + (defun . ediff-quit) + (defun . ediff-really-quit) + (defun . ediff-good-frame-under-mouse) + (defun . ediff-delete-temp-files) + (defun . ediff-cleanup-mess) + (defun . ediff-janitor) + (defun . ediff-dispose-of-variant-according-to-user) + (defun . ediff-maybe-save-and-delete-merge) + (defun . ediff-write-merge-buffer-and-maybe-kill) + (defun . ediff-default-suspend-function) + (defun . ediff-suspend) + (defun . ediff-status-info) + (defun . ediff-select-difference) + (defun . ediff-unselect-difference) + (defun . ediff-unselect-and-select-difference) + (defun . ediff-highlight-diff-in-one-buffer) + (defun . ediff-unhighlight-diff-in-one-buffer) + (defun . ediff-unhighlight-diffs-totally-in-one-buffer) + (defun . ediff-highlight-diff) + (defun . ediff-unhighlight-diff) + (defun . ediff-unhighlight-diffs-totally) + (defun . ediff-read-file-name) + (defun . ediff-make-temp-file) + (defun . ediff-make-empty-tmp-file) + (defun . ediff-verify-file-buffer) + (defun . ediff-verify-file-merge-buffer) + (defun . ediff-filename-magic-p) + (defun . ediff-save-buffer) + (defun . ediff-clone-buffer-for-region-comparison) + (defun . ediff-clone-buffer-for-window-comparison) + (defun . ediff-clone-buffer-for-current-diff-comparison) + (defun . ediff-make-cloned-buffer) + (defun . ediff-make-indirect-buffer) + (defun . ediff-compute-custom-diffs-maybe) + (defun . ediff-show-diff-output) + (defun . ediff-inferior-compare-regions) + (defun . ediff-remove-flags-from-buffer) + (defun . ediff-place-flags-in-buffer) + (defun . ediff-place-flags-in-buffer1) + (defun . ediff-empty-diff-region-p) + (defun . ediff-whitespace-diff-region-p) + (defun . ediff-get-region-contents) + (defun . ediff-get-diff-posn) + (defun . ediff-restore-highlighting) + (defun . ediff-clear-diff-vector) + (defun . ediff-make-bullet-proof-overlay) + (defun . ediff-make-current-diff-overlay) + (defun . ediff-other-buffer) + (defun . ediff-get-selected-buffers) + (defun . ediff-unique-buffer-name) + (defun . ediff-submit-report) + (defun . ediff-choose-syntax-table) + (defun . ediff-deactivate-mark) + (defun . ediff-activate-mark) + (defun . ediff-nuke-selective-display) + (defun . ediff-save-variables) + (defun . ediff-restore-variables) + (defun . ediff-change-saved-variable) + (defun . ediff-save-protected-variables) + (defun . ediff-restore-protected-variables) + (defun . ediff-save-buffer-in-file) + ediff-command-begin-time + (defun . ediff-calc-command-time) + (defun . ediff-save-time) + (defun . ediff-profile) + (defun . ediff-print-diff-vector) + (defun . ediff-debug-info) + (defun . ediff-member) + (defun . ediff-format-bindings-of) + (defun . ediff-intersection) + (defun . ediff-union) + (defun . ediff-set-difference) + (defun . ediff-add-to-history) + (defun . ediff-copy-list)) + ("/usr/share/emacs/23.0.93/lisp/ediff-merg.elc" + (require . ediff-init) + ediff-quit-merge-hook ediff-default-variant ediff-combination-pattern ediff-show-clashes-only ediff-skip-merge-regions-that-differ-from-default + (defun . ediff-merge-region-is-non-clash) + (defun . ediff-merge-region-is-non-clash-to-skip) + (defun . ediff-skip-merge-region-if-changed-from-default-p) + (defun . ediff-get-combined-region) + (defun . ediff-set-state-of-all-diffs-in-all-buffers) + (defun . ediff-set-state-of-diff-in-all-buffers) + (defun . ediff-set-merge-mode) + (defun . ediff-do-merge) + (defun . ediff-re-merge) + (defun . ediff-shrink-window-C) + (defun . ediff-combine-diffs) + (defun . ediff-looks-like-combined-merge) + (defun . ediff-merge-changed-from-default-p) + (provide . ediff-merg)) + ("/usr/share/emacs/23.0.93/lisp/ediff-diff.elc" + (provide . ediff-diff) + (require . ediff-init) + ediff-diff-program ediff-diff3-program ediff-shell ediff-cmp-program ediff-cmp-options + (defun . ediff-set-diff-options) + ediff-diff-options ediff-ignore-case ediff-ignore-case-option ediff-ignore-case-option3 ediff-actual-diff-options ediff-custom-diff-program ediff-custom-diff-options ediff-match-diff3-line ediff-diff3-options ediff-actual-diff3-options ediff-diff3-ok-lines-regexp ediff-diff-status ediff-auto-refine ediff-ignore-similar-regions ediff-auto-refine-limit ediff-diff-ok-lines-regexp ediff-match-diff-line ediff-setup-diff-regions-function + (defun . ediff-setup-diff-regions) + (defun . ediff-make-diff2-buffer) + (defun . ediff-setup-fine-diff-regions) + (defun . ediff-prepare-error-list) + (defun . ediff-extract-diffs) + (defun . ediff-convert-diffs-to-overlays) + (defun . ediff-set-diff-overlays-in-one-buffer) + (defun . ediff-make-fine-diffs) + (defun . ediff-install-fine-diff-if-necessary) + (defun . ediff-set-fine-diff-properties) + (defun . ediff-set-fine-diff-properties-in-one-buffer) + (defun . ediff-set-fine-overlays-for-combined-merge) + (defun . ediff-set-fine-overlays-in-one-buffer) + (defun . ediff-convert-fine-diffs-to-overlays) + (defun . ediff-get-diff3-group) + (defun . ediff-extract-diffs3) + (defun . ediff-setup-diff-regions3) + (defun . ediff-exec-process) + (defun . ediff-process-filter) + (defun . ediff-process-sentinel) + ediff-forward-word-function ediff-whitespace ediff-word-1 ediff-word-2 ediff-word-3 ediff-word-4 + (defun . ediff-forward-word) + (defun . ediff-wordify) + (defun . ediff-copy-to-buffer) + (defun . ediff-goto-word) + (defun . ediff-same-file-contents) + (defun . ediff-same-contents) + (defun . ediff-same-file-contents-lists) + (defun . ediff-delete-all-matches) + (defun . ediff-set-actual-diff-options) + (defun . ediff-toggle-ignore-case)) + ("/usr/share/emacs/23.0.93/lisp/ediff-wind.elc" + (require . ediff-init) + (defun . ediff-compute-toolbar-width) + (defun . ediff-choose-window-setup-function-automatically) + ediff-window-setup-function ediff-multiframe ediff-merge-window-share ediff-control-window ediff-window-A ediff-window-B ediff-window-C ediff-window-config-saved ediff-window-alist ediff-window-alist ediff-split-window-function ediff-merge-split-window-function ediff-control-frame-parameters ediff-mouse-pixel-position ediff-mouse-pixel-threshold ediff-grab-mouse ediff-control-frame-position-function ediff-control-frame-upward-shift ediff-narrow-control-frame-leftward-shift ediff-wide-control-frame-rightward-shift ediff-wide-display-p ediff-wide-display-orig-parameters ediff-wide-display-frame ediff-make-wide-display-function ediff-control-frame ediff-prefer-iconified-control-frame + (defun . ediff-get-window-by-clicking) + (defun . ediff-select-lowest-window) + (defun . ediff-setup-windows) + (defun . ediff-setup-windows-plain) + (defun . ediff-setup-windows-plain-merge) + (defun . ediff-setup-windows-plain-compare) + (defun . ediff-setup-windows-multiframe) + (defun . ediff-setup-windows-multiframe-merge) + (defun . ediff-setup-windows-multiframe-compare) + (defun . ediff-skip-unsuitable-frames) + (defun . ediff-frame-has-dedicated-windows) + (defun . ediff-window-ok-for-display) + (defun . ediff-setup-control-frame) + (defun . ediff-destroy-control-frame) + (defun . ediff-make-frame-position) + (defun . ediff-xemacs-select-frame-hook) + (defun . ediff-make-wide-display) + (defun . ediff-refresh-mode-lines) + (defun . ediff-refresh-control-frame) + (defun . ediff-make-narrow-control-buffer-id) + (defun . ediff-make-base-title) + (defun . ediff-make-wide-control-buffer-id) + (defun . ediff-get-visible-buffer-window) + (defun . ediff-keep-window-config) + (provide . ediff-wind)) + ("/usr/share/emacs/23.0.93/lisp/ediff-help.elc" + (require . ediff-init) + ediff-long-help-message-head ediff-long-help-message-tail ediff-long-help-message-compare3 ediff-long-help-message-compare2 ediff-long-help-message-narrow2 ediff-long-help-message-word-mode ediff-long-help-message-merge ediff-long-help-message ediff-brief-message-string ediff-brief-help-message ediff-brief-help-message-function ediff-long-help-message-function ediff-use-long-help-message ediff-help-message ediff-help-region-map + (defun . ediff-set-help-overlays) + (defun . ediff-help-for-quick-help) + (defun . ediff-help-message-line-length) + (defun . ediff-indent-help-message) + (defun . ediff-set-help-message) + (t . ediff-customize) + (defun . ediff-customize) + (provide . ediff-help)) + ("/usr/share/emacs/23.0.93/lisp/ediff-mult.elc" + (provide . ediff-mult) + (require . ediff-init) + ediff-meta-buffer ediff-parent-meta-buffer ediff-registry-buffer ediff-meta-buffer-brief-message ediff-meta-buffer-brief-message ediff-meta-buffer-verbose-message ediff-meta-buffer-verbose-message ediff-meta-buffer-map ediff-dir-diffs-buffer-map ediff-meta-action-function ediff-meta-redraw-function ediff-session-action-function ediff-metajob-name ediff-meta-diff-buffer ediff-recurse-to-subdirectories ediff-filtering-regexp-history ediff-default-filtering-regexp ediff-meta-list ediff-meta-session-number ediff-dir-difference-list ediff-dir-diffs-buffer ediff-session-registry ediff-meta-truncate-filenames ediff-meta-mode-hook ediff-registry-setup-hook ediff-before-session-group-setup-hooks ediff-after-session-group-setup-hook ediff-quit-session-group-hook ediff-show-registry-hook ediff-show-session-group-hook ediff-meta-buffer-keymap-setup-hook ediff-meta-patchbufer + (defun . ediff-get-group-buffer) + (defun . ediff-get-group-regexp) + (defun . ediff-get-group-objA) + (defun . ediff-get-group-objB) + (defun . ediff-get-group-objC) + (defun . ediff-get-group-merge-autostore-dir) + (defun . ediff-get-group-comparison-func) + (defun . ediff-get-session-buffer) + (defun . ediff-get-session-status) + (defun . ediff-set-session-status) + (defun . ediff-get-session-objA) + (defun . ediff-get-session-objB) + (defun . ediff-get-session-objC) + (defun . ediff-get-session-objA-name) + (defun . ediff-get-session-objB-name) + (defun . ediff-get-session-objC-name) + (defun . ediff-get-file-eqstatus) + (defun . ediff-set-file-eqstatus) + (defun . ediff-make-new-meta-list-element) + (defun . ediff-make-new-meta-list-header) + (defun . ediff-get-session-activity-marker) + (defun . ediff-meta-session-p) + ediff-verbose-help-enabled + (defun . ediff-toggle-verbose-help-meta-buffer) + (defun . ediff-setup-meta-map) + (defun . ediff-meta-mode) + (defun . ediff-next-meta-item) + (defun . ediff-next-meta-item1) + (defun . ediff-previous-meta-item) + (defun . ediff-previous-meta-item1) + (defun . ediff-add-slash-if-directory) + (defun . ediff-toggle-filename-truncation) + ediff-membership-code1 ediff-membership-code2 ediff-membership-code3 ediff-product-of-memcodes + (defun . ediff-intersect-directories) + (defun . ediff-get-directory-files-under-revision) + (defun . ediff-prepare-meta-buffer) + (defun . ediff-insert-session-activity-marker-in-meta-buffer) + (defun . ediff-insert-session-status-in-meta-buffer) + (defun . ediff-replace-session-activity-marker-in-meta-buffer) + (defun . ediff-replace-session-status-in-meta-buffer) + (defun . ediff-insert-session-info-in-meta-buffer) + (defun . ediff-redraw-directory-group-buffer) + (defun . ediff-update-markers-in-dir-meta-buffer) + (defun . ediff-update-session-marker-in-dir-meta-buffer) + (defun . ediff-problematic-session-p) + (defun . ediff-meta-insert-file-info1) + ediff-months + (defun . ediff-fill-leading-zero) + (defun . ediff-format-date) + (defun . ediff-insert-dirs-in-meta-buffer) + (defun . ediff-draw-dir-diffs) + (defun . ediff-bury-dir-diffs-buffer) + (defun . ediff-show-dir-diffs) + (defun . ediff-dir-diff-copy-file) + (defun . ediff-up-meta-hierarchy) + (defun . ediff-redraw-registry-buffer) + (defun . ediff-set-meta-overlay) + (defun . ediff-mark-for-hiding-at-pos) + (defun . ediff-mark-session-for-hiding) + (defun . ediff-mark-for-operation-at-pos) + (defun . ediff-mark-session-for-operation) + (defun . ediff-hide-marked-sessions) + (defun . ediff-operate-on-marked-sessions) + (defun . ediff-append-custom-diff) + (defun . ediff-collect-custom-diffs) + (defun . ediff-meta-show-patch) + (defun . ediff-filegroup-action) + (defun . ediff-registry-action) + (defun . ediff-show-meta-buffer) + (defun . ediff-show-current-session-meta-buffer) + (defun . ediff-show-meta-buff-from-registry) + (t . ediff-show-registry) + (defun . ediff-show-registry) + (defun . eregistry) + (defun . ediff-update-meta-buffer) + (defun . ediff-update-registry) + (defun . ediff-cleanup-meta-buffer) + (defun . ediff-safe-to-quit) + (defun . ediff-quit-meta-buffer) + (defun . ediff-dispose-of-meta-buffer) + (defun . ediff-get-meta-info) + (defun . ediff-get-meta-overlay-at-pos) + (defun . ediff-get-session-number-at-pos) + (defun . ediff-next-meta-overlay-start) + (defun . ediff-previous-meta-overlay-start) + (defun . ediff-patch-file-form-meta) + (defun . ediff-unmark-all-for-operation) + (defun . ediff-unmark-all-for-hiding) + (defun . ediff-meta-mark-equal-files) + (defun . ediff-mark-if-equal)) + ("/usr/share/emacs/23.0.93/lisp/ediff-init.elc" ediff-force-faces + (defun . ediff-device-type) + (defun . ediff-window-display-p) + (defun . ediff-has-face-support-p) + (defun . ediff-has-toolbar-support-p) + (defun . ediff-has-gutter-support-p) + (defun . ediff-use-toolbar-p) + (defun . ediff-defvar-local) + ediff-buffer-A ediff-buffer-B ediff-buffer-C ediff-ancestor-buffer ediff-control-buffer ediff-temp-indirect-buffer ediff-buffer-alist ediff-buffer-alist + (defun . ediff-odd-p) + (defun . ediff-buffer-live-p) + (defun . ediff-get-buffer) + (defun . ediff-get-value-according-to-buffer-type) + (defun . ediff-char-to-buftype) + (defun . ediff-get-symbol-from-alist) + ediff-difference-vector-alist ediff-difference-vector-alist + (defun . ediff-get-difference) + (defun . ediff-no-fine-diffs-p) + (defun . ediff-get-diff-overlay-from-diff-record) + (defun . ediff-get-diff-overlay) + (defun . ediff-get-fine-diff-vector-from-diff-record) + (defun . ediff-set-fine-diff-vector) + (defun . ediff-get-state-of-diff) + (defun . ediff-set-state-of-diff) + (defun . ediff-get-state-of-merge) + (defun . ediff-set-state-of-merge) + (defun . ediff-get-state-of-ancestor) + (defun . ediff-mark-diff-as-space-only) + (defun . ediff-get-fine-diff-vector) + (defun . ediff-with-current-buffer) + (defun . ediff-multiframe-setup-p) + (defun . ediff-narrow-control-frame-p) + (defun . ediff-3way-comparison-job) + ediff-3way-comparison-job + (defun . ediff-merge-job) + ediff-merge-job + (defun . ediff-patch-job) + (defun . ediff-merge-with-ancestor-job) + ediff-merge-with-ancestor-job + (defun . ediff-3way-job) + ediff-3way-job + (defun . ediff-diff3-job) + ediff-diff3-job + (defun . ediff-windows-job) + ediff-windows-job + (defun . ediff-word-mode-job) + ediff-word-mode-job + (defun . ediff-narrow-job) + ediff-narrow-job + (defun . ediff-ancestor-metajob) + (defun . ediff-revision-metajob) + (defun . ediff-patch-metajob) + (defun . ediff-one-filegroup-metajob) + (defun . ediff-collect-diffs-metajob) + (defun . ediff-merge-metajob) + (defun . ediff-metajob3) + (defun . ediff-comparison-metajob3) + (defun . ediff-in-control-buffer-p) + (defun . ediff-barf-if-not-control-buffer) + ediff-before-setup-hook ediff-before-setup-windows-hook ediff-after-setup-windows-hook ediff-before-setup-control-frame-hook ediff-after-setup-control-frame-hook ediff-startup-hook ediff-select-hook ediff-unselect-hook ediff-prepare-buffer-hook ediff-load-hook ediff-mode-hook ediff-keymap-setup-hook ediff-display-help-hook ediff-suspend-hook ediff-quit-hook ediff-cleanup-hook ediff-KILLED-VITAL-BUFFER ediff-KILLED-VITAL-BUFFER ediff-NO-DIFFERENCES ediff-NO-DIFFERENCES ediff-BAD-DIFF-NUMBER ediff-BAD-DIFF-NUMBER ediff-BAD-INFO ediff-BAD-INFO ediff-skip-diff-region-function ediff-hide-regexp-matches-function ediff-focus-on-regexp-matches-function ediff-regexp-focus-A ediff-regexp-focus-B ediff-regexp-focus-C ediff-focus-regexp-connective ediff-regexp-hide-A ediff-regexp-hide-B ediff-regexp-hide-C ediff-hide-regexp-connective ediff-killed-diffs-alist ediff-syntax-table ediff-before-flag-bol ediff-after-flag-eol ediff-before-flag-mol ediff-after-flag-mol ediff-use-faces ediff-use-faces ediff-word-mode ediff-job-name ediff-narrow-bounds ediff-wide-bounds ediff-visible-bounds ediff-start-narrowed ediff-quit-widened ediff-keep-variants ediff-highlight-all-diffs ediff-highlight-all-diffs ediff-control-buffer-suffix ediff-control-buffer-number ediff-buffer-values-orig-A ediff-buffer-values-orig-B ediff-buffer-values-orig-C ediff-buffer-values-orig-Ancestor ediff-buffer-values-orig-alist ediff-buffer-values-orig-alist ediff-protected-variables ediff-protected-variables ediff-difference-vector-A ediff-difference-vector-B ediff-difference-vector-C ediff-difference-vector-Ancestor ediff-difference-vector-alist ediff-difference-vector-alist ediff-state-of-merge ediff-current-difference ediff-number-of-differences ediff-diff-buffer ediff-custom-diff-buffer ediff-fine-diff-buffer ediff-tmp-buffer ediff-msg-buffer ediff-error-buffer ediff-debug-buffer ediff-this-buffer-ediff-sessions ediff-disturbed-overlays ediff-shadow-overlay-priority ediff-version-control-package ediff-coding-system-for-read ediff-coding-system-for-write + (defun . ediff-read-event) + (defun . ediff-overlayp) + (defun . ediff-make-overlay) + (defun . ediff-delete-overlay) + (defun . ediff-check-version) + (defun . ediff-color-display-p) + ediff-highlighting-style + (defun . ediff-valid-color-p) + (defun . ediff-get-face) + (defun . ediff-display-pixel-width) + (defun . ediff-display-pixel-height) + ediff-current-diff-overlay-alist ediff-current-diff-overlay-alist ediff-current-diff-face-alist ediff-current-diff-face-alist + (defun . ediff-set-overlay-face) + (defun . ediff-region-help-echo) + (defun . ediff-set-face-pixmap) + (defun . ediff-hide-face) + (defface . ediff-current-diff-A) + ediff-current-diff-face-A + (defface . ediff-current-diff-B) + ediff-current-diff-face-B + (defface . ediff-current-diff-C) + ediff-current-diff-face-C + (defface . ediff-current-diff-Ancestor) + ediff-current-diff-face-Ancestor + (defface . ediff-fine-diff-A) + ediff-fine-diff-face-A + (defface . ediff-fine-diff-B) + ediff-fine-diff-face-B + (defface . ediff-fine-diff-C) + ediff-fine-diff-face-C + (defface . ediff-fine-diff-Ancestor) + ediff-fine-diff-face-Ancestor stipple-pixmap + (defface . ediff-even-diff-A) + ediff-even-diff-face-A + (defface . ediff-even-diff-B) + ediff-even-diff-face-B + (defface . ediff-even-diff-C) + ediff-even-diff-face-C + (defface . ediff-even-diff-Ancestor) + ediff-even-diff-face-Ancestor ediff-even-diff-face-alist ediff-even-diff-face-alist + (defface . ediff-odd-diff-A) + ediff-odd-diff-face-A + (defface . ediff-odd-diff-B) + ediff-odd-diff-face-B + (defface . ediff-odd-diff-C) + ediff-odd-diff-face-C + (defface . ediff-odd-diff-Ancestor) + ediff-odd-diff-face-Ancestor ediff-odd-diff-face-alist ediff-odd-diff-face-alist ediff-fine-diff-face-alist ediff-fine-diff-face-alist ediff-current-diff-overlay-A ediff-current-diff-overlay-B ediff-current-diff-overlay-C ediff-current-diff-overlay-Ancestor + (defun . ediff-highest-priority) + ediff-toggle-read-only-function ediff-make-buffers-readonly-at-startup ediff-verbose-p ediff-autostore-merges ediff-merge-store-file ediff-merge-filename-prefix ediff-no-emacs-help-in-control-buffer ediff-temp-file-prefix ediff-temp-file-mode ediff-metachars ediff-H-glyph ediff-temp-file-A ediff-temp-file-B ediff-temp-file-C + (defun . ediff-file-remote-p) + (defun . ediff-listable-file) + (defun . ediff-frame-unsplittable-p) + (defun . ediff-get-next-window) + (defun . ediff-kill-buffer-carefully) + (defun . ediff-background-face) + (defun . ediff-paint-background-regions-in-one-buffer) + (defun . ediff-paint-background-regions) + (defun . ediff-clear-fine-diff-vector) + (defun . ediff-clear-fine-differences-in-one-buffer) + (defun . ediff-clear-fine-differences) + (defun . ediff-mouse-event-p) + (defun . ediff-key-press-event-p) + (defun . ediff-event-point) + (defun . ediff-event-buffer) + (defun . ediff-event-key) + (defun . ediff-frame-iconified-p) + (defun . ediff-window-visible-p) + (defun . ediff-frame-char-width) + (defun . ediff-reset-mouse) + (defun . ediff-spy-after-mouse) + (defun . ediff-user-grabbed-mouse) + (defun . ediff-frame-char-height) + (defun . ediff-overlay-start) + (defun . ediff-overlay-end) + (defun . ediff-empty-overlay-p) + (defun . ediff-overlay-buffer) + (defun . ediff-overlay-get) + (defun . ediff-move-overlay) + (defun . ediff-overlay-put) + (defun . ediff-abbreviate-file-name) + (defun . ediff-strip-last-dir) + (defun . ediff-truncate-string-left) + (defun . ediff-nonempty-string-p) + (defun . ediff-abbrev-jobname) + (defun . ediff-strip-mode-line-format) + (defun . ediff-valid-difference-p) + (defun . ediff-show-all-diffs) + (defun . ediff-message-if-verbose) + (defun . ediff-file-attributes) + (defun . ediff-file-size) + (defun . ediff-file-modtime) + (defun . ediff-convert-standard-filename) + (defun . ediff-with-syntax-table) + (provide . ediff-init)) + ("/home/hobbes/nxhtml/nxhtml/html-imenu.el" html-imenu:version + (require . imenu) + html-imenu-title html-imenu-regexp + (defun . html-imenu-index) + (defun . html-imenu-setup) + (defun . html-imenu-update-menubar) + (defun . html-imenu-update-menubar-1) + (provide . html-imenu)) + ("/usr/share/emacs/23.0.93/lisp/imenu.elc" imenu-use-markers imenu-max-item-length imenu-auto-rescan imenu-auto-rescan-maxout imenu-always-use-completion-buffer-p imenu-use-popup-menu imenu-eager-completion-buffer imenu-after-jump-hook imenu-sort-function imenu-max-items imenu-space-replacement imenu-level-separator imenu-generic-expression imenu-create-index-function imenu-prev-index-position-function imenu-extract-index-name-function imenu-name-lookup-function imenu-default-goto-function + (defun . imenu--subalist-p) + (defun . imenu-progress-message) + (defun . imenu-example--name-and-position) + (defun . imenu-example--lisp-extract-index-name) + (defun . imenu-example--create-lisp-index) + imenu-example--function-name-regexp-c + (defun . imenu-example--create-c-index) + imenu--rescan-item imenu--rescan-item imenu--index-alist imenu--last-menubar-index-alist imenu--history-list + (defun . imenu--sort-by-name) + (defun . imenu--sort-by-position) + (defun . imenu--relative-position) + (defun . imenu--split) + (defun . imenu--split-menu) + (defun . imenu--split-submenus) + (defun . imenu--truncate-items) + (defun . imenu--make-index-alist) + (defun . imenu--cleanup) + (defun . imenu--create-keymap) + (defun . imenu--in-alist) + imenu-syntax-alist + (defun . imenu-default-create-index-function) + imenu-case-fold-search + (defun . imenu--generic-function) + (defun . imenu-find-default) + (defun . imenu--completion-buffer) + (defun . imenu--mouse-menu) + (defun . imenu-choose-buffer-index) + (t . imenu-add-to-menubar) + (defun . imenu-add-to-menubar) + (t . imenu-add-menubar-index) + (defun . imenu-add-menubar-index) + imenu-buffer-menubar imenu-menubar-modified-tick + (defun . imenu-update-menubar) + (defun . imenu--menubar-select) + (defun . imenu-default-goto-function) + (t . imenu) + (defun . imenu) + (provide . imenu)) + ("/home/hobbes/nxhtml/util/popcmp.el" + (require . ourcomments-util) + popcmp-popup-completion + (defun . popcmp-popup-completion-toggle) + popcmp-short-help-beside-alts + (defun . popcmp-short-help-beside-alts-toggle) + popcmp-group-alternatives + (defun . popcmp-group-alternatives-toggle) + (defun . popcmp-getsets) + (defun . popcmp-getset-alts) + popcmp-completing-with-help + (defun . popcmp-add-help) + (defun . popcmp-remove-help) + (defun . popcmp-completing-read-nopop) + (defun . popcmp-completing-read-pop) + (defun . popcmp-completing-read) + popcmp-mark-completing-ovl + (defun . popcmp-mark-completing) + (defun . popcmp-unmark-completing) + (provide . popcmp)) + ("/home/hobbes/nxhtml/nxhtml/rngalt.el" rngalt:version + (require . rng-valid) + (require . rng-nxml) + rngalt-complete-first-try rngalt-complete-last-try rngalt-completing-read-tag rngalt-completing-read-attribute-name rngalt-completing-read-attribute-value + (defun . rngalt-finish-element) + (defun . rngalt-finish-element-1) + (defun . rngalt-complete) + (defun . rngalt-validate) + rngalt-region-ovl rngalt-region-prepared + (defun . rngalt-complete-tag-region-prepare) + (defun . rngalt-complete-tag-region-cleanup) + (defun . rngalt-complete-tag-region-finish) + (defun . rngalt-complete-tag) + rngalt-complete-tag-hooks + (defun . rngalt-complete-attribute-name) + (defun . rngalt-complete-attribute-value) + (defun . rngalt-complete-before-point) + (defun . rngalt-get-missing-required-attr) + rngalt-validation-header rngalt-current-schema-file-name rngalt-validation-header-overlay rngalt-major-mode + (defun . rngalt-after-change-major) + rngalt-validation-header-keymap + (defun . rngalt-update-validation-header-overlay) + (defun . rngalt-update-validation-header-overlay-everywhere) + rngalt-display-validation-header + (defun . rngalt-display-validation-header-toggle) + rngalt-minimal-validation-header + (defun . rngalt-minimal-validation-header-toggle) + (defface . rngalt-validation-header-top) + (defface . rngalt-validation-header-bottom) + (require . bytecomp) + (defun . advice-compilation) + (t . rngalt-set-validation-header) + (defun . rngalt-set-validation-header) + (defun . rngalt-reapply-validation-header) + (defun . rngalt-get-validation-header-buffer) + (defun . rngalt-get-state-after) + (defun . rngalt-show-validation-header) + (defun . rngalt-update-validation-header-buffer) + (provide . rngalt)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-nxml.elc" + (require . easymenu) + (require . xmltok) + (require . nxml-util) + (require . nxml-ns) + (require . rng-match) + (require . rng-util) + (require . rng-valid) + (require . nxml-mode) + (require . rng-loc) + rng-nxml-auto-validate-flag rng-preferred-prefix-alist rng-complete-end-tags-after-< rng-nxml-easy-menu + (t . rng-nxml-mode-init) + (defun . rng-nxml-mode-init) + rng-tag-history rng-attribute-name-history rng-attribute-value-history rng-complete-target-names rng-complete-name-attribute-flag rng-complete-extra-strings + (defun . rng-complete) + rng-in-start-tag-name-regex rng-in-start-tag-name-regex + (defun . rng-complete-tag) + rng-in-end-tag-name-regex rng-in-end-tag-name-regex + (defun . rng-complete-end-tag) + rng-in-attribute-regex rng-in-attribute-regex rng-undeclared-prefixes + (defun . rng-complete-attribute-name) + rng-in-attribute-value-regex rng-in-attribute-value-regex + (defun . rng-complete-attribute-value) + (defun . rng-possible-namespace-uris) + rng-qname-regexp rng-qname-regexp + (defun . rng-qname-p) + (defun . rng-expand-qname) + (defun . rng-start-tag-expand-recover) + (defun . rng-split-qname) + (defun . rng-in-mixed-content-p) + (defun . rng-set-state-after) + (defun . rng-adjust-state-for-attribute) + (defun . rng-find-undeclared-prefixes) + (defun . rng-prune-attribute-at) + (defun . rng-adjust-state-for-attribute-value) + (defun . rng-complete-qname-function) + (defun . rng-generate-qname-list) + (defun . rng-get-preferred-unused-prefix) + (defun . rng-strings-to-completion-alist) + (provide . rng-nxml)) + ("/usr/share/emacs/23.0.93/lisp/loadhist.elc" + (defun . feature-symbols) + (defun . feature-file) + (defun . file-loadhist-lookup) + (defun . file-provides) + (defun . file-requires) + (defun . file-set-intersect) + (defun . file-dependents) + (defun . read-feature) + loadhist-hook-functions unload-feature-special-hooks unload-function-defs-list unload-hook-features-list + (t . unload-feature) + (defun . unload-feature) + (provide . loadhist)) + ("/home/hobbes/nxhtml/util/appmenu-fold.el" appmenu-fold:version + (require . fold-dwim) + (require . appmenu) + (defun . appmenu-fold-no-hs-minor-mode) + (defun . appmenu-fold-no-outline-minor-mode) + (defun . appmenu-fold-setup) + (provide . appmenu-fold)) + ("/home/hobbes/nxhtml/related/fold-dwim.el" fold-dwim:version + (require . outline) + (require . hideshow) + fold-dwim-outline-style-default fold-dwim-toggle-selective-display + (defun . fold-dwim-maybe-recenter) + (defun . fold-dwim-toggle-selective-display) + (defun . fold-dwim-hide-all) + (defun . fold-dwim-show-all) + (defun . fold-dwim-hide) + (defun . fold-dwim-show) + (defun . fold-dwim-toggle) + (defun . fold-dwim-auctex-env-or-macro) + (defun . fold-dwim-outline-invisible-p) + (defun . fold-dwim-outline-nested-p) + (provide . fold-dwim)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/hideshow.elc" hs-hide-comments-when-hiding-all hs-minor-mode-hook hs-isearch-open hs-special-modes-alist hs-hide-all-non-comment-function hs-allow-nesting hs-hide-hook hs-show-hook hs-set-up-overlay hs-minor-mode hs-minor-mode-map hs-minor-mode-menu + (defun . hs-minor-mode-menu) + 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 hs-headline + (defun . hs-discard-overlays) + (defun . hs-make-overlay) + (defun . hs-isearch-show) + (defun . hs-isearch-show-temporary) + (defun . hs-forward-sexp) + (defun . hs-hide-comment-region) + (defun . hs-hide-block-at-point) + (defun . hs-inside-comment-p) + (defun . hs-grok-mode-type) + (defun . hs-find-block-beginning) + (defun . hs-hide-level-recursive) + (defun . hs-life-goes-on) + (defun . hs-overlay-at) + (defun . hs-already-hidden-p) + (defun . hs-c-like-adjust-block-beginning) + (defun . hs-hide-all) + (defun . hs-show-all) + (defun . hs-hide-block) + (defun . hs-show-block) + (defun . hs-hide-level) + (defun . hs-toggle-hiding) + (defun . hs-mouse-toggle-hiding) + (defun . hs-hide-initial-comment-block) + hs-minor-mode + (t . hs-minor-mode) + (defun . hs-minor-mode) + (t . turn-off-hideshow) + (defun . turn-off-hideshow) + (provide . hideshow)) + ("/usr/share/emacs/23.0.93/lisp/outline.elc" outline-regexp outline-heading-end-regexp outline-mode-prefix-map outline-mode-menu-bar-map outline-minor-mode-menu-bar-map outline-mode-map outline-font-lock-keywords + (defface . outline-1) + (defface . outline-2) + (defface . outline-3) + (defface . outline-4) + (defface . outline-5) + (defface . outline-6) + (defface . outline-7) + (defface . outline-8) + outline-font-lock-faces + (defun . outline-font-lock-face) + outline-view-change-hook outline-mode-hook outline-blank-line outline-mode-map outline-mode-syntax-table outline-mode-abbrev-table outline-mode-abbrev-table + (t . outline-mode) + (defun . outline-mode) + outline-minor-mode-prefix outline-minor-mode + (t . outline-minor-mode) + (defun . outline-minor-mode) + outline-minor-mode-map outline-level outline-heading-alist + (defun . outline-level) + (defun . outline-next-preface) + (defun . outline-next-heading) + (defun . outline-previous-heading) + (defun . outline-invisible-p) + (defun . outline-visible) + (defun . outline-back-to-heading) + (defun . outline-on-heading-p) + (defun . outline-insert-heading) + (defun . outline-invent-heading) + (defun . outline-promote) + (defun . outline-demote) + (defun . outline-head-from-level) + (defun . outline-map-region) + (defun . outline-move-subtree-up) + (defun . outline-move-subtree-down) + (defun . outline-end-of-heading) + (defun . outline-next-visible-heading) + (defun . outline-previous-visible-heading) + (defun . outline-mark-subtree) + outline-isearch-open-invisible-function + (defun . outline-flag-region) + (defun . outline-reveal-toggle-invisible) + (defun . outline-isearch-open-invisible) + (defun . hide-entry) + (defun . show-entry) + (defun . hide-body) + (defun . hide-region-body) + (defun . show-all) + (defun . hide-subtree) + (defun . hide-leaves) + (defun . show-subtree) + (defun . outline-show-heading) + (defun . hide-sublevels) + (defun . hide-other) + (defun . outline-toggle-children) + (defun . outline-flag-subtree) + (defun . outline-end-of-subtree) + (defun . show-branches) + (defun . show-children) + (defun . outline-up-heading) + (defun . outline-forward-same-level) + (defun . outline-get-next-sibling) + (defun . outline-backward-same-level) + (defun . outline-get-last-sibling) + (defun . outline-headers-as-kill) + (provide . outline) + (provide . noutline)) + ("/home/hobbes/nxhtml/util/mumamo.el" mumamo:version + (require . cl) + (require . flyspell) + (require . mlinks) + (require . nxml-mode) + (require . rng-valid) + (require . sgml-mode) + msgtrc-buffer + (defun . msgtrc) + mumamo-message-file-buffer + (defun . mumamo-msgtrc-to-file) + (defun . mumamo-msgfntfy) + (defun . mumamo-msgindent) + mumamo-display-error-lwarn mumamo-display-error-stop + (defun . mumamo-message-with-face) + (defun . mumamo-show-report-message) + (defun . mumamo-display-error) + (defun . mumamo-debug-to-backtrace) + mumamo-use-condition-case mumamo-debugger + (defun . mumamo-condition-case) + mumamo-warned-once + (defun . mumamo-warn-once) + (defun . mumamo-add-help-tabs) + (defun . mumamo-insert-describe-button) + (defface . mumamo-border-face-in) + (defface . mumamo-border-face-out) + mumamo-set-major-mode-delay + (defface . mumamo-background-chunk-submode) + mumamo-background-chunk-major + (defface . mumamo-background-chunk-major) + mumamo-background-chunk-submode mumamo-background-colors + (defun . mumamo-background-color) + mumamo-chunk-coloring mumamo-submode-indent-offset mumamo-submode-indent-offset-0 mumamo-major-mode-indent-specials mumamo-check-chunk-major-same mumamo-major-modes + (defun . mumamo-jit-lock-function) + (defun . mumamo-jit-lock-register) + (defun . mumamo-jit-with-buffer-unmodified) + (defun . mumamo-with-buffer-prepared-for-jit-lock) + mumamo-find-chunks-timer mumamo-find-chunk-delay + (defun . mumamo-stop-find-chunks-timer) + (defun . mumamo-start-find-chunks-timer) + (defun . mumamo-find-chunks-in-timer) + mumamo-last-chunk mumamo-last-new-chunk mumamo-last-chunk-change-pos mumamo-old-chunks mumamo-find-chunk-is-active mumamo-use-new-chunks + (defun . mumamo-toggle-use-new-chunks) + mumamo-use-both-chunks + (defun . mumamo-toggle-use-both-chunks) + (defun . mumamo-make-old-chunks) + (defun . mumamo-make-new-chunks) + (defun . mumamo-toggle-and-normal-mode-and-what-at-cursor) + mumamo-find-chunks-level + (defun . mumamo-find-chunks) + (defun . mumamo-find-chunk-after-change) + (defun . mumamo-after-change) + (defun . mumamo-jit-lock-after-change) + (defun . mumamo-jit-lock-after-change-1) + (defun . mumamo-mark-chunk) + (defun . mumamo-save-buffer-state) + (t . mumamo-mark-for-refontification) + (defun . mumamo-mark-for-refontification) + mumamo-internal-major-modes-alist mumamo-ppss-last-chunk mumamo-ppss-last-major mumamo-major-mode-substitute + (defun . mumamo-get-major-mode-substitute) + (defun . mumamo-with-major-mode-setup) + (defun . mumamo-with-major-mode-fontification) + (defun . mumamo-with-major-mode-indentation) + (defun . mumamo-assert-fontified-t) + (defun . mumamo-do-fontify) + (defun . mumamo-do-unfontify) + (defun . mumamo-fontify-region-with) + (defun . mumamo-unfontify-region-with) + (defun . mumamo-unfontify-buffer) + (defun . mumamo-fontify-buffer) + (defun . mumamo-unfontify-chunk) + mumamo-just-changed-major + (defun . mumamo-fontify-region) + mumamo-dbg-pretend-fontified + (defun . mumamo-exc-mode) + (defun . mumamo-chunk-value-set-min) + (defun . mumamo-chunk-value-set-max) + (defun . mumamo-chunk-value-set-syntax-min) + (defun . mumamo-chunk-value-set-syntax-max) + (defun . mumamo-chunk-value-min) + (defun . mumamo-chunk-value-max) + (defun . mumamo-chunk-value-major) + (defun . mumamo-chunk-value-syntax-min) + (defun . mumamo-chunk-value-syntax-max) + (defun . mumamo-chunk-value-parseable-by) + (defun . mumamo-chunk-value-fw-exc-fun) + mumamo-chunks-to-remove + (defun . mumamo-flush-chunk-syntax) + (defun . mumamo-fontify-region-1) + (defun . mumamo-remove-old-overlays) + mumamo-known-buffer-local-fontifications mumamo-irrelevant-buffer-local-vars + (defun . mumamo-get-relevant-buffer-local-vars) + mumamo-major-modes-local-maps + (defun . mumamo-fetch-major-mode-setup) + (defun . mumamo-bad-mode) + (defun . mumamo-get-major-mode-setup) + (defun . mumamo-remove-chunk-overlays) + (defun . mumamo-remove-all-chunk-overlays) + (defun . mumamo-create-chunk-values-at) + (defun . mumamo-define-no-mode) + (defun . mumamo-major-mode-from-modespec) + (defun . mumamo-chunk-equal-chunk-values) + (defun . mumamo-create-chunk-from-chunk-values) + (defun . mumamo-create-chunk-at) + (defun . mumamo-get-existing-chunk-at) + (defun . mumamo-get-existing-new-chunk-at) + (defun . mumamo-get-chunk-save-buffer-state) + (defun . mumamo-chunk-major-mode) + (defun . mumamo-chunk-syntax-min) + (defun . mumamo-chunk-syntax-max) + (defun . mumamo-syntax-maybe-completable) + mumamo-current-chunk-family + (defun . mumamo-main-major-mode) + (defun . mumamo-chunk-start-fw-str) + (defun . mumamo-chunk-start-fw-re) + (defun . mumamo-chunk-start-fw-str-inc) + (defun . mumamo-chunk-start-bw-str) + (defun . mumamo-chunk-start-bw-re) + (defun . mumamo-chunk-start-bw-str-inc) + (defun . mumamo-chunk-end-fw-str) + (defun . mumamo-chunk-end-fw-re) + (defun . mumamo-chunk-end-fw-str-inc) + (defun . mumamo-chunk-end-bw-str) + (defun . mumamo-chunk-end-bw-re) + (defun . mumamo-chunk-end-bw-str-inc) + mumamo-string-syntax-table + (defun . mumamo-guess-in-string) + mumamo-find-possible-chunk-new + (defun . mumamo-find-possible-chunk) + (defun . mumamo-find-possible-chunk-new) + (defun . mumamo-find-possible-chunk-old) + (defun . temp-overlays-here) + (defun . temp-cursor-pos) + (defun . temp-test-new-create-chunk) + (defun . temp-create-last-chunk) + (defun . mumamo-delete-new-chunks) + (defun . mumamo-new-create-chunk) + (defun . mumamo-new-chunk-value-min) + (defun . mumamo-new-chunk-value-max) + (defun . mumamo-new-chunk-equal-chunk-values) + (defun . mumamo-find-next-chunk-values) + (defun . mumamo-valid-nxml-point) + (defun . mumamo-valid-nxml-chunk) + (defun . mumamo-end-chunk-is-valid) + (defun . mumamo-quick-static-chunk) + mumamo-unread-command-events-timer + (defun . mumamo-unread-command-events) + mumamo-idle-set-major-mode-timer + (defun . mumamotemp-pre-command) + (defun . mumamotemp-post-command) + (defun . mumamotemp-start) + (defun . mumamo-idle-set-major-mode) + (defun . mumamo-request-idle-set-major-mode) + mumamo-done-first-set-major mumamo-multi-major-mode mumamo-safe-commands-in-wrong-major + (defun . mumamo-set-major-pre-command) + (defun . mumamo-fetch-local-map) + (defun . mumamo-set-major-post-command) + (defun . mumamo-post-command-1) + (defun . mumamo-post-command) + mumamo-set-major-running + (defun . mumamo-change-major-function) + (defun . mumamo-derived-from-mode) + mumamo-test-add-hook mumamo-survive-hooks mumamo-survive + (defun . mumamo-make-variable-buffer-permanent) + mumamo-survive-done-by-me + (defun . mumamo-hook-p) + mumamo-major-mode mumamo-change-major-mode-no-nos mumamo-after-change-major-mode-no-nos mumamo-removed-from-hook + (defun . mumamo-remove-from-hook) + (defun . mumamo-addback-to-hooks) + (defun . mumamo-addback-to-hook) + mumamo-buffer-locals-dont-set + (defun . mumamo-save-most-buffer-locals) + mumamo-restore-most-buffer-locals-in-hook-major + (defun . mumamo-restore-most-buffer-locals-in-hook) + (defun . mumamo-restore-most-buffer-locals) + mumamo-buffer-locals-per-major + (defun . mumamo-get-hook-value) + (defun . mumamo-set-major) + (defun . mumamo-setup-local-fontification-vars) + (defun . mumamo-set-fontification-functions) + (defun . mumamo-initialize-state) + (defun . mumamo-turn-on-actions) + (defun . mumamo-turn-off-actions) + mumamo-turn-on-hook mumamo-change-major-mode-hook mumamo-after-change-major-mode-hook mumamo-defined-turn-on-functions + (defun . mumamo-describe-chunks) + (defun . mumamo-add-multi-keymap) + mumamo-map + (defun . define-mumamo-multi-major-mode) + (defun . mumamo-indent-line-function) + (defun . mumamo-indent-line-chunks) + (defun . mumamo-indent-line-function-1) + (defun . mumamo-indent-use-widen) + (defun . mumamo-indent-special-or-default) + (defun . mumamo-call-indent-line) + (defun . mumamo-indent-region-function) + (defun . mumamo-fill-forward-paragraph-function) + (defun . mumamo-fill-paragraph-function) + (defun . mumamo-forward-chunk) + (defun . mumamo-backward-chunk) + (defun . mumamo-flyspell-verify) + (defun . flyspell-mumamo-mode) + (require . bytecomp) + (defun . advice-compilation) + mumamo-syntax-chunk-at-pos + (defun . advice-compilation) + mumamo-syntax-ppss-major + (defun . advice-compilation) + rng-get-major-mode-chunk-function rng-valid-nxml-major-mode-chunk-function rng-end-major-mode-chunk-function + (defun . advice-compilation) + (defun . advice-compilation) + (defun . advice-compilation) + (provide . mumamo)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/byte-opt.elc" + (require . bytecomp) + (defun . byte-compile-log-lap-1) + (defun . byte-compile-log-lap) + (defun . byte-optimize-inline-handler) + (defun . byte-inline-lapcode) + (t . byte-compile-inline-expand) + (defun . byte-compile-inline-expand) + (t . byte-compile-unfold-lambda) + (defun . byte-compile-unfold-lambda) + (defun . byte-optimize-form-code-walker) + (defun . byte-optimize-all-constp) + (t . byte-optimize-form) + (defun . byte-optimize-form) + (defun . byte-optimize-body) + (defun . byte-compile-trueconstp) + (defun . byte-compile-nilconstp) + (defun . byte-optimize-associative-math) + (defun . byte-optimize-nonassociative-math) + (defun . byte-optimize-approx-equal) + (defun . byte-optimize-delay-constants-math) + (defun . byte-compile-butlast) + (defun . byte-optimize-plus) + (defun . byte-optimize-minus) + (defun . byte-optimize-multiply) + (defun . byte-optimize-divide) + (defun . byte-optimize-logmumble) + (defun . byte-optimize-binary-predicate) + (defun . byte-optimize-predicate) + (defun . byte-optimize-identity) + (defun . byte-optimize-quote) + (defun . byte-optimize-zerop) + (defun . byte-optimize-and) + (defun . byte-optimize-or) + (defun . byte-optimize-cond) + (defun . byte-optimize-if) + (defun . byte-optimize-while) + (defun . byte-optimize-funcall) + (defun . byte-optimize-apply) + (defun . byte-optimize-letX) + (defun . byte-optimize-nth) + (defun . byte-optimize-nthcdr) + (defun . byte-optimize-featurep) + (defun . byte-optimize-set) + (defun . byte-compile-splice-in-already-compiled-code) + byte-constref-ops byte-constref-ops + (defun . disassemble-offset) + (t . byte-decompile-bytecode) + (defun . byte-decompile-bytecode) + (defun . byte-decompile-bytecode-1) + byte-tagref-ops byte-tagref-ops byte-conditional-ops byte-conditional-ops byte-after-unbind-ops byte-compile-side-effect-and-error-free-ops byte-compile-side-effect-and-error-free-ops byte-compile-side-effect-free-ops byte-compile-side-effect-free-ops + (t . byte-optimize-lapcode) + (defun . byte-optimize-lapcode) + (provide . byte-opt)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/bytecomp.elc" + (require . backquote) + (defun . byte-compile-single-version) + (defun . byte-compile-version-cond) + emacs-lisp-file-regexp + (defun . byte-compiler-base-file-name) + (defun . byte-compile-dest-file) + (autoload . byte-compile-inline-expand) + (autoload . byte-optimize-form) + (autoload . byte-optimize-lapcode) + (autoload . byte-compile-unfold-lambda) + (autoload . byte-decompile-bytecode) + byte-compile-verbose byte-compile-compatibility byte-optimize byte-compile-delete-errors byte-compile-dynamic byte-compile-disable-print-circle byte-compile-dynamic-docstrings byte-optimize-log byte-compile-error-on-warn byte-compile-warning-types byte-compile-warnings + (t . byte-compile-warnings-safe-p) + (defun . byte-compile-warnings-safe-p) + (defun . byte-compile-warning-enabled-p) + (t . byte-compile-disable-warning) + (defun . byte-compile-disable-warning) + (t . byte-compile-enable-warning) + (defun . byte-compile-enable-warning) + byte-compile-interactive-only-functions byte-compile-not-obsolete-var byte-compile-generate-call-tree byte-compile-call-tree byte-compile-call-tree-sort byte-compile-debug byte-compile-constants byte-compile-variables byte-compile-bound-variables byte-compile-const-variables byte-compile-initial-macro-environment byte-compile-macro-environment byte-compile-function-environment byte-compile-unresolved-functions byte-compile-noruntime-functions byte-compile-tag-number byte-compile-output byte-compile-depth byte-compile-maxdepth byte-code-vector byte-stack+-info + (defun . byte-defop) + (defun . byte-extrude-byte-code-vectors) + byte-varref byte-varset byte-varbind byte-call byte-unbind byte-nth byte-nth byte-symbolp byte-symbolp byte-consp byte-consp byte-stringp byte-stringp byte-listp byte-listp byte-eq byte-eq byte-memq byte-memq byte-not byte-not byte-car byte-car byte-cdr byte-cdr byte-cons byte-cons byte-list1 byte-list1 byte-list2 byte-list2 byte-list3 byte-list3 byte-list4 byte-list4 byte-length byte-length byte-aref byte-aref byte-aset byte-aset byte-symbol-value byte-symbol-value byte-symbol-function byte-symbol-function byte-set byte-set byte-fset byte-fset byte-get byte-get byte-substring byte-substring byte-concat2 byte-concat2 byte-concat3 byte-concat3 byte-concat4 byte-concat4 byte-sub1 byte-sub1 byte-add1 byte-add1 byte-eqlsign byte-eqlsign byte-gtr byte-gtr byte-lss byte-lss byte-leq byte-leq byte-geq byte-geq byte-diff byte-diff byte-negate byte-negate byte-plus byte-plus byte-max byte-max byte-min byte-min byte-mult byte-mult byte-point byte-point byte-goto-char byte-goto-char byte-insert byte-insert byte-point-max byte-point-max byte-point-min byte-point-min byte-char-after byte-char-after byte-following-char byte-following-char byte-preceding-char byte-preceding-char byte-current-column byte-current-column byte-indent-to byte-indent-to byte-scan-buffer-OBSOLETE byte-scan-buffer-OBSOLETE byte-eolp byte-eolp byte-eobp byte-eobp byte-bolp byte-bolp byte-bobp byte-bobp byte-current-buffer byte-current-buffer byte-set-buffer byte-set-buffer byte-save-current-buffer byte-set-mark-OBSOLETE byte-set-mark-OBSOLETE byte-interactive-p byte-interactive-p byte-forward-char byte-forward-char byte-forward-word byte-forward-word byte-skip-chars-forward byte-skip-chars-forward byte-skip-chars-backward byte-skip-chars-backward byte-forward-line byte-forward-line byte-char-syntax byte-char-syntax byte-buffer-substring byte-buffer-substring byte-delete-region byte-delete-region byte-narrow-to-region byte-narrow-to-region byte-widen byte-widen byte-end-of-line byte-end-of-line byte-constant2 byte-goto byte-goto-if-nil byte-goto-if-not-nil byte-goto-if-nil-else-pop byte-goto-if-not-nil-else-pop byte-return byte-discard byte-dup byte-save-excursion byte-save-window-excursion byte-save-restriction byte-catch byte-unwind-protect byte-condition-case byte-condition-case byte-temp-output-buffer-setup byte-temp-output-buffer-setup byte-temp-output-buffer-show byte-temp-output-buffer-show byte-unbind-all byte-unbind-all byte-set-marker byte-set-marker byte-match-beginning byte-match-beginning byte-match-end byte-match-end byte-upcase byte-upcase byte-downcase byte-downcase byte-string= byte-string= byte-string< byte-string< byte-equal byte-equal byte-nthcdr byte-nthcdr byte-elt byte-elt byte-member byte-member byte-assq byte-assq byte-nreverse byte-nreverse byte-setcar byte-setcar byte-setcdr byte-setcdr byte-car-safe byte-car-safe byte-cdr-safe byte-cdr-safe byte-nconc byte-nconc byte-quo byte-quo byte-rem byte-rem byte-numberp byte-numberp byte-integerp byte-integerp byte-listN byte-listN byte-concatN byte-concatN byte-insertN byte-insertN byte-constant byte-constant-limit byte-goto-ops byte-goto-always-pop-ops byte-goto-always-pop-ops + (defun . byte-compile-lapcode) + (defun . byte-compile-eval) + (defun . byte-compile-eval-before-compile) + byte-compile-current-form byte-compile-dest-file byte-compile-current-file byte-compile-current-group byte-compile-current-buffer + (defun . byte-compile-log) + (defun . byte-compile-log-1) + byte-compile-read-position byte-compile-last-position + (defun . byte-compile-delete-first) + (defun . byte-compile-set-symbol-position) + byte-compile-last-warned-form byte-compile-last-logged-file + (defun . byte-compile-warning-prefix) + (defun . byte-compile-warning-series) + (defun . byte-compile-log-file) + (defun . byte-compile-log-warning) + (defun . byte-compile-warn) + (defun . byte-compile-warn-obsolete) + (defun . byte-compile-report-error) + (defun . byte-compile-obsolete) + (defun . byte-compile-fdefinition) + (defun . byte-compile-arglist-signature) + (defun . byte-compile-arglist-signatures-congruent-p) + (defun . byte-compile-arglist-signature-string) + (defun . byte-compile-callargs-warn) + (defun . byte-compile-format-warn) + (defun . byte-compile-nogroup-warn) + (defun . byte-compile-arglist-warn) + byte-compile-cl-functions + (defun . byte-compile-find-cl-functions) + (defun . byte-compile-cl-warn) + (defun . byte-compile-print-syms) + (defun . byte-compile-warn-about-unresolved-functions) + (defun . byte-compile-const-symbol-p) + (defun . byte-compile-constp) + (defun . byte-compile-close-variables) + (defun . displaying-byte-compile-warnings) + (t . byte-force-recompile) + (defun . byte-force-recompile) + (t . byte-recompile-directory) + (defun . byte-recompile-directory) + no-byte-compile + (t . byte-compile-file) + (defun . byte-compile-file) + (t . compile-defun) + (defun . compile-defun) + (defun . byte-compile-from-buffer) + (defun . byte-compile-fix-header) + (defun . byte-compile-insert-header) + (defun . byte-compile-output-file-form) + (defun . byte-compile-output-docform) + (defun . byte-compile-keep-pending) + (defun . byte-compile-flush-pending) + (defun . byte-compile-file-form) + (defun . byte-compile-file-form-defsubst) + (defun . byte-compile-file-form-autoload) + (defun . byte-compile-file-form-defvar) + (defun . byte-compile-file-form-define-abbrev-table) + (defun . byte-compile-file-form-custom-declare-variable) + (defun . byte-compile-file-form-require) + (defun . byte-compile-file-form-progn) + (defun . byte-compile-file-form-eval) + (defun . byte-compile-file-form-defun) + (defun . byte-compile-file-form-defmacro) + (defun . byte-compile-file-form-defmumble) + (defun . byte-compile-output-as-comment) + (t . byte-compile) + (defun . byte-compile) + (defun . byte-compile-sexp) + (defun . byte-compile-byte-code-maker) + (defun . byte-compile-byte-code-unmake) + (defun . byte-compile-check-lambda-list) + (defun . byte-compile-lambda) + (defun . byte-compile-constants-vector) + (defun . byte-compile-top-level) + (defun . byte-compile-out-toplevel) + (defun . byte-compile-top-level-body) + (defun . byte-compile-declare-function) + (defun . byte-compile-form) + (defun . byte-compile-normal-call) + (defun . byte-compile-variable-ref) + (defun . byte-compile-get-constant) + (defun . byte-compile-constant) + (defun . byte-compile-push-constant) + (defun . byte-defop-compiler) + (defun . byte-defop-compiler19) + (defun . byte-defop-compiler-1) + (defun . byte-compile-subr-wrong-args) + (defun . byte-compile-no-args) + (defun . byte-compile-one-arg) + (defun . byte-compile-two-args) + (defun . byte-compile-three-args) + (defun . byte-compile-zero-or-one-arg) + (defun . byte-compile-one-or-two-args) + (defun . byte-compile-two-or-three-args) + (defun . byte-compile-noop) + (defun . byte-compile-discard) + (defun . byte-compile-associative) + (defun . byte-compile-char-before) + (defun . byte-compile-backward-char) + (defun . byte-compile-backward-word) + (defun . byte-compile-list) + (defun . byte-compile-concat) + (defun . byte-compile-minus) + (defun . byte-compile-quo) + (defun . byte-compile-nconc) + (defun . byte-compile-fset) + (defun . byte-compile-funarg) + (defun . byte-compile-funarg-2) + (defun . byte-compile-function-form) + (defun . byte-compile-indent-to) + (defun . byte-compile-insert) + (defun . byte-compile-setq) + (defun . byte-compile-setq-default) + (defun . byte-compile-quote) + (defun . byte-compile-quote-form) + (defun . byte-compile-body) + (defun . byte-compile-body-do-effect) + (defun . byte-compile-form-do-effect) + (defun . byte-compile-progn) + (defun . byte-compile-prog1) + (defun . byte-compile-prog2) + (defun . byte-compile-goto-if) + (defun . byte-compile-find-bound-condition) + (defun . byte-compile-maybe-guarded) + (defun . byte-compile-if) + (defun . byte-compile-cond) + (defun . byte-compile-and) + (defun . byte-compile-and-recursion) + (defun . byte-compile-or) + (defun . byte-compile-or-recursion) + (defun . byte-compile-while) + (defun . byte-compile-funcall) + (defun . byte-compile-let) + (defun . byte-compile-let*) + (defun . byte-compile-negated) + (defun . byte-compile-negation-optimizer) + (defun . byte-compile-catch) + (defun . byte-compile-unwind-protect) + (defun . byte-compile-track-mouse) + (defun . byte-compile-condition-case) + (defun . byte-compile-save-excursion) + (defun . byte-compile-save-restriction) + (defun . byte-compile-save-current-buffer) + (defun . byte-compile-save-window-excursion) + (defun . byte-compile-with-output-to-temp-buffer) + (defun . byte-compile-defun) + (defun . byte-compile-defmacro) + (defun . byte-compile-defvar) + (defun . byte-compile-autoload) + (defun . byte-compile-lambda-form) + (defun . byte-compile-file-form-defalias) + (defun . byte-compile-defalias-warn) + (defun . byte-compile-no-warnings) + (defun . byte-compile-make-variable-buffer-local) + (defun . byte-compile-form-make-variable-buffer-local) + (defun . byte-compile-make-tag) + (defun . byte-compile-out-tag) + (defun . byte-compile-goto) + (defun . byte-compile-out) + (defun . byte-compile-annotate-call-tree) + (t . display-call-tree) + (defun . display-call-tree) + (t . batch-byte-compile-if-not-done) + (defun . batch-byte-compile-if-not-done) + (t . batch-byte-compile) + (defun . batch-byte-compile) + (defun . batch-byte-compile-file) + (t . batch-byte-recompile-directory) + (defun . batch-byte-recompile-directory) + (provide . byte-compile) + (provide . bytecomp) + (defun . byte-compile-report-ops)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/cl-macs.elc" + (require . cl) + (defun . cl-pop2) + (require . bytecomp) + cl-old-bc-file-form cl-simple-funcs cl-simple-funcs cl-safe-funcs cl-safe-funcs + (defun . cl-simple-expr-p) + (defun . cl-simple-exprs-p) + (defun . cl-safe-expr-p) + (defun . cl-const-expr-p) + (defun . cl-const-exprs-p) + (defun . cl-const-expr-val) + (defun . cl-expr-access-order) + (defun . cl-expr-contains) + (defun . cl-expr-contains-any) + (defun . cl-expr-depends-p) + (defun . gensym) + (defun . gentemp) + (defun . defun*) + (defun . defmacro*) + (defun . function*) + (defun . cl-transform-function-property) + lambda-list-keywords lambda-list-keywords cl-macro-environment + (defun . cl-transform-lambda) + (defun . cl-do-arglist) + (defun . cl-arglist-args) + (defun . destructuring-bind) + cl-not-toplevel + (defun . eval-when) + (defun . cl-compile-time-too) + (defun . load-time-value) + (defun . case) + (defun . ecase) + (defun . typecase) + (defun . etypecase) + (defun . block) + cl-active-block-names + (defun . cl-byte-compile-block) + (defun . cl-byte-compile-throw) + (defun . return) + (defun . return-from) + (defun . loop) + (defun . cl-parse-loop-clause) + (defun . cl-loop-let) + (defun . cl-loop-handle-accum) + (defun . cl-loop-build-ands) + (defun . do) + (defun . do*) + (defun . cl-expand-do-loop) + (defun . dolist) + (defun . dotimes) + (defun . do-symbols) + (defun . do-all-symbols) + (defun . psetq) + (defun . progv) + (defun . flet) + (defun . labels) + (defun . macrolet) + (defun . symbol-macrolet) + cl-closure-vars + (defun . lexical-let) + (defun . lexical-let*) + (defun . cl-defun-expander) + (defun . multiple-value-bind) + (defun . multiple-value-setq) + (defun . locally) + (defun . the) + cl-proclaim-history cl-declare-stack + (defun . cl-do-proclaim) + (defun . declare) + (defun . define-setf-method) + (defun . define-setf-expander) + (defun . defsetf) + (defun . cl-setf-make-apply) + (defun . get-setf-method) + (defun . cl-setf-do-modify) + (defun . cl-setf-do-store) + (defun . cl-setf-simple-store-p) + (defun . setf) + (defun . psetf) + (defun . cl-do-pop) + (defun . remf) + (defun . shiftf) + (defun . rotatef) + (defun . letf) + (defun . letf*) + (defun . callf) + (defun . callf2) + (defun . define-modify-macro) + (defun . defstruct) + (defun . cl-struct-setf-expander) + (defun . deftype) + (defun . cl-make-type-test) + (defun . typep) + (defun . check-type) + (defun . assert) + (defun . define-compiler-macro) + (defun . compiler-macroexpand) + (defun . cl-byte-compile-compiler-macro) + (defun . defsubst*) + (defun . cl-defsubst-expand)) + ("/usr/share/emacs/23.0.93/lisp/textmodes/sgml-mode.elc" sgml-basic-offset sgml-transformation-function sgml-transformation sgml-mode-hook sgml-specials sgml-quick-keys sgml-mode-map + (defun . sgml-make-syntax-table) + sgml-mode-syntax-table sgml-tag-syntax-table sgml-name-8bit-mode sgml-char-names sgml-char-names-table sgml-validate-command sgml-saved-validate-command sgml-slash-distance sgml-namespace-re sgml-namespace-re sgml-name-re sgml-name-re sgml-tag-name-re sgml-tag-name-re sgml-attrs-re sgml-attrs-re sgml-start-tag-regex + (defface . sgml-namespace) + sgml-namespace-face sgml-font-lock-keywords-1 sgml-font-lock-keywords-1 sgml-font-lock-keywords-2 sgml-font-lock-keywords-2 sgml-font-lock-keywords sgml-font-lock-syntactic-keywords sgml-face-tag-alist sgml-tag-face-alist sgml-display-text sgml-tags-invisible sgml-tag-alist sgml-tag-help sgml-xml-mode sgml-empty-tags sgml-unclosed-tags + (defun . sgml-xml-guess) + (defun . sgml-comment-indent-new-line) + (defun . sgml-mode-facemenu-add-face-function) + (defun . sgml-fill-nobreak) + sgml-mode-map sgml-mode-syntax-table sgml-mode-abbrev-table sgml-mode-abbrev-table + (t . sgml-mode) + (defun . sgml-mode) + (defun . xml-mode) + (defun . sgml-comment-indent) + (defun . sgml-slash) + (defun . sgml-slash-matching) + (defun . sgml-name-char) + (defun . sgml-namify-char) + (defun . sgml-name-self) + (defun . sgml-maybe-name-self) + (defun . sgml-name-8bit-mode) + sgml-tag-last sgml-tag-history + (defun . sgml-tag) + (autoload . skeleton-read) + (defun . sgml-attributes) + (defun . sgml-auto-attributes) + (defun . sgml-tag-help) + (defun . sgml-maybe-end-tag) + (defun . sgml-skip-tag-backward) + sgml-electric-tag-pair-overlays sgml-electric-tag-pair-timer + (defun . sgml-electric-tag-pair-before-change-function) + (defun . sgml-electric-tag-pair-flush-overlays) + sgml-electric-tag-pair-mode + (defun . sgml-electric-tag-pair-mode) + (defun . sgml-skip-tag-forward) + (defun . sgml-delete-tag) + (defun . sgml-tags-invisible) + (defun . sgml-point-entered) + (defun . sgml-validate) + (defun . sgml-at-indentation-p) + (defun . sgml-lexical-context) + (defun . sgml-beginning-of-tag) + (defun . sgml-value) + (defun . sgml-quote) + (defun . sgml-pretty-print) + (defun . sgml-tag-type) + (defun . sgml-tag-start) + (defun . sgml-tag-end) + (defun . sgml-tag-name) + (defun . sgml-tag-p) + (defun . copy-sgml-tag) + (defun . make-sgml-tag) + (defun . sgml-make-tag) + (defun . sgml-parse-tag-name) + (defun . sgml-looking-back-at) + (defun . sgml-tag-text-p) + (defun . sgml-parse-tag-backward) + (defun . sgml-get-context) + (defun . sgml-show-context) + (defun . sgml-close-tag) + (defun . sgml-empty-tag-p) + (defun . sgml-unclosed-tag-p) + (defun . sgml-calculate-indent) + (defun . sgml-indent-line) + (defun . sgml-guess-indent) + (defun . sgml-parse-dtd) + html-mode-hook html-quick-keys html-mode-map html-face-tag-alist html-tag-face-alist html-display-text html-tag-alist html-tag-help html-mode-map html-mode-syntax-table html-mode-abbrev-table html-mode-abbrev-table + (t . html-mode) + (defun . html-mode) + html-imenu-regexp + (defun . html-imenu-index) + html-autoview-mode + (defun . html-autoview-mode) + (defun . html-href-anchor) + (defun . html-name-anchor) + (defun . html-headline-1) + (defun . html-headline-2) + (defun . html-headline-3) + (defun . html-headline-4) + (defun . html-headline-5) + (defun . html-headline-6) + (defun . html-horizontal-rule) + (defun . html-image) + (defun . html-line) + (defun . html-ordered-list) + (defun . html-unordered-list) + (defun . html-list-item) + (defun . html-paragraph) + (defun . html-checkboxes) + (defun . html-radio-buttons) + (provide . sgml-mode)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-valid.elc" + (require . xmltok) + (require . nxml-enc) + (require . nxml-util) + (require . nxml-ns) + (require . rng-match) + (require . rng-util) + (require . rng-loc) + (defface . rng-error) + rng-state-cache-distance rng-validate-chunk-size rng-validate-delay rng-validate-quick-delay rng-validate-timer rng-validate-quick-timer rng-error-count rng-message-overlay rng-message-overlay-inhibit-point rng-message-overlay-current rng-open-elements rng-pending-contents rng-collecting-text rng-validate-up-to-date-end rng-conditional-up-to-date-start rng-conditional-up-to-date-end rng-parsing-for-state rng-validate-mode rng-dtd + (t . rng-validate-mode) + (defun . rng-validate-mode) + (defun . rng-set-schema-file-and-validate) + (defun . rng-set-document-type-and-validate) + (defun . rng-auto-set-schema-and-validate) + (defun . rng-after-change-function) + (defun . rng-compute-mode-line-string) + (defun . rng-cancel-timers) + (defun . rng-kill-timers) + (defun . rng-activate-timers) + (defun . rng-validate-clear) + rng-validate-display-point rng-validate-display-modified-p + (defun . rng-validate-while-idle-continue-p) + (defun . rng-validate-while-idle) + (defun . rng-validate-quick-while-idle) + (defun . rng-validate-done) + (defun . rng-do-some-validation) + (defun . rng-validate-prepare) + (defun . rng-do-some-validation-1) + (defun . rng-clear-conditional-region) + (defun . rng-clear-cached-state) + (defun . rng-cache-state) + (defun . rng-state-matches-current) + (defun . rng-get-state) + (defun . rng-restore-state) + (defun . rng-set-initial-state) + (defun . rng-clear-overlays) + (defun . rng-mark-xmltok-dependent-regions) + (defun . rng-mark-xmltok-dependent-region) + (defun . rng-dependent-region-changed) + (defun . rng-mark-xmltok-errors) + (defun . rng-mark-invalid) + (defun . rng-mark-not-well-formed) + (defun . rng-mark-error) + (defun . rng-error-modified) + (defun . rng-echo-area-clear-function) + (defun . rng-maybe-echo-error-at-point) + (defun . rng-error-overlay-after) + (defun . rng-first-error) + (defun . rng-mouse-first-error) + (defun . rng-next-error) + (defun . rng-previous-error) + (defun . rng-next-error-1) + (defun . rng-previous-error-1) + (defun . rng-goto-error-overlay) + (defun . rng-error-overlay-message) + (defun . rng-current-message-from-error-overlay-p) + (defun . rng-find-next-error-overlay) + (defun . rng-find-previous-error-overlay) + (defun . rng-forward) + (defun . rng-process-start-tag) + (defun . rng-process-namespaces) + (defun . rng-process-tag-name) + (defun . rng-process-attributes) + (defun . rng-process-start-tag-close) + (defun . rng-mark-start-tag-close) + (defun . rng-recover-bad-element-prefix) + (defun . rng-recover-bad-attribute-prefix) + (defun . rng-recover-duplicate-attribute-name) + (defun . rng-recover-start-tag-open) + (defun . rng-recover-attribute-value) + (defun . rng-recover-attribute-name) + (defun . rng-missing-attributes-message) + (defun . rng-process-end-tag) + (defun . rng-end-element) + (defun . rng-missing-element-message) + (defun . rng-recover-mismatched-end-tag) + (defun . rng-mark-missing-end-tags) + (defun . rng-mark-mismatched-end-tag) + (defun . rng-push-tag) + (defun . rng-pop-tag) + (defun . rng-contents-string) + (defun . rng-segment-string) + (defun . rng-segment-blank-p) + (defun . rng-contents-region) + (defun . rng-process-text) + (defun . rng-process-unknown-char) + (defun . rng-process-unknown-entity) + (defun . rng-region-blank-p) + (defun . rng-flush-text) + (defun . rng-process-end-document) + (defun . rng-process-encoding-name) + (defun . rng-name-to-string) + (provide . rng-valid)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-loc.elc" + (require . nxml-util) + (require . nxml-parse) + (require . rng-parse) + (require . rng-uri) + (require . rng-util) + (require . xmltok) + rng-current-schema-file-name rng-schema-locating-files-default rng-schema-locating-file-schema-file rng-schema-locating-file-schema rng-schema-locating-files rng-schema-loader-alist rng-cached-document-element rng-document-type-history + (defun . rng-set-document-type) + (defun . rng-read-type-id) + (defun . rng-set-schema-file) + (defun . rng-set-vacuous-schema) + (defun . rng-set-schema-file-1) + (defun . rng-load-schema) + (defun . rng-what-schema) + (defun . rng-auto-set-schema) + (defun . rng-locate-schema-file) + (defun . rng-possible-type-ids) + (defun . rng-locate-schema-file-using) + (defun . rng-match-document-element-rule) + (defun . rng-match-namespace-rule) + (defun . rng-document-element) + (defun . rng-get-start-tag-namespace) + (defun . rng-match-transform-uri-rule) + (defun . rng-match-uri-rule) + (defun . rng-file-name-matches-uri-pattern-p) + (defun . rng-match-default-rule) + (defun . rng-possible-type-ids-using) + (defun . rng-locate-schema-file-from-type-id) + rng-schema-locating-file-alist + (defun . rng-get-parsed-schema-locating-file) + rng-locate-namespace-uri rng-locate-namespace-uri + (defun . rng-parse-schema-locating-file) + (defun . rng-save-schema-location) + (defun . rng-save-schema-location-1) + (provide . rng-loc)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-uri.elc" + (defun . rng-file-name-uri) + (defun . rng-uri-escape-multibyte) + (defun . rng-percent-encode) + (defun . rng-uri-file-name) + (defun . rng-uri-pattern-file-name-regexp) + (defun . rng-uri-pattern-file-name-replace-match) + (defun . rng-uri-file-name-1) + (defun . rng-uri-error) + (defun . rng-uri-split) + (defun . rng-uri-join) + (defun . rng-uri-resolve) + (defun . rng-resolve-path) + (defun . rng-relative-uri) + (defun . rng-relative-path) + (defun . rng-split-path) + (defun . rng-join-path) + (defun . rng-uri-unescape-multibyte) + (defun . rng-multibyte-percent-decode) + (defun . rng-uri-unescape-unibyte) + (defun . rng-uri-unescape-unibyte-match) + (defun . rng-uri-unescape-unibyte-replace) + (provide . rng-uri)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-parse.elc" + (require . nxml-parse) + (require . rng-match) + (require . rng-dt) + rng-parse-prev-was-start-tag + (defun . rng-parse-validate-file) + (defun . rng-parse-do-validate) + (defun . rng-parse-to-match-name) + (provide . rng-parse)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-parse.elc" + (require . nxml-util) + (require . xmltok) + (require . nxml-enc) + (require . nxml-ns) + nxml-parse-file-name nxml-validate-function + (defun . nxml-parse-file) + (defun . nxml-parse-find-file) + (defun . nxml-parse-instance) + (defun . nxml-parse-instance-1) + (defun . nxml-parse-start-tag) + (defun . nxml-validate-tag) + (defun . nxml-validate-error-position) + (defun . nxml-make-name) + (defun . nxml-current-text-string) + (defun . nxml-parse-error) + (defun . nxml-check-xmltok-errors) + (provide . nxml-parse)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-match.elc" + (require . rng-pttrn) + (require . rng-util) + (require . rng-dt) + rng-not-allowed-ipattern rng-empty-ipattern rng-text-ipattern rng-compile-table rng-being-compiled rng-ipattern-table rng-last-ipattern-index rng-match-state + (defun . rng-update-match-state) + (defun . rng-ipattern-defslot) + (defun . rng-ipattern-get-type) + (defun . rng-ipattern-set-type) + (defun . rng-ipattern-get-index) + (defun . rng-ipattern-set-index) + (defun . rng-ipattern-get-name-class) + (defun . rng-ipattern-set-name-class) + (defun . rng-ipattern-get-datatype) + (defun . rng-ipattern-set-datatype) + (defun . rng-ipattern-get-after) + (defun . rng-ipattern-set-after) + (defun . rng-ipattern-get-child) + (defun . rng-ipattern-set-child) + (defun . rng-ipattern-get-value-object) + (defun . rng-ipattern-set-value-object) + (defun . rng-ipattern-get-nullable) + (defun . rng-ipattern-set-nullable) + (defun . rng-ipattern-get-memo-text-typed) + (defun . rng-ipattern-set-memo-text-typed) + (defun . rng-ipattern-get-memo-map-start-tag-open-deriv) + (defun . rng-ipattern-set-memo-map-start-tag-open-deriv) + (defun . rng-ipattern-get-memo-map-start-attribute-deriv) + (defun . rng-ipattern-set-memo-map-start-attribute-deriv) + (defun . rng-ipattern-get-memo-start-tag-close-deriv) + (defun . rng-ipattern-set-memo-start-tag-close-deriv) + (defun . rng-ipattern-get-memo-text-only-deriv) + (defun . rng-ipattern-set-memo-text-only-deriv) + (defun . rng-ipattern-get-memo-mixed-text-deriv) + (defun . rng-ipattern-set-memo-mixed-text-deriv) + (defun . rng-ipattern-get-memo-map-data-deriv) + (defun . rng-ipattern-set-memo-map-data-deriv) + (defun . rng-ipattern-get-memo-end-tag-deriv) + (defun . rng-ipattern-set-memo-end-tag-deriv) + rng-memo-map-alist-max rng-memo-map-alist-max + (defun . rng-memo-map-get) + (defun . rng-memo-map-add) + (defun . rng-make-ipattern) + (defun . rng-ipattern-maybe-init) + (defun . rng-ipattern-clear) + (defun . rng-gen-ipattern-index) + (defun . rng-put-ipattern) + (defun . rng-get-ipattern) + rng-const-ipatterns rng-const-ipatterns + (defun . rng-intern-after) + (defun . rng-intern-attribute) + (defun . rng-intern-data) + (defun . rng-intern-data-except) + (defun . rng-intern-value) + (defun . rng-intern-one-or-more) + (defun . rng-intern-one-or-more-shortcut) + (defun . rng-intern-list) + (defun . rng-intern-group) + (defun . rng-intern-group-shortcut) + (defun . rng-normalize-group-list) + (defun . rng-intern-interleave) + (defun . rng-normalize-interleave-list) + (defun . rng-intern-choice) + (defun . rng-intern-optional) + (defun . rng-intern-choice1) + (defun . rng-intern-choice-shortcut) + (defun . rng-normalize-choice-list) + (defun . rng-compare-ipattern) + (defun . rng-name-class-contains) + (defun . rng-name-class-contains1) + (defun . rng-name-class-possible-names) + (defun . rng-ipattern-to-string) + (defun . rng-name-class-to-string) + (defun . rng-compile-maybe-init) + (defun . rng-compile-clear) + (defun . rng-compile) + (defun . rng-compile-not-allowed) + (defun . rng-compile-empty) + (defun . rng-compile-text) + (defun . rng-compile-element) + (defun . rng-element-get-child) + (defun . rng-compile-attribute) + (defun . rng-compile-ref) + (defun . rng-compile-one-or-more) + (defun . rng-compile-zero-or-more) + (defun . rng-compile-optional) + (defun . rng-compile-mixed) + (defun . rng-compile-list) + (defun . rng-compile-choice) + (defun . rng-compile-group) + (defun . rng-compile-interleave) + (defun . rng-compile-dt) + (defun . rng-compile-data) + (defun . rng-compile-data-except) + (defun . rng-compile-value) + (defun . rng-compile-name-class) + (defun . rng-map-element-attribute) + (defun . rng-find-element-content-pattern) + (defun . rng-search-name) + (defun . rng-find-name-class-uris) + (defun . rng-accum-namespace-uri) + (defun . rng-ipattern-text-typed-p) + (defun . rng-ipattern-compute-text-typed-p) + (defun . rng-start-tag-open-deriv) + (defun . rng-ipattern-memo-start-tag-open-deriv) + (defun . rng-compute-start-tag-open-deriv) + (defun . rng-start-attribute-deriv) + (defun . rng-ipattern-memo-start-attribute-deriv) + (defun . rng-compute-start-attribute-deriv) + (defun . rng-cons-group-after) + (defun . rng-subst-group-after) + (defun . rng-subst-interleave-after) + (defun . rng-apply-after) + (defun . rng-start-tag-close-deriv) + rng-transform-map rng-transform-map + (defun . rng-compute-start-tag-close-deriv) + (defun . rng-ignore-attributes-deriv) + (defun . rng-text-only-deriv) + (defun . rng-compute-text-only-deriv) + (defun . rng-mixed-text-deriv) + (defun . rng-compute-mixed-text-deriv) + (defun . rng-end-tag-deriv) + (defun . rng-compute-end-tag-deriv) + (defun . rng-data-deriv) + (defun . rng-namespace-context-tracer) + (defun . rng-namespace-context-get-no-trace) + rng-memo-data-deriv-max-length + (defun . rng-ipattern-memo-data-deriv) + (defun . rng-compute-data-deriv) + (defun . rng-transform-multi) + (defun . rng-transform-choice) + (defun . rng-transform-group) + (defun . rng-transform-interleave) + (defun . rng-transform-one-or-more) + (defun . rng-transform-after-child) + (defun . rng-transform-interleave-single) + (defun . rng-transform-group-nullable) + (defun . rng-transform-group-nullable-gen-choices) + (defun . rng-members-eq) + (defun . rng-ipattern-after) + (defun . rng-unknown-start-tag-open-deriv) + (defun . rng-ipattern-optionalize-elements) + (defun . rng-ipattern-empty-before-p) + (defun . rng-ipattern-possible-start-tags) + (defun . rng-ipattern-start-tag-possible-p) + (defun . rng-ipattern-possible-attributes) + (defun . rng-ipattern-possible-values) + (defun . rng-ipattern-required-element) + (defun . rng-ipattern-required-attributes) + (defun . rng-compile-error) + (defun . rng-match-state) + (defun . rng-set-match-state) + (defun . rng-match-state-equal) + (defun . rng-schema-changed) + (defun . rng-match-init-buffer) + (defun . rng-match-start-document) + (defun . rng-match-start-tag-open) + (defun . rng-match-attribute-name) + (defun . rng-match-attribute-value) + (defun . rng-match-element-value) + (defun . rng-match-start-tag-close) + (defun . rng-match-mixed-text) + (defun . rng-match-end-tag) + (defun . rng-match-after) + (defun . rng-match-out-of-context-start-tag-open) + (defun . rng-match-possible-namespace-uris) + (defun . rng-match-unknown-start-tag-open) + (defun . rng-match-optionalize-elements) + (defun . rng-match-ignore-attributes) + (defun . rng-match-text-typed-p) + (defun . rng-match-empty-content) + (defun . rng-match-empty-before-p) + (defun . rng-match-infer-start-tag-namespace) + (defun . rng-match-nullable-p) + (defun . rng-match-possible-start-tag-names) + (defun . rng-match-start-tag-possible-p) + (defun . rng-match-possible-attribute-names) + (defun . rng-match-possible-value-strings) + (defun . rng-match-required-element-name) + (defun . rng-match-required-attribute-names) + (defun . rng-match-save) + (defun . rng-match-with-schema) + (provide . rng-match)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-dt.elc" + (require . rng-util) + rng-dt-error-reporter + (defun . rng-dt-error) + rng-dt-namespace-context-getter + (defun . rng-dt-make-value) + (defun . rng-dt-builtin-compile) + (provide . rng-dt)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-util.elc" + (defun . rng-make-datatypes-uri) + rng-xsd-datatypes-uri rng-xsd-datatypes-uri rng-builtin-datatypes-uri rng-builtin-datatypes-uri + (defun . rng-uniquify-eq) + (defun . rng-uniquify-equal) + (defun . rng-blank-p) + (defun . rng-substq) + (defun . rng-complete-before-point) + (defun . rng-completion-exact-p) + (defun . rng-quote-string) + (defun . rng-escape-string) + (defun . rng-collapse-space) + (provide . rng-util)) + ("/usr/share/emacs/23.0.93/lisp/nxml/rng-pttrn.elc" rng-schema-change-hook rng-current-schema + (defun . rng-make-ref) + (defun . rng-ref-set) + (defun . rng-ref-get) + (defun . rng-make-choice) + (defun . rng-make-group) + (defun . rng-make-interleave) + (defun . rng-make-zero-or-more) + (defun . rng-make-one-or-more) + (defun . rng-make-optional) + (defun . rng-make-mixed) + (defun . rng-make-value) + (defun . rng-make-data) + (defun . rng-make-data-except) + (defun . rng-make-list) + (defun . rng-make-element) + (defun . rng-make-attribute) + (defun . rng-make-text) + (defun . rng-make-empty) + (defun . rng-make-not-allowed) + (defun . rng-make-any-name-name-class) + (defun . rng-make-any-name-except-name-class) + (defun . rng-make-ns-name-name-class) + (defun . rng-make-ns-name-except-name-class) + (defun . rng-make-name-name-class) + (defun . rng-make-choice-name-class) + rng-any-content rng-any-element + (defun . rng-make-name) + (defun . rng-make-datatype) + (provide . rng-pttrn)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-ns.elc" + (require . nxml-util) + nxml-ns-state nxml-ns-initial-state + (defun . nxml-ns-state) + (defun . nxml-ns-set-state) + (defun . nxml-ns-state-equal) + (defun . nxml-ns-save) + (defun . nxml-ns-init) + (defun . nxml-ns-push-state) + (defun . nxml-ns-pop-state) + (defun . nxml-ns-get-prefix) + (defun . nxml-ns-set-prefix) + (defun . nxml-ns-get-default) + (defun . nxml-ns-set-default) + (defun . nxml-ns-get-context) + (defun . nxml-ns-prefixes-for) + (defun . nxml-ns-prefix-for) + (defun . nxml-ns-changed-prefixes) + (provide . nxml-ns)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-mode.elc" + (require . xmltok) + (require . nxml-enc) + (require . nxml-glyph) + (require . nxml-util) + (require . nxml-rap) + (require . nxml-outln) + nxml-char-ref-display-glyph-flag nxml-mode-hook nxml-sexp-element-flag nxml-slash-auto-complete-flag nxml-child-indent nxml-attribute-indent nxml-bind-meta-tab-to-complete-flag nxml-prefer-utf-16-to-utf-8-flag nxml-prefer-utf-16-little-to-big-endian-flag nxml-default-buffer-file-coding-system nxml-auto-insert-xml-declaration-flag + (defface . nxml-delimited-data) + (defface . nxml-name) + (defface . nxml-ref) + (defface . nxml-delimiter) + (defface . nxml-text) + (defface . nxml-comment-content) + (defface . nxml-comment-delimiter) + (defface . nxml-processing-instruction-delimiter) + (defface . nxml-processing-instruction-target) + (defface . nxml-processing-instruction-content) + (defface . nxml-cdata-section-delimiter) + (defface . nxml-cdata-section-CDATA) + (defface . nxml-cdata-section-content) + (defface . nxml-char-ref-number) + (defface . nxml-char-ref-delimiter) + (defface . nxml-entity-ref-name) + (defface . nxml-entity-ref-delimiter) + (defface . nxml-tag-delimiter) + (defface . nxml-tag-slash) + (defface . nxml-element-prefix) + (defface . nxml-element-colon) + (defface . nxml-element-local-name) + (defface . nxml-attribute-prefix) + (defface . nxml-attribute-colon) + (defface . nxml-attribute-local-name) + (defface . nxml-namespace-attribute-xmlns) + (defface . nxml-namespace-attribute-colon) + (defface . nxml-namespace-attribute-prefix) + (defface . nxml-attribute-value) + (defface . nxml-attribute-value-delimiter) + (defface . nxml-namespace-attribute-value) + (defface . nxml-namespace-attribute-value-delimiter) + (defface . nxml-prolog-literal-delimiter) + (defface . nxml-prolog-literal-content) + (defface . nxml-prolog-keyword) + (defface . nxml-markup-declaration-delimiter) + (defface . nxml-hash) + (defface . nxml-glyph) + nxml-prolog-regions nxml-last-fontify-end nxml-degraded nxml-completion-hook nxml-in-mixed-content-hook nxml-mixed-scan-distance nxml-end-tag-indent-scan-distance nxml-char-ref-extra-display nxml-mode-map nxml-font-lock-keywords + (defun . nxml-set-face) + (t . nxml-mode) + (defun . nxml-mode) + (defun . nxml-cleanup) + (defun . nxml-degrade) + (defun . nxml-debug-region) + (defun . nxml-after-change) + (defun . nxml-after-change1) + (defun . nxml-insert-xml-declaration) + (defun . nxml-prepare-to-save) + (defun . nxml-select-coding-system) + (defun . nxml-unsuitable-coding-system-message) + nxml-utf-16-coding-systems nxml-utf-16-coding-systems nxml-utf-coding-systems nxml-utf-coding-systems + (defun . nxml-coding-system-unicode-p) + (defun . nxml-coding-system-name) + (defun . nxml-fix-encoding-declaration) + (defun . nxml-choose-suitable-coding-system) + (defun . nxml-choose-utf-coding-system) + (defun . nxml-choose-utf-16-coding-system) + (defun . nxml-coding-system-member) + (defun . nxml-unfontify-region) + (defun . nxml-extend-region) + (defun . nxml-extend-after-change-region) + (defun . nxml-extend-after-change-region1) + (defun . nxml-fontify-matcher) + (defun . nxml-fontify-prolog) + (defun . nxml-apply-fontify-rule) + (defun . nxml-fontify-attributes) + (defun . nxml-fontify-attribute) + (defun . nxml-fontify-qname) + (defun . nxml-electric-slash) + (defun . nxml-balanced-close-start-tag-block) + (defun . nxml-balanced-close-start-tag-inline) + (defun . nxml-balanced-close-start-tag) + (defun . nxml-finish-element) + nxml-last-split-position + (defun . nxml-split-element) + (defun . nxml-finish-element-1) + (defun . nxml-indent-line) + (defun . nxml-compute-indent) + (defun . nxml-compute-indent-from-matching-start-tag) + (defun . nxml-compute-indent-from-previous-line) + (defun . nxml-merge-indent-context-type) + (defun . nxml-compute-indent-in-token) + (defun . nxml-compute-indent-in-start-tag) + (defun . nxml-attribute-value-boundary) + (defun . nxml-compute-indent-in-delimited-token) + (defun . nxml-complete) + (defun . nxml-forward-balanced-item) + (defun . nxml-forward-single-balanced-item) + (defun . nxml-backward-single-balanced-item) + (defun . nxml-scan-forward-within) + (defun . nxml-scan-backward-within) + (defun . nxml-scan-forward-in-attribute-value) + (defun . nxml-scan-backward-in-attribute-value) + (defun . nxml-find-following-attribute) + (defun . nxml-find-preceding-attribute) + (defun . nxml-up-element) + (defun . nxml-backward-up-element) + (defun . nxml-down-element) + (defun . nxml-backward-down-element) + (defun . nxml-forward-element) + (defun . nxml-backward-element) + (defun . nxml-mark-token-after) + (defun . nxml-mark-paragraph) + (defun . nxml-forward-paragraph) + (defun . nxml-backward-paragraph) + (defun . nxml-forward-single-paragraph) + (defun . nxml-backward-single-paragraph) + (defun . nxml-token-contains-data-p) + (defun . nxml-paragraph-end-pos) + (defun . nxml-paragraph-start-pos) + (defun . nxml-token-ends-line-p) + (defun . nxml-token-begins-line-p) + (defun . nxml-in-mixed-content-p) + (defun . nxml-preceding-sibling-data-p) + (defun . nxml-following-sibling-data-p) + (defun . nxml-do-fill-paragraph) + (defun . nxml-newline-and-indent) + nxml-dynamic-markup-prev-pos nxml-dynamic-markup-prev-lengths nxml-dynamic-markup-prev-found-marker nxml-dynamic-markup-prev-start-tags + (defun . nxml-dynamic-markup-word) + (defun . nxml-try-copy-markup) + nxml-char-name-ignore-case nxml-char-name-alist nxml-char-name-table nxml-autoload-char-name-set-list + (defun . nxml-enable-char-name-set) + (defun . nxml-disable-char-name-set) + (defun . nxml-char-name-set-enabled-p) + (defun . nxml-autoload-char-name-set) + (defun . nxml-define-char-name-set) + (defun . nxml-get-char-name) + nxml-named-char-history + (defun . nxml-insert-named-char) + (defun . nxml-maybe-load-char-name-set) + (defun . nxml-toggle-char-ref-extra-display) + (defun . nxml-char-ref-display-extra) + (defun . nxml-clear-char-ref-extra-display) + (defun . nxml-start-delimiter-length) + (defun . nxml-end-delimiter-length) + (defun . nxml-token-type-friendly-name) + (provide . nxml-mode)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-outln.elc" + (require . xmltok) + (require . nxml-util) + (require . nxml-rap) + nxml-section-element-name-regexp nxml-heading-element-name-regexp nxml-outline-child-indent + (defface . nxml-heading) + (defface . nxml-outline-indicator) + (defface . nxml-outline-active-indicator) + (defface . nxml-outline-ellipsis) + nxml-heading-scan-distance nxml-outline-prefix-map + (defun . nxml-show-all) + (defun . nxml-hide-all-text-content) + (defun . nxml-show-direct-text-content) + (defun . nxml-show-direct-subheadings) + (defun . nxml-hide-direct-text-content) + (defun . nxml-hide-subheadings) + (defun . nxml-show) + (defun . nxml-hide-text-content) + (defun . nxml-show-subheadings) + (defun . nxml-hide-other) + nxml-outline-state-transform-exceptions nxml-target-section-pos nxml-depth-in-target-section nxml-outline-state-transform-alist + (defun . nxml-transform-buffer-outline) + (defun . nxml-transform-subtree-outline) + (defun . nxml-outline-pre-adjust-point) + (defun . nxml-outline-adjust-point) + (defun . nxml-transform-outline-state) + (defun . nxml-section-tag-transform-outline-state) + (defun . nxml-get-outline-state) + (defun . nxml-set-outline-state) + (defun . nxml-mouse-show-direct-text-content) + (defun . nxml-mouse-hide-direct-text-content) + (defun . nxml-mouse-hide-subheadings) + (defun . nxml-mouse-show-direct-subheadings) + (defun . nxml-mouse-set-point) + (defun . nxml-token-start-tag-p) + (defun . nxml-token-end-tag-p) + (defun . nxml-refresh-outline) + nxml-outline-display-section-tag-function + (defun . nxml-outline-display-rest) + nxml-highlighted-less-than nxml-highlighted-less-than nxml-highlighted-greater-than nxml-highlighted-greater-than nxml-highlighted-colon nxml-highlighted-colon nxml-highlighted-slash nxml-highlighted-slash nxml-highlighted-ellipsis nxml-highlighted-ellipsis nxml-highlighted-empty-end-tag nxml-highlighted-empty-end-tag nxml-highlighted-inactive-minus nxml-highlighted-inactive-minus nxml-highlighted-active-minus nxml-highlighted-active-minus nxml-highlighted-active-plus nxml-highlighted-active-plus + (defun . nxml-display-section) + (defun . nxml-highlighted-qname) + (defun . nxml-outline-display-single-line-end-tag) + (defun . nxml-outline-display-multi-line-end-tag) + nxml-outline-show-map nxml-outline-show-help nxml-outline-hiding-tag-map nxml-outline-hiding-tag-help nxml-outline-showing-tag-map nxml-outline-showing-tag-help + (defun . nxml-outline-set-overlay) + (defun . nxml-end-of-heading) + (defun . nxml-token-starts-line-p) + nxml-cached-section-tag-regexp nxml-cached-section-element-name-regexp + (defun . nxml-make-section-tag-regexp) + (defun . nxml-make-section-tag-regexp-1) + (defun . nxml-section-tag-forward) + (defun . nxml-section-tag-backward) + (defun . nxml-section-start-position) + (defun . nxml-back-to-section-start) + (defun . nxml-after-section-start-tag) + (defun . nxml-heading-start-position) + (defun . nxml-report-outline-error) + (defun . nxml-outline-error) + (defun . nxml-debug-overlays) + (provide . nxml-outln)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-rap.elc" + (require . xmltok) + (require . nxml-util) + nxml-prolog-end nxml-scan-end + (defun . nxml-get-inside) + (defun . nxml-clear-inside) + (defun . nxml-set-inside) + (defun . nxml-inside-end) + (defun . nxml-inside-start) + (defun . nxml-scan-after-change) + (defun . nxml-scan-prolog) + (defun . nxml-adjust-start-for-dependent-regions) + (defun . nxml-mark-parse-dependent-regions) + (defun . nxml-mark-parse-dependent-region) + (defun . nxml-clear-dependent-regions) + (defun . nxml-token-after) + (defun . nxml-token-before) + (defun . nxml-tokenize-forward) + (defun . nxml-move-tag-backwards) + (defun . nxml-move-outside-backwards) + (defun . nxml-ensure-scan-up-to-date) + (defun . nxml-scan-element-forward) + (defun . nxml-scan-element-backward) + (defun . nxml-scan-error) + (provide . nxml-rap)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-util.elc" nxml-debug + (defun . nxml-debug) + (defun . nxml-debug-change) + (defun . nxml-debug-set-inside) + (defun . nxml-debug-clear-inside) + (defun . nxml-make-namespace) + (defun . nxml-namespace-name) + nxml-xml-namespace-uri nxml-xml-namespace-uri nxml-xmlns-namespace-uri nxml-xmlns-namespace-uri + (defun . nxml-with-degradation-on-error) + (defun . nxml-with-unmodifying-text-property-changes) + (defun . nxml-with-invisible-motion) + (defun . nxml-display-file-parse-error) + (defun . nxml-signal-file-parse-error) + (provide . nxml-util)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-glyph.elc" nxml-ascii-glyph-set nxml-ascii-glyph-set nxml-latin1-glyph-set nxml-latin1-glyph-set nxml-misc-fixed-1-glyph-set nxml-misc-fixed-2-glyph-set nxml-misc-fixed-3-glyph-set nxml-wgl4-glyph-set nxml-glyph-set-hook nxml-glyph-set + (defun . nxml-x-set-glyph-set) + (defun . nxml-w32-set-glyph-set) + (defun . nxml-window-system-set-glyph-set) + (defun . nxml-terminal-set-glyph-set) + (t . nxml-glyph-display-string) + (defun . nxml-glyph-display-string) + (defun . nxml-glyph-set-contains-p) + (provide . nxml-glyph)) + ("/usr/share/emacs/23.0.93/lisp/nxml/nxml-enc.elc" nxml-file-name-ignore-case nxml-cached-file-name-auto-coding-regexp nxml-cached-auto-mode-alist + (defun . nxml-file-name-auto-coding-regexp) + nxml-non-xml-set-auto-coding-function + (defun . nxml-set-auto-coding) + (defun . nxml-set-xml-coding) + (defun . nxml-detect-coding-system) + (defun . nxml-mime-charset-coding-system) + (defun . nxml-start-auto-coding) + (defun . nxml-stop-auto-coding) + (provide . nxml-enc)) + ("/usr/share/emacs/23.0.93/lisp/nxml/xmltok.elc" xmltok-type xmltok-start xmltok-name-colon xmltok-name-end xmltok-replacement xmltok-attributes xmltok-namespace-attributes xmltok-dtd xmltok-dependent-regions xmltok-errors + (defun . xmltok-save) + (defun . xmltok-attribute-name-start) + (defun . xmltok-attribute-name-colon) + (defun . xmltok-attribute-name-end) + (defun . xmltok-attribute-value-start) + (defun . xmltok-attribute-value-end) + (defun . xmltok-attribute-raw-normalized-value) + (defun . xmltok-attribute-refs) + (defun . xmltok-attribute-prefix) + (defun . xmltok-attribute-local-name) + (defun . xmltok-attribute-value) + (defun . xmltok-start-tag-prefix) + (defun . xmltok-start-tag-local-name) + (defun . xmltok-end-tag-prefix) + (defun . xmltok-end-tag-local-name) + (defun . xmltok-start-tag-qname) + (defun . xmltok-end-tag-qname) + (defun . xmltok-make-attribute) + (defun . xmltok-error-message) + (defun . xmltok-error-start) + (defun . xmltok-error-end) + (defun . xmltok-make-error) + (defun . xmltok-add-error) + (defun . xmltok-add-dependent) + (defun . xmltok-forward) + (defun . xmltok-forward-special) + xmltok-ncname-regexp xmltok-ncname-regexp + (defun . xmltok-scan-after-lt) + (defun . xmltok-scan-after-processing-instruction-open) + (defun . xmltok-scan-after-comment-open) + (defun . xmltok-scan-attributes) + (defun . xmltok-add-attribute) + (defun . xmltok-normalize-attribute) + (defun . xmltok-scan-after-amp) + xmltok-entity-error-messages xmltok-entity-error-messages + (defun . xmltok-handle-entity) + (defun . xmltok-scan-char-ref) + (defun . xmltok-char-number) + (defun . xmltok-unclosed-reparse-p) + (defun . xmltok-semi-closed-reparse-p) + (defun . xmltok-valid-char-p) + (defun . xmltok-unicode-to-char) + xmltok-contains-doctype xmltok-doctype-external-subset-flag xmltok-internal-subset-start xmltok-had-param-entity-ref xmltok-prolog-regions xmltok-standalone xmltok-markup-declaration-doctype-flag xmltok-predefined-entity-alist xmltok-predefined-entity-alist + (defun . xmltok-forward-prolog) + xmltok-bad-xml-decl-regexp xmltok-bad-xml-decl-regexp + (t . xmltok-get-declared-encoding-position) + (defun . xmltok-get-declared-encoding-position) + (defun . xmltok-scan-xml-declaration) + xmltok-markup-declaration-alist xmltok-markup-declaration-alist + (defun . xmltok-parse-prolog-item) + (defun . xmltok-parse-doctype) + (defun . xmltok-parse-attlist-declaration) + (defun . xmltok-parse-nmtoken-group) + (defun . xmltok-parse-element-declaration) + (defun . xmltok-parse-model-group) + (defun . xmltok-parse-model-group-member) + (defun . xmltok-parse-entity-declaration) + (defun . xmltok-define-entity) + (defun . xmltok-parse-entity-value) + (defun . xmltok-parse-notation-declaration) + (defun . xmltok-parse-external-id) + (defun . xmltok-require-next-token) + (defun . xmltok-require-token) + (defun . xmltok-current-token-string) + (defun . xmltok-markup-declaration-parse-error) + (defun . xmltok-skip-markup-declaration) + (defun . xmltok-prolog-region-type) + (defun . xmltok-next-prolog-token) + (defun . xmltok-scan-prolog-literal) + (defun . xmltok-scan-prolog-after-processing-instruction-open) + (defun . xmltok-parse-entities) + (defun . xmltok-parse-entity) + (defun . xmltok-parse-entity-replacement) + (defun . xmltok-handle-nested-entity) + (defun . xmltok-append-entity-def) + (defun . xmltok-add-prolog-region) + (defun . xmltok-merge-attributes) + (defun . xmltok-forward-test) + (defun . xmltok-next-prolog-token-test) + (provide . xmltok)) + ("/home/hobbes/nxhtml/util/mlinks.el" mlinks:version + (require . cl) + (require . ourcomments-util) + (require . url-parse) + (require . url-expand) + (require . appmenu) + mlinks-mode-functions mlinks-mode-map + (defun . mlinks-want-marked-links) + (defun . mlinks-after-change-major-mode) + mlinks-hilight-this-buffer mlinks-hilight-point-ovl mlinks-hilighter-timer + (defun . mlinks-toggle-hilight) + (defun . mlinks-stop-hilighter) + (defun . mlinks-start-hilighter) + (defun . mlinks-make-point-ovl) + (defun . mlinks-link-at-point) + (defun . mlinks-hilighter) + mlinks-active-hilight-keymap mlinks-inactive-hilight-keymap + (defun . mlinks-pre-command) + (defun . mlinks-activate-hilight) + (defun . mlinks-deactivate-hilight) + (defun . mlinks-someactivate-hilight) + (defun . mlinks-backward-link) + (defun . mlinks-forward-link) + (defun . mlinks-goto) + (defun . mlinks-goto-other-window) + (defun . mlinks-goto-other-frame) + (defun . mlinks-goto-1) + (defun . mlinks-get-boolean) + (defun . mlinks-get-action) + (defun . mlinks-prev-saved-position) + (defun . mlinks-next-saved-position) + (defun . mlinks-goto-n) + mlinks-places-n mlinks-places mlinks-temp-buffer-where + (defun . mlinks-switch-to-buffer) + (defun . mlinks-switch-to-buffer-1) + (defun . mlinks-custom) + (defun . mlinks-appmenu) + (defun . mlinks-add-appmenu) + (defun . mlinks-remove-overlays) + mlinks-mode + (t . mlinks-mode) + (defun . mlinks-mode) + (defun . mlinks-turn-on-in-buffer) + mlinks-mode-major-mode mlinks-global-mode + (defun . mlinks-global-mode) + mlinks-global-mode-buffers + (defun . mlinks-global-mode-enable-in-buffers) + (defun . mlinks-global-mode-check-buffers) + (defun . mlinks-global-mode-cmhh) + mlinks-active-links + (defun . mlinks-active-links-toggle) + (defface . mlinks-link) + mlinks-link + (defun . mlinks-mark-link) + mlinks-mark-links-timer + (defun . mlinks-mark-next-link) + mlinks-link-update-pos-min mlinks-link-update-pos-max + (defun . mlinks-stop-marking-links) + (defun . mlinks-start-marking-links) + mlinks-after-change-extra + (defun . mlinks-after-change) + (defun . mlinks-html-style-goto) + (defun . mlinks-html-style-hili) + (require . rx) + mlinks-html-link-regex + (defun . mlinks-html-forward-link) + (defun . mlinks-html-backward-link) + (defun . mlinks-html-style-mode-fun) + (defun . mlink-check-file-to-edit) + (defun . mlinks-html-edit-at) + (defun . mlinks-html-mail-to) + (defun . mlinks-html-href-act-on) + (defun . mlinks-html-possible-href-actions) + (defun . mlinks-html-find-base-href) + (defun . mlinks-elisp-custom-goto) + (defun . mlinks-custom-next-mark) + (defun . mlinks-elisp-goto) + (defun . mlinks-elisp-hili) + (defun . mlinks-elisp-mode-fun) + (defun . mlinks-elisp-function) + (defun . mlinks-elisp-mode-symbol) + (defun . mlinks-elisp-mode-require) + (defun . mlinks-hit-test) + (defun . mlinks-handle-reg-fun-list) + (provide . mlinks)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/rx.elc" rx-constituents rx-syntax rx-categories rx-greedy-flag + (defun . rx-info) + (defun . rx-check) + (defun . rx-group-if) + (defun . rx-and) + (defun . rx-or) + (defun . rx-anything) + (defun . rx-any-delete-from-range) + (defun . rx-any-condense-range) + (defun . rx-check-any-string) + (defun . rx-check-any) + (defun . rx-any) + (defun . rx-check-not) + (defun . rx-not) + (defun . rx-not-char) + (defun . rx-not-syntax) + (defun . rx-trans-forms) + (defun . rx-=) + (defun . rx->=) + (defun . rx-**) + (defun . rx-repeat) + (defun . rx-submatch) + (defun . rx-backref) + (defun . rx-check-backref) + (defun . rx-kleene) + (defun . rx-atomic-p) + (defun . rx-syntax) + (defun . rx-check-category) + (defun . rx-category) + (defun . rx-eval) + (defun . rx-greedy) + (defun . rx-regexp) + (defun . rx-form) + (t . rx-to-string) + (defun . rx-to-string) + (t . rx) + (defun . rx) + (provide . rx)) + ("/home/hobbes/nxhtml/util/appmenu.el" appmenu:version + (require . cl) + appmenu-show-help appmenu-show-point-menu appmenu-alist + (defun . appmenu-sort-by-priority) + (t . appmenu-add) + (defun . appmenu-add) + (defun . appmenu-remove) + (defun . appmenu-help) + (defun . appmenu-keymap-len) + appmenu-mouse-only + (defun . appmenu-make-menu-for-point) + (defun . appmenu-map) + (defun . appmenu-popup) + appmenu-mode-map appmenu-mode + (defun . appmenu-mode) + (provide . appmenu)) + ("/usr/share/emacs/23.0.93/lisp/textmodes/flyspell.elc" + (require . ispell) + flyspell-highlight-flag flyspell-mark-duplications-flag flyspell-mark-duplications-exceptions flyspell-sort-corrections flyspell-duplicate-distance flyspell-delay flyspell-persistent-highlight flyspell-highlight-properties flyspell-default-delayed-commands flyspell-delayed-commands flyspell-default-deplacement-commands flyspell-deplacement-commands flyspell-issue-welcome-flag flyspell-issue-message-flag flyspell-incorrect-hook flyspell-default-dictionary flyspell-tex-command-regexp flyspell-check-tex-math-command flyspell-dictionaries-that-consider-dash-as-word-delimiter flyspell-abbrev-p flyspell-use-global-abbrev-table-p flyspell-mode-line-string flyspell-large-region flyspell-insert-function flyspell-before-incorrect-word-string flyspell-after-incorrect-word-string flyspell-use-meta-tab flyspell-auto-correct-binding flyspell-generic-check-word-predicate flyspell-generic-check-word-p + (defun . mail-mode-flyspell-verify) + (defun . texinfo-mode-flyspell-verify) + (defun . tex-mode-flyspell-verify) + (defun . sgml-mode-flyspell-verify) + flyspell-prog-text-faces + (defun . flyspell-generic-progmode-verify) + (t . flyspell-prog-mode) + (defun . flyspell-prog-mode) + flyspell-mouse-map flyspell-mode-map flyspell-consider-dash-as-word-delimiter-flag flyspell-dash-dictionary flyspell-dash-local-dictionary + (defface . flyspell-incorrect) + (defface . flyspell-duplicate) + flyspell-overlay flyspell-mode + (t . flyspell-mode) + (defun . flyspell-mode) + (t . turn-on-flyspell) + (defun . turn-on-flyspell) + (t . turn-off-flyspell) + (defun . turn-off-flyspell) + flyspell-buffers + (defun . flyspell-minibuffer-p) + flyspell-last-buffer + (defun . flyspell-accept-buffer-local-defs) + (defun . flyspell-hack-local-variables-hook) + (defun . flyspell-kill-ispell-hook) + (defun . flyspell-mode-on) + (defun . flyspell-delay-commands) + (defun . flyspell-delay-command) + (defun . flyspell-deplacement-commands) + (defun . flyspell-deplacement-command) + flyspell-word-cache-start flyspell-word-cache-end flyspell-word-cache-word flyspell-word-cache-result flyspell-pre-buffer flyspell-pre-point flyspell-pre-column flyspell-pre-pre-buffer flyspell-pre-pre-point flyspell-previous-command + (defun . flyspell-pre-command-hook) + (t . flyspell-mode-off) + (defun . flyspell-mode-off) + (defun . flyspell-check-pre-word-p) + flyspell-changes + (defun . flyspell-after-change-function) + (defun . flyspell-check-changed-word-p) + (defun . flyspell-check-word-p) + (defun . flyspell-debug-signal-no-check) + (defun . flyspell-debug-signal-pre-word-checked) + (defun . flyspell-debug-signal-word-checked) + (defun . flyspell-debug-signal-changed-checked) + (defun . flyspell-post-command-hook) + (defun . flyspell-notify-misspell) + (defun . flyspell-word-search-backward) + (defun . flyspell-word-search-forward) + (defun . flyspell-word) + (defun . flyspell-math-tex-command-p) + (defun . flyspell-tex-command-p) + flyspell-casechars-cache flyspell-ispell-casechars-cache + (defun . flyspell-get-casechars) + flyspell-not-casechars-cache flyspell-ispell-not-casechars-cache + (defun . flyspell-get-not-casechars) + (defun . flyspell-get-word) + (defun . flyspell-small-region) + flyspell-external-ispell-process flyspell-external-ispell-buffer flyspell-large-region-buffer flyspell-large-region-beg flyspell-large-region-end + (defun . flyspell-external-point-words) + (defun . flyspell-process-localwords) + (defun . flyspell-check-region-doublons) + (defun . flyspell-large-region) + (t . flyspell-region) + (defun . flyspell-region) + (t . flyspell-buffer) + (defun . flyspell-buffer) + flyspell-old-buffer-error flyspell-old-pos-error + (defun . flyspell-goto-next-error) + (defun . flyspell-overlay-p) + (defun . flyspell-delete-region-overlays) + (defun . flyspell-delete-all-overlays) + (defun . flyspell-unhighlight-at) + (defun . flyspell-properties-at-p) + (defun . make-flyspell-overlay) + (defun . flyspell-highlight-incorrect-region) + (defun . flyspell-highlight-duplicate-region) + flyspell-auto-correct-pos flyspell-auto-correct-region flyspell-auto-correct-ring flyspell-auto-correct-word + (defun . flyspell-check-previous-highlighted-word) + (defun . flyspell-display-next-corrections) + (defun . flyspell-abbrev-table) + (defun . flyspell-define-abbrev) + (defun . flyspell-auto-correct-word) + flyspell-auto-correct-previous-pos + (defun . flyspell-auto-correct-previous-hook) + (defun . flyspell-auto-correct-previous-word) + (defun . flyspell-correct-word) + (defun . flyspell-correct-word-before-point) + (defun . flyspell-do-correct) + (defun . flyspell-ajust-cursor-point) + (defun . flyspell-emacs-popup) + (defun . flyspell-xemacs-popup) + (defun . flyspell-maybe-correct-transposition) + (defun . flyspell-maybe-correct-doubling) + (defun . flyspell-already-abbrevp) + (defun . flyspell-change-abbrev) + (provide . flyspell)) + ("/usr/share/emacs/23.0.93/lisp/textmodes/ispell.elc" + (defun . ispell-check-minver) + (defun . check-ispell-version) + ispell-highlight-p ispell-lazy-highlight ispell-highlight-face ispell-check-comments ispell-query-replace-choices ispell-skip-tib ispell-tib-ref-beginning ispell-tib-ref-end ispell-keep-choices-win ispell-choices-win-default-height ispell-program-name ispell-alternate-dictionary ispell-complete-word-dict ispell-message-dictionary-alist ispell-message-fcc-skip ispell-grep-command ispell-grep-options ispell-look-command ispell-look-p ispell-have-new-look ispell-look-options ispell-use-ptys-p ispell-following-word ispell-help-in-bufferp ispell-quietly ispell-format-word-function ispell-format-word ispell-use-framepop-p ispell-personal-dictionary ispell-silently-savep ispell-local-dictionary-overridden ispell-local-dictionary ispell-extra-args ispell-skip-html ispell-local-dictionary-alist ispell-dictionary-base-alist ispell-dictionary-alist ispell-really-aspell ispell-really-hunspell ispell-encoding8-command ispell-aspell-supports-utf8 ispell-required-version ispell-offset ispell-version ispell-version + (defun . ispell-check-version) + (defun . ispell-call-process) + (defun . ispell-call-process-region) + ispell-menu-map ispell-menu-xemacs ispell-menu-map-needed ispell-library-directory ispell-process ispell-async-processp ispell-aspell-dictionary-alist + (defun . ispell-find-aspell-dictionaries) + ispell-aspell-data-dir ispell-aspell-dict-dir + (defun . ispell-get-aspell-config-value) + (defun . ispell-aspell-find-dictionary) + (defun . ispell-aspell-add-aliases) + ispell-last-program-name ispell-initialize-spellchecker-hook + (defun . ispell-set-spellchecker-params) + (defun . ispell-valid-dictionary-list) + (defun . ispell-int-char) + ispell-current-dictionary ispell-current-personal-dictionary ispell-dictionary + (defun . ispell-decode-string) + (defun . ispell-get-decoded-string) + (defun . ispell-get-casechars) + (defun . ispell-get-not-casechars) + (defun . ispell-get-otherchars) + (defun . ispell-get-many-otherchars-p) + (defun . ispell-get-ispell-args) + (defun . ispell-get-extended-character-mode) + (defun . ispell-get-coding-system) + ispell-pdict-modified-p ispell-quit ispell-process-directory ispell-filter ispell-filter-continue ispell-output-buffer ispell-session-buffer ispell-cmd-args ispell-query-replace-marker ispell-recursive-edit-marker ispell-checking-message ispell-choices-buffer ispell-choices-buffer ispell-overlay ispell-words-keyword ispell-dictionary-keyword ispell-pdict-keyword ispell-parsing-keyword ispell-skip-region-alist ispell-tex-skip-alists ispell-html-skip-alists ispell-local-pdict ispell-buffer-local-name ispell-parser ispell-region-end ispell-check-only + (defun . ispell-accept-output) + (defun . ispell-send-replacement) + (defun . ispell-send-string) + (defun . ispell-insert-word) + (t . ispell-word) + (defun . ispell-word) + (defun . ispell-get-word) + (t . ispell-pdict-save) + (defun . ispell-pdict-save) + (defun . ispell-command-loop) + (defun . ispell-show-choices) + (t . ispell-help) + (defun . ispell-help) + (defun . lookup-words) + (defun . ispell-filter) + (defun . ispell-highlight-spelling-error-generic) + (defun . ispell-highlight-spelling-error-xemacs) + (defun . ispell-highlight-spelling-error-overlay) + (defun . ispell-highlight-spelling-error) + (defun . ispell-adjusted-window-height) + (defun . ispell-overlay-window) + (defun . ispell-parse-output) + (defun . ispell-process-status) + (defun . ispell-start-process) + (defun . ispell-init-process) + (t . ispell-kill-ispell) + (defun . ispell-kill-ispell) + (t . ispell-change-dictionary) + (defun . ispell-change-dictionary) + (defun . ispell-internal-change-dictionary) + (t . ispell-region) + (defun . ispell-region) + (defun . ispell-begin-skip-region-regexp) + (defun . ispell-begin-skip-region) + (defun . ispell-begin-tex-skip-regexp) + (defun . ispell-skip-region-list) + (defun . ispell-tex-arg-end) + (defun . ispell-ignore-fcc) + (defun . ispell-skip-region) + (defun . ispell-get-line) + (defun . ispell-looking-at) + (defun . ispell-process-line) + (t . ispell-comments-and-strings) + (defun . ispell-comments-and-strings) + (t . ispell-buffer) + (defun . ispell-buffer) + (t . ispell-continue) + (defun . ispell-continue) + (defun . ispell-horiz-scroll) + (t . ispell-complete-word) + (defun . ispell-complete-word) + (t . ispell-complete-word-interior-frag) + (defun . ispell-complete-word-interior-frag) + (t . ispell) + (defun . ispell) + ispell-minor-mode ispell-minor-keymap + (t . ispell-minor-mode) + (defun . ispell-minor-mode) + (defun . ispell-minor-check) + ispell-message-text-end + (defun . ispell-mime-multipartp) + (defun . ispell-mime-skip-part) + (t . ispell-message) + (defun . ispell-message) + (defun . ispell-non-empty-string) + (defun . ispell-accept-buffer-local-defs) + (defun . ispell-buffer-local-parsing) + (defun . ispell-buffer-local-dict) + (defun . ispell-buffer-local-words) + (defun . ispell-add-per-file-word-list) + (provide . ispell)) + ("/home/hobbes/nxhtml/nxhtml/html-site.el" html-site:version + (require . ourcomments-util) + (require . cl) + (require . dired) + (require . ffip) + (require . grep) + (defun . html-site-looks-like-local-url) + (require . url-parse) + (require . url-http) + (defun . html-site-dir-contains) + (defun . html-site-lwarn) + (defun . html-site-chk-wtocdir) + (t . html-site-buffer-or-dired-file-name) + (defun . html-site-buffer-or-dired-file-name) + (t . html-site-set-site) + (defun . html-site-set-site) + (t . html-site-dired-current) + (defun . html-site-dired-current) + (t . html-site-find-file) + (defun . html-site-find-file) + (t . html-site-rgrep) + (defun . html-site-rgrep) + (t . html-site-query-replace) + (defun . html-site-query-replace) + (defun . html-site-ensure-site-defined) + (defun . html-site-current-ensure-site-defined) + (defun . html-site-remote-contains) + (defun . html-site-current-remote-contains) + (defun . html-site-ensure-file-in-site) + (defun . html-site-current-ensure-file-in-site) + (defun . html-site-ensure-buffer-in-site) + (defun . html-site-current-ensure-buffer-in-site) + (defun . html-site-site-dir) + (defun . html-site-current-site-dir) + (defun . html-site-contains) + (defun . html-site-current-contains) + (defun . html-site-page-list) + (defun . html-site-current-page-list) + (defun . html-site-frames-file) + (defun . html-site-current-frames-file) + (defun . html-site-toc-file) + (defun . html-site-current-toc-file) + (defun . html-site-merge-dir) + (defun . html-site-current-merge-dir) + (defun . html-site-merge-template) + (defun . html-site-current-merge-template) + (defun . html-site-extra-fun) + (defun . html-site-current-extra-fun) + (defun . html-site-ftp-host) + (defun . html-site-current-ftp-host) + (defun . html-site-ftp-user) + (defun . html-site-current-ftp-user) + (defun . html-site-ftp-password) + (defun . html-site-current-ftp-password) + (defun . html-site-ftp-dir) + (defun . html-site-current-ftp-dir) + (defun . html-site-ftp-wtoc-dir) + (defun . html-site-current-ftp-wtoc-dir) + (defun . html-site-web-host) + (defun . html-site-current-web-host) + (defun . html-site-web-dir) + (defun . html-site-current-web-dir) + (defun . html-site-web-wtoc-dir) + (defun . html-site-current-web-wtoc-dir) + (defun . html-site-web-full) + (defun . html-site-current-web-full) + html-site-ftp-temporary-passwords + (defun . html-site-get-ftp-pw) + (defun . html-site-path-in-mirror) + (defun . html-site-local-to-web) + (defun . html-site-current-local-to-web) + (defun . html-site-remote-root) + (defun . html-site-current-remote-root) + (defun . html-site-local-to-remote) + (defun . html-site-current-local-to-remote) + (defun . html-site-remote-to-local) + (defun . html-site-current-remote-to-local) + html-site-files-re + (defun . html-site-edit-pages-file) + (defun . html-site-get-sub-files) + (defun . html-site-file-is-local) + html-site-list html-site-current noshell-procbuf-name noshell-proc-name + (defun . noshell-procbuf-setup) + (defun . noshell-procbuf-teardown) + (defun . noshell-procbuf-run) + (defun . noshell-sentinel) + (defun . noshell-procbuf-syncrun) + noshell-process-mode-map noshell-process-mode-syntax-table noshell-process-mode-abbrev-table noshell-process-mode-abbrev-table + (defun . noshell-process-mode) + (defun . noshell-quit) + (defun . noshell-kill-subprocess) + (provide . html-site) + (require . html-upl) + html-site-mode-menu-map html-site-mode-map html-site-mode + (defun . html-site-mode) + html-site-mode-off-list html-site-mode-major-mode html-site-global-mode + (defun . html-site-global-mode) + html-site-global-mode-buffers + (defun . html-site-global-mode-enable-in-buffers) + (defun . html-site-global-mode-check-buffers) + (defun . html-site-global-mode-cmhh)) + ("/home/hobbes/nxhtml/nxhtml/html-upl.el" html-upl:version + (require . html-site) + html-upl-dir + (defun . html-upl-browse-remote) + (defun . html-upl-browse-remote-with-toc) + (defun . html-upl-browse-remote-frames) + (defun . html-upl-upload-site-with-toc) + (defun . html-upl-upload-site) + (defun . html-upl-upload-site1) + (defun . html-upl-ensure-site-has-host) + (defun . html-upl-remote-dired) + (defun . html-upl-upload-file) + (defun . html-upl-edit-remote-file) + (defun . html-upl-edit-remote-file-with-toc) + (defun . html-upl-edit-remote-file1) + (defun . html-upl-ediff-file) + (provide . html-upl)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/derived.elc" + (defun . derived-mode-hook-name) + (defun . derived-mode-map-name) + (defun . derived-mode-syntax-table-name) + (defun . derived-mode-abbrev-table-name) + (t . define-derived-mode) + (defun . define-derived-mode) + (defun . derived-mode-class) + (defun . derived-mode-make-docstring) + (defun . derived-mode-setup-function-name) + (t . derived-mode-init-mode-variables) + (defun . derived-mode-init-mode-variables) + (defun . derived-mode-set-keymap) + (defun . derived-mode-set-syntax-table) + (defun . derived-mode-set-abbrev-table) + (defun . derived-mode-run-hooks) + (defun . derived-mode-merge-keymaps) + (defun . derived-mode-merge-syntax-tables) + (defun . derived-mode-merge-abbrev-tables) + (provide . derived)) + ("/usr/share/emacs/23.0.93/lisp/url/url-http.elc" + (require . url-gw) + (require . url-util) + (require . url-parse) + (require . url-cookie) + (require . mail-parse) + (require . url-auth) + (require . url) + (autoload . url-cache-create-filename) + url-http-default-port url-http-asynchronous-p + (defun . url-http-expand-file-name) + url-http-real-basic-auth-storage url-http-proxy-basic-auth-storage url-http-open-connections url-http-version url-http-attempt-keepalives + (defun . url-http-debug) + (defun . url-http-mark-connection-as-busy) + (defun . url-http-mark-connection-as-free) + (defun . url-http-find-free-connection) + (defun . url-http-user-agent-string) + (defun . url-http-create-request) + (defun . url-http-clean-headers) + (defun . url-http-handle-authentication) + (defun . url-http-parse-response) + (defun . url-http-handle-cookies) + (defun . url-http-parse-headers) + (defun . url-http-activate-callback) + (defun . url-http-idle-sentinel) + (defun . url-http-end-of-document-sentinel) + (defun . url-http-simple-after-change-function) + (defun . url-http-content-length-after-change-function) + (defun . url-http-chunked-encoding-after-change-function) + (defun . url-http-wait-for-headers-change-function) + (t . url-http) + (defun . url-http) + (defun . url-http-async-sentinel) + (defun . url-http-generic-filter) + (defun . url-http-symbol-value-in-buffer) + (defun . url-http-head) + (t . url-http-file-exists-p) + (defun . url-http-file-exists-p) + (defun . url-http-file-readable-p) + (defun . url-http-head-file-attributes) + (t . url-http-file-attributes) + (defun . url-http-file-attributes) + (t . url-http-options) + (defun . url-http-options) + (require . tls) + url-https-default-port url-https-asynchronous-p + (defun . url-https-expand-file-name) + (defun . url-https-create-secure-wrapper) + (t . url-https) + (defun . url-https) + (t . url-https-file-exists-p) + (defun . url-https-file-exists-p) + (t . url-https-file-readable-p) + (defun . url-https-file-readable-p) + (t . url-https-file-attributes) + (defun . url-https-file-attributes) + (provide . url-http)) + ("/usr/share/emacs/23.0.93/lisp/net/tls.elc" + (autoload . format-spec) + (autoload . format-spec-make) + tls-end-of-info tls-program tls-process-connection-type tls-success tls-checktrust tls-untrusted tls-hostmismatch tls-certtool-program + (defun . tls-certificate-information) + (t . open-tls-stream) + (defun . open-tls-stream) + (provide . tls)) + ("/usr/share/emacs/23.0.93/lisp/url/url.elc" + (require . mailcap) + (require . url-vars) + (require . url-cookie) + (require . url-history) + (require . url-expand) + (require . url-privacy) + (require . url-methods) + (require . url-proxy) + (require . url-parse) + (require . url-util) + url-configuration-directory + (t . url-do-setup) + (defun . url-do-setup) + url-redirect-buffer + (t . url-retrieve) + (defun . url-retrieve) + (defun . url-retrieve-internal) + (t . url-retrieve-synchronously) + (defun . url-retrieve-synchronously) + (defun . url-mm-callback) + (defun . url-mm-url) + url-dead-buffer-list + (defun . url-mark-buffer-as-dead) + (defun . url-gc-dead-buffers) + (t . url-warn) + (defun . url-warn) + (provide . url)) + ("/usr/share/emacs/23.0.93/lisp/url/url-proxy.elc" + (require . url-parse) + (autoload . url-warn) + (defun . url-default-find-proxy-for-url) + url-proxy-locator + (defun . url-find-proxy-for-url) + (defun . url-proxy) + (provide . url-proxy)) + ("/usr/share/emacs/23.0.93/lisp/url/url-privacy.elc" + (require . url-vars) + (defun . url-device-type) + (t . url-setup-privacy-info) + (defun . url-setup-privacy-info) + (provide . url-privacy)) + ("/usr/share/emacs/23.0.93/lisp/url/url-expand.elc" + (require . url-methods) + (require . url-util) + (require . url-parse) + (defun . url-expander-remove-relative-links) + (defun . url-expand-file-name) + (defun . url-identity-expander) + (t . url-default-expander) + (defun . url-default-expander) + (provide . url-expand)) + ("/usr/share/emacs/23.0.93/lisp/url/url-history.elc" + (require . url-parse) + (autoload . url-do-setup) + url-history-track url-history-file url-history-save-interval url-history-timer url-history-changed-since-last-save url-history-hash-table + (defun . url-history-setup-save-timer) + (defun . url-history-parse-history) + (defun . url-history-update-url) + (defun . url-history-save-history) + (defun . url-have-visited-url) + (defun . url-completion-function) + (provide . url-history)) + ("/usr/share/emacs/23.0.93/lisp/gnus/mailcap.elc" + (defun . mailcap-delete-duplicates) + (defun . mailcap-replace-in-string) + mailcap-parse-args-syntax-table mailcap-print-command mailcap-mime-data mailcap-download-directory mailcap-poor-system-types + (defun . mailcap-save-binary-file) + mailcap-maybe-eval-warning + (defun . mailcap-maybe-eval) + (defun . mailcap-replace-regexp) + mailcap-parsed-p + (defun . mailcap-parse-mailcaps) + (defun . mailcap-parse-mailcap) + (defun . mailcap-parse-mailcap-extras) + (defun . mailcap-mailcap-entry-passes-test) + (defun . mailcap-possible-viewers) + (defun . mailcap-unescape-mime-test) + mailcap-viewer-test-cache + (defun . mailcap-viewer-passes-test) + (defun . mailcap-add-mailcap-entry) + (defun . mailcap-add) + (defun . mailcap-viewer-lessp) + (defun . mailcap-mime-info) + mailcap-mime-extensions mailcap-mimetypes-parsed-p + (defun . mailcap-parse-mimetypes) + (defun . mailcap-parse-mimetype-file) + (defun . mailcap-extension-to-mime) + (defun . mailcap-command-p) + (defun . mailcap-mime-types) + (defun . mailcap-file-default-commands) + (provide . mailcap)) + ("/usr/share/emacs/23.0.93/lisp/url/url-auth.elc" + (require . url-vars) + (require . url-parse) + (autoload . url-warn) + (autoload . auth-source-user-or-password) + (defun . url-auth-user-prompt) + url-basic-auth-storage + (defun . url-basic-auth) + url-digest-auth-storage + (defun . url-digest-auth-create-key) + (defun . url-digest-auth) + url-registered-auth-schemes + (t . url-get-authentication) + (defun . url-get-authentication) + (t . url-register-auth-scheme) + (defun . url-register-auth-scheme) + (defun . url-auth-registered) + (provide . url-auth)) + ("/usr/share/emacs/23.0.93/lisp/gnus/mail-parse.elc" + (require . mail-prsvr) + (require . ietf-drums) + (require . rfc2231) + (require . rfc2047) + (require . rfc2045) + (defun . mail-header-parse-content-type) + (defun . mail-header-parse-content-disposition) + (defun . mail-content-type-get) + (defun . mail-header-encode-parameter) + (t . mail-header-remove-comments) + (defun . mail-header-remove-comments) + (t . mail-header-remove-whitespace) + (defun . mail-header-remove-whitespace) + (defun . mail-header-strip) + (defun . mail-header-get-comment) + (defun . mail-header-parse-address) + (defun . mail-header-parse-addresses) + (defun . mail-header-parse-date) + (defun . mail-narrow-to-head) + (defun . mail-quote-string) + (defun . mail-header-make-address) + (defun . mail-header-fold-field) + (defun . mail-header-unfold-field) + (defun . mail-header-narrow-to-field) + (defun . mail-header-field-value) + (defun . mail-encode-encoded-word-region) + (defun . mail-encode-encoded-word-buffer) + (defun . mail-encode-encoded-word-string) + (defun . mail-decode-encoded-word-region) + (defun . mail-decode-encoded-word-string) + (defun . mail-decode-encoded-address-region) + (defun . mail-decode-encoded-address-string) + (provide . mail-parse)) + ("/usr/share/emacs/23.0.93/lisp/gnus/rfc2231.elc" + (require . ietf-drums) + (require . rfc2047) + (autoload . mm-encode-body) + (autoload . mail-header-remove-whitespace) + (autoload . mail-header-remove-comments) + (defun . rfc2231-get-value) + (defun . rfc2231-parse-qp-string) + (defun . rfc2231-parse-string) + (defun . rfc2231-decode-encoded-string) + (defun . rfc2231-encode-string) + (provide . rfc2231)) + ("/usr/share/emacs/23.0.93/lisp/gnus/rfc2047.elc" + (require . qp) + (require . mm-util) + (require . ietf-drums) + (require . mail-prsvr) + (require . rfc2045) + (autoload . mm-body-7-or-8) + rfc2047-header-encoding-alist rfc2047-charset-encoding-alist rfc2047-encode-function-alist rfc2047-encode-encoded-words rfc2047-allow-irregular-q-encoded-words rfc2047-encoded-word-regexp rfc2047-encoded-word-regexp-loose + (defun . rfc2047-qp-or-base64) + (defun . rfc2047-narrow-to-field) + (defun . rfc2047-field-value) + (defun . rfc2047-quote-special-characters-in-quoted-strings) + rfc2047-encoding-type + (defun . rfc2047-encode-message-header) + (defun . rfc2047-encodable-p) + rfc2047-syntax-table rfc2047-syntax-table + (defun . rfc2047-encode-region) + (defun . rfc2047-encode-string) + rfc2047-encode-max-chars + (defun . rfc2047-encode-1) + (defun . rfc2047-encode) + (defun . rfc2047-fold-field) + (defun . rfc2047-fold-region) + (defun . rfc2047-unfold-field) + (defun . rfc2047-unfold-region) + (defun . rfc2047-b-encode-string) + (defun . rfc2047-q-encode-string) + (defun . rfc2047-encode-parameter) + rfc2047-quote-decoded-words-containing-tspecials rfc2047-allow-incomplete-encoded-text + (defun . rfc2047-strip-backslashes-in-quoted-strings) + (defun . rfc2047-charset-to-coding-system) + (defun . rfc2047-decode-encoded-words) + (defun . rfc2047-decode-region) + (defun . rfc2047-decode-address-region) + (defun . rfc2047-decode-string) + (defun . rfc2047-decode-address-string) + (defun . rfc2047-pad-base64) + (provide . rfc2047)) + ("/usr/share/emacs/23.0.93/lisp/gnus/rfc2045.elc" + (require . ietf-drums) + (defun . rfc2045-encode-string) + (provide . rfc2045)) + ("/usr/share/emacs/23.0.93/lisp/gnus/qp.elc" + (require . mm-util) + (t . quoted-printable-decode-region) + (defun . quoted-printable-decode-region) + (defun . quoted-printable-decode-string) + (defun . quoted-printable-encode-region) + (defun . quoted-printable-encode-string) + (provide . qp)) + ("/usr/share/emacs/23.0.93/lisp/gnus/ietf-drums.elc" + (require . time-date) + (require . mm-util) + ietf-drums-no-ws-ctl-token ietf-drums-text-token ietf-drums-specials-token ietf-drums-quote-token ietf-drums-wsp-token ietf-drums-fws-regexp ietf-drums-atext-token ietf-drums-dot-atext-token ietf-drums-qtext-token ietf-drums-tspecials ietf-drums-syntax-table + (defun . ietf-drums-token-to-list) + (defun . ietf-drums-init) + (defun . ietf-drums-remove-comments) + (defun . ietf-drums-remove-whitespace) + (defun . ietf-drums-get-comment) + (defun . ietf-drums-strip) + (defun . ietf-drums-parse-address) + (defun . ietf-drums-parse-addresses) + (defun . ietf-drums-unfold-fws) + (defun . ietf-drums-parse-date) + (defun . ietf-drums-narrow-to-header) + (defun . ietf-drums-quote-string) + (defun . ietf-drums-make-address) + (provide . ietf-drums)) + ("/usr/share/emacs/23.0.93/lisp/calendar/time-date.elc" + (defun . with-decoded-time-value) + (defun . encode-time-value) + (autoload . parse-time-string) + (t . date-to-time) + (defun . date-to-time) + (t . time-to-seconds) + (defun . time-to-seconds) + (t . seconds-to-time) + (defun . seconds-to-time) + (t . time-less-p) + (defun . time-less-p) + (t . days-to-time) + (defun . days-to-time) + (t . time-since) + (defun . time-since) + (defun . subtract-time) + (t . time-subtract) + (defun . time-subtract) + (t . time-add) + (defun . time-add) + (t . date-to-day) + (defun . date-to-day) + (t . days-between) + (defun . days-between) + (t . date-leap-year-p) + (defun . date-leap-year-p) + (t . time-to-day-in-year) + (defun . time-to-day-in-year) + (t . time-to-days) + (defun . time-to-days) + (defun . time-to-number-of-days) + (t . safe-date-to-time) + (defun . safe-date-to-time) + (t . format-seconds) + (defun . format-seconds) + (provide . time-date)) + ("/usr/share/emacs/23.0.93/lisp/url/url-cookie.elc" + (require . timezone) + (require . url-util) + (require . url-parse) + (defun . url-cookie-tag) + (defun . url-cookie-name) + (defun . url-cookie-value) + (defun . url-cookie-expires) + (defun . url-cookie-localpart) + (defun . url-cookie-domain) + (defun . url-cookie-secure) + (defun . url-cookie-create) + url-cookie-storage url-cookie-secure-storage url-cookie-file url-cookie-confirmation url-cookie-multiple-line url-cookies-changed-since-last-save + (defun . url-cookie-parse-file) + (defun . url-cookie-clean-up) + (defun . url-cookie-write-file) + (defun . url-cookie-store) + (defun . url-cookie-expired-p) + (defun . url-cookie-retrieve) + (defun . url-cookie-generate-header-lines) + url-cookie-two-dot-domains url-cookie-trusted-urls url-cookie-untrusted-urls + (defun . url-cookie-host-can-set-p) + (defun . url-cookie-handle-set-cookie) + url-cookie-timer url-cookie-save-interval + (defun . url-cookie-setup-save-timer) + (provide . url-cookie)) + ("/usr/share/emacs/23.0.93/lisp/timezone.elc" timezone-world-timezones timezone-months-assoc + (t . timezone-make-date-arpa-standard) + (defun . timezone-make-date-arpa-standard) + (defun . timezone-make-date-sortable) + (defun . timezone-make-arpa-date) + (defun . timezone-make-sortable-date) + (defun . timezone-make-time-string) + (t . timezone-parse-date) + (defun . timezone-parse-date) + (defun . timezone-parse-time) + (defun . timezone-zone-to-minute) + (defun . timezone-time-from-absolute) + (defun . timezone-time-zone-from-absolute) + (defun . timezone-fix-time) + (defun . timezone-last-day-of-month) + (defun . timezone-leap-year-p) + (defun . timezone-day-number) + (defun . timezone-absolute-from-gregorian) + (provide . timezone)) + ("/usr/share/emacs/23.0.93/lisp/url/url-util.elc" + (require . url-parse) + (autoload . timezone-parse-date) + (autoload . timezone-make-date-arpa-standard) + (autoload . mail-header-extract) + url-parse-args-syntax-table url-debug + (t . url-debug) + (defun . url-debug) + (t . url-parse-args) + (defun . url-parse-args) + (t . url-insert-entities-in-string) + (defun . url-insert-entities-in-string) + (t . url-normalize-url) + (defun . url-normalize-url) + (t . url-lazy-message) + (defun . url-lazy-message) + (t . url-get-normalized-date) + (defun . url-get-normalized-date) + (t . url-eat-trailing-space) + (defun . url-eat-trailing-space) + (t . url-strip-leading-spaces) + (defun . url-strip-leading-spaces) + (t . url-pretty-length) + (defun . url-pretty-length) + (t . url-display-percentage) + (defun . url-display-percentage) + (t . url-percentage) + (defun . url-percentage) + (defun . url-basepath) + (t . url-file-directory) + (defun . url-file-directory) + (t . url-file-nondirectory) + (defun . url-file-nondirectory) + (t . url-parse-query-string) + (defun . url-parse-query-string) + (defun . url-unhex) + (t . url-unhex-string) + (defun . url-unhex-string) + url-unreserved-chars + (t . url-hexify-string) + (defun . url-hexify-string) + (t . url-file-extension) + (defun . url-file-extension) + (t . url-truncate-url-for-viewing) + (defun . url-truncate-url-for-viewing) + (t . url-view-url) + (defun . url-view-url) + url-get-url-filename-chars + (defun . url-get-url-at-point) + (defun . url-generate-unique-filename) + (defun . url-extract-mime-headers) + (defun . url-make-private-file) + (provide . url-util)) + ("/usr/share/emacs/23.0.93/lisp/url/url-gw.elc" + (require . url-vars) + (autoload . socks-open-network-stream) + (autoload . open-ssl-stream) + (autoload . open-tls-stream) + url-gateway-local-host-regexp url-gateway-prompt-pattern url-gateway-rlogin-host url-gateway-rlogin-user-name url-gateway-rlogin-parameters url-gateway-telnet-host url-gateway-telnet-parameters url-gateway-telnet-login-prompt url-gateway-telnet-password-prompt url-gateway-telnet-user-name url-gateway-telnet-password url-gateway-broken-resolution url-gateway-nslookup-program + (t . url-gateway-nslookup-host) + (defun . url-gateway-nslookup-host) + (defun . url-wait-for-string) + (defun . url-open-rlogin) + (defun . url-open-telnet) + (t . url-open-stream) + (defun . url-open-stream) + (provide . url-gw)) + ("/usr/share/emacs/23.0.93/lisp/url/url-methods.elc" + (require . url-parse) + url-scheme-registry url-scheme-methods url-scheme-default-properties url-scheme-default-properties + (defun . url-scheme-default-loader) + (defun . url-scheme-register-proxy) + (t . url-scheme-get-property) + (defun . url-scheme-get-property) + (provide . url-methods)) + ("/usr/share/emacs/23.0.93/lisp/url/url-parse.elc" + (require . url-vars) + (autoload . url-scheme-get-property) + (defun . url-type) + (defun . url-user) + (defun . url-password) + (defun . url-host) + (defun . url-portspec) + (defun . url-filename) + (defun . url-target) + (defun . url-attributes) + (defun . url-fullness) + (defun . url-p) + (defun . url-parse-make-urlobj) + (defun . url-port) + (t . url-recreate-url) + (defun . url-recreate-url) + (defun . url-recreate-url-attributes) + (t . url-generic-parse-url) + (defun . url-generic-parse-url) + (provide . url-parse)) + ("/usr/share/emacs/23.0.93/lisp/url/url-vars.elc" + (require . mm-util) + url-version url-current-object url-current-mime-headers url-honor-refresh-requests url-automatic-caching url-cache-expired url-bug-address url-personal-mail-address url-directory-index-file url-privacy-level url-inhibit-uncompression url-uncompressor-alist url-mail-command url-proxy-services url-standalone-mode url-mime-separator-chars url-bad-port-list url-mime-content-type-charset-regexp url-request-data url-request-extra-headers url-request-method url-mime-encoding-string + (defun . url-mime-charset-string) + url-mime-charset-string + (defun . url-set-mime-charset-string) + url-mime-language-string url-mime-accept-string url-package-version url-package-name url-system-type url-os-type url-max-password-attempts url-temporary-directory url-show-status url-using-proxy url-news-server url-nonrelative-link url-max-redirections url-confirmation-func url-gateway-method url-setup-done url-weekday-alist url-weekday-alist url-monthabbrev-alist url-monthabbrev-alist url-lazy-message-time url-extensions-header url-parse-syntax-table url-load-hook url-working-buffer url-working-buffer url-gateway-unplugged + (provide . url-vars)) + ("/usr/share/emacs/23.0.93/lisp/gnus/mm-util.elc" + (require . mail-prsvr) + (require . timer) + (defun . mm-coding-system-list) + (defun . mm-char-int) + (defun . mm-coding-system-equal) + (defun . mm-annotationp) + (defun . mm-set-buffer-file-coding-system) + (defun . mm-read-charset) + (defun . mm-subst-char-in-string) + (defun . mm-replace-in-string) + (defun . mm-string-as-unibyte) + (defun . mm-string-make-unibyte) + (defun . mm-string-as-multibyte) + (defun . mm-multibyte-string-p) + (defun . mm-insert-byte) + (defun . mm-multibyte-char-to-unibyte) + (defun . mm-set-buffer-multibyte) + (defun . mm-special-display-p) + (defun . mm-substring-no-properties) + (defun . mm-line-number-at-pos) + (defun . mm-decode-coding-string) + (defun . mm-encode-coding-string) + (defun . mm-decode-coding-region) + (defun . mm-encode-coding-region) + (defun . mm-string-to-multibyte) + (defun . mm-char-or-char-int-p) + (defun . mm-ucs-to-char) + (defun . mm-read-coding-system) + mm-coding-system-list + (defun . mm-get-coding-system-list) + (defun . mm-coding-system-p) + (defun . mm-codepage-setup) + mm-charset-synonym-alist mm-codepage-iso-8859-list mm-codepage-ibm-list + (defun . mm-setup-codepage-iso-8859) + (defun . mm-setup-codepage-ibm) + mm-charset-eval-alist + (defun . mm-charset-to-coding-system) + mm-charset-override-alist mm-binary-coding-system mm-text-coding-system mm-text-coding-system-for-write mm-auto-save-coding-system mm-universal-coding-system mm-mime-mule-charset-alist + (defun . mm-enrich-utf-8-by-mule-ucs) + mm-hack-charsets mm-iso-8859-15-compatible mm-iso-8859-x-to-15-table mm-coding-system-priorities mm-use-find-coding-systems-region + (defun . mm-mule-charset-to-mime-charset) + mm-emacs-mule + (defun . mm-enable-multibyte) + (defun . mm-disable-multibyte) + (defun . mm-preferred-coding-system) + (defun . mm-guess-charset) + (defun . mm-charset-after) + (defun . mm-mime-charset) + (defun . mm-delete-duplicates) + (defun . mm-multibyte-p) + (defun . mm-default-multibyte-p) + (defun . mm-iso-8859-x-to-15-region) + (defun . mm-sort-coding-systems-predicate) + (defun . mm-xemacs-find-mime-charset-1) + (defun . mm-xemacs-find-mime-charset) + (defun . mm-find-mime-charset-region) + (defun . mm-with-unibyte-buffer) + (defun . mm-with-multibyte-buffer) + (defun . mm-with-unibyte-current-buffer) + (defun . mm-find-charset-region) + (defun . mm-auto-mode-alist) + mm-inhibit-file-name-handlers + (defun . mm-insert-file-contents) + (defun . mm-append-to-file) + (defun . mm-write-region) + (autoload . gmm-write-region) + (defun . mm-make-temp-file) + (defun . mm-image-load-path) + (defun . mm-detect-coding-region) + (defun . mm-detect-mime-charset-region) + (defun . mm-coding-system-to-mime-charset) + (defun . mm-decompress-buffer) + (defun . mm-find-buffer-file-coding-system) + (provide . mm-util)) + ("/usr/share/emacs/23.0.93/lisp/gnus/mail-prsvr.elc" mail-parse-charset mail-parse-mule-charset mail-parse-ignored-charsets + (provide . mail-prsvr)) + ("/home/hobbes/nxhtml/util/ffip.el" + (require . cl) + ffip-project-name ffip-project-roots ffip-project-type ffip-project-file-types ffip-project-file-matcher ffip-project-files-table + (defun . ffip-reset-project) + (defun . ffip-is-current) + (defun . ffip-set-current-project) + (defun . ffip-cache-project-files) + (defun . ffip-file-matcher) + (defun . ffip-project-files) + (defun . ffip-project-root) + (defun . ffip-populate-files-table) + (defun . ffip-get-unique-directory-names) + (defun . ffip-file-is-in-project) + (defun . ffip-add-file-if-in-project) + (defun . ffip-after-save) + (defun . ffip-find-file-in-dirtree) + (defun . ffip-find-file-in-project) + (provide . ffip)) + ("/home/hobbes/nxhtml/util/ourcomments-util.el" ourcomments-util:version + (require . apropos) + (require . cl) + (require . grep) + (require . ido) + (require . recentf) + (defun . point-to-coord) + (t . popup-menu-at-point) + (defun . popup-menu-at-point) + (t . define-toggle) + (defun . define-toggle) + (t . unfill-paragraph) + (defun . unfill-paragraph) + (t . unfill-region) + (defun . unfill-region) + (t . unfill-individual-paragraphs) + (defun . unfill-individual-paragraphs) + (defun . with-unfilling) + (t . major-or-multi-majorp) + (defun . major-or-multi-majorp) + (t . multi-major-modep) + (defun . multi-major-modep) + (t . major-modep) + (defun . major-modep) + (t . ourcomments-move-beginning-of-line) + (defun . ourcomments-move-beginning-of-line) + (t . ourcomments-move-end-of-line) + (defun . ourcomments-move-end-of-line) + (defun . ourcomments-find-keymap-variables) + (defun . key-bindings) + (defun . describe-keymap-placement) + (t . describe-key-and-map-briefly) + (defun . describe-key-and-map-briefly) + wrap-to-fill-left-marg wrap-to-fill-left-marg-use wrap-to-fill-left-marg-modes + (defun . wrap-to-fill-set-prefix) + (defun . wrap-to-fill-after-change) + (defun . wrap-to-fill-scroll-fun) + (defun . wrap-to-fill-wider) + (defun . wrap-to-fill-narrower) + wrap-to-fill-column-mode-map wrap-to-fill-column-mode + (t . wrap-to-fill-column-mode) + (defun . wrap-to-fill-column-mode) + (defun . wrap-to-fill-set-values) + (defun . wrap-to-fill-set-values-1) + better-bottom-angles-defaults + (defun . better-fringes-bottom-angles) + (defun . better-fringes-faces) + (defface . better-fringes-bitmap) + (defface . better-fringes-important-bitmap) + better-fringes-mode + (t . better-fringes-mode) + (defun . better-fringes-mode) + (t . find-emacs-other-file) + (defun . find-emacs-other-file) + (t . ourcomments-ediff-files) + (defun . ourcomments-ediff-files) + (defun . ourcomments-latest-changelog) + (defun . ourcomments-read-symbol) + (defun . ourcomments-command-at-point) + (t . describe-command) + (defun . describe-command) + (defun . buffer-narrowed-p) + describe-symbol-alist + (defun . describe-symbol-add-known) + (defun . property-list-keys) + (defun . ourcomments-symbol-type) + (defun . ourcomments-defstruct-p) + (defun . ourcomments-defstruct-slots) + (defun . ourcomments-defstruct-file) + (defun . ourcomments-member-defstruct) + (defun . ourcomments-custom-group-p) + (t . describe-custom-group) + (defun . describe-custom-group) + (t . describe-defstruct) + (defun . describe-defstruct) + (t . describe-symbol) + (defun . describe-symbol) + (defun . ourcomments-format-plist) + ourcomments-ido-visit-method + (t . ourcomments-ido-buffer-other-window) + (defun . ourcomments-ido-buffer-other-window) + (t . ourcomments-ido-buffer-other-frame) + (defun . ourcomments-ido-buffer-other-frame) + (t . ourcomments-ido-buffer-raise-frame) + (defun . ourcomments-ido-buffer-raise-frame) + (defun . ourcomments-ido-mode-advice) + ourcomments-ido-adviced ourcomments-ido-old-state + (defun . ourcomments-ido-ctrl-tab-activate) + ourcomments-ido-ctrl-tab + (defun . ourcomments-find-emacs) + (t . emacs) + (defun . emacs) + (t . emacs-buffer-file) + (defun . emacs-buffer-file) + (t . emacs--debug-init) + (defun . emacs--debug-init) + (t . emacs-Q) + (defun . emacs-Q) + (t . emacs-Q-nxhtml) + (defun . emacs-Q-nxhtml) + (defun . grep-get-buffer-files) + grep-query-replace-defaults + (t . grep-query-replace) + (defun . grep-query-replace) + (defun . ldir-query-replace) + (defun . rdir-query-replace) + (defun . rdir-get-files) + (defun . dir-replace-read-parameters) + replace-read-files-history + (defun . replace-read-files) + (t . info-open-file) + (defun . info-open-file) + (provide . ourcomments-util)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/advice.elc" + (provide . advice-preload) + (require . advice-preload) + ad-version ad-version ad-redefinition-action ad-default-compilation-action + (defun . ad-substitute-tree) + (defun . ad-copy-tree) + (defun . ad-dolist) + (defun . ad-do-return) + (defun . ad-save-real-definition) + (defun . ad-save-real-definitions) + ad-advised-functions + (defun . ad-pushnew-advised-function) + (defun . ad-pop-advised-function) + (defun . ad-do-advised-functions) + (defun . ad-get-advice-info) + (defun . ad-get-advice-info-macro) + (defun . ad-set-advice-info) + (defun . ad-copy-advice-info) + (defun . ad-is-advised) + (defun . ad-initialize-advice-info) + (defun . ad-get-advice-info-field) + (defun . ad-set-advice-info-field) + (defun . ad-is-active) + (defun . ad-make-advice) + (defun . ad-advice-name) + (defun . ad-advice-protected) + (defun . ad-advice-enabled) + (defun . ad-advice-definition) + (defun . ad-advice-set-enabled) + (defun . ad-class-p) + (defun . ad-name-p) + (defun . ad-position-p) + ad-advice-classes + (defun . ad-has-enabled-advice) + (defun . ad-has-redefining-advice) + (defun . ad-has-any-advice) + (defun . ad-get-enabled-advices) + (defun . ad-activate-internal) + (defun . ad-activate-internal-off) + ad-activate-on-top-level + (defun . ad-with-auto-activation-disabled) + (defun . ad-safe-fset) + (defun . ad-make-origname) + (defun . ad-get-orig-definition) + (defun . ad-set-orig-definition) + (defun . ad-clear-orig-definition) + (defun . ad-read-advised-function) + ad-advice-class-completion-table + (defun . ad-read-advice-class) + (defun . ad-read-advice-name) + (defun . ad-read-advice-specification) + ad-last-regexp + (defun . ad-read-regexp) + (defun . ad-find-advice) + (defun . ad-advice-position) + (defun . ad-find-some-advice) + (defun . ad-enable-advice-internal) + (t . ad-enable-advice) + (defun . ad-enable-advice) + (t . ad-disable-advice) + (defun . ad-disable-advice) + (defun . ad-enable-regexp-internal) + (defun . ad-enable-regexp) + (defun . ad-disable-regexp) + (defun . ad-remove-advice) + (t . ad-add-advice) + (defun . ad-add-advice) + (defun . ad-macrofy) + (defun . ad-lambdafy) + (defun . ad-special-form-p) + (defun . ad-subr-p) + (defun . ad-macro-p) + (defun . ad-lambda-p) + (defun . ad-advice-p) + (defun . ad-compiled-p) + (defun . ad-compiled-code) + (defun . ad-lambda-expression) + (defun . ad-arglist) + (defun . ad-define-subr-args) + (defun . ad-undefine-subr-args) + (defun . ad-subr-args-defined-p) + (defun . ad-get-subr-args) + (defun . ad-subr-arglist) + (defun . ad-docstring) + (defun . ad-interactive-form) + (defun . ad-body-forms) + (defun . ad-make-advised-definition-docstring) + (defun . ad-advised-definition-p) + (defun . ad-definition-type) + (defun . ad-has-proper-definition) + (defun . ad-real-definition) + (defun . ad-real-orig-definition) + (defun . ad-is-compilable) + (defun . ad-compile-function) + (defun . ad-prognify) + (defun . ad-parse-arglist) + (defun . ad-retrieve-args-form) + (defun . ad-arg-binding-field) + (defun . ad-list-access) + (defun . ad-element-access) + (defun . ad-access-argument) + (defun . ad-get-argument) + (defun . ad-set-argument) + (defun . ad-get-arguments) + (defun . ad-set-arguments) + (defun . ad-insert-argument-access-forms) + (defun . ad-map-arglists) + (defun . ad-make-mapped-call) + (defun . ad-make-single-advice-docstring) + (require . help-fns) + (defun . ad-make-advised-docstring) + (defun . ad-make-plain-docstring) + (defun . ad-make-freeze-docstring) + (defun . ad-advised-arglist) + (defun . ad-advised-interactive-form) + (defun . ad-make-advised-definition) + (defun . ad-assemble-advised-definition) + (defun . ad-make-hook-form) + (defun . ad-get-cache-definition) + (defun . ad-get-cache-id) + (defun . ad-set-cache) + (defun . ad-clear-cache) + (defun . ad-make-cache-id) + (defun . ad-get-cache-class-id) + (defun . ad-verify-cache-class-id) + (defun . ad-cache-id-verification-code) + (defun . ad-verify-cache-id) + (defun . ad-preactivate-advice) + (defun . ad-make-freeze-definition) + (defun . ad-should-compile) + (defun . ad-activate-advised-definition) + (defun . ad-handle-definition) + (t . ad-activate) + (defun . ad-activate) + (defun . ad-activate-on) + (defun . ad-deactivate) + (defun . ad-update) + (defun . ad-unadvise) + (defun . ad-recover) + (defun . ad-activate-regexp) + (defun . ad-deactivate-regexp) + (defun . ad-update-regexp) + (defun . ad-activate-all) + (defun . ad-deactivate-all) + (defun . ad-update-all) + (defun . ad-unadvise-all) + (defun . ad-recover-all) + ad-defadvice-flags + (t . defadvice) + (defun . defadvice) + (defun . ad-with-originals) + (defun . ad-start-advice) + (defun . ad-stop-advice) + (defun . ad-recover-normality) + (provide . advice)) + ("/usr/share/emacs/23.0.93/lisp/help-fns.elc" + (require . help-mode) + (t . describe-function) + (defun . describe-function) + (defun . help-split-fundoc) + (defun . help-add-fundoc-usage) + (defun . help-function-arglist) + (defun . help-make-usage) + (t . help-C-file-name) + (defun . help-C-file-name) + (defface . help-argument-name) + (defun . help-default-arg-highlight) + (defun . help-do-arg-highlight) + (defun . help-highlight-arguments) + (t . find-lisp-object-file-name) + (defun . find-lisp-object-file-name) + (t . describe-function-1) + (defun . describe-function-1) + (t . variable-at-point) + (defun . variable-at-point) + (defun . describe-variable-custom-version-info) + (t . describe-variable) + (defun . describe-variable) + (t . describe-syntax) + (defun . describe-syntax) + (defun . help-describe-category-set) + (t . describe-categories) + (defun . describe-categories) + (provide . help-fns)) + ("/usr/share/emacs/23.0.93/lisp/help-mode.elc" + (require . button) + (require . view) + help-mode-map help-mode-menu + (defun . help-mode-menu) + help-xref-stack help-xref-forward-stack help-xref-stack-item help-xref-stack-forward-item help-mode-hook + (defun . help-button-action) + (t . help-mode) + (defun . help-mode) + (t . help-mode-setup) + (defun . help-mode-setup) + (t . help-mode-finish) + (defun . help-mode-finish) + help-back-label help-forward-label help-xref-symbol-regexp help-xref-mule-regexp help-xref-info-regexp help-xref-url-regexp + (t . help-setup-xref) + (defun . help-setup-xref) + help-xref-following + (t . help-buffer) + (defun . help-buffer) + help-xref-override-view-map + (t . help-make-xrefs) + (defun . help-make-xrefs) + (t . help-xref-button) + (defun . help-xref-button) + (t . help-insert-xref-button) + (defun . help-insert-xref-button) + (t . help-xref-on-pp) + (defun . help-xref-on-pp) + (defun . help-xref-interned) + (defun . help-xref-go-back) + (defun . help-xref-go-forward) + (defun . help-go-back) + (defun . help-go-forward) + (defun . help-do-xref) + (defun . help-follow-mouse) + (defun . help-follow) + (defun . help-follow-symbol) + (defun . help-insert-string) + (provide . help-mode)) + ("/usr/share/emacs/23.0.93/lisp/view.elc" view-highlight-face view-scroll-auto-exit view-try-extend-at-buffer-end view-remove-frame-by-deleting view-exits-all-viewing-windows view-inhibit-help-message view-mode view-mode-hook view-old-buffer-read-only view-page-size view-half-page-size view-last-regexp view-return-to-alist view-exit-action view-no-disable-on-exit view-overlay view-mode-map + (t . kill-buffer-if-not-modified) + (defun . kill-buffer-if-not-modified) + (t . view-file) + (defun . view-file) + (t . view-file-other-window) + (defun . view-file-other-window) + (t . view-file-other-frame) + (defun . view-file-other-frame) + (t . view-buffer) + (defun . view-buffer) + (t . view-buffer-other-window) + (defun . view-buffer-other-window) + (t . view-buffer-other-frame) + (defun . view-buffer-other-frame) + (t . view-mode) + (defun . view-mode) + (defun . view-mode-enable) + (defun . view-mode-disable) + (t . view-return-to-alist-update) + (defun . view-return-to-alist-update) + (t . view-mode-enter) + (defun . view-mode-enter) + (defun . view-mode-exit) + (defun . View-exit) + (t . View-exit-and-edit) + (defun . View-exit-and-edit) + (defun . View-leave) + (defun . View-quit) + (defun . View-quit-all) + (defun . View-kill-and-leave) + (defun . view-window-size) + (defun . view-recenter) + (defun . view-page-size-default) + (defun . view-set-half-page-size-default) + (defun . View-goto-percent) + (defun . View-goto-line) + (defun . View-back-to-mark) + (defun . view-scroll-lines) + (defun . view-really-at-end) + (defun . view-end-message) + (defun . View-scroll-to-buffer-end) + (defun . View-scroll-page-forward) + (defun . View-scroll-page-backward) + (defun . View-scroll-page-forward-set-page-size) + (defun . View-scroll-page-backward-set-page-size) + (defun . View-scroll-line-forward) + (defun . View-scroll-line-backward) + (defun . View-scroll-half-page-forward) + (defun . View-scroll-half-page-backward) + (defun . View-revert-buffer-scroll-page-forward) + (defun . View-search-regexp-forward) + (defun . View-search-regexp-backward) + (defun . View-search-last-regexp-forward) + (defun . View-search-last-regexp-backward) + (defun . view-search) + (defun . view-search-no-match-lines) + (provide . view)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/easy-mmode.elc" + (defun . easy-mmode-pretty-mode-name) + (defun . easy-mmode-define-minor-mode) + (t . define-minor-mode) + (defun . define-minor-mode) + (defun . easy-mmode-define-global-mode) + (defun . define-global-minor-mode) + (t . define-globalized-minor-mode) + (defun . define-globalized-minor-mode) + (defun . easy-mmode-set-keymap-parents) + (t . easy-mmode-define-keymap) + (defun . easy-mmode-define-keymap) + (t . easy-mmode-defmap) + (defun . easy-mmode-defmap) + (defun . easy-mmode-define-syntax) + (t . easy-mmode-defsyntax) + (defun . easy-mmode-defsyntax) + (defun . easy-mmode-define-navigation) + (provide . easy-mmode)) + ("/usr/share/emacs/23.0.93/lisp/recentf.elc" + (require . easymenu) + (require . tree-widget) + (require . timer) + recentf-list + (defun . recentf-enabled-p) + recentf-max-saved-items recentf-save-file recentf-save-file-modes recentf-exclude + (defun . recentf-keep-default-predicate) + recentf-keep + (defun . recentf-menu-customization-changed) + recentf-menu-title recentf-menu-path recentf-menu-before recentf-menu-action recentf-max-menu-items recentf-menu-filter recentf-menu-open-all-flag recentf-menu-append-commands-p recentf-menu-append-commands-flag recentf-auto-cleanup recentf-initialize-file-name-history recentf-load-hook recentf-filename-handlers recentf-show-file-shortcuts-flag recentf-case-fold-search + (defun . recentf-string-equal) + (defun . recentf-string-lessp) + (defun . recentf-string-member) + (defun . recentf-trunc-list) + (defun . recentf-dump-variable) + recentf-auto-cleanup-timer + (defun . recentf-auto-cleanup) + (defun . recentf-push) + (defun . recentf-apply-filename-handlers) + (defun . recentf-expand-file-name) + (defun . recentf-include-p) + (defun . recentf-keep-p) + (defun . recentf-add-file) + (defun . recentf-remove-if-non-kept) + (defun . recentf-directory-compare) + (defun . recentf-digit-shortcut-command-name) + (defun . recentf-open-most-recent-file-0) + (defun . recentf-open-most-recent-file-9) + (defun . recentf-open-most-recent-file-8) + (defun . recentf-open-most-recent-file-7) + (defun . recentf-open-most-recent-file-6) + (defun . recentf-open-most-recent-file-5) + (defun . recentf-open-most-recent-file-4) + (defun . recentf-open-most-recent-file-3) + (defun . recentf-open-most-recent-file-2) + (defun . recentf-open-most-recent-file-1) + recentf--shortcuts-keymap recentf-menu-items-for-commands recentf-menu-filter-commands + (defun . recentf-elements) + (defun . recentf-make-menu-element) + (defun . recentf-menu-element-item) + (defun . recentf-menu-element-value) + (defun . recentf-set-menu-element-item) + (defun . recentf-set-menu-element-value) + (defun . recentf-sub-menu-element-p) + (defun . recentf-make-default-menu-element) + (defun . recentf-menu-elements) + (defun . recentf-apply-menu-filter) + (defun . recentf-make-menu-items) + (defun . recentf-menu-value-shortcut) + (defun . recentf-make-menu-item) + (defun . recentf-menu-bar) + (defun . recentf-show-menu) + (defun . recentf-hide-menu) + (defun . recentf-sort-ascending) + (defun . recentf-sort-descending) + (defun . recentf-sort-basenames-ascending) + (defun . recentf-sort-basenames-descending) + (defun . recentf-sort-directories-ascending) + (defun . recentf-sort-directories-descending) + (defun . recentf-show-basenames) + (defun . recentf-show-basenames-ascending) + (defun . recentf-show-basenames-descending) + (defun . recentf-relative-filter) + recentf-arrange-rules recentf-arrange-by-rule-others recentf-arrange-by-rules-min-items recentf-arrange-by-rule-subfilter + (defun . recentf-match-rule) + (defun . recentf-arrange-by-rule) + (defun . recentf-indirect-mode-rule) + (defun . recentf-build-mode-rules) + (defun . recentf-arrange-by-mode) + (defun . recentf-file-name-nondir) + (defun . recentf-dir-rule) + (defun . recentf-arrange-by-dir) + recentf-filter-changer-current recentf-filter-changer-alist + (defun . recentf-filter-changer-select) + (defun . recentf-filter-changer) + (defun . recentf-track-opened-file) + (defun . recentf-track-closed-file) + recentf-used-hooks + (defun . recentf-cancel-dialog) + (defun . recentf-dialog-goto-first) + recentf-dialog-mode-map recentf-dialog-mode-map + (defun . recentf-dialog-mode) + (defun . recentf-dialog) + recentf-edit-list + (defun . recentf-edit-list-select) + (defun . recentf-edit-list-validate) + (defun . recentf-edit-list) + (defun . recentf-open-files-action) + recentf--files-with-key + (defun . recentf-show-digit-shortcut-filter) + (defun . recentf-open-files-item) + (defun . recentf-open-files-items) + (defun . recentf-open-files) + (defun . recentf-open-more-files) + (defun . recentf-open-most-recent-file) + recentf-save-file-header recentf-save-file-coding-system + (defun . recentf-save-list) + (defun . recentf-load-list) + (defun . recentf-cleanup) + recentf-mode-map recentf-mode + (t . recentf-mode) + (defun . recentf-mode) + (provide . recentf)) + ("/usr/share/emacs/23.0.93/lisp/tree-widget.elc" + (require . wid-edit) + tree-widget-image-enable tree-widget-themes-load-path tree-widget-themes-directory tree-widget-theme tree-widget-image-properties-emacs tree-widget-image-properties-xemacs tree-widget-space-width + (defun . tree-widget-use-image-p) + (defun . tree-widget-create-image) + (defun . tree-widget-image-formats) + tree-widget--theme + (defun . tree-widget-theme-name) + (defun . tree-widget-set-parent-theme) + (defun . tree-widget-set-theme) + (defun . tree-widget--locate-sub-directory) + (defun . tree-widget-themes-path) + tree-widget--cursors tree-widget--cursors + (defun . tree-widget-set-image-properties) + (defun . tree-widget-image-properties) + (defun . tree-widget-lookup-image) + (defun . tree-widget-find-image) + (defun . tree-widget-button-click) + tree-widget-button-keymap + (defun . tree-widget-p) + (defun . tree-widget-node) + (defun . tree-widget-keep) + (defun . tree-widget-children-value-save) + tree-widget-before-create-icon-functions + (defun . tree-widget-icon-create) + (defun . tree-widget-convert-widget) + (defun . tree-widget-value-create) + (defun . tree-widget-leaf-node-icon-p) + (defun . tree-widget-icon-action) + (defun . tree-widget-icon-help-echo) + tree-widget-after-toggle-functions + (defun . tree-widget-action) + (defun . tree-widget-help-echo) + (defun . tree-widget-expander-p) + (provide . tree-widget)) + ("/usr/share/emacs/23.0.93/lisp/ido.elc" + (defun . ido-fractionp) + ido-mode ido-everywhere ido-case-fold ido-ignore-buffers ido-ignore-files ido-ignore-extensions ido-show-dot-for-dired ido-file-extensions-order ido-ignore-directories ido-ignore-directories-merge ido-default-file-method ido-default-buffer-method ido-enable-flex-matching ido-enable-regexp ido-enable-prefix ido-enable-dot-prefix ido-confirm-unique-completion ido-cannot-complete-command ido-record-commands ido-max-prospects ido-max-file-prompt-width ido-max-window-height ido-enable-last-directory-history ido-max-work-directory-list ido-work-directory-list-ignore-regexps ido-use-filename-at-point ido-use-url-at-point ido-enable-tramp-completion ido-record-ftp-work-directories ido-merge-ftp-work-directories ido-cache-ftp-work-directory-time ido-slow-ftp-hosts ido-slow-ftp-host-regexps ido-unc-hosts-cache ido-unc-hosts ido-downcase-unc-hosts ido-ignore-unc-host-regexps ido-cache-unc-host-shares-time ido-max-work-file-list ido-work-directory-match-only ido-auto-merge-work-directories-length ido-auto-merge-delay-time ido-auto-merge-inhibit-characters-regexp ido-merged-indicator ido-max-dir-file-cache ido-max-directory-size ido-rotate-file-list-default ido-enter-matching-directory ido-create-new-buffer ido-setup-hook ido-separator ido-decorations ido-use-faces + (defface . ido-first-match) + (defface . ido-only-match) + (defface . ido-subdir) + (defface . ido-indicator) + (defface . ido-incomplete-regexp) + ido-make-file-list-hook ido-make-dir-list-hook ido-make-buffer-list-hook ido-rewrite-file-prompt-functions ido-rewrite-file-prompt-rules ido-completion-buffer ido-completion-buffer-all-completions ido-all-frames ido-minibuffer-setup-hook ido-save-directory-list-file ido-read-file-name-as-directory-commands ido-read-file-name-non-ido ido-before-fallback-functions ido-completion-map ido-common-completion-map ido-file-completion-map ido-file-dir-completion-map ido-buffer-completion-map ido-file-history ido-buffer-history ido-last-directory-list ido-work-directory-list ido-work-file-list ido-dir-file-cache ido-ignore-item-temp-list ido-eoinput ido-common-match-string ido-rescan ido-rotate ido-text ido-text-init ido-input-stack ido-matches ido-report-no-match ido-exit ido-current-directory ido-auto-merge-timer ido-use-mycompletion-depth ido-incomplete-regexp ido-initial-position + (defun . ido-active) + ido-trace-enable + (defun . ido-trace) + (defun . ido-toggle-trace) + (defun . ido-local-file-exists-p) + (defun . ido-unc-hosts) + (defun . ido-unc-hosts-net-view) + (defun . ido-is-tramp-root) + (defun . ido-is-unc-root) + (defun . ido-is-unc-host) + (defun . ido-is-root-directory) + (defun . ido-is-ftp-directory) + (defun . ido-is-slow-ftp-host) + (defun . ido-time-stamp) + (defun . ido-cache-ftp-valid) + (defun . ido-cache-unc-valid) + (defun . ido-may-cache-directory) + (defun . ido-pp) + (defun . ido-save-history) + (defun . ido-load-history) + (defun . ido-wash-history) + (defun . ido-kill-emacs-hook) + ido-minor-mode-map-entry + (t . ido-mode) + (defun . ido-mode) + (defun . ido-everywhere) + (defun . ido-init-completion-maps) + (defun . ido-setup-completion-map) + (defun . ido-final-slash) + (defun . ido-no-final-slash) + (defun . ido-nonreadable-directory-p) + (defun . ido-directory-too-big-p) + (defun . ido-set-current-directory) + (defun . ido-set-current-home) + (defun . ido-record-command) + (defun . ido-make-prompt) + (defun . ido-read-internal) + (defun . ido-edit-input) + (defun . ido-buffer-internal) + (defun . ido-record-work-directory) + (defun . ido-forget-work-directory) + (defun . ido-record-work-file) + (defun . ido-expand-directory) + (defun . ido-file-internal) + (defun . ido-existing-item-p) + (defun . ido-set-common-completion) + (defun . ido-complete) + (defun . ido-complete-space) + (defun . ido-undo-merge-work-directory) + (defun . ido-magic-forward-char) + (defun . ido-magic-backward-char) + (defun . ido-magic-delete-char) + (defun . ido-toggle-case) + (defun . ido-toggle-regexp) + (defun . ido-toggle-prefix) + (defun . ido-toggle-ignore) + (defun . ido-toggle-vc) + (defun . ido-toggle-literal) + (defun . ido-reread-directory) + (defun . ido-exit-minibuffer) + (defun . ido-select-text) + (defun . ido-fallback-command) + (defun . ido-enter-find-file) + (defun . ido-enter-switch-buffer) + (defun . ido-enter-dired) + (defun . ido-enter-insert-buffer) + (defun . ido-enter-insert-file) + (defun . ido-up-directory) + (defun . ido-delete-backward-updir) + (defun . ido-delete-backward-word-updir) + (defun . ido-get-work-directory) + (defun . ido-prev-work-directory) + (defun . ido-next-work-directory) + (defun . ido-merge-work-directories) + (defun . ido-wide-find-file) + (defun . ido-wide-find-dir) + (defun . ido-wide-find-dir-or-delete-dir) + (defun . ido-take-first-match) + (defun . ido-push-dir) + (defun . ido-push-dir-first) + (defun . ido-pop-dir) + (defun . ido-wide-find-file-or-pop-dir) + (defun . ido-make-directory) + (defun . ido-get-work-file) + (defun . ido-prev-work-file) + (defun . ido-next-work-file) + (defun . ido-copy-current-file-name) + (defun . ido-copy-current-word) + (defun . ido-next-match) + (defun . ido-prev-match) + (defun . ido-next-match-dir) + (defun . ido-prev-match-dir) + (defun . ido-restrict-to-matches) + (defun . ido-chop) + (defun . ido-name) + (defun . ido-all-completions) + (defun . ido-file-lessp) + (defun . ido-file-extension-lessp) + (defun . ido-file-extension-aux) + (defun . ido-file-extension-order) + (defun . ido-sort-merged-list) + (defun . ido-wide-find-dirs-or-files) + (defun . ido-flatten-merged-list) + (defun . ido-make-merged-file-list-1) + (defun . ido-make-merged-file-list) + (defun . ido-make-buffer-list-1) + (defun . ido-make-buffer-list) + (defun . ido-make-choice-list) + (defun . ido-to-end) + (defun . ido-file-name-all-completions-1) + (defun . ido-file-name-all-completions) + (defun . ido-remove-cached-dir) + (defun . ido-make-file-list-1) + (defun . ido-make-file-list) + (defun . ido-make-dir-list-1) + (defun . ido-make-dir-list) + (defun . ido-get-buffers-in-frames) + (defun . ido-get-bufname) + (defun . ido-set-matches-1) + (defun . ido-set-matches) + (defun . ido-ignore-item-p) + (defun . ido-find-common-substring) + (defun . ido-word-matching-substring) + (defun . ido-makealist) + (defun . ido-choose-completion-string) + (defun . ido-completion-help) + (defun . ido-kill-buffer-at-head) + (defun . ido-delete-file-at-head) + (defun . ido-visit-buffer) + (defun . ido-buffer-window-other-frame) + (t . ido-switch-buffer) + (defun . ido-switch-buffer) + (t . ido-switch-buffer-other-window) + (defun . ido-switch-buffer-other-window) + (t . ido-display-buffer) + (defun . ido-display-buffer) + (t . ido-kill-buffer) + (defun . ido-kill-buffer) + (t . ido-insert-buffer) + (defun . ido-insert-buffer) + (t . ido-switch-buffer-other-frame) + (defun . ido-switch-buffer-other-frame) + (t . ido-find-file-in-dir) + (defun . ido-find-file-in-dir) + (t . ido-find-file) + (defun . ido-find-file) + (t . ido-find-file-other-window) + (defun . ido-find-file-other-window) + (t . ido-find-alternate-file) + (defun . ido-find-alternate-file) + (t . ido-find-file-read-only) + (defun . ido-find-file-read-only) + (t . ido-find-file-read-only-other-window) + (defun . ido-find-file-read-only-other-window) + (t . ido-find-file-read-only-other-frame) + (defun . ido-find-file-read-only-other-frame) + (t . ido-display-file) + (defun . ido-display-file) + (t . ido-find-file-other-frame) + (defun . ido-find-file-other-frame) + (t . ido-write-file) + (defun . ido-write-file) + (t . ido-insert-file) + (defun . ido-insert-file) + (t . ido-dired) + (defun . ido-dired) + (defun . ido-list-directory) + (defun . ido-initiate-auto-merge) + (defun . ido-exhibit) + (defun . ido-completions) + (defun . ido-minibuffer-setup) + (defun . ido-tidy) + (defun . ido-summary-buffers-to-end) + (t . ido-read-buffer) + (defun . ido-read-buffer) + (t . ido-read-file-name) + (defun . ido-read-file-name) + (t . ido-read-directory-name) + (defun . ido-read-directory-name) + (t . ido-completing-read) + (defun . ido-completing-read) + (defun . ido-unload-function) + (provide . ido)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/grep.elc" + (require . compile) + grep-window-height grep-highlight-matches grep-scroll-output grep-command grep-template grep-use-null-device grep-find-command grep-find-template grep-files-aliases grep-find-ignored-directories grep-error-screen-columns grep-setup-hook grep-mode-map grep-mode-tool-bar-map + (defun . kill-grep) + grep-last-buffer grep-regexp-alist grep-error grep-hit-face grep-error-face grep-match-face grep-context-face grep-mode-font-lock-keywords grep-program find-program xargs-program grep-find-use-xargs grep-history grep-find-history grep-regexp-history grep-files-history grep-host-defaults-alist + (t . grep-process-setup) + (defun . grep-process-setup) + (defun . grep-probe) + (t . grep-compute-defaults) + (defun . grep-compute-defaults) + (defun . grep-tag-default) + (defun . grep-default-command) + grep-mode-map grep-mode-syntax-table grep-mode-abbrev-table grep-mode-abbrev-table + (t . grep-mode) + (defun . grep-mode) + (t . grep) + (defun . grep) + (t . grep-find) + (defun . grep-find) + (defun . find-grep) + grep-expand-keywords + (defun . grep-expand-template) + (defun . grep-read-regexp) + (defun . grep-read-files) + (t . lgrep) + (defun . lgrep) + (t . rgrep) + (defun . rgrep) + (provide . grep)) + ("/usr/share/emacs/23.0.93/lisp/progmodes/compile.elc" + (require . tool-bar) + (require . comint) + compilation-mode-hook compilation-start-hook compilation-window-height compilation-first-column compilation-parse-errors-filename-function compilation-process-setup-function compilation-buffer-name-function compilation-finish-function compilation-finish-functions compilation-in-progress compilation-error compilation-arguments compilation-error-regexp-alist-alist compilation-error-regexp-alist compilation-directory compilation-directory-matcher compilation-page-delimiter compilation-mode-font-lock-keywords compilation-highlight-regexp compilation-highlight-overlay compilation-error-screen-columns compilation-read-command compilation-ask-about-save compilation-search-path compile-command compilation-disable-input compilation-locs compilation-debug compilation-exit-message-function compilation-environment compile-history + (defface . compilation-error) + (defface . compilation-warning) + (defface . compilation-info) + (defface . compilation-line-number) + (defface . compilation-column-number) + compilation-message-face compilation-error-face compilation-warning-face compilation-info-face compilation-line-face compilation-column-face compilation-enter-directory-face compilation-leave-directory-face compilation-last-buffer compilation-parsing-end compilation-parse-errors-function compilation-error-list compilation-old-error-list compilation-auto-jump-to-first-error compilation-auto-jump-to-next compilation-skip-to-next-location compilation-skip-threshold compilation-skip-visited + (defun . compilation-face) + (defun . compilation-directory-properties) + (defun . compilation-auto-jump) + (defun . compilation-error-properties) + (defun . compilation-move-to-column) + (defun . compilation-internal-error-properties) + (defun . compilation-mode-font-lock-keywords) + (defun . compilation-read-command) + (t . compile) + (defun . compile) + (defun . recompile) + compilation-scroll-output + (defun . compilation-buffer-name) + (defun . compile-internal) + (t . compilation-start) + (defun . compilation-start) + (defun . compilation-set-window-height) + compilation-menu-map compilation-minor-mode-map compilation-shell-minor-mode-map compilation-button-map compilation-mode-map compilation-mode-tool-bar-map + (t . compilation-mode) + (defun . compilation-mode) + (defun . define-compilation-mode) + (defun . compilation-revert-buffer) + compilation-current-error compilation-messages-start compilation-turn-on-font-lock compilation-turn-on-font-lock + (defun . compilation-setup) + compilation-shell-minor-mode + (t . compilation-shell-minor-mode) + (defun . compilation-shell-minor-mode) + compilation-minor-mode + (t . compilation-minor-mode) + (defun . compilation-minor-mode) + (defun . compilation-handle-exit) + (defun . compilation-sentinel) + (defun . compilation-filter) + (defun . compilation-buffer-internal-p) + (defun . compilation-buffer-p) + (defun . compilation-loop) + (defun . compilation-next-error) + (defun . compilation-previous-error) + (defun . compilation-next-file) + (defun . compilation-previous-file) + (defun . kill-compilation) + (defun . compile-mouse-goto-error) + (defun . compile-goto-error) + (defun . compilation-find-buffer) + (t . compilation-next-error-function) + (defun . compilation-next-error-function) + compilation-gcpro + (defun . compilation-fake-loc) + compilation-context-lines + (defun . compilation-set-window) + (defun . compilation-goto-locus) + (defun . compilation-goto-locus-delete-o) + (defun . compilation-find-file) + (defun . compilation-get-file-structure) + (defun . compile-buffer-substring) + (defun . compilation-compat-error-properties) + (defun . compilation-compat-parse-errors) + (defun . compilation-forget-errors) + (provide . compile)) + ("/usr/share/emacs/23.0.93/lisp/comint.elc" + (require . ring) + comint-prompt-regexp comint-prompt-read-only comint-delimiter-argument-list comint-input-autoexpand + (defface . comint-highlight-input) + (defface . comint-highlight-prompt) + comint-input-ignoredups comint-input-ring-file-name comint-scroll-to-bottom-on-input comint-move-point-for-output comint-scroll-to-bottom-on-output comint-scroll-show-maximum-output comint-buffer-maximum-size comint-input-ring-size comint-input-ring-separator comint-input-history-ignore comint-process-echoes comint-password-prompt-regexp comint-get-old-input comint-dynamic-complete-functions comint-input-filter comint-input-filter-functions comint-output-filter-functions comint-input-sender-no-newline comint-input-sender comint-eol-on-send comint-use-prompt-regexp comint-use-prompt-regexp-instead-of-fields comint-mode-hook comint-exec-hook comint-mode-map comint-ptyp comint-input-ring comint-last-input-start comint-last-input-end comint-last-output-start comint-input-ring-index comint-matching-input-from-input-string comint-save-input-ring-index comint-accum-marker comint-stored-incomplete-input comint-mode-map comint-mode-syntax-table comint-mode-abbrev-table comint-mode-abbrev-table + (defun . comint-mode) + (defun . comint-check-proc) + (t . make-comint-in-buffer) + (defun . make-comint-in-buffer) + (t . make-comint) + (defun . make-comint) + (t . comint-run) + (defun . comint-run) + (defun . comint-exec) + (defun . comint-exec-1) + (defun . comint-insert-input) + (defun . comint-read-input-ring) + (defun . comint-write-input-ring) + (defun . comint-dynamic-list-input-ring-select) + (defun . comint-dynamic-list-input-ring) + (defun . comint-regexp-arg) + (defun . comint-search-arg) + (defun . comint-restore-input) + (defun . comint-search-start) + (defun . comint-previous-input-string) + (defun . comint-previous-input) + (defun . comint-next-input) + (defun . comint-previous-matching-input-string) + (defun . comint-previous-matching-input-string-position) + (defun . comint-delete-input) + (defun . comint-previous-matching-input) + (defun . comint-next-matching-input) + (defun . comint-previous-matching-input-from-input) + (defun . comint-next-matching-input-from-input) + (defun . comint-replace-by-expanded-history) + (defun . comint-replace-by-expanded-history-before-point) + (defun . comint-magic-space) + (defun . comint-within-quotes) + (defun . comint-how-many-region) + (defun . comint-args) + (defun . comint-delim-arg) + (defun . comint-arguments) + (defun . comint-add-to-input-history) + (defun . comint-send-input) + comint-preoutput-filter-functions comint-inhibit-carriage-motion comint-last-prompt-overlay + (defun . comint-snapshot-last-prompt) + (defun . comint-carriage-motion) + (defun . comint-output-filter) + (defun . comint-preinput-scroll-to-bottom) + (defun . comint-postoutput-scroll-to-bottom) + (defun . comint-truncate-buffer) + (defun . comint-strip-ctrl-m) + (defun . shell-strip-ctrl-m) + (defun . comint-show-maximum-output) + (defun . comint-get-old-input-default) + (defun . comint-copy-old-input) + (defun . comint-skip-prompt) + (defun . comint-after-pmark-p) + (defun . comint-simple-send) + (defun . comint-line-beginning-position) + (defun . comint-bol) + (defun . comint-read-noecho) + (defun . send-invisible) + (defun . comint-watch-for-password-prompt) + (defun . comint-send-string) + (defun . comint-send-region) + (defun . comint-delete-output) + (defun . comint-kill-output) + (defun . comint-write-output) + (defun . comint-append-output-to-file) + (defun . comint-show-output) + (defun . comint-interrupt-subjob) + (defun . comint-kill-subjob) + (defun . comint-quit-subjob) + (defun . comint-stop-subjob) + (defun . comint-continue-subjob) + (defun . comint-skip-input) + (defun . comint-kill-input) + (defun . comint-delchar-or-maybe-eof) + (defun . comint-send-eof) + (defun . comint-backward-matching-input) + (defun . comint-forward-matching-input) + (defun . comint-next-prompt) + (defun . comint-previous-prompt) + comint-insert-previous-argument-last-start-pos comint-insert-previous-argument-last-index + (defun . comint-insert-previous-argument) + (defun . comint-update-fence) + (defun . comint-kill-whole-line) + (defun . comint-kill-region) + (defun . comint-source-default) + (defun . comint-check-source) + (defun . comint-extract-string) + (defun . comint-get-source) + (defun . comint-proc-query) + comint-completion-autolist comint-completion-addsuffix comint-completion-recexact comint-completion-fignore comint-file-name-prefix comint-file-name-chars comint-file-name-quote-list + (defun . comint-directory) + (defun . comint-word) + (defun . comint-substitute-in-file-name) + (defun . comint-match-partial-filename) + (defun . comint-quote-filename) + (defun . comint-unquote-filename) + (defun . comint-dynamic-complete) + (defun . comint-dynamic-complete-filename) + (defun . comint-dynamic-complete-as-filename) + (defun . comint-replace-by-expanded-filename) + (defun . comint-dynamic-simple-complete) + (defun . comint-dynamic-list-filename-completions) + comint-displayed-dynamic-completions comint-dynamic-list-completions-config + (defun . comint-dynamic-list-completions) + (defun . comint-get-next-from-history) + (defun . comint-accumulate) + (defun . comint-goto-process-mark) + (defun . comint-bol-or-process-mark) + (defun . comint-set-process-mark) + comint-redirect-verbose comint-redirect-filter-functions comint-redirect-output-buffer comint-redirect-finished-regexp comint-redirect-insert-matching-regexp comint-redirect-echo-input comint-redirect-completed comint-redirect-original-mode-line-process comint-redirect-perform-sanity-check comint-redirect-original-filter-function comint-redirect-subvert-readonly + (defun . comint-redirect-setup) + (defun . comint-redirect-cleanup) + (defun . comint-redirect-remove-redirection) + (defun . comint-redirect-filter) + (defun . comint-redirect-preoutput-filter) + (t . comint-redirect-send-command) + (defun . comint-redirect-send-command) + (t . comint-redirect-send-command-to-process) + (defun . comint-redirect-send-command-to-process) + (t . comint-redirect-results-list) + (defun . comint-redirect-results-list) + (t . comint-redirect-results-list-from-process) + (defun . comint-redirect-results-list-from-process) + (provide . comint)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/ring.elc" + (t . ring-p) + (defun . ring-p) + (t . make-ring) + (defun . make-ring) + (defun . ring-insert-at-beginning) + (defun . ring-plus1) + (defun . ring-minus1) + (defun . ring-length) + (defun . ring-index) + (defun . ring-empty-p) + (defun . ring-size) + (defun . ring-copy) + (defun . ring-insert) + (defun . ring-remove) + (defun . ring-ref) + (defun . ring-elements) + (defun . ring-member) + (defun . ring-next) + (defun . ring-previous) + (defun . ring-insert+extend) + (defun . ring-remove+insert+extend) + (defun . ring-convert-sequence-to-ring) + (provide . ring)) + ("/usr/share/emacs/23.0.93/lisp/apropos.elc" + (require . button) + apropos-do-all apropos-symbol-face apropos-keybinding-face apropos-label-face apropos-property-face apropos-match-face apropos-sort-by-scores apropos-documentation-sort-by-scores apropos-mode-map apropos-mode-hook apropos-pattern apropos-pattern-quoted apropos-words apropos-all-words apropos-regexp apropos-all-words-regexp apropos-files-scanned apropos-accumulator apropos-item apropos-synonyms + (defun . apropos-symbol-button-display-help) + (defun . apropos-next-label-button) + (defun . apropos-words-to-regexp) + (t . apropos-read-pattern) + (defun . apropos-read-pattern) + (defun . apropos-parse-pattern) + (defun . apropos-calc-scores) + (defun . apropos-score-str) + (defun . apropos-score-doc) + (defun . apropos-score-symbol) + (defun . apropos-true-hit) + (defun . apropos-false-hit-symbol) + (defun . apropos-false-hit-str) + (defun . apropos-true-hit-doc) + apropos-mode-map apropos-mode-syntax-table apropos-mode-abbrev-table apropos-mode-abbrev-table + (defun . apropos-mode) + apropos-multi-type + (t . apropos-variable) + (defun . apropos-variable) + (defun . command-apropos) + (t . apropos-command) + (defun . apropos-command) + (t . apropos-documentation-property) + (defun . apropos-documentation-property) + (t . apropos) + (defun . apropos) + (defun . apropos-library-button) + (t . apropos-library) + (defun . apropos-library) + (defun . apropos-symbols-internal) + (t . apropos-value) + (defun . apropos-value) + (t . apropos-documentation) + (defun . apropos-documentation) + (defun . apropos-value-internal) + (defun . apropos-documentation-internal) + (defun . apropos-format-plist) + (defun . apropos-documentation-check-doc-file) + (defun . apropos-documentation-check-elc-file) + (defun . apropos-safe-documentation) + apropos-compact-layout + (defun . apropos-print) + (defun . apropos-macrop) + (defun . apropos-print-doc) + (defun . apropos-follow) + (defun . apropos-describe-plist) + (provide . apropos)) + ("/home/hobbes/nxhtml/util/gimp.el" gimp:version + (require . w32-regdat) + (defun . gimp-get-remote-command) + gimp-remote-command + (defun . gimp-get-gimp-exe) + gimp-exe gimp-remote-command-list + (t . gimp-edit-file) + (defun . gimp-edit-file) + (t . gimp-edit-buffer) + (defun . gimp-edit-buffer) + (t . gimp-can-edit) + (defun . gimp-can-edit) + gimp-point-key-bindings + (defun . gimp-add-point-bindings) + (provide . gimp)) + ("/usr/share/emacs/23.0.93/lisp/dired.elc" dired-listing-switches dired-subdir-switches dired-chown-program dired-use-ls-dired dired-chmod-program dired-touch-program dired-ls-F-marks-symlinks dired-trivial-filenames dired-keep-marker-rename dired-keep-marker-copy dired-keep-marker-hardlink dired-keep-marker-symlink dired-dwim-target dired-copy-preserve-time dired-free-space-program dired-free-space-args dired-load-hook dired-mode-hook dired-before-readin-hook dired-after-readin-hook dired-dnd-protocol-alist dired-marker-char dired-del-marker dired-shrink-to-fit dired-flagging-regexp dired-directory dired-actual-switches dired-re-inode-size dired-re-mark dired-re-maybe-mark dired-re-dir dired-re-sym dired-re-exe dired-re-perms dired-re-dot dired-subdir-alist dired-switches-alist dired-move-to-filename-regexp dired-subdir-regexp + (defface . dired-header) + dired-header-face + (defface . dired-mark) + dired-mark-face + (defface . dired-marked) + dired-marked-face + (defface . dired-flagged) + dired-flagged-face + (defface . dired-warning) + dired-warning-face + (defface . dired-perm-write) + dired-perm-write-face + (defface . dired-directory) + dired-directory-face + (defface . dired-symlink) + dired-symlink-face + (defface . dired-ignored) + dired-ignored-face dired-font-lock-keywords + (defun . dired-mark-if) + (defun . dired-map-over-marks) + (defun . dired-get-marked-files) + (defun . dired-read-dir-and-switches) + (t . dired) + (defun . dired) + (t . dired-other-window) + (defun . dired-other-window) + (t . dired-other-frame) + (defun . dired-other-frame) + (t . dired-noselect) + (defun . dired-noselect) + (defun . dired-directory-changed-p) + (defun . dired-buffer-stale-p) + (defun . dired-internal-noselect) + dired-buffers + (defun . dired-find-buffer-nocreate) + (defun . dired-readin) + (defun . dired-readin-insert) + (defun . dired-align-file) + (defun . dired-insert-directory) + (defun . dired-insert-set-properties) + (defun . dired-revert) + (defun . dired-remember-marks) + (defun . dired-mark-remembered) + (defun . dired-remember-hidden) + (defun . dired-insert-old-subdirs) + (defun . dired-uncache) + dired-mode-map + (t . dired-mode) + (defun . dired-mode) + (defun . dired-summary) + (defun . dired-undo) + (defun . dired-toggle-read-only) + (defun . dired-next-line) + (defun . dired-previous-line) + (defun . dired-next-dirline) + (defun . dired-prev-dirline) + (defun . dired-up-directory) + (defun . dired-get-file-for-visit) + (defun . dired-advertised-find-file) + (defun . dired-find-file) + (defun . dired-find-alternate-file) + (defun . dired-mouse-find-file-other-window) + (defun . dired-view-file) + (defun . dired-find-file-other-window) + (defun . dired-display-file) + (defun . dired-get-filename) + (defun . dired-string-replace-match) + (defun . dired-make-absolute) + (defun . dired-make-relative) + dired-permission-flags-regexp + (defun . dired-move-to-filename) + (defun . dired-move-to-end-of-filename) + (defun . dired-copy-filename-as-kill) + (defun . dired-buffers-for-dir) + (defun . dired-glob-regexp) + (defun . dired-advertise) + (defun . dired-unadvertise) + (defun . dired-in-this-tree) + (defun . dired-normalize-subdir) + (defun . dired-get-subdir) + (defun . dired-get-subdir-min) + (defun . dired-get-subdir-max) + (defun . dired-clear-alist) + (defun . dired-subdir-index) + (defun . dired-next-subdir) + (defun . dired-build-subdir-alist) + (defun . dired-alist-add-1) + (defun . dired-goto-next-nontrivial-file) + (defun . dired-goto-next-file) + (defun . dired-goto-file) + (defun . dired-initial-position) + (defun . dired-current-directory) + (defun . dired-subdir-max) + dired-recursive-deletes dired-re-no-dot + (defun . dired-delete-file) + (defun . dired-do-flagged-delete) + (defun . dired-do-delete) + dired-deletion-confirmer + (defun . dired-internal-do-deletions) + (defun . dired-fun-in-all-buffers) + (defun . dired-delete-entry) + (defun . dired-clean-up-after-deletion) + (defun . dired-marker-regexp) + (defun . dired-plural-s) + (defun . dired-mark-prompt) + (defun . dired-pop-to-buffer) + dired-no-confirm + (defun . dired-mark-pop-up) + (defun . dired-format-columns-of-files) + (defun . dired-repeat-over-lines) + (defun . dired-between-files) + (defun . dired-next-marked-file) + (defun . dired-prev-marked-file) + (defun . dired-file-marker) + (defun . dired-mark-files-in-region) + (defun . dired-mark) + (defun . dired-unmark) + (defun . dired-flag-file-deletion) + (defun . dired-unmark-backward) + (defun . dired-toggle-marks) + dired-regexp-history + (defun . dired-read-regexp) + (defun . dired-mark-files-regexp) + (defun . dired-mark-files-containing-regexp) + (defun . dired-flag-files-regexp) + (defun . dired-mark-symlinks) + (defun . dired-mark-directories) + (defun . dired-mark-executables) + (defun . dired-flag-auto-save-files) + dired-garbage-files-regexp + (defun . dired-flag-garbage-files) + (defun . dired-flag-backup-files) + (defun . dired-change-marks) + (defun . dired-unmark-all-marks) + (defun . dired-unmark-all-files) + dired-log-buffer + (defun . dired-why) + (defun . dired-log) + (defun . dired-log-summary) + dired-ls-sorting-switches dired-sort-by-date-regexp dired-sort-by-name-regexp dired-sort-inhibit + (defun . dired-sort-set-modeline) + (defun . dired-sort-toggle-or-edit) + (defun . dired-sort-toggle) + (defun . dired-replace-in-string) + (defun . dired-sort-other) + dired-subdir-alist-pre-R + (defun . dired-sort-R-check) + dired-recursive-copies + (defun . dired-dnd-popup-notice) + (defun . dired-dnd-do-ask-action) + (defun . dired-dnd-handle-local-file) + (defun . dired-dnd-handle-file) + (defun . dired-desktop-buffer-misc-data) + (defun . dired-restore-desktop-buffer) + (provide . dired)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/regexp-opt.elc" + (t . regexp-opt) + (defun . regexp-opt) + (t . regexp-opt-depth) + (defun . regexp-opt-depth) + (defun . regexp-opt-group) + (defun . regexp-opt-charset) + (provide . regexp-opt)) + ("/usr/share/emacs/23.0.93/lisp/cus-edit.elc" + (require . cus-face) + (require . wid-edit) + (require . cus-load) + (require . cus-start) + custom-mode-map custom-mode-link-map custom-field-keymap + (defun . custom-split-regexp-maybe) + (defun . custom-variable-prompt) + (defun . custom-menu-filter) + custom-prefix-list custom-unlispify-menu-entries custom-unlispify-remove-prefixes + (defun . custom-unlispify-menu-entry) + custom-unlispify-tag-names + (defun . custom-unlispify-tag-name) + (defun . custom-prefix-add) + custom-guess-name-alist custom-guess-doc-alist + (defun . custom-guess-type) + custom-browse-sort-alphabetically custom-browse-order-groups custom-browse-only-groups custom-buffer-sort-alphabetically custom-buffer-order-groups custom-menu-sort-alphabetically custom-menu-order-groups + (defun . custom-sort-items) + custom-commands + (defun . Custom-help) + custom-reset-menu custom-options + (defun . custom-command-apply) + (defun . Custom-set) + (defun . Custom-save) + (defun . custom-reset) + (defun . Custom-reset-current) + (defun . Custom-reset-saved) + custom-reset-standard-variables-list custom-reset-standard-faces-list + (defun . custom-reset-standard-save-and-update) + (defun . Custom-reset-standard) + (defun . custom-prompt-variable) + (t . customize-set-value) + (defun . customize-set-value) + (t . customize-set-variable) + (defun . customize-set-variable) + (t . customize-save-variable) + (defun . customize-save-variable) + (t . customize) + (defun . customize) + (t . customize-mode) + (defun . customize-mode) + (defun . customize-read-group) + (t . customize-group) + (defun . customize-group) + (t . customize-group-other-window) + (defun . customize-group-other-window) + (defun . customize-variable) + (t . customize-option) + (defun . customize-option) + (defun . customize-variable-other-window) + (t . customize-option-other-window) + (defun . customize-option-other-window) + customize-changed-options-previous-release customize-package-emacs-version-alist + (defun . customize-changed) + (t . customize-changed-options) + (defun . customize-changed-options) + (defun . customize-package-emacs-version) + (defun . customize-version-lessp) + (t . customize-face) + (defun . customize-face) + (t . customize-face-other-window) + (defun . customize-face-other-window) + (defun . customize-customized) + (t . customize-unsaved) + (defun . customize-unsaved) + (t . customize-rogue) + (defun . customize-rogue) + (t . customize-saved) + (defun . customize-saved) + (t . customize-apropos) + (defun . customize-apropos) + (t . customize-apropos-options) + (defun . customize-apropos-options) + (t . customize-apropos-faces) + (defun . customize-apropos-faces) + (t . customize-apropos-groups) + (defun . customize-apropos-groups) + custom-buffer-style custom-buffer-done-kill custom-buffer-indent + (defun . custom-get-fresh-buffer) + (t . custom-buffer-create) + (defun . custom-buffer-create) + (t . custom-buffer-create-other-window) + (defun . custom-buffer-create-other-window) + custom-reset-button-menu custom-buffer-verbose-help + (defun . Custom-buffer-done) + custom-button custom-button-mouse custom-button-pressed custom-raised-buttons + (defun . custom-buffer-create-internal) + (t . customize-browse) + (defun . customize-browse) + (defun . custom-browse-visibility-action) + (defun . custom-browse-group-tag-action) + (defun . custom-browse-variable-tag-action) + (defun . custom-browse-face-tag-action) + custom-browse-alist custom-browse-alist + (defun . custom-browse-insert-prefix) + (defface . custom-invalid) + (defface . custom-rogue) + (defface . custom-modified) + (defface . custom-set) + (defface . custom-changed) + (defface . custom-themed) + (defface . custom-saved) + custom-magic-alist custom-magic-show custom-magic-show-hidden custom-magic-show-button + (defun . widget-magic-mouse-down-action) + (defun . custom-magic-value-create) + (defun . custom-magic-reset) + (defface . custom-button) + (defface . custom-button-mouse) + (defface . custom-button-unraised) + (defface . custom-button-pressed) + (defface . custom-button-pressed-unraised) + (defface . custom-documentation) + (defface . custom-state) + (defface . custom-link) + (defun . custom-convert-widget) + (defun . custom-notify) + (defun . custom-redraw) + (defun . custom-redraw-magic) + (defun . custom-show) + (defun . custom-load-widget) + (defun . custom-unloaded-symbol-p) + (defun . custom-unloaded-widget-p) + (defun . custom-toggle-hide) + (defun . custom-toggle-parent) + (defun . custom-add-see-also) + (defun . custom-add-parent-links) + (defface . custom-comment) + (defface . custom-comment-tag) + (defun . custom-comment-create) + (defun . custom-comment-hide) + (defun . custom-comment-show) + (defun . custom-comment-invisible-p) + (defface . custom-variable-tag) + (defface . custom-variable-button) + custom-variable-default-form + (defun . custom-variable-documentation) + (defun . custom-variable-type) + (defun . custom-variable-value-create) + (defun . custom-tag-action) + (defun . custom-tag-mouse-down-action) + (defun . custom-variable-state-set) + (defun . custom-variable-standard-value) + custom-variable-menu + (defun . custom-variable-action) + (defun . custom-variable-edit) + (defun . custom-variable-edit-lisp) + (defun . custom-variable-set) + (defun . custom-variable-mark-to-save) + (defun . custom-variable-state-set-and-redraw) + (defun . custom-variable-save) + (defun . custom-variable-reset-saved) + (defun . custom-variable-mark-to-reset-standard) + (defun . custom-variable-reset-standard) + (defun . custom-variable-backup-value) + (defun . custom-variable-reset-backup) + (defface . custom-visibility) + (defun . custom-face-edit-fix-value) + (defun . custom-face-edit-convert-widget) + (defun . custom-face-edit-deactivate) + (defun . custom-face-edit-activate) + (defun . custom-face-edit-delete) + (defun . custom-face-edit-attribute-tag) + (defface . custom-face-tag) + custom-face-default-form custom-face-all + (defun . custom-display-unselected-match) + custom-face-selected + (defun . custom-filter-face-spec) + (defun . custom-pre-filter-face-spec) + (defun . custom-post-filter-face-spec) + (defun . custom-face-value-create) + custom-face-menu + (defun . custom-face-edit-selected) + (defun . custom-face-edit-all) + (defun . custom-face-edit-lisp) + (defun . custom-face-state-set) + (defun . custom-face-action) + (defun . custom-face-set) + (defun . custom-face-mark-to-save) + (defun . custom-face-state-set-and-redraw) + (defun . custom-face-save) + (defun . custom-face-save-command) + (defun . custom-face-reset-saved) + (defun . custom-face-standard-value) + (defun . custom-face-mark-to-reset-standard) + (defun . custom-face-reset-standard) + widget-face-prompt-value-history + (defun . widget-face-sample-face-get) + (defun . widget-face-notify) + (defun . custom-hook-convert-widget) + (defun . custom-group-link-action) + custom-group-tag-faces + (defface . custom-group-tag-1) + (defface . custom-group-tag) + (defun . custom-group-sample-face-get) + (defun . custom-group-visibility-create) + (defun . custom-group-members) + (defun . custom-group-value-create) + custom-group-menu + (defun . custom-group-action) + (defun . custom-group-set) + (defun . custom-group-mark-to-save) + (defun . custom-group-state-set-and-redraw) + (defun . custom-group-save) + (defun . custom-group-reset-current) + (defun . custom-group-reset-saved) + (defun . custom-group-reset-standard) + (defun . custom-group-mark-to-reset-standard) + (defun . custom-group-state-update) + custom-file + (defun . custom-file) + (t . custom-save-all) + (defun . custom-save-all) + (t . customize-save-customized) + (defun . customize-save-customized) + (defun . custom-save-delete) + (defun . custom-save-variables) + (defun . custom-save-faces) + custom-menu-nesting + (defun . custom-face-menu-create) + (defun . custom-variable-menu-create) + (defun . custom-group-menu-create) + (t . custom-menu-create) + (defun . custom-menu-create) + (t . customize-menu-create) + (defun . customize-menu-create) + Custom-mode-menu + (defun . Custom-mode-menu) + custom-tool-bar-map + (defun . Custom-no-edit) + (defun . Custom-newline) + (defun . Custom-goto-parent) + Custom-mode-hook + (defun . custom-state-buffer-message) + Custom-mode-map Custom-mode-syntax-table Custom-mode-abbrev-table Custom-mode-abbrev-table + (defun . Custom-mode) + (defun . custom-mode) + custom-mode-hook + (provide . cus-edit)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/easymenu.elc" easy-menu-precalculate-equivalent-keybindings + (defun . easy-menu-intern) + (t . easy-menu-define) + (defun . easy-menu-define) + (defun . easy-menu-binding) + (t . easy-menu-do-define) + (defun . easy-menu-do-define) + (defun . easy-menu-filter-return) + easy-menu-avoid-duplicate-keys + (t . easy-menu-create-menu) + (defun . easy-menu-create-menu) + easy-menu-button-prefix easy-menu-converted-items-table + (defun . easy-menu-convert-item) + (defun . easy-menu-convert-item-1) + (defun . easy-menu-define-key) + (defun . easy-menu-name-match) + (defun . easy-menu-always-true-p) + easy-menu-item-count + (defun . easy-menu-make-symbol) + (t . easy-menu-change) + (defun . easy-menu-change) + (defun . easy-menu-remove) + (defun . easy-menu-add) + (defun . add-submenu) + (defun . easy-menu-add-item) + (defun . easy-menu-item-present-p) + (defun . easy-menu-remove-item) + (defun . easy-menu-return-item) + (defun . easy-menu-lookup-name) + (defun . easy-menu-get-map) + (provide . easymenu)) + ("/usr/share/emacs/23.0.93/lisp/cus-start.elc" + (provide . cus-start)) + ("/usr/share/emacs/23.0.93/lisp/cus-load.el" + (defun . custom-put-if-not) + custom-versions-load-alist + (provide . cus-load)) + ("/usr/share/emacs/23.0.93/lisp/wid-edit.elc" + (defun . widget-event-point) + (defun . widget-button-release-event-p) + widget-documentation-face + (defface . widget-documentation) + widget-button-face + (defface . widget-button) + widget-mouse-face + (defface . widget-field) + (defface . widget-single-line-field) + (defun . widget-princ-to-string) + (defun . widget-clear-undo) + widget-menu-max-size widget-menu-max-shortcuts widget-menu-minibuffer-flag + (defun . widget-choose) + (defun . widget-remove-if) + widget-field-add-space widget-field-use-before-change + (defun . widget-specify-field) + (defun . widget-specify-secret) + (defun . widget-specify-button) + (defun . widget-mouse-help) + (defun . widget-specify-sample) + (defun . widget-specify-doc) + (defun . widget-specify-insert) + (defface . widget-inactive) + (defun . widget-specify-inactive) + (defun . widget-overlay-inactive) + (defun . widget-specify-active) + (defun . widget-type) + (t . widgetp) + (defun . widgetp) + (defun . widget-get-indirect) + (defun . widget-member) + (t . widget-value) + (defun . widget-value) + (defun . widget-value-set) + (defun . widget-default-get) + (defun . widget-match-inline) + (defun . widget-apply-action) + (t . widget-prompt-value) + (defun . widget-prompt-value) + (defun . widget-get-sibling) + (defun . widget-map-buttons) + widget-image-directory widget-image-enable widget-image-conversion + (defun . widget-image-find) + widget-button-pressed-face + (defun . widget-image-insert) + (defun . widget-move-and-invoke) + widget-button-prefix widget-button-suffix + (t . widget-create) + (defun . widget-create) + (defun . widget-create-child-and-convert) + (defun . widget-create-child) + (defun . widget-create-child-value) + (t . widget-delete) + (defun . widget-delete) + (defun . widget-copy) + (defun . widget-convert) + (t . widget-insert) + (defun . widget-insert) + (defun . widget-convert-text) + (defun . widget-convert-button) + (defun . widget-leave-text) + (defun . advertised-widget-backward) + widget-keymap widget-global-map widget-field-keymap widget-text-keymap + (defun . widget-field-activate) + (defface . widget-button-pressed) + widget-button-click-moves-point + (defun . widget-button-click) + (defun . widget-button-press) + (defun . widget-tabable-at) + widget-use-overlay-change + (defun . widget-move) + (defun . widget-forward) + (defun . widget-backward) + (defun . widget-beginning-of-line) + (defun . widget-end-of-line) + (defun . widget-kill-line) + widget-complete-field + (defun . widget-narrow-to-field) + (defun . widget-complete) + widget-field-new widget-field-list + (defun . widget-at) + (t . widget-setup) + (defun . widget-setup) + widget-field-last widget-field-was + (defun . widget-field-at) + (defun . widget-field-buffer) + (defun . widget-field-start) + (defun . widget-field-end) + (defun . widget-field-find) + (defun . widget-before-change) + (defun . widget-add-change) + (defun . widget-after-change) + (defun . widget-parent-action) + (defun . widget-children-value-delete) + (defun . widget-children-validate) + (defun . widget-child-value-get) + (defun . widget-child-value-inline) + (defun . widget-child-validate) + (defun . widget-type-value-create) + (defun . widget-type-default-get) + (defun . widget-type-match) + (defun . widget-types-copy) + (defun . widget-types-convert-widget) + (defun . widget-value-convert-widget) + (defun . widget-value-value-get) + (defun . widget-default-complete) + (defun . widget-default-create) + (defun . widget-default-format-handler) + (defun . widget-default-button-face-get) + (defun . widget-default-mouse-face-get) + (defun . widget-default-sample-face-get) + (defun . widget-default-delete) + (defun . widget-default-value-set) + (defun . widget-default-value-inline) + (defun . widget-default-default-get) + (defun . widget-default-menu-tag-get) + (defun . widget-default-active) + (defun . widget-default-deactivate) + (defun . widget-default-action) + (defun . widget-default-notify) + (defun . widget-default-prompt-value) + (defun . widget-docstring) + (defun . widget-item-value-create) + (defun . widget-item-match) + (defun . widget-item-match-inline) + (defun . widget-sublist) + (defun . widget-item-action) + widget-push-button-prefix widget-push-button-suffix + (defun . widget-push-button-value-create) + widget-link-prefix widget-link-suffix + (defun . widget-info-link-action) + (defun . widget-url-link-action) + (defun . widget-function-link-action) + (defun . widget-variable-link-action) + (defun . widget-file-link-action) + (defun . widget-emacs-library-link-action) + (defun . widget-emacs-commentary-link-action) + widget-field-history + (defun . widget-field-prompt-internal) + (defun . widget-field-prompt-value) + widget-edit-functions + (defun . widget-field-action) + (defun . widget-field-validate) + (defun . widget-field-value-create) + (defun . widget-field-value-delete) + (defun . widget-field-value-get) + (defun . widget-field-match) + (defun . widget-choice-value-create) + (defun . widget-choice-default-get) + widget-choice-toggle + (defun . widget-choice-mouse-down-action) + (defun . widget-choice-action) + (defun . widget-choice-validate) + (defun . widget-choice-match) + (defun . widget-choice-match-inline) + (defun . widget-toggle-value-create) + (defun . widget-toggle-action) + (defun . widget-checkbox-action) + (defun . widget-checklist-value-create) + (defun . widget-checklist-add-item) + (defun . widget-checklist-match) + (defun . widget-checklist-match-inline) + (defun . widget-checklist-match-find) + (defun . widget-checklist-match-up) + (defun . widget-checklist-value-get) + (defun . widget-checklist-validate) + (defun . widget-radio-button-notify) + (defun . widget-radio-value-create) + (defun . widget-radio-add-item) + (defun . widget-radio-value-get) + (defun . widget-radio-chosen) + (defun . widget-radio-value-inline) + (defun . widget-radio-value-set) + (defun . widget-radio-validate) + (defun . widget-radio-action) + (defun . widget-insert-button-action) + (defun . widget-delete-button-action) + (defun . widget-editable-list-format-handler) + (defun . widget-editable-list-value-create) + (defun . widget-editable-list-value-get) + (defun . widget-editable-list-match) + (defun . widget-editable-list-match-inline) + (defun . widget-editable-list-insert-before) + (defun . widget-editable-list-delete-at) + (defun . widget-editable-list-entry-create) + (defun . widget-group-value-create) + (defun . widget-group-default-get) + (defun . widget-group-match) + (defun . widget-group-match-inline) + (defun . widget-visibility-value-create) + (defun . widget-documentation-link-action) + widget-documentation-links widget-documentation-link-regexp widget-documentation-link-p widget-documentation-link-type + (defun . widget-documentation-link-add) + (defun . widget-documentation-string-value-create) + (defun . widget-documentation-string-action) + (defun . widget-add-documentation-string-button) + (defun . widget-const-prompt-value) + widget-string-prompt-value-history + (defun . widget-string-complete) + (defun . widget-regexp-match) + (defun . widget-regexp-validate) + (defun . widget-file-complete) + (defun . widget-file-prompt-value) + widget-symbol-prompt-value-history + (defun . widget-symbol-prompt-internal) + widget-function-prompt-value-history widget-variable-prompt-value-history + (defun . widget-coding-system-prompt-value) + (defun . widget-coding-system-action) + widget-key-sequence-prompt-value-history widget-key-sequence-default-value widget-key-sequence-map + (defun . widget-key-sequence-read-event) + (defun . widget-key-sequence-validate) + (defun . widget-key-sequence-value-to-internal) + (defun . widget-key-sequence-value-to-external) + (defun . widget-sexp-value-to-internal) + (defun . widget-sexp-validate) + widget-sexp-prompt-value-history + (defun . widget-sexp-prompt-value) + (defun . widget-restricted-sexp-match) + (defun . widget-vector-match) + (defun . widget-cons-match) + (defun . widget-plist-convert-widget) + (defun . widget-plist-convert-option) + (defun . widget-alist-convert-widget) + (defun . widget-alist-convert-option) + (defun . widget-choice-prompt-value) + (defun . widget-boolean-prompt-value) + (defun . widget-color-complete) + (defun . widget-color-sample-face-get) + (defun . widget-color-action) + (defun . widget-color-notify) + (defun . widget-echo-help) + (provide . wid-edit)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/cl.elc" cl-optimize-speed cl-optimize-safety custom-print-functions + (defun . cl-unload-function) + (defun . incf) + (defun . decf) + (defun . pop) + (defun . push) + (defun . pushnew) + (defun . cl-set-elt) + (defun . cl-set-nthcdr) + (defun . cl-set-buffer-substring) + (defun . cl-set-substring) + (defun . cl-map-extents) + (defun . cl-block-wrapper) + (defun . cl-block-throw) + (defun . values) + (defun . values-list) + (defun . multiple-value-list) + (defun . multiple-value-apply) + (defun . multiple-value-call) + (defun . nth-value) + cl-macro-environment cl-old-macroexpand + (defun . macroexpand) + (defun . cl-macroexpand) + cl-compiling-file + (defun . cl-compiling-file) + cl-proclaims-deferred + (defun . proclaim) + (defun . declaim) + (defun . cl-random-time) + *gensym-counter* + (defun . floatp-safe) + (defun . plusp) + (defun . minusp) + (defun . oddp) + (defun . evenp) + *random-state* most-positive-float most-positive-float most-negative-float most-negative-float least-positive-float least-positive-float least-negative-float least-negative-float least-positive-normalized-float least-positive-normalized-float least-negative-normalized-float least-negative-normalized-float float-epsilon float-epsilon float-negative-epsilon float-negative-epsilon + (defun . copy-seq) + (defun . mapcar*) + (defun . svref) + (defun . first) + (defun . second) + (defun . rest) + (defun . endp) + (defun . third) + (defun . fourth) + (defun . fifth) + (defun . sixth) + (defun . seventh) + (defun . eighth) + (defun . ninth) + (defun . tenth) + (defun . caaar) + (defun . caadr) + (defun . cadar) + (defun . caddr) + (defun . cdaar) + (defun . cdadr) + (defun . cddar) + (defun . cdddr) + (defun . caaaar) + (defun . caaadr) + (defun . caadar) + (defun . caaddr) + (defun . cadaar) + (defun . cadadr) + (defun . caddar) + (defun . cadddr) + (defun . cdaaar) + (defun . cdaadr) + (defun . cdadar) + (defun . cdaddr) + (defun . cddaar) + (defun . cddadr) + (defun . cdddar) + (defun . cddddr) + (defun . list*) + (defun . ldiff) + (defun . copy-list) + (defun . cl-maclisp-member) + (defun . cl-member) + (defun . cl-floor) + (defun . cl-ceiling) + (defun . cl-truncate) + (defun . cl-round) + (defun . cl-mod) + (defun . adjoin) + (defun . subst) + (defun . cl-do-subst) + (defun . acons) + (defun . pairlis) + (provide . cl-19) + (provide . cl) + cl-hacked-flag + (defun . cl-hack-byte-compiler) + (provide . cl)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/cl-loaddefs.el" + (autoload . coerce) + (autoload . equalp) + (autoload . cl-mapcar-many) + (autoload . map) + (autoload . maplist) + (autoload . mapl) + (autoload . mapcan) + (autoload . mapcon) + (autoload . some) + (autoload . every) + (autoload . notany) + (autoload . notevery) + (defun . cl-map-keymap) + (autoload . cl-map-keymap-recursively) + (autoload . cl-map-intervals) + (autoload . cl-map-overlays) + (autoload . cl-set-frame-visible-p) + (autoload . cl-progv-before) + (autoload . gcd) + (autoload . lcm) + (autoload . isqrt) + (autoload . floor*) + (autoload . ceiling*) + (autoload . truncate*) + (autoload . round*) + (autoload . mod*) + (autoload . rem*) + (autoload . signum) + (autoload . random*) + (autoload . make-random-state) + (autoload . random-state-p) + (autoload . cl-float-limits) + (autoload . subseq) + (autoload . concatenate) + (autoload . revappend) + (autoload . nreconc) + (autoload . list-length) + (autoload . tailp) + (autoload . get*) + (autoload . getf) + (autoload . cl-set-getf) + (autoload . cl-do-remf) + (autoload . cl-remprop) + (defun . remprop) + (defun . cl-gethash) + (defun . cl-puthash) + (defun . cl-remhash) + (defun . cl-clrhash) + (defun . cl-maphash) + (defun . cl-make-hash-table) + (defun . cl-hash-table-p) + (defun . cl-hash-table-count) + (autoload . cl-macroexpand-all) + (autoload . cl-prettyexpand) + (autoload . gensym) + (autoload . gentemp) + (autoload . defun*) + (autoload . defmacro*) + (autoload . function*) + (autoload . destructuring-bind) + (autoload . eval-when) + (autoload . load-time-value) + (autoload . case) + (autoload . ecase) + (autoload . typecase) + (autoload . etypecase) + (autoload . block) + (autoload . return) + (autoload . return-from) + (autoload . loop) + (autoload . do) + (autoload . do*) + (autoload . dolist) + (autoload . dotimes) + (autoload . do-symbols) + (autoload . do-all-symbols) + (autoload . psetq) + (autoload . progv) + (autoload . flet) + (autoload . labels) + (autoload . macrolet) + (autoload . symbol-macrolet) + (autoload . lexical-let) + (autoload . lexical-let*) + (autoload . multiple-value-bind) + (autoload . multiple-value-setq) + (autoload . locally) + (autoload . the) + (autoload . declare) + (autoload . define-setf-method) + (autoload . defsetf) + (autoload . get-setf-method) + (autoload . setf) + (autoload . psetf) + (autoload . cl-do-pop) + (autoload . remf) + (autoload . shiftf) + (autoload . rotatef) + (autoload . letf) + (autoload . letf*) + (autoload . callf) + (autoload . callf2) + (autoload . define-modify-macro) + (autoload . defstruct) + (autoload . cl-struct-setf-expander) + (autoload . typep) + (autoload . check-type) + (autoload . assert) + (autoload . define-compiler-macro) + (autoload . compiler-macroexpand) + (autoload . reduce) + (autoload . fill) + (autoload . replace) + (autoload . remove*) + (autoload . remove-if) + (autoload . remove-if-not) + (autoload . delete*) + (autoload . delete-if) + (autoload . delete-if-not) + (autoload . remove-duplicates) + (autoload . delete-duplicates) + (autoload . substitute) + (autoload . substitute-if) + (autoload . substitute-if-not) + (autoload . nsubstitute) + (autoload . nsubstitute-if) + (autoload . nsubstitute-if-not) + (autoload . find) + (autoload . find-if) + (autoload . find-if-not) + (autoload . position) + (autoload . position-if) + (autoload . position-if-not) + (autoload . count) + (autoload . count-if) + (autoload . count-if-not) + (autoload . mismatch) + (autoload . search) + (autoload . sort*) + (autoload . stable-sort) + (autoload . merge) + (autoload . member*) + (autoload . member-if) + (autoload . member-if-not) + (autoload . cl-adjoin) + (autoload . assoc*) + (autoload . assoc-if) + (autoload . assoc-if-not) + (autoload . rassoc*) + (autoload . rassoc-if) + (autoload . rassoc-if-not) + (autoload . union) + (autoload . nunion) + (autoload . intersection) + (autoload . nintersection) + (autoload . set-difference) + (autoload . nset-difference) + (autoload . set-exclusive-or) + (autoload . nset-exclusive-or) + (autoload . subsetp) + (autoload . subst-if) + (autoload . subst-if-not) + (autoload . nsubst) + (autoload . nsubst-if) + (autoload . nsubst-if-not) + (autoload . sublis) + (autoload . nsublis) + (autoload . tree-equal)) + ("/home/hobbes/nxhtml/nxhtml-loaddefs.el" + (autoload . html-site-buffer-or-dired-file-name) + (autoload . html-site-set-site) + (autoload . html-site-dired-current) + (autoload . html-site-find-file) + (autoload . html-site-rgrep) + (autoload . html-site-query-replace) + (autoload . inlimg-mode) + (autoload . inlimg-toggle-img-display) + (autoload . nxhtml-report-bug) + (autoload . nxhtml-edit-with-gimp) + (autoload . nxhtml-browse-file) + (autoload . nxhtml-browse-region) + nxhtml-global-minor-mode + (autoload . nxhtml-global-minor-mode) + (autoload . nxhtml-mode) + (autoload . nxhtml-short-tag-help) + (autoload . nxhtml-validation-header-mode) + (autoload . nxhtml-mumamo-mode) + (autoload . embperl-nxhtml-mumamo-mode) + (autoload . django-nxhtml-mumamo-mode) + (autoload . genshi-nxhtml-mumamo-mode) + (autoload . mjt-nxhtml-mumamo-mode) + (autoload . smarty-nxhtml-mumamo-mode) + (autoload . jsp-nxhtml-mumamo-mode) + (autoload . eruby-nxhtml-mumamo-mode) + (autoload . asp-nxhtml-mumamo-mode) + (autoload . mako-nxhtml-mumamo-mode) + nxml-where-global-mode + (autoload . nxml-where-global-mode) + (autoload . rngalt-set-validation-header) + (autoload . tidy-build-menu) + (autoload . xhtml-help-show-css-ref) + (autoload . xhtml-help-show-tag-ref) + (autoload . csharp-mode) + (autoload . django-mode) + (autoload . javascript-mode) + (autoload . moz-minor-mode) + (autoload . inferior-moz-mode) + php-file-patterns + (autoload . php-mode) + (autoload . smarty-mode) + (autoload . tt-mode) + (autoload . wikipedia-mode) + (autoload . wikipedia-draft) + (autoload . wikipedia-draft-page) + (autoload . wikipedia-draft-buffer) + wikipedia-draft-send-archive + (autoload . ert-deftest) + (autoload . ert-run-tests-interactively) + (autoload . nxhtmltest-run-Q) + (autoload . nxhtmltest-run-indent) + (autoload . nxhtmltest-run) + (autoload . appmenu-add) + (autoload . as-external-for-xhtml) + (autoload . as-external-for-mail) + (autoload . as-external-for-wiki) + as-external-mode + (autoload . as-external-mode) + (autoload . chart-complete) + (autoload . chart-make-chart) + css-color-global-mode + (autoload . css-color-global-mode) + (autoload . css-color-mode) + (autoload . css-palette-mode) + css-palette-global-mode + (autoload . css-palette-global-mode) + (autoload . freemind-show) + (autoload . freemind-from-org-mode-node) + (autoload . freemind-from-org-mode) + (autoload . freemind-from-org-sparse-tree) + (autoload . freemind-to-org-mode) + (autoload . gimp-edit-file) + (autoload . gimp-edit-buffer) + (autoload . gimp-can-edit) + (autoload . gpl-mode) + (autoload . html-write-mode) + (autoload . htmlfontify-buffer) + (autoload . majmodpri-sort-lists) + (autoload . majmodpri-apply) + (autoload . majmodpri-apply-priorities) + (autoload . mlinks-mode) + (autoload . mumamo-mark-for-refontification) + (autoload . html-mumamo-mode) + (autoload . nxml-mumamo-mode) + (autoload . embperl-html-mumamo-mode) + (autoload . django-html-mumamo-mode) + (autoload . genshi-html-mumamo-mode) + (autoload . mjt-html-mumamo-mode) + (autoload . smarty-html-mumamo-mode) + (autoload . jsp-html-mumamo-mode) + (autoload . eruby-mumamo-mode) + (autoload . eruby-html-mumamo-mode) + (autoload . perl-mumamo-mode) + (autoload . cperl-mumamo-mode) + (autoload . metapost-mumamo-mode) + (autoload . laszlo-nxml-mumamo-mode) + (autoload . csound-sgml-mumamo-mode) + (autoload . noweb2-mumamo-mode) + (autoload . asp-html-mumamo-mode) + (autoload . org-mumamo-mode) + (autoload . mako-html-mumamo-mode) + (autoload . popup-menu-at-point) + (autoload . define-toggle) + (autoload . unfill-paragraph) + (autoload . unfill-region) + (autoload . unfill-individual-paragraphs) + (autoload . major-or-multi-majorp) + (autoload . multi-major-modep) + (autoload . major-modep) + (autoload . ourcomments-move-beginning-of-line) + (autoload . ourcomments-move-end-of-line) + (autoload . describe-key-and-map-briefly) + wrap-to-fill-left-marg wrap-to-fill-left-marg-modes + (autoload . wrap-to-fill-column-mode) + better-fringes-mode + (autoload . better-fringes-mode) + (autoload . find-emacs-other-file) + (autoload . ourcomments-ediff-files) + (autoload . describe-command) + (autoload . describe-custom-group) + (autoload . describe-defstruct) + (autoload . describe-symbol) + (autoload . ourcomments-ido-buffer-other-window) + (autoload . ourcomments-ido-buffer-other-frame) + (autoload . ourcomments-ido-buffer-raise-frame) + ourcomments-ido-ctrl-tab + (autoload . emacs) + (autoload . emacs-buffer-file) + (autoload . emacs--debug-init) + (autoload . emacs-Q) + (autoload . emacs-Q-nxhtml) + (autoload . grep-query-replace) + (autoload . info-open-file) + (autoload . rnc-mode) + (autoload . search-form) + sex-mode + (autoload . sex-mode) + tabkey2-mode + (autoload . tabkey2-mode) + (autoload . tyda-lookup-word) + (autoload . udev-cedet-update) + (autoload . udev-ecb-update) + (autoload . udev-rinari-update) + (autoload . viper-tutorial) + (autoload . winsav-put-window-tree) + winsav-save-mode + (autoload . winsav-save-mode) + (autoload . winsav-save-named-config) + (autoload . winsav-switch-config) + (autoload . resize-windows) + (autoload . winsize-balance-siblings) + (autoload . winsize-save-window-configuration) + (autoload . nxhtmlmaint-start-byte-compilation) + (autoload . nxhtmlmaint-byte-uncompile-all)) + ("/usr/share/emacs/23.0.93/lisp/international/encoded-kb.elc" encoded-kbd-mode-map encoded-kbd-iso2022-esc-map encoded-kbd-iso2022-esc-dollar-map encoded-kbd-iso2022-designation-map encoded-kbd-iso2022-designations encoded-kbd-iso2022-invocations + (defun . encoded-kbd-last-key) + (defun . encoded-kbd-iso2022-designation) + (defun . encoded-kbd-iso2022-single-shift) + (defun . encoded-kbd-self-insert-iso2022-7bit) + (defun . encoded-kbd-self-insert-iso2022-8bit) + (defun . encoded-kbd-self-insert-sjis) + (defun . encoded-kbd-self-insert-big5) + (defun . encoded-kbd-self-insert-ccl) + (defun . encoded-kbd-decode-code-list) + (defun . encoded-kbd-self-insert-charset) + (defun . encoded-kbd-self-insert-utf-8) + (defun . encoded-kbd-setup-keymap) + (t . encoded-kbd-setup-display) + (defun . encoded-kbd-setup-display) + (provide . encoded-kb)) + ("/usr/share/emacs/23.0.93/leim/leim-list.el" + (autoload . ucs-input-activate) + (autoload . hangul-input-method-activate)) + ("/usr/share/emacs/23.0.93/lisp/subdirs.el") + ("/usr/share/emacs-snapshot/site-lisp/subdirs.el") + ("/usr/share/emacs/23.0.93/lisp/site-init.elc") + ("/usr/share/emacs/23.0.93/lisp/tooltip.elc" tooltip-mode + (defun . tooltip-mode) + tooltip-delay tooltip-short-delay tooltip-recent-seconds tooltip-hide-delay tooltip-x-offset tooltip-y-offset tooltip-frame-parameters + (defface . tooltip) + tooltip-use-echo-area tooltip-functions tooltip-hook tooltip-timeout-id tooltip-last-mouse-motion-event tooltip-hide-time + (defun . tooltip-event-buffer) + (defun . tooltip-delay) + (defun . tooltip-cancel-delayed-tip) + (defun . tooltip-start-delayed-tip) + (defun . tooltip-timeout) + (defun . tooltip-set-param) + (defun . tooltip-show) + (defun . tooltip-hide) + (defun . tooltip-identifier-from-point) + (defun . tooltip-region-active-p) + (defun . tooltip-expr-to-print) + (defun . tooltip-process-prompt-regexp) + (defun . tooltip-strip-prompt) + tooltip-help-message tooltip-previous-message + (defun . tooltip-show-help-non-mode) + (defun . tooltip-show-help) + (defun . tooltip-help-tips) + (provide . tooltip)) + ("/usr/share/emacs/23.0.93/lisp/ediff-hook.elc" menu-bar-ediff-misc-menu menu-bar-epatch-menu menu-bar-ediff-merge-menu menu-bar-ediff-menu + (provide . ediff-hook)) + ("/usr/share/emacs/23.0.93/lisp/vc-hooks.elc" vc-ignore-vc-files vc-master-templates vc-header-alist vc-ignore-dir-regexp vc-handled-backends vc-directory-exclusion-list vc-path vc-make-backup-files vc-follow-symlinks vc-display-status vc-consult-headers vc-keep-workfiles vc-mistrust-permissions + (defun . vc-mistrust-permissions) + vc-stay-local + (defun . vc-stay-local-p) + (defun . vc-mode) + (defun . vc-error-occurred) + vc-file-prop-obarray vc-touched-properties + (defun . vc-file-setprop) + (defun . vc-file-getprop) + (defun . vc-file-clearprops) + (defun . vc-make-backend-sym) + (defun . vc-find-backend-function) + (defun . vc-call-backend) + (defun . vc-call) + (defun . vc-parse-buffer) + (defun . vc-insert-file) + (defun . vc-find-root) + (defun . vc-registered) + (defun . vc-backend) + (defun . vc-backend-subdirectory-name) + (defun . vc-name) + (defun . vc-checkout-model) + (defun . vc-user-login-name) + (defun . vc-state) + (defun . vc-up-to-date-p) + (defun . vc-default-state-heuristic) + (defun . vc-workfile-unchanged-p) + (defun . vc-default-workfile-unchanged-p) + (defun . vc-working-revision) + (defun . vc-workfile-version) + (defun . vc-default-working-revision) + (defun . vc-default-registered) + (defun . vc-possible-master) + (defun . vc-check-master-templates) + (defun . vc-toggle-read-only) + (defun . vc-default-make-version-backups-p) + (defun . vc-version-backup-file-name) + (defun . vc-delete-automatic-version-backups) + (defun . vc-make-version-backup) + (defun . vc-before-save) + (defun . vc-after-save) + vc-menu-entry vc-mode-line-map vc-mode-line-map + (defun . vc-mode-line) + (defun . vc-default-mode-line-string) + (defun . vc-follow-link) + (defun . vc-default-find-file-hook) + (defun . vc-find-file-hook) + (defun . vc-file-not-found-hook) + (defun . vc-default-find-file-not-found-hook) + (defun . vc-kill-buffer-hook) + vc-prefix-map vc-menu-map + (defun . vc-menu-map) + (defun . vc-menu-map-filter) + (defun . vc-default-extra-menu) + (provide . vc-hooks)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/float-sup.elc" pi e degrees-to-radians radians-to-degrees + (defun . degrees-to-radians) + (defun . radians-to-degrees) + (provide . lisp-float-type)) + ("/usr/share/emacs/23.0.93/lisp/term/x-win.elc" + (require . frame) + (require . mouse) + (require . scroll-bar) + (require . faces) + (require . select) + (require . menu-bar) + (require . fontset) + (require . x-dnd) + (defun . x-handle-no-bitmap-icon) + (defun . x-handle-parent-id) + (defun . x-handle-smid) + emacs-save-session-functions + (defun . emacs-session-filename) + (defun . emacs-session-save) + (defun . emacs-session-restore) + x-pointer-X-cursor x-pointer-X-cursor x-pointer-arrow x-pointer-arrow x-pointer-based-arrow-down x-pointer-based-arrow-down x-pointer-based-arrow-up x-pointer-based-arrow-up x-pointer-boat x-pointer-boat x-pointer-bogosity x-pointer-bogosity x-pointer-bottom-left-corner x-pointer-bottom-left-corner x-pointer-bottom-right-corner x-pointer-bottom-right-corner x-pointer-bottom-side x-pointer-bottom-side x-pointer-bottom-tee x-pointer-bottom-tee x-pointer-box-spiral x-pointer-box-spiral x-pointer-center-ptr x-pointer-center-ptr x-pointer-circle x-pointer-circle x-pointer-clock x-pointer-clock x-pointer-coffee-mug x-pointer-coffee-mug x-pointer-cross x-pointer-cross x-pointer-cross-reverse x-pointer-cross-reverse x-pointer-crosshair x-pointer-crosshair x-pointer-diamond-cross x-pointer-diamond-cross x-pointer-dot x-pointer-dot x-pointer-dotbox x-pointer-dotbox x-pointer-double-arrow x-pointer-double-arrow x-pointer-draft-large x-pointer-draft-large x-pointer-draft-small x-pointer-draft-small x-pointer-draped-box x-pointer-draped-box x-pointer-exchange x-pointer-exchange x-pointer-fleur x-pointer-fleur x-pointer-gobbler x-pointer-gobbler x-pointer-gumby x-pointer-gumby x-pointer-hand1 x-pointer-hand1 x-pointer-hand2 x-pointer-hand2 x-pointer-heart x-pointer-heart x-pointer-icon x-pointer-icon x-pointer-iron-cross x-pointer-iron-cross x-pointer-left-ptr x-pointer-left-ptr x-pointer-left-side x-pointer-left-side x-pointer-left-tee x-pointer-left-tee x-pointer-leftbutton x-pointer-leftbutton x-pointer-ll-angle x-pointer-ll-angle x-pointer-lr-angle x-pointer-lr-angle x-pointer-man x-pointer-man x-pointer-middlebutton x-pointer-middlebutton x-pointer-mouse x-pointer-mouse x-pointer-pencil x-pointer-pencil x-pointer-pirate x-pointer-pirate x-pointer-plus x-pointer-plus x-pointer-question-arrow x-pointer-question-arrow x-pointer-right-ptr x-pointer-right-ptr x-pointer-right-side x-pointer-right-side x-pointer-right-tee x-pointer-right-tee x-pointer-rightbutton x-pointer-rightbutton x-pointer-rtl-logo x-pointer-rtl-logo x-pointer-sailboat x-pointer-sailboat x-pointer-sb-down-arrow x-pointer-sb-down-arrow x-pointer-sb-h-double-arrow x-pointer-sb-h-double-arrow x-pointer-sb-left-arrow x-pointer-sb-left-arrow x-pointer-sb-right-arrow x-pointer-sb-right-arrow x-pointer-sb-up-arrow x-pointer-sb-up-arrow x-pointer-sb-v-double-arrow x-pointer-sb-v-double-arrow x-pointer-shuttle x-pointer-shuttle x-pointer-sizing x-pointer-sizing x-pointer-spider x-pointer-spider x-pointer-spraycan x-pointer-spraycan x-pointer-star x-pointer-star x-pointer-target x-pointer-target x-pointer-tcross x-pointer-tcross x-pointer-top-left-arrow x-pointer-top-left-arrow x-pointer-top-left-corner x-pointer-top-left-corner x-pointer-top-right-corner x-pointer-top-right-corner x-pointer-top-side x-pointer-top-side x-pointer-top-tee x-pointer-top-tee x-pointer-trek x-pointer-trek x-pointer-ul-angle x-pointer-ul-angle x-pointer-umbrella x-pointer-umbrella x-pointer-ur-angle x-pointer-ur-angle x-pointer-watch x-pointer-watch x-pointer-xterm x-pointer-xterm x-pointer-invisible x-pointer-invisible + (defun . xw-defined-colors) + x-alternatives-map + (defun . x-setup-function-keys) + (defun . vendor-specific-keysyms) + x-last-selected-text-clipboard x-last-selected-text-primary x-last-selected-text-cut x-last-selected-text-cut-encoded x-last-cut-buffer-coding x-cut-buffer-max x-select-enable-clipboard x-select-enable-primary + (defun . x-select-text) + x-select-request-type + (defun . x-selection-value) + (defun . x-cut-buffer-or-selection-value) + (defun . x-clipboard-yank) + (defun . x-menu-bar-open) + (defun . x-win-suspend-error) + x-initialized + (defun . x-initialize-window-system) + x-gtk-stock-map icon-map-list x-gtk-stock-cache x-gtk-stock-cache + (defun . x-gtk-map-stock) + (provide . x-win)) + ("/usr/share/emacs/23.0.93/lisp/term/common-win.elc" x-command-line-resources + (defun . x-handle-switch) + (defun . x-handle-numeric-switch) + (defun . x-handle-initial-switch) + (defun . x-handle-iconic) + (defun . x-handle-xrm-switch) + (defun . x-handle-geometry) + (defun . x-handle-name-switch) + x-display-name + (defun . x-handle-display) + (defun . x-handle-args) + x-colors) + ("/usr/share/emacs/23.0.93/lisp/x-dnd.elc" + (require . dnd) + x-dnd-test-function x-dnd-types-alist x-dnd-known-types x-dnd-current-state x-dnd-empty-state + (defun . x-dnd-init-frame) + (defun . x-dnd-get-state-cons-for-frame) + (defun . x-dnd-get-state-for-frame) + (defun . x-dnd-default-test-function) + (defun . x-dnd-current-type) + (defun . x-dnd-forget-drop) + (defun . x-dnd-maybe-call-test-function) + (defun . x-dnd-save-state) + (defun . x-dnd-handle-moz-url) + (defun . x-dnd-insert-utf8-text) + (defun . x-dnd-insert-utf16-text) + (defun . x-dnd-insert-ctext) + (defun . x-dnd-handle-uri-list) + (defun . x-dnd-handle-file-name) + (defun . x-dnd-choose-type) + (defun . x-dnd-drop-data) + (defun . x-dnd-handle-drag-n-drop-event) + (defun . x-dnd-handle-old-kde) + x-dnd-xdnd-to-action + (defun . x-dnd-init-xdnd-for-frame) + (defun . x-dnd-get-drop-width-height) + (defun . x-dnd-get-drop-x-y) + (defun . x-dnd-handle-xdnd) + (defun . x-dnd-init-motif-for-frame) + (defun . x-dnd-get-motif-value) + (defun . x-dnd-motif-value-to-list) + x-dnd-motif-message-types x-dnd-motif-to-action + (defun . x-dnd-handle-motif) + (provide . x-dnd)) + ("/usr/share/emacs/23.0.93/lisp/tool-bar.elc" tool-bar-mode + (defun . tool-bar-mode) + (t . toggle-tool-bar-mode-from-frame) + (defun . toggle-tool-bar-mode-from-frame) + tool-bar-map tool-bar-keymap-cache tool-bar-keymap-cache + (defun . tool-bar-make-keymap) + (defun . tool-bar-make-keymap-1) + (t . tool-bar-add-item) + (defun . tool-bar-add-item) + (t . tool-bar-local-item) + (defun . tool-bar-local-item) + (t . tool-bar-add-item-from-menu) + (defun . tool-bar-add-item-from-menu) + (t . tool-bar-local-item-from-menu) + (defun . tool-bar-local-item-from-menu) + (defun . tool-bar-setup) + (provide . tool-bar)) + ("/usr/share/emacs/23.0.93/lisp/mwheel.elc" + (require . custom) + (require . timer) + (defun . mouse-wheel-change-button) + mouse-wheel-down-button mouse-wheel-down-event mouse-wheel-up-button mouse-wheel-up-event mouse-wheel-click-button mouse-wheel-click-event mouse-wheel-inhibit-click-time mouse-wheel-scroll-amount mouse-wheel-progressive-speed mouse-wheel-follow-mouse + (defun . mwheel-event-button) + (defun . mwheel-event-window) + mwheel-inhibit-click-event-timer + (defun . mwheel-inhibit-click-timeout) + (defun . mwheel-filter-click-events) + (defun . mwheel-scroll) + mouse-wheel-mode + (t . mouse-wheel-mode) + (defun . mouse-wheel-mode) + (t . mwheel-install) + (defun . mwheel-install) + (provide . mwheel)) + ("/usr/share/emacs/23.0.93/lisp/dnd.elc" dnd-protocol-alist dnd-open-remote-file-function dnd-open-file-other-window + (defun . dnd-handle-one-url) + (defun . dnd-get-local-file-uri) + (defun . dnd-get-local-file-name) + (defun . dnd-open-local-file) + (defun . dnd-open-remote-url) + (defun . dnd-open-file) + (defun . dnd-insert-text) + (provide . dnd)) + ("/usr/share/emacs/23.0.93/lisp/international/fontset.elc" + (defun . setup-default-fontset) + (defun . create-default-fontset) + (defun . set-font-encoding) + x-font-name-charset-alist xlfd-regexp-family-subnum xlfd-regexp-family-subnum xlfd-regexp-weight-subnum xlfd-regexp-weight-subnum xlfd-regexp-slant-subnum xlfd-regexp-slant-subnum xlfd-regexp-swidth-subnum xlfd-regexp-swidth-subnum xlfd-regexp-adstyle-subnum xlfd-regexp-adstyle-subnum xlfd-regexp-pixelsize-subnum xlfd-regexp-pixelsize-subnum xlfd-regexp-pointsize-subnum xlfd-regexp-pointsize-subnum xlfd-regexp-resx-subnum xlfd-regexp-resx-subnum xlfd-regexp-resy-subnum xlfd-regexp-resy-subnum xlfd-regexp-spacing-subnum xlfd-regexp-spacing-subnum xlfd-regexp-avgwidth-subnum xlfd-regexp-avgwidth-subnum xlfd-regexp-registry-subnum xlfd-regexp-registry-subnum xlfd-tight-regexp xlfd-tight-regexp xlfd-style-regexp xlfd-style-regexp xlfd-regexp-numeric-subnums xlfd-regexp-numeric-subnums + (defun . x-decompose-font-name) + (defun . x-compose-font-name) + (defun . x-must-resolve-font-name) + (defun . x-complement-fontset-spec) + (defun . fontset-name-p) + (defun . generate-fontset-menu) + (defun . fontset-plain-name) + charset-script-alist + (defun . create-fontset-from-fontset-spec) + (defun . create-fontset-from-ascii-font) + standard-fontset-spec + (defun . create-fontset-from-x-resource) + (provide . fontset)) + ("/usr/share/emacs/23.0.93/lisp/image.elc" image-type-header-regexps image-type-file-name-regexps image-type-auto-detectable image-load-path + (defun . image-load-path-for-library) + (defun . image-jpeg-p) + (t . image-type-from-data) + (defun . image-type-from-data) + (t . image-type-from-buffer) + (defun . image-type-from-buffer) + (t . image-type-from-file-header) + (defun . image-type-from-file-header) + (t . image-type-from-file-name) + (defun . image-type-from-file-name) + (t . image-type) + (defun . image-type) + (t . image-type-available-p) + (defun . image-type-available-p) + (t . image-type-auto-detected-p) + (defun . image-type-auto-detected-p) + (t . create-image) + (defun . create-image) + (t . put-image) + (defun . put-image) + (t . insert-image) + (defun . insert-image) + (t . insert-sliced-image) + (defun . insert-sliced-image) + (t . remove-images) + (defun . remove-images) + (defun . image-search-load-path) + (t . find-image) + (defun . find-image) + (t . defimage) + (defun . defimage) + (provide . image)) + ("/usr/share/emacs/23.0.93/lisp/fringe.elc" + (defun . fringe-bitmap-p) + fringe-mode-explicit + (defun . set-fringe-mode-1) + (defun . set-fringe-mode) + (defun . fringe-mode-initialize) + fringe-mode + (defun . fringe-query-style) + (defun . fringe-mode) + (defun . set-fringe-style) + (defun . fringe-columns) + (provide . fringe)) + ("/usr/share/emacs/23.0.93/lisp/buff-menu.elc" Buffer-menu-use-header-line + (defface . buffer-menu-buffer) + Buffer-menu-buffer+size-width Buffer-menu-mode-width Buffer-menu-use-frame-buffer-list Buffer-menu-sort-column Buffer-menu-buffer-column Buffer-menu-buffer-column Buffer-menu-files-only Buffer-menu-mode-map Buffer-menu-mode-map Buffer-menu-mode-syntax-table Buffer-menu-mode-abbrev-table Buffer-menu-mode-abbrev-table + (defun . Buffer-menu-mode) + buffer-menu-mode-hook + (defun . Buffer-menu-revert-function) + (defun . Buffer-menu-toggle-files-only) + (defun . Buffer-menu-buffer) + (defun . buffer-menu) + (defun . buffer-menu-other-window) + (defun . Buffer-menu-no-header) + (defun . Buffer-menu-mark) + (defun . Buffer-menu-unmark) + (defun . Buffer-menu-backup-unmark) + (defun . Buffer-menu-delete) + (defun . Buffer-menu-delete-backwards) + (defun . Buffer-menu-save) + (defun . Buffer-menu-not-modified) + (defun . Buffer-menu-beginning) + (defun . Buffer-menu-execute) + (defun . Buffer-menu-select) + (defun . Buffer-menu-marked-buffers) + (defun . Buffer-menu-isearch-buffers) + (defun . Buffer-menu-isearch-buffers-regexp) + (defun . Buffer-menu-visit-tags-table) + (defun . Buffer-menu-1-window) + (defun . Buffer-menu-mouse-select) + (defun . Buffer-menu-this-window) + (defun . Buffer-menu-other-window) + (defun . Buffer-menu-switch-other-window) + (defun . Buffer-menu-2-window) + (defun . Buffer-menu-toggle-read-only) + (defun . Buffer-menu-bury) + (defun . Buffer-menu-view) + (defun . Buffer-menu-view-other-window) + (defun . list-buffers) + Buffer-menu-short-ellipsis Buffer-menu-short-ellipsis + (defun . Buffer-menu-buffer+size) + (defun . Buffer-menu-sort) + (defun . Buffer-menu-sort-by-column) + Buffer-menu-sort-button-map + (defun . Buffer-menu-make-sort-button) + (defun . list-buffers-noselect)) + ("/usr/share/emacs/23.0.93/lisp/replace.elc" case-replace query-replace-history query-replace-defaults query-replace-interactive query-replace-from-history-variable query-replace-to-history-variable query-replace-skip-read-only query-replace-show-replacement query-replace-highlight query-replace-lazy-highlight + (defface . query-replace) + (defun . query-replace-descr) + (defun . query-replace-read-from) + (defun . query-replace-compile-replacement) + (defun . query-replace-read-to) + (defun . query-replace-read-args) + (defun . query-replace) + (defun . query-replace-regexp) + (defun . query-replace-regexp-eval) + (defun . map-query-replace-regexp) + (defun . replace-string) + (defun . replace-regexp) + regexp-history + (defun . read-regexp) + (defun . delete-non-matching-lines) + (defun . delete-matching-lines) + (defun . count-matches) + (defun . keep-lines-read-args) + (defun . keep-lines) + (defun . flush-lines) + (defun . how-many) + occur-mode-map occur-revert-arguments occur-mode-hook occur-hook occur-mode-find-occurrence-hook + (defun . occur-mode) + (defun . occur-revert-function) + (defun . occur-mode-find-occurrence) + (defun . occur-mode-mouse-goto) + (defun . occur-mode-goto-occurrence) + (defun . occur-mode-goto-occurrence-other-window) + (defun . occur-mode-display-occurrence) + (defun . occur-find-match) + (defun . occur-next) + (defun . occur-prev) + (defun . occur-next-error) + (defface . match) + list-matching-lines-default-context-lines + (defun . list-matching-lines) + list-matching-lines-face list-matching-lines-buffer-name-face occur-excluded-properties + (defun . occur-accumulate-lines) + (defun . occur-read-primary-args) + (defun . occur-rename-buffer) + (defun . occur) + (defun . multi-occur) + (defun . multi-occur-in-matching-buffers) + (defun . occur-1) + (defun . occur-engine-add-prefix) + (defun . occur-engine) + (defun . occur-context-lines) + query-replace-help query-replace-map multi-query-replace-map + (defun . replace-match-string-symbols) + (defun . replace-eval-replacement) + (defun . replace-quote) + (defun . replace-loop-through-replacements) + (defun . replace-match-data) + (defun . replace-match-maybe-edit) + replace-search-function replace-re-search-function + (defun . perform-replace) + replace-overlay + (defun . replace-highlight) + (defun . replace-dehighlight)) + ("/usr/share/emacs/23.0.93/lisp/textmodes/fill.elc" fill-individual-varying-indent colon-double-space fill-paragraph-function fill-paragraph-handle-comment enable-kinsoku + (defun . set-fill-prefix) + adaptive-fill-mode adaptive-fill-regexp adaptive-fill-first-line-regexp adaptive-fill-function fill-indent-according-to-mode + (defun . current-fill-column) + (defun . canonically-space-region) + (defun . fill-common-string-prefix) + (defun . fill-match-adaptive-prefix) + (defun . fill-context-prefix) + (defun . fill-single-word-nobreak-p) + (defun . fill-french-nobreak-p) + fill-nobreak-predicate fill-nobreak-invisible + (defun . fill-nobreak-p) + fill-find-break-point-function-table fill-nospace-between-words-table + (defun . fill-find-break-point) + (defun . fill-delete-prefix) + (defun . fill-delete-newlines) + (defun . fill-move-to-break-point) + (defun . fill-text-properties-at) + (defun . fill-newline) + (defun . fill-indent-to-left-margin) + (defun . fill-region-as-paragraph) + (defun . skip-line-prefix) + (defun . fill-minibuffer-function) + fill-forward-paragraph-function + (defun . fill-forward-paragraph) + (defun . fill-paragraph) + (defun . fill-comment-paragraph) + (defun . fill-region) + default-justification + (defun . current-justification) + (defun . set-justification) + (defun . set-justification-none) + (defun . set-justification-left) + (defun . set-justification-right) + (defun . set-justification-full) + (defun . set-justification-center) + (defun . justify-current-line) + (defun . unjustify-current-line) + (defun . unjustify-region) + (defun . fill-nonuniform-paragraphs) + (defun . fill-individual-paragraphs) + (defun . fill-individual-paragraphs-prefix) + (defun . fill-individual-paragraphs-citation)) + ("/usr/share/emacs/23.0.93/lisp/textmodes/text-mode.elc" text-mode-hook text-mode-variant text-mode-syntax-table text-mode-map text-mode-map text-mode-syntax-table text-mode-abbrev-table text-mode-abbrev-table + (defun . text-mode) + paragraph-indent-text-mode-map + (defun . paragraph-indent-text-mode) + (defun . paragraph-indent-minor-mode) + (defun . indented-text-mode) + (defun . text-mode-hook-identify) + (defun . toggle-text-mode-auto-fill) + (defun . center-paragraph) + (defun . center-region) + (defun . center-line)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/lisp-mode.elc" lisp-mode-abbrev-table lisp-mode-abbrev-table emacs-lisp-mode-syntax-table lisp-mode-syntax-table lisp-imenu-generic-expression lisp-doc-string-elt-property + (defun . lisp-font-lock-syntactic-face-function) + (defun . lisp-mode-variables) + (defun . lisp-outline-level) + lisp-mode-shared-map emacs-lisp-mode-map + (defun . emacs-lisp-byte-compile) + (defun . emacs-lisp-byte-compile-and-load) + emacs-lisp-mode-hook lisp-mode-hook lisp-interaction-mode-hook + (defun . emacs-lisp-mode) + lisp-mode-map + (defun . lisp-mode) + (defun . lisp-find-tag-default) + (defun . common-lisp-mode) + (defun . lisp-eval-defun) + lisp-interaction-mode-map lisp-interaction-mode-abbrev-table lisp-interaction-mode-map lisp-interaction-mode-syntax-table lisp-interaction-mode-abbrev-table + (defun . lisp-interaction-mode) + (defun . eval-print-last-sexp) + (defun . last-sexp-setup-props) + (defun . last-sexp-toggle-display) + (defun . prin1-char) + (defun . preceding-sexp) + (defun . eval-last-sexp-1) + (defun . eval-last-sexp-print-value) + eval-last-sexp-fake-value + (defun . eval-last-sexp) + (defun . eval-defun-1) + (defun . eval-defun-2) + (defun . eval-defun) + (defun . lisp-comment-indent) + (defun . lisp-mode-auto-fill) + lisp-indent-offset lisp-indent-function + (defun . lisp-indent-line) + (defun . calculate-lisp-indent) + (defun . lisp-indent-function) + lisp-body-indent + (defun . lisp-indent-specform) + (defun . lisp-indent-defform) + (defun . indent-sexp) + (defun . lisp-indent-region) + (defun . indent-pp-sexp) + emacs-lisp-docstring-fill-column + (defun . lisp-fill-paragraph) + (defun . indent-code-rigidly) + (provide . lisp-mode)) + ("/usr/share/emacs/23.0.93/lisp/textmodes/paragraphs.elc" use-hard-newlines + (defun . use-hard-newlines) + paragraph-start paragraph-separate sentence-end-double-space sentence-end-without-period sentence-end-without-space sentence-end sentence-end-base + (defun . sentence-end) + page-delimiter paragraph-ignore-fill-prefix + (defun . forward-paragraph) + (defun . backward-paragraph) + (defun . mark-paragraph) + (defun . kill-paragraph) + (defun . backward-kill-paragraph) + (defun . transpose-paragraphs) + (defun . start-of-paragraph-text) + (defun . end-of-paragraph-text) + (defun . forward-sentence) + (defun . repunctuate-sentences) + (defun . backward-sentence) + (defun . kill-sentence) + (defun . backward-kill-sentence) + (defun . mark-end-of-sentence) + (defun . transpose-sentences)) + ("/usr/share/emacs/23.0.93/lisp/register.elc" register-alist + (defun . get-register) + (defun . set-register) + (defun . point-to-register) + (defun . window-configuration-to-register) + (defun . frame-configuration-to-register) + (defun . register-to-point) + (defun . jump-to-register) + (defun . register-swap-out) + (defun . number-to-register) + (defun . increment-register) + (defun . view-register) + (defun . list-registers) + (defun . describe-register-1) + (defun . insert-register) + (defun . copy-to-register) + (defun . append-to-register) + (defun . prepend-to-register) + (defun . copy-rectangle-to-register) + (provide . register)) + ("/usr/share/emacs/23.0.93/lisp/textmodes/page.elc" + (defun . forward-page) + (defun . backward-page) + (defun . mark-page) + (defun . narrow-to-page) + (defun . count-lines-page) + (defun . what-page) + (provide . page)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/lisp.elc" defun-prompt-regexp parens-require-spaces forward-sexp-function + (defun . forward-sexp) + (defun . backward-sexp) + (defun . mark-sexp) + (defun . forward-list) + (defun . backward-list) + (defun . down-list) + (defun . backward-up-list) + (defun . up-list) + (defun . kill-sexp) + (defun . backward-kill-sexp) + (defun . kill-backward-up-list) + beginning-of-defun-function + (defun . beginning-of-defun) + (defun . beginning-of-defun-raw) + end-of-defun-function + (defun . buffer-end) + (defun . end-of-defun) + (defun . mark-defun) + (defun . narrow-to-defun) + insert-pair-alist + (defun . insert-pair) + (defun . insert-parentheses) + (defun . delete-pair) + (defun . raise-sexp) + (defun . move-past-close-and-reindent) + (defun . check-parens) + (defun . field-complete) + (defun . lisp-complete-symbol)) + ("/usr/share/emacs/23.0.93/lisp/paths.el" + (defun . prune-directory-list) + Info-default-directory-list news-directory news-path news-inews-program gnus-default-nntp-server gnus-nntp-service gnus-local-organization rmail-file-name rmail-spool-directory remote-shell-program term-file-prefix abbrev-file-name) + ("/usr/share/emacs/23.0.93/lisp/menu-bar.elc" menu-bar-help-menu menu-bar-tools-menu global-buffers-menu-map menu-bar-options-menu menu-bar-edit-menu menu-bar-file-menu menu-bar-files-menu + (defun . menu-find-file-existing) + menu-bar-last-search-type + (defun . nonincremental-repeat-search-forward) + (defun . nonincremental-repeat-search-backward) + (defun . nonincremental-search-forward) + (defun . nonincremental-search-backward) + (defun . nonincremental-re-search-forward) + (defun . nonincremental-re-search-backward) + menu-bar-search-menu menu-bar-i-search-menu menu-bar-replace-menu menu-bar-goto-menu + (defun . menu-bar-next-tag-other-window) + (defun . menu-bar-next-tag) + yank-menu + (defun . menu-bar-kill-ring-save) + (defun . clipboard-yank) + (defun . clipboard-kill-ring-save) + (defun . clipboard-kill-region) + (defun . menu-bar-enable-clipboard) + menu-bar-custom-menu + (defun . menu-bar-make-mm-toggle) + (defun . menu-bar-make-toggle) + (defun . menu-set-font) + (defun . menu-bar-options-save) + menu-bar-showhide-menu menu-bar-showhide-fringe-menu menu-bar-showhide-fringe-ind-menu + (defun . menu-bar-showhide-fringe-ind-customize) + (defun . menu-bar-showhide-fringe-ind-mixed) + (defun . menu-bar-showhide-fringe-ind-box) + (defun . menu-bar-showhide-fringe-ind-right) + (defun . menu-bar-showhide-fringe-ind-left) + (defun . menu-bar-showhide-fringe-ind-none) + (defun . toggle-indicate-empty-lines) + (defun . menu-bar-showhide-fringe-menu-customize) + (defun . menu-bar-showhide-fringe-menu-customize-reset) + (defun . menu-bar-showhide-fringe-menu-customize-right) + (defun . menu-bar-showhide-fringe-menu-customize-left) + (defun . menu-bar-showhide-fringe-menu-customize-disable) + menu-bar-showhide-scroll-bar-menu + (defun . menu-bar-right-scroll-bar) + (defun . menu-bar-left-scroll-bar) + (defun . menu-bar-no-scroll-bar) + (defun . toggle-debug-on-quit) + (defun . toggle-debug-on-error) + (defun . toggle-save-place-globally) + (defun . toggle-uniquify-buffer-names) + (defun . toggle-case-fold-search) + (defun . menu-bar-text-mode-auto-fill) + menu-bar-line-wrapping-menu + (defun . send-mail-item-name) + (defun . read-mail-item-name) + menu-bar-games-menu menu-bar-encryption-decryption-menu + (defun . menu-bar-read-mail) + menu-bar-describe-menu menu-bar-search-documentation-menu + (defun . menu-bar-read-lispref) + (defun . menu-bar-read-lispintro) + (defun . search-emacs-glossary) + (defun . emacs-index-search) + (defun . elisp-index-search) + (defun . debian-emacs-changelog) + (defun . debian-emacs-news) + (defun . debian-emacs-readme) + menu-bar-manuals-menu + (defun . menu-bar-help-extra-packages) + (defun . help-with-tutorial-spec-language) + (defun . menu-bar-menu-frame-live-and-visible-p) + (defun . menu-bar-non-minibuffer-window-p) + (defun . kill-this-buffer) + (defun . kill-this-buffer-enabled-p) + (defun . delete-frame-enabled-p) + yank-menu-length + (defun . menu-bar-update-yank-menu) + (defun . menu-bar-select-yank) + buffers-menu-max-size buffers-menu-buffer-name-length buffers-menu-show-directories buffers-menu-show-status list-buffers-directory + (defun . menu-bar-select-buffer) + (defun . menu-bar-select-frame) + (defun . menu-bar-update-buffers-1) + menu-bar-buffers-menu-command-entries + (defun . menu-bar-update-buffers) + menu-bar-mode + (defun . menu-bar-mode) + (defun . toggle-menu-bar-mode-from-frame) + (defun . menu-bar-open) + (provide . menu-bar)) + ("/usr/share/emacs/23.0.93/lisp/rfn-eshadow.elc" file-name-shadow-properties-custom-type file-name-shadow-properties-custom-type file-name-shadow-properties file-name-shadow-tty-properties + (defface . file-name-shadow) + rfn-eshadow-setup-minibuffer-hook rfn-eshadow-update-overlay-hook rfn-eshadow-frobbed-minibufs + (defun . rfn-eshadow-setup-minibuffer) + (defun . rfn-eshadow-sifn-equal) + (defun . rfn-eshadow-update-overlay) + file-name-shadow-mode + (defun . file-name-shadow-mode) + (provide . rfn-eshadow)) + ("/usr/share/emacs/23.0.93/lisp/isearch.elc" search-exit-option search-slow-window-lines search-slow-speed search-upper-case search-nonincremental-instead search-whitespace-regexp search-invisible isearch-hide-immediately isearch-resume-in-command-history isearch-mode-hook isearch-mode-end-hook isearch-mode-end-hook-quit isearch-message-function isearch-wrap-function isearch-push-state-function isearch-filter-predicate search-ring regexp-search-ring search-ring-max regexp-search-ring-max search-ring-yank-pointer regexp-search-ring-yank-pointer search-ring-update search-highlight + (defface . isearch) + isearch + (defface . isearch-fail) + isearch-lazy-highlight lazy-highlight-cleanup isearch-lazy-highlight-cleanup lazy-highlight-initial-delay isearch-lazy-highlight-initial-delay lazy-highlight-interval isearch-lazy-highlight-interval lazy-highlight-max-at-a-time isearch-lazy-highlight-max-at-a-time + (defface . lazy-highlight) + lazy-highlight-face isearch-lazy-highlight-face isearch-help-map + (defun . isearch-help-for-help-internal-doc) + (defun . isearch-help-for-help-internal) + (defun . isearch-help-for-help) + (defun . isearch-describe-bindings) + (defun . isearch-describe-key) + (defun . isearch-describe-mode) + (defun . isearch-mode-help) + isearch-mode-map minibuffer-local-isearch-map isearch-forward isearch-regexp isearch-word isearch-hidden isearch-cmds isearch-string isearch-message isearch-message-prefix-add isearch-message-suffix-add isearch-success isearch-error isearch-other-end isearch-wrapped isearch-barrier isearch-just-started isearch-start-hscroll isearch-case-fold-search isearch-last-case-fold-search isearch-original-minibuffer-message-timeout isearch-adjusted isearch-slow-terminal-mode isearch-small-window isearch-opoint isearch-window-configuration isearch-yank-flag isearch-op-fun isearch-recursive-edit isearch-nonincremental isearch-new-forward isearch-opened-overlays isearch-input-method-function isearch-input-method-local-p isearch-mode + (defun . isearch-forward) + (defun . isearch-forward-regexp) + (defun . isearch-forward-word) + (defun . isearch-backward) + (defun . isearch-backward-regexp) + (defun . isearch-mode) + (defun . isearch-update) + (defun . isearch-done) + (defun . isearch-update-ring) + (defun . isearch-string-state) + (defun . isearch-message-state) + (defun . isearch-point-state) + (defun . isearch-success-state) + (defun . isearch-forward-state) + (defun . isearch-other-end-state) + (defun . isearch-word-state) + (defun . isearch-error-state) + (defun . isearch-wrapped-state) + (defun . isearch-barrier-state) + (defun . isearch-case-fold-search-state) + (defun . isearch-pop-fun-state) + (defun . isearch-top-state) + (defun . isearch-pop-state) + (defun . isearch-push-state) + (defun . isearch-exit) + (defun . isearch-edit-string) + (defun . isearch-nonincremental-exit-minibuffer) + (defun . isearch-forward-exit-minibuffer) + (defun . isearch-reverse-exit-minibuffer) + (defun . isearch-cancel) + (defun . isearch-abort) + (defun . isearch-repeat) + (defun . isearch-repeat-forward) + (defun . isearch-repeat-backward) + (defun . isearch-toggle-regexp) + (defun . isearch-toggle-word) + (defun . isearch-toggle-case-fold) + (defun . isearch-query-replace) + (defun . isearch-query-replace-regexp) + (defun . isearch-occur) + (defun . isearch-highlight-regexp) + (defun . isearch-delete-char) + (defun . isearch-del-char) + (defun . isearch-yank-string) + (defun . isearch-yank-kill) + (defun . isearch-yank-x-selection) + (defun . isearch-mouse-2) + (defun . isearch-yank-internal) + (defun . isearch-yank-char-in-minibuffer) + (defun . isearch-yank-char) + (defun . isearch-yank-word-or-char) + (defun . isearch-yank-word) + (defun . isearch-yank-line) + (defun . isearch-search-and-update) + (defun . isearch-backslash) + (defun . isearch-fallback) + (defun . isearch-unread-key-sequence) + isearch-allow-scroll + (defun . isearch-string-out-of-window) + (defun . isearch-back-into-window) + (defun . isearch-reread-key-sequence-naturally) + (defun . isearch-lookup-scroll-key) + (defun . isearch-other-control-char) + (defun . isearch-other-meta-char) + (defun . isearch-quote-char) + (defun . isearch-return-char) + (defun . isearch-printing-char) + (defun . isearch-process-search-char) + (defun . isearch-process-search-string) + (defun . isearch-ring-adjust1) + (defun . isearch-ring-adjust) + (defun . isearch-ring-advance) + (defun . isearch-ring-retreat) + (defun . isearch-complete1) + (defun . isearch-complete) + (defun . isearch-complete-edit) + (defun . isearch-message) + (defun . isearch-message-prefix) + (defun . isearch-message-suffix) + isearch-search-fun-function + (defun . isearch-search-fun) + (defun . isearch-search-string) + (defun . isearch-search) + (defun . isearch-open-overlay-temporary) + (defun . isearch-open-necessary-overlays) + (defun . isearch-clean-overlays) + (defun . isearch-intersects-p) + (defun . isearch-close-unnecessary-overlays) + (defun . isearch-range-invisible) + (defun . isearch-filter-visible) + (defun . isearch-no-upper-case-p) + (defun . isearch-text-char-description) + (defun . isearch-unread) + isearch-overlay + (defun . isearch-highlight) + (defun . isearch-dehighlight) + isearch-lazy-highlight-overlays isearch-lazy-highlight-wrapped isearch-lazy-highlight-start-limit isearch-lazy-highlight-end-limit isearch-lazy-highlight-start isearch-lazy-highlight-end isearch-lazy-highlight-timer isearch-lazy-highlight-last-string isearch-lazy-highlight-window isearch-lazy-highlight-window-start isearch-lazy-highlight-window-end isearch-lazy-highlight-case-fold-search isearch-lazy-highlight-regexp isearch-lazy-highlight-space-regexp + (defun . lazy-highlight-cleanup) + (defun . isearch-lazy-highlight-cleanup) + (defun . isearch-lazy-highlight-new-loop) + (defun . isearch-lazy-highlight-search) + (defun . isearch-lazy-highlight-update) + (defun . isearch-resume)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/timer.elc" + (defun . timer--triggered) + (defun . timer--high-seconds) + (defun . timer--low-seconds) + (defun . timer--usecs) + (defun . timer--repeat-delay) + (defun . timer--function) + (defun . timer--args) + (defun . timer--idle-delay) + (defun . timer-create) + (defun . timerp) + (defun . timer--time) + (defun . timer-set-time) + (defun . timer-set-idle-time) + (defun . timer-next-integral-multiple-of-time) + (defun . timer-relative-time) + (defun . timer--time-less-p) + (defun . timer-inc-time) + (defun . timer-set-time-with-usecs) + (defun . timer-set-function) + (defun . timer--activate) + (defun . timer-activate) + (defun . timer-activate-when-idle) + (defun . disable-timeout) + (defun . cancel-timer) + (defun . cancel-timer-internal) + (defun . cancel-function-timers) + timer-event-last timer-event-last-1 timer-event-last-2 timer-max-repeats + (defun . timer-until) + (defun . timer-event-handler) + (defun . timeout-event-p) + (defun . run-at-time) + (defun . run-with-timer) + (defun . add-timeout) + (defun . run-with-idle-timer) + (defun . with-timeout-handler) + with-timeout-timers + (defun . with-timeout) + (defun . with-timeout-suspend) + (defun . with-timeout-unsuspend) + (defun . y-or-n-p-with-timeout) + timer-duration-words + (defun . timer-duration) + (provide . timer)) + ("/usr/share/emacs/23.0.93/lisp/select.elc" selection-coding-system next-selection-coding-system + (defun . x-selection) + (defun . x-get-selection) + (defun . x-get-clipboard) + (defun . x-set-selection) + (defun . x-valid-simple-selection-p) + (defun . x-get-cut-buffer) + (defun . x-set-cut-buffer) + (defun . xselect-convert-to-string) + (defun . xselect-convert-to-length) + (defun . xselect-convert-to-targets) + (defun . xselect-convert-to-delete) + (defun . xselect-convert-to-filename) + (defun . xselect-convert-to-charpos) + (defun . xselect-convert-to-lineno) + (defun . xselect-convert-to-colno) + (defun . xselect-convert-to-os) + (defun . xselect-convert-to-host) + (defun . xselect-convert-to-user) + (defun . xselect-convert-to-class) + (defun . xselect-convert-to-name) + (defun . xselect-convert-to-integer) + (defun . xselect-convert-to-atom) + (defun . xselect-convert-to-identity) + (provide . select)) + ("/usr/share/emacs/23.0.93/lisp/scroll-bar.elc" + (require . mouse) + (defun . scroll-bar-event-ratio) + (defun . scroll-bar-scale) + (defun . scroll-bar-columns) + previous-scroll-bar-mode scroll-bar-mode-explicit + (defun . set-scroll-bar-mode-1) + (defun . set-scroll-bar-mode) + scroll-bar-mode + (defun . scroll-bar-mode) + (defun . toggle-scroll-bar) + (defun . toggle-horizontal-scroll-bar) + (defun . scroll-bar-set-window-start) + (defun . scroll-bar-drag-position) + (defun . scroll-bar-maybe-set-window-start) + (defun . scroll-bar-drag-1) + (defun . scroll-bar-drag) + (defun . scroll-bar-scroll-down) + (defun . scroll-bar-scroll-up) + (defun . scroll-bar-toolkit-scroll) + (provide . scroll-bar)) + ("/usr/share/emacs/23.0.93/lisp/mouse.elc" mouse-yank-at-point mouse-drag-copy-region mouse-1-click-follows-link mouse-1-click-in-non-selected-windows + (defun . popup-menu) + (defun . minor-mode-menu-from-indicator) + (defun . mouse-minor-mode-menu) + (defun . mouse-menu-major-mode-map) + (defun . mouse-menu-non-singleton) + (defun . mouse-menu-bar-map) + (defun . mouse-major-mode-menu) + (defun . mouse-popup-menubar) + (defun . mouse-popup-menubar-stuff) + (defun . mouse-minibuffer-check) + (defun . mouse-delete-window) + (defun . mouse-select-window) + (defun . mouse-tear-off-window) + (defun . mouse-delete-other-windows) + (defun . mouse-split-window-vertically) + (defun . mouse-split-window-horizontally) + (defun . mouse-drag-window-above) + (defun . mouse-drag-move-window-bottom) + (defun . mouse-drag-move-window-top) + (defun . mouse-drag-mode-line-1) + (defun . mouse-drag-mode-line) + (defun . mouse-drag-header-line) + (defun . mouse-drag-vertical-line-rightward-window) + (defun . mouse-drag-vertical-line) + (defun . mouse-set-point) + mouse-last-region-beg mouse-last-region-end mouse-last-region-tick + (defun . mouse-region-match) + (defun . mouse-set-region) + (defun . mouse-set-region-1) + mouse-scroll-delay mouse-scroll-min-lines + (defun . mouse-scroll-subr) + mouse-drag-overlay mouse-drag-overlay mouse-selection-click-count mouse-selection-click-count-buffer + (defun . mouse-drag-region) + (defun . mouse-posn-property) + (defun . mouse-on-link-p) + (defun . mouse-fixup-help-message) + (defun . mouse-move-drag-overlay) + (defun . mouse-drag-track) + (defun . mouse-skip-word) + (defun . mouse-start-end) + (defun . mouse-set-mark-fast) + (defun . mouse-undouble-last-event) + mouse-region-delete-keys + (defun . mouse-show-mark) + (defun . mouse-set-mark) + (defun . mouse-kill) + (defun . mouse-yank-at-click) + (defun . mouse-yank-primary) + (defun . mouse-kill-ring-save) + mouse-save-then-kill-posn + (defun . mouse-save-then-kill-delete-region) + (defun . mouse-save-then-kill) + mouse-secondary-overlay mouse-secondary-click-count mouse-secondary-start + (defun . mouse-start-secondary) + (defun . mouse-set-secondary) + (defun . mouse-drag-secondary) + (defun . mouse-yank-secondary) + (defun . mouse-kill-secondary) + (defun . mouse-secondary-save-then-kill) + mouse-buffer-menu-maxlen mouse-buffer-menu-mode-mult mouse-buffer-menu-mode-groups + (defun . mouse-buffer-menu) + (defun . mouse-buffer-menu-alist) + (defun . mouse-buffer-menu-split) + (defun . mouse-choose-completion) + (defun . font-menu-add-default) + x-fixed-font-alist + (defun . mouse-select-font) + (defun . mouse-set-font) + mouse-appearance-menu-map + (defun . mouse-appearance-menu) + (provide . mouse) + (defun . mldrag-drag-mode-line) + (defun . mldrag-drag-vertical-line) + (provide . mldrag)) + ("/usr/share/emacs/23.0.93/lisp/jit-lock.elc" jit-lock-chunk-size jit-lock-stealth-time jit-lock-stealth-nice jit-lock-stealth-load jit-lock-stealth-verbose jit-lock-defer-contextually jit-lock-contextually jit-lock-context-time jit-lock-defer-time jit-lock-mode jit-lock-functions jit-lock-context-unfontify-pos jit-lock-stealth-timer jit-lock-stealth-repeat-timer jit-lock-context-timer jit-lock-defer-timer jit-lock-defer-buffers jit-lock-stealth-buffers + (defun . jit-lock-mode) + (defun . jit-lock-register) + (defun . jit-lock-unregister) + (defun . jit-lock-refontify) + (defun . jit-lock-function) + (defun . jit-lock-fontify-now) + (defun . jit-lock-force-redisplay) + (defun . jit-lock-stealth-chunk-start) + (defun . jit-lock-stealth-fontify) + (defun . jit-lock-deferred-fontify) + (defun . jit-lock-context-fontify) + jit-lock-after-change-extend-region-functions + (defun . jit-lock-after-change) + (provide . jit-lock)) + ("/usr/share/emacs/23.0.93/lisp/font-lock.elc" + (require . syntax) + font-lock-maximum-size font-lock-maximum-decoration font-lock-verbose font-lock-comment-face font-lock-comment-delimiter-face font-lock-string-face font-lock-doc-face font-lock-keyword-face font-lock-builtin-face font-lock-function-name-face font-lock-variable-name-face font-lock-type-face font-lock-constant-face font-lock-warning-face font-lock-negation-char-face font-lock-preprocessor-face font-lock-reference-face font-lock-keywords font-lock-keywords-alist font-lock-removed-keywords-alist font-lock-keywords-only font-lock-keywords-case-fold-search font-lock-syntactically-fontified font-lock-syntactic-face-function font-lock-syntactic-keywords font-lock-syntax-table font-lock-beginning-of-syntax-function font-lock-mark-block-function font-lock-fontify-buffer-function font-lock-unfontify-buffer-function font-lock-fontify-region-function font-lock-unfontify-region-function font-lock-inhibit-thing-lock font-lock-multiline font-lock-fontified + (defun . font-lock-mode-internal) + (defun . font-lock-add-keywords) + (defun . font-lock-update-removed-keyword-alist) + (defun . font-lock-remove-keywords) + font-lock-support-mode + (defun . font-lock-turn-on-thing-lock) + (defun . font-lock-turn-off-thing-lock) + (defun . font-lock-after-fontify-buffer) + (defun . font-lock-after-unfontify-buffer) + font-lock-extend-after-change-region-function + (defun . font-lock-fontify-buffer) + (defun . font-lock-unfontify-buffer) + (defun . font-lock-fontify-region) + (defun . font-lock-unfontify-region) + (defun . font-lock-default-fontify-buffer) + (defun . font-lock-default-unfontify-buffer) + font-lock-dont-widen font-lock-extend-region-functions + (defun . font-lock-extend-region-multiline) + (defun . font-lock-extend-region-wholelines) + (defun . font-lock-default-fontify-region) + font-lock-extra-managed-props + (defun . font-lock-default-unfontify-region) + (defun . font-lock-after-change-function) + (defun . font-lock-extend-jit-lock-region-after-change) + (defun . font-lock-fontify-block) + (defun . font-lock-prepend-text-property) + (defun . font-lock-append-text-property) + (defun . font-lock-fillin-text-property) + (defun . font-lock-apply-syntactic-highlight) + (defun . font-lock-fontify-syntactic-anchored-keywords) + (defun . font-lock-fontify-syntactic-keywords-region) + font-lock-comment-start-skip font-lock-comment-end-skip + (defun . font-lock-fontify-syntactically-region) + (defun . font-lock-apply-highlight) + (defun . font-lock-fontify-anchored-keywords) + (defun . font-lock-fontify-keywords-region) + (defun . font-lock-compile-keywords) + (defun . font-lock-compile-keyword) + (defun . font-lock-eval-keywords) + (defun . font-lock-value-in-major-mode) + (defun . font-lock-choose-keywords) + font-lock-set-defaults + (defun . font-lock-set-defaults) + (defface . font-lock-comment-face) + (defface . font-lock-comment-delimiter-face) + (defface . font-lock-string-face) + (defface . font-lock-doc-face) + (defface . font-lock-keyword-face) + (defface . font-lock-builtin-face) + (defface . font-lock-function-name-face) + (defface . font-lock-variable-name-face) + (defface . font-lock-type-face) + (defface . font-lock-constant-face) + (defface . font-lock-warning-face) + (defface . font-lock-negation-char-face) + (defface . font-lock-preprocessor-face) + (defface . font-lock-regexp-grouping-backslash) + (defface . font-lock-regexp-grouping-construct) + (defun . font-lock-match-c-style-declaration-item-and-skip-to-next) + cpp-font-lock-keywords-source-directives cpp-font-lock-keywords-source-depth cpp-font-lock-keywords lisp-font-lock-keywords-1 lisp-font-lock-keywords-2 lisp-font-lock-keywords + (provide . font-lock)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/syntax.elc" + (defun . syntax-ppss-depth) + (defun . syntax-ppss-toplevel-pos) + (defun . syntax-ppss-context) + syntax-ppss-max-span syntax-begin-function syntax-ppss-cache syntax-ppss-last + (defun . syntax-ppss-after-change-function) + (defun . syntax-ppss-flush-cache) + syntax-ppss-stats + (defun . syntax-ppss-stats) + (defun . syntax-ppss) + (defun . syntax-ppss-debug) + (provide . syntax)) + ("/usr/share/emacs/23.0.93/lisp/facemenu.elc" facemenu-keybindings facemenu-new-faces-at-end facemenu-unlisted-faces facemenu-listed-faces facemenu-face-menu + (defun . facemenu-face-menu) + facemenu-foreground-menu + (defun . facemenu-foreground-menu) + facemenu-background-menu + (defun . facemenu-background-menu) + (defun . facemenu-enable-faces-p) + facemenu-special-menu + (defun . facemenu-special-menu) + facemenu-justification-menu + (defun . facemenu-justification-menu) + facemenu-indentation-menu + (defun . facemenu-indentation-menu) + facemenu-menu + (defun . facemenu-menu) + facemenu-keymap + (defun . facemenu-keymap) + facemenu-add-face-function facemenu-end-add-face facemenu-remove-face-function facemenu-color-alist + (defun . facemenu-update) + (defun . facemenu-set-face) + (defun . facemenu-set-foreground) + (defun . facemenu-set-background) + (defun . facemenu-set-face-from-menu) + (defun . facemenu-set-invisible) + (defun . facemenu-set-intangible) + (defun . facemenu-set-read-only) + (defun . facemenu-remove-face-props) + (defun . facemenu-remove-all) + (defun . facemenu-remove-special) + (defun . facemenu-read-color) + (defun . list-colors-display) + (defun . list-colors-print) + (defun . list-colors-duplicates) + (defun . facemenu-color-equal) + (defun . facemenu-add-face) + (defun . facemenu-active-faces) + (defun . facemenu-add-new-face) + (defun . facemenu-add-new-color) + (defun . facemenu-complete-face-list) + (defun . facemenu-iterate) + (provide . facemenu)) + ("/usr/share/emacs/23.0.93/lisp/font-core.elc" font-lock-defaults font-lock-defaults-alist font-lock-function font-lock-mode + (defun . font-lock-mode) + (defun . font-lock-change-mode) + (defun . font-lock-defontify) + (defun . font-lock-default-function) + (defun . turn-on-font-lock) + font-lock-global-modes + (defun . turn-on-font-lock-if-desired) + font-lock-mode-major-mode global-font-lock-mode + (defun . global-font-lock-mode) + global-font-lock-mode-buffers + (defun . global-font-lock-mode-enable-in-buffers) + (defun . global-font-lock-mode-check-buffers) + (defun . global-font-lock-mode-cmhh) + (provide . font-core)) + ("/usr/share/emacs/23.0.93/lisp/term/tty-colors.elc" color-name-rgb-alist tty-standard-colors tty-color-mode-alist tty-defined-color-alist + (defun . tty-color-alist) + (defun . tty-modify-color-alist) + (defun . tty-register-default-colors) + (defun . tty-color-canonicalize) + (defun . tty-color-define) + (defun . tty-color-clear) + (defun . tty-color-off-gray-diag) + (defun . tty-color-approximate) + (defun . tty-color-standard-values) + (defun . tty-color-translate) + (defun . tty-color-by-index) + (defun . tty-color-values) + (defun . tty-color-desc) + (defun . tty-color-gray-shades)) + ("/usr/share/emacs/23.0.93/lisp/frame.elc" frame-creation-function-alist window-system-default-frame-alist initial-frame-alist minibuffer-frame-alist pop-up-frame-alist pop-up-frame-function special-display-frame-alist + (defun . special-display-popup-frame) + (defun . handle-delete-frame) + frame-initial-frame frame-initial-geometry-arguments + (defun . frame-initialize) + frame-notice-user-settings + (defun . frame-notice-user-settings) + (defun . make-initial-minibuffer-frame) + (defun . modify-all-frames-parameters) + (defun . get-other-frame) + (defun . next-multiframe-window) + (defun . previous-multiframe-window) + (defun . make-frame-on-display) + (defun . close-display-connection) + (defun . make-frame-command) + before-make-frame-hook after-make-frame-functions after-setting-font-hook + (defun . new-frame) + frame-inherited-parameters + (defun . make-frame) + (defun . filtered-frame-list) + (defun . minibuffer-frame-list) + (defun . get-device-terminal) + (defun . frames-on-display-list) + (defun . framep-on-display) + (defun . frame-remove-geometry-params) + (defun . select-frame-set-input-focus) + (defun . other-frame) + (defun . iconify-or-deiconify-frame) + (defun . suspend-frame) + (defun . make-frame-names-alist) + frame-name-history + (defun . select-frame-by-name) + (defun . current-frame-configuration) + (defun . set-frame-configuration) + (defun . frame-height) + (defun . frame-width) + (defun . set-default-font) + (defun . set-frame-font) + (defun . set-frame-parameter) + (defun . set-background-color) + (defun . set-foreground-color) + (defun . set-cursor-color) + (defun . set-mouse-color) + (defun . set-border-color) + (defun . auto-raise-mode) + (defun . auto-lower-mode) + (defun . set-frame-name) + (defun . frame-current-scroll-bars) + (defun . selected-terminal) + (defun . display-mouse-p) + (defun . display-popup-menus-p) + (defun . display-graphic-p) + (defun . display-images-p) + (defun . display-multi-frame-p) + (defun . display-multi-font-p) + (defun . display-selections-p) + (defun . display-screens) + (defun . display-pixel-height) + (defun . display-pixel-width) + display-mm-dimensions-alist + (defun . display-mm-height) + (defun . display-mm-width) + (defun . display-backing-store) + (defun . display-save-under) + (defun . display-planes) + (defun . display-color-cells) + (defun . display-visual-class) + (defun . frame-geom-value-cons) + (defun . frame-geom-spec-cons) + (defun . screen-height) + (defun . screen-width) + (defun . set-screen-width) + (defun . set-screen-height) + (defun . delete-other-frames) + delete-frame-hook show-trailing-whitespace auto-hscroll-mode automatic-hscrolling blink-cursor-delay blink-cursor-interval blink-cursor-idle-timer blink-cursor-timer + (defun . blink-cursor-start) + (defun . blink-cursor-timer-function) + (defun . blink-cursor-end) + blink-cursor-mode + (defun . blink-cursor-mode) + blink-cursor display-hourglass hourglass-delay cursor-in-non-selected-windows + (provide . frame)) + ("/usr/share/emacs/23.0.93/lisp/window.elc" window-size-fixed + (defun . save-selected-window) + (defun . window-body-height) + (defun . one-window-p) + (defun . window-current-scroll-bars) + (defun . walk-windows) + (defun . get-window-with-predicate) + (defun . some-window) + (defun . get-buffer-window-list) + (defun . minibuffer-window-active-p) + (defun . count-windows) + (defun . bw-get-tree) + (defun . bw-get-tree-1) + (defun . bw-find-tree-sub) + (defun . bw-find-tree-sub-1) + (defun . bw-l) + (defun . bw-t) + (defun . bw-r) + (defun . bw-b) + (defun . bw-dir) + (defun . bw-eqdir) + (defun . bw-refresh-edges) + (defun . balance-windows) + (defun . bw-adjust-window) + (defun . bw-balance-sub) + (defun . window-fixed-size-p) + window-area-factor + (defun . balance-windows-area) + display-buffer-function special-display-buffer-names special-display-regexps + (defun . special-display-p) + special-display-function same-window-buffer-names same-window-regexps + (defun . same-window-p) + pop-up-frames display-buffer-reuse-frames pop-up-windows split-height-threshold split-width-threshold split-window-preferred-function + (defun . window--splittable-p) + (defun . window--try-to-split-window) + (defun . window--frame-usable-p) + even-window-heights + (defun . window--even-window-heights) + (defun . window--display-buffer-1) + (defun . window--display-buffer-2) + (defun . display-buffer) + (defun . pop-to-buffer) + split-window-keep-point + (defun . split-window-vertically) + (defun . split-window-save-restore-data) + (defun . split-window-horizontally) + (defun . set-window-text-height) + (defun . enlarge-window-horizontally) + (defun . shrink-window-horizontally) + (defun . window-buffer-height) + (defun . count-screen-lines) + (defun . fit-window-to-buffer) + (defun . window-safely-shrinkable-p) + (defun . shrink-window-if-larger-than-buffer) + (defun . kill-buffer-and-window) + (defun . quit-window) + recenter-last-op + (defun . recenter-top-bottom) + mouse-autoselect-window-timer mouse-autoselect-window-position mouse-autoselect-window-window mouse-autoselect-window-state + (defun . mouse-autoselect-window-cancel) + (defun . mouse-autoselect-window-start) + (defun . mouse-autoselect-window-select) + (defun . handle-select-window) + (defun . delete-other-windows-vertically) + (defun . truncated-partial-width-window-p)) + ("/usr/share/emacs/23.0.93/lisp/indent.elc" standard-indent indent-line-function tab-always-indent + (defun . indent-according-to-mode) + (defun . indent-for-tab-command) + (defun . insert-tab) + (defun . indent-rigidly) + (defun . indent-line-to) + (defun . current-left-margin) + (defun . move-to-left-margin) + (defun . indent-to-left-margin) + (defun . delete-to-left-margin) + (defun . set-left-margin) + (defun . set-right-margin) + (defun . alter-text-property) + (defun . increase-left-margin) + (defun . decrease-left-margin) + (defun . increase-right-margin) + (defun . decrease-right-margin) + (defun . beginning-of-line-text) + indent-region-function + (defun . indent-region) + (defun . indent-relative-maybe) + (defun . indent-relative) + tab-stop-list edit-tab-stops-map edit-tab-stops-buffer + (defun . edit-tab-stops) + (defun . edit-tab-stops-note-changes) + (defun . tab-to-tab-stop) + (defun . move-to-tab-stop)) + ("/usr/share/emacs/23.0.93/lisp/language/cham.el" + (provide . cham)) + ("/usr/share/emacs/23.0.93/lisp/language/burmese.el") + ("/usr/share/emacs/23.0.93/lisp/language/khmer.el") + ("/usr/share/emacs/23.0.93/lisp/language/georgian.el" + (provide . georgian)) + ("/usr/share/emacs/23.0.93/lisp/language/utf-8-lang.el" + (provide . utf-8-lang)) + ("/usr/share/emacs/23.0.93/lisp/language/misc-lang.el" + (provide . misc-lang)) + ("/usr/share/emacs/23.0.93/lisp/language/vietnamese.elc" + (provide . vietnamese)) + ("/usr/share/emacs/23.0.93/lisp/language/tibetan.elc" tibetan-composable-pattern tibetan-consonant-transcription-alist tibetan-consonant-transcription-alist tibetan-vowel-transcription-alist tibetan-vowel-transcription-alist tibetan-modifier-transcription-alist tibetan-modifier-transcription-alist tibetan-precomposed-transcription-alist tibetan-precomposed-transcription-alist tibetan-subjoined-transcription-alist tibetan-subjoined-transcription-alist tibetan-base-to-subjoined-alist tibetan-base-to-subjoined-alist tibetan-composite-vowel-alist tibetan-composite-vowel-alist tibetan-precomposition-rule-alist tibetan-precomposition-rule-alist tibetan-regexp tibetan-precomposed-regexp tibetan-precomposition-rule-regexp tibetan-decomposed tibetan-decomposed-temp + (provide . tibetan)) + ("/usr/share/emacs/23.0.93/lisp/language/thai.el" + (provide . thai)) + ("/usr/share/emacs/23.0.93/lisp/language/tai-viet.el" + (provide . tai-viet)) + ("/usr/share/emacs/23.0.93/lisp/language/lao.el" + (provide . lao)) + ("/usr/share/emacs/23.0.93/lisp/language/korean.el" + (provide . korean)) + ("/usr/share/emacs/23.0.93/lisp/language/japanese.el" + (defun . compose-gstring-for-variation-glyph) + (provide . japanese)) + ("/usr/share/emacs/23.0.93/lisp/international/eucjp-ms.el") + ("/usr/share/emacs/23.0.93/lisp/international/cp51932.el") + ("/usr/share/emacs/23.0.93/lisp/language/hebrew.el" + (provide . hebrew)) + ("/usr/share/emacs/23.0.93/lisp/language/greek.el" + (provide . greek)) + ("/usr/share/emacs/23.0.93/lisp/language/romanian.el" + (provide . romanian)) + ("/usr/share/emacs/23.0.93/lisp/language/slovak.el" + (provide . slovak)) + ("/usr/share/emacs/23.0.93/lisp/language/czech.el" + (provide . czech)) + ("/usr/share/emacs/23.0.93/lisp/language/european.elc" + (defun . turkish-case-conversion-enable) + (defun . turkish-case-conversion-disable) + (provide . european)) + ("/usr/share/emacs/23.0.93/lisp/language/ethiopic.elc" ccl-encode-ethio-font ccl-encode-ethio-font + (provide . ethiopic)) + ("/usr/share/emacs/23.0.93/lisp/language/english.el") + ("/usr/share/emacs/23.0.93/lisp/language/sinhala.el") + ("/usr/share/emacs/23.0.93/lisp/language/indian.elc" devanagari-composable-pattern tamil-composable-pattern kannada-composable-pattern malayalam-composable-pattern + (provide . indian)) + ("/usr/share/emacs/23.0.93/lisp/language/cyrillic.elc" + (provide . cyrillic)) + ("/usr/share/emacs/23.0.93/lisp/language/chinese.elc" + (provide . chinese)) + ("/usr/share/emacs/23.0.93/lisp/international/charprop.el") + ("/usr/share/emacs/23.0.93/lisp/composite.elc" reference-point-alist + (t . encode-composition-rule) + (defun . encode-composition-rule) + (defun . decode-composition-rule) + (defun . encode-composition-components) + (defun . decode-composition-components) + (defun . compose-region) + (defun . decompose-region) + (defun . compose-string) + (defun . decompose-string) + (defun . compose-chars) + (defun . find-composition) + (defun . compose-chars-after) + (defun . compose-last-chars) + (defun . lgstring-header) + (defun . lgstring-set-header) + (defun . lgstring-font) + (defun . lgstring-char) + (defun . lgstring-char-len) + (defun . lgstring-shaped-p) + (defun . lgstring-set-id) + (defun . lgstring-glyph) + (defun . lgstring-glyph-len) + (defun . lgstring-set-glyph) + (defun . lglyph-from) + (defun . lglyph-to) + (defun . lglyph-char) + (defun . lglyph-code) + (defun . lglyph-width) + (defun . lglyph-lbearing) + (defun . lglyph-rbearing) + (defun . lglyph-ascent) + (defun . lglyph-descent) + (defun . lglyph-adjustment) + (defun . lglyph-set-from-to) + (defun . lglyph-set-char) + (defun . lglyph-set-code) + (defun . lglyph-set-width) + (defun . lglyph-set-adjustment) + (defun . lglyph-copy) + (defun . lgstring-insert-glyph) + (defun . compose-glyph-string) + (defun . compose-glyph-string-relative) + (defun . compose-gstring-for-graphic) + (defun . compose-gstring-for-terminal) + (defun . auto-compose-chars) + auto-composition-mode + (t . auto-composition-mode) + (defun . auto-composition-mode) + (defun . turn-on-auto-composition-if-enabled) + auto-composition-mode-major-mode global-auto-composition-mode + (t . global-auto-composition-mode) + (defun . global-auto-composition-mode) + global-auto-composition-mode-buffers + (defun . global-auto-composition-mode-enable-in-buffers) + (defun . global-auto-composition-mode-check-buffers) + (defun . global-auto-composition-mode-cmhh) + (defun . toggle-auto-composition) + (defun . decompose-composite-char)) + ("/usr/share/emacs/23.0.93/lisp/international/characters.elc" cjk-char-width-table + (defun . use-cjk-char-width-table) + (defun . use-default-char-width-table) + (defun . build-unicode-category-table)) + ("/usr/share/emacs/23.0.93/lisp/case-table.elc" + (defun . describe-buffer-case-table) + (defun . get-upcase-table) + (defun . copy-case-table) + (defun . set-case-syntax-delims) + (defun . set-case-syntax-pair) + (defun . set-upcase-syntax) + (defun . set-downcase-syntax) + (defun . set-case-syntax) + (provide . case-table)) + ("/usr/share/emacs/23.0.93/lisp/international/mule-cmds.elc" mule-keymap mule-menu-keymap describe-language-environment-map setup-language-environment-map set-coding-system-map help-xref-mule-regexp-template help-xref-mule-regexp-template + (defun . coding-system-change-eol-conversion) + (defun . coding-system-change-text-conversion) + (defun . canonicalize-coding-system-name) + (defun . coding-system-from-name) + (defun . toggle-enable-multibyte-characters) + (defun . view-hello-file) + (defun . universal-coding-system-argument) + (defun . set-default-coding-systems) + (defun . prefer-coding-system) + sort-coding-systems-predicate + (defun . sort-coding-systems) + (defun . find-coding-systems-region) + (defun . find-coding-systems-string) + (defun . find-coding-systems-for-charsets) + (defun . find-multibyte-characters) + (defun . search-unencodable-char) + last-coding-system-specified select-safe-coding-system-accept-default-p + (defun . select-safe-coding-system-interactively) + (defun . select-safe-coding-system) + (defun . select-message-coding-system) + language-info-alist + (defun . get-language-info) + (defun . set-language-info) + (defun . set-language-info-internal) + (defun . set-language-info-alist) + (defun . read-language-name) + leim-list-file-name leim-list-header leim-list-entry-regexp update-leim-list-functions + (defun . update-leim-list-file) + current-input-method current-input-method-title default-input-method input-method-history inactivate-current-input-method-function describe-current-input-method-function input-method-alist + (defun . register-input-method) + (defun . read-input-method-name) + (defun . activate-input-method) + (defun . inactivate-input-method) + (defun . set-input-method) + toggle-input-method-active + (defun . toggle-input-method) + (defun . describe-input-method) + (defun . describe-current-input-method) + (defun . read-multilingual-string) + input-method-verbose-flag input-method-highlight-flag input-method-activate-hook input-method-inactivate-hook input-method-after-insert-chunk-hook input-method-exit-on-first-char input-method-use-echo-area input-method-exit-on-invalid-key set-language-environment-hook exit-language-environment-hook + (defun . setup-specified-language-environment) + current-language-environment + (defun . reset-language-environment) + (defun . set-display-table-and-terminal-coding-system) + (defun . set-language-environment) + language-info-custom-alist + (defun . standard-display-european-internal) + (defun . set-language-environment-coding-systems) + (defun . set-language-environment-input-method) + (defun . set-language-environment-nonascii-translation) + (defun . set-language-environment-charset) + (defun . set-language-environment-unibyte) + (defun . princ-list) + (defun . describe-specified-language-support) + (defun . describe-language-environment) + locale-translation-file-name locale-language-names locale-charset-language-names locale-preferred-coding-systems + (defun . locale-name-match) + (defun . locale-charset-match-p) + locale-charset-alist + (defun . locale-charset-to-coding-system) + (defun . locale-translate) + (defun . set-locale-environment) + char-code-property-alist + (defun . define-char-code-property) + char-code-property-table + (defun . get-char-code-property) + (defun . put-char-code-property) + (defun . char-code-property-description) + iso-2022-control-alist + (defun . encoded-string-description) + (defun . encode-coding-char) + unify-8859-on-encoding-mode + (defun . unify-8859-on-encoding-mode) + unify-8859-on-decoding-mode + (defun . unify-8859-on-decoding-mode) + nonascii-insert-offset nonascii-translation-table ucs-names + (defun . ucs-names) + ucs-completions + (defun . read-char-by-name) + (defun . ucs-insert)) + ("/usr/share/emacs/23.0.93/lisp/epa-hook.elc" + (defun . epa-file--file-name-regexp-set) + epa-file-name-regexp epa-file-inhibit-auto-save epa-file-encrypt-to epa-file-handler epa-file-auto-mode-alist-entry + (defun . epa-file-name-regexp-update) + (defun . epa-file-find-file-hook) + auto-encryption-mode + (defun . auto-encryption-mode) + (provide . epa-hook)) + ("/usr/share/emacs/23.0.93/lisp/jka-cmpr-hook.elc" jka-compr-added-to-file-coding-system-alist jka-compr-file-name-handler-entry jka-compr-compression-info-list--internal jka-compr-mode-alist-additions--internal jka-compr-load-suffixes--internal + (defun . jka-compr-build-file-regexp) + (defun . jka-compr-info-regexp) + (defun . jka-compr-info-compress-message) + (defun . jka-compr-info-compress-program) + (defun . jka-compr-info-compress-args) + (defun . jka-compr-info-uncompress-message) + (defun . jka-compr-info-uncompress-program) + (defun . jka-compr-info-uncompress-args) + (defun . jka-compr-info-can-append) + (defun . jka-compr-info-strip-extension) + (defun . jka-compr-info-file-magic-bytes) + (defun . jka-compr-get-compression-info) + (defun . jka-compr-install) + (defun . jka-compr-installed-p) + (defun . jka-compr-update) + (defun . jka-compr-set) + jka-compr-compression-info-list jka-compr-mode-alist-additions jka-compr-load-suffixes auto-compression-mode + (defun . auto-compression-mode) + (defun . with-auto-compression-mode) + (provide . jka-cmpr-hook)) + ("/usr/share/emacs/23.0.93/lisp/help.elc" help-window help-window-point-marker help-map help-button-cache + (defun . help-quit) + help-return-method + (defun . print-help-return-message) + (defun . help) + (defun . help-for-help) + (defun . help-for-help-internal-doc) + (defun . help-for-help-internal) + (defun . function-called-at-point) + (defun . view-help-file) + (defun . describe-distribution) + (defun . describe-copying) + (defun . describe-gnu-project) + (defun . describe-project) + (defun . describe-no-warranty) + (defun . describe-prefix-bindings) + (defun . view-emacs-news) + (defun . view-emacs-todo) + (defun . view-todo) + (defun . view-echo-area-messages) + (defun . view-order-manuals) + (defun . view-emacs-FAQ) + (defun . view-emacs-problems) + (defun . view-emacs-debugging) + (defun . view-external-packages) + (defun . view-lossage) + (defun . describe-bindings) + (defun . describe-bindings-internal) + (defun . where-is) + (defun . help-key-description) + (defun . describe-key-briefly) + (defun . describe-key) + (defun . describe-mode) + (defun . describe-minor-mode) + (defun . describe-minor-mode-completion-table-for-symbol) + (defun . describe-minor-mode-from-symbol) + (defun . describe-minor-mode-completion-table-for-indicator) + (defun . describe-minor-mode-from-indicator) + (defun . lookup-minor-mode-from-indicator) + temp-buffer-max-height temp-buffer-resize-mode + (defun . temp-buffer-resize-mode) + (defun . resize-temp-buffer-window) + help-window-select + (defun . help-window-display-message) + (defun . help-window-setup-finish) + (defun . help-window-setup) + (defun . with-help-window) + (provide . help)) + ("/usr/share/emacs/23.0.93/lisp/simple.elc" idle-update-delay + (defun . get-next-valid-buffer) + (defun . last-buffer) + (defun . next-buffer) + (defun . previous-buffer) + (defface . next-error) + next-error-highlight next-error-highlight-no-select next-error-recenter next-error-hook next-error-highlight-timer next-error-overlay-arrow-position next-error-last-buffer next-error-function + (defun . next-error-buffer-p) + (defun . next-error-find-buffer) + (defun . next-error) + (defun . next-error-internal) + (defun . goto-next-locus) + (defun . next-match) + (defun . previous-error) + (defun . first-error) + (defun . next-error-no-select) + (defun . previous-error-no-select) + next-error-follow-last-line next-error-follow-minor-mode + (defun . next-error-follow-minor-mode) + (defun . next-error-follow-mode-post-command-hook) + (defun . fundamental-mode) + special-mode-map special-mode-map special-mode-syntax-table special-mode-abbrev-table special-mode-abbrev-table + (defun . special-mode) + hard-newline + (defun . newline) + (defun . set-hard-newline-properties) + (defun . open-line) + (defun . split-line) + (defun . delete-indentation) + (defun . join-line) + (defun . delete-blank-lines) + (defun . delete-trailing-whitespace) + (defun . newline-and-indent) + (defun . reindent-then-newline-and-indent) + (defun . quoted-insert) + (defun . forward-to-indentation) + (defun . backward-to-indentation) + (defun . back-to-indentation) + (defun . fixup-whitespace) + (defun . delete-horizontal-space) + (defun . just-one-space) + (defun . beginning-of-buffer) + (defun . end-of-buffer) + (defun . mark-whole-buffer) + (defun . goto-line) + (defun . count-lines-region) + (defun . what-line) + (defun . count-lines) + (defun . line-number-at-pos) + (defun . what-cursor-position) + read-expression-history minibuffer-completing-symbol minibuffer-default eval-expression-print-level eval-expression-print-length eval-expression-debug-on-error + (defun . eval-expression-print-format) + (defun . eval-expression) + (defun . edit-and-eval-command) + (defun . repeat-complex-command) + minibuffer-history minibuffer-history-sexp-flag minibuffer-history-search-history minibuffer-text-before-history + (defun . minibuffer-history-initialize) + (defun . minibuffer-avoid-prompt) + minibuffer-history-case-insensitive-variables + (defun . previous-matching-history-element) + (defun . next-matching-history-element) + minibuffer-temporary-goal-position minibuffer-default-add-function minibuffer-default-add-done + (defun . minibuffer-default-add-completions) + (defun . goto-history-element) + (defun . next-history-element) + (defun . previous-history-element) + (defun . next-complete-history-element) + (defun . previous-complete-history-element) + (defun . minibuffer-prompt-width) + (defun . minibuffer-history-isearch-setup) + (defun . minibuffer-history-isearch-end) + (defun . minibuffer-history-isearch-search) + (defun . minibuffer-history-isearch-message) + (defun . minibuffer-history-isearch-wrap) + (defun . minibuffer-history-isearch-push-state) + (defun . minibuffer-history-isearch-pop-state) + (defun . advertised-undo) + undo-equiv-table undo-in-region undo-no-redo pending-undo-list + (defun . undo) + (defun . buffer-disable-undo) + (defun . undo-only) + undo-in-progress + (defun . undo-more) + (defun . undo-copy-list) + (defun . undo-copy-list-1) + (defun . undo-start) + (defun . undo-make-selective-list) + (defun . undo-elt-in-region) + (defun . undo-elt-crosses-region) + (defun . undo-delta) + undo-ask-before-discard undo-extra-outer-limit + (defun . undo-outer-limit-truncate) + shell-command-history shell-command-switch shell-command-default-error-buffer + (defun . minibuffer-default-add-shell-commands) + (defun . minibuffer-complete-shell-command) + minibuffer-local-shell-command-map + (defun . read-shell-command) + (defun . shell-command) + (defun . display-message-or-buffer) + (defun . shell-command-sentinel) + (defun . shell-command-on-region) + (defun . shell-command-to-string) + (defun . process-file) + (defun . start-file-process) + universal-argument-map universal-argument-num-events overriding-map-is-bound saved-overriding-map + (defun . ensure-overriding-map-is-bound) + (defun . restore-overriding-map) + (defun . universal-argument) + (defun . universal-argument-more) + (defun . negative-argument) + (defun . digit-argument) + (defun . universal-argument-minus) + (defun . universal-argument-other-key) + buffer-substring-filters + (defun . filter-buffer-substring) + interprogram-cut-function interprogram-paste-function kill-ring kill-ring-max kill-ring-yank-pointer + (defun . kill-new) + (defun . kill-append) + yank-pop-change-selection + (defun . current-kill) + kill-read-only-ok + (defun . kill-region) + (defun . copy-region-as-kill) + (defun . kill-ring-save) + (defun . append-next-kill) + yank-excluded-properties yank-window-start yank-undo-function + (defun . yank-pop) + (defun . yank) + (defun . rotate-yank-pointer) + (defun . kill-forward-chars) + (defun . kill-backward-chars) + backward-delete-char-untabify-method + (defun . backward-delete-char-untabify) + (defun . zap-to-char) + kill-whole-line + (defun . kill-line) + (defun . kill-whole-line) + (defun . forward-visible-line) + (defun . end-of-visible-line) + (defun . insert-buffer) + (defun . append-to-buffer) + (defun . prepend-to-buffer) + (defun . copy-to-buffer) + activate-mark-hook deactivate-mark-hook + (defun . mark) + (defun . deactivate-mark) + (defun . activate-mark) + select-active-regions + (defun . set-mark) + use-empty-active-region + (defun . use-region-p) + (defun . region-active-p) + mark-ring mark-ring-max global-mark-ring global-mark-ring-max + (defun . pop-to-mark-command) + (defun . push-mark-command) + set-mark-command-repeat-pop set-mark-default-inactive + (defun . set-mark-command) + (defun . push-mark) + (defun . pop-mark) + (defun . exchange-dot-and-mark) + (defun . exchange-point-and-mark) + shift-select-mode + (defun . handle-shift-selection) + transient-mark-mode + (defun . transient-mark-mode) + transient-mark-mode widen-automatically + (defun . pop-global-mark) + next-line-add-newlines + (defun . next-line) + (defun . previous-line) + track-eol goal-column temporary-goal-column line-move-ignore-invisible line-move-visual + (defun . line-move-partial) + (defun . line-move) + (defun . line-move-visual) + (defun . line-move-1) + (defun . line-move-finish) + (defun . line-move-to-column) + (defun . move-end-of-line) + (defun . move-beginning-of-line) + (defun . set-goal-column) + (defun . end-of-visual-line) + (defun . beginning-of-visual-line) + (defun . kill-visual-line) + (defun . next-logical-line) + (defun . previous-logical-line) + visual-line-mode-map visual-line-fringe-indicators visual-line--saved-state visual-line-mode + (defun . visual-line-mode) + (defun . turn-on-visual-line-mode) + visual-line-mode-major-mode global-visual-line-mode + (defun . global-visual-line-mode) + global-visual-line-mode-buffers + (defun . global-visual-line-mode-enable-in-buffers) + (defun . global-visual-line-mode-check-buffers) + (defun . global-visual-line-mode-cmhh) + (defun . scroll-other-window-down) + (defun . beginning-of-buffer-other-window) + (defun . end-of-buffer-other-window) + (defun . transpose-chars) + (defun . transpose-words) + (defun . transpose-sexps) + (defun . transpose-lines) + (defun . transpose-subr) + (defun . transpose-subr-1) + (defun . backward-word) + (defun . mark-word) + (defun . kill-word) + (defun . backward-kill-word) + (defun . current-word) + fill-prefix auto-fill-inhibit-regexp + (defun . do-auto-fill) + comment-line-break-function + (defun . default-indent-new-line) + normal-auto-fill-function + (defun . auto-fill-mode) + (defun . auto-fill-function) + (defun . turn-on-auto-fill) + (defun . turn-off-auto-fill) + (defun . set-fill-column) + (defun . set-selective-display) + indicate-unused-lines + (defun . toggle-truncate-lines) + (defun . toggle-word-wrap) + overwrite-mode-textual overwrite-mode-binary + (defun . overwrite-mode) + (defun . binary-overwrite-mode) + line-number-mode + (defun . line-number-mode) + column-number-mode + (defun . column-number-mode) + size-indication-mode + (defun . size-indication-mode) + blink-matching-paren blink-matching-paren-on-screen blink-matching-paren-distance blink-matching-delay blink-matching-paren-dont-ignore-comments + (defun . blink-matching-open) + (defun . keyboard-quit) + buffer-quit-function + (defun . keyboard-escape-quit) + (defun . play-sound-file) + read-mail-command mail-user-agent + (defun . rfc822-goto-eoh) + (defun . sendmail-user-agent-compose) + (defun . compose-mail) + (defun . compose-mail-other-window) + (defun . compose-mail-other-frame) + set-variable-value-history + (defun . set-variable) + completion-list-mode-map completion-reference-buffer completion-no-auto-exit completion-base-size + (defun . delete-completion-window) + (defun . previous-completion) + (defun . next-completion) + (defun . choose-completion) + (defun . choose-completion-delete-max-match) + choose-completion-string-functions + (defun . choose-completion-string) + completion-list-mode-map completion-list-mode-syntax-table completion-list-mode-abbrev-table completion-list-mode-abbrev-table + (defun . completion-list-mode) + (defun . completion-list-mode-finish) + completion-show-help completion-root-regexp + (defun . completion-setup-function) + (defun . switch-to-completions) + (defun . event-apply-alt-modifier) + (defun . event-apply-super-modifier) + (defun . event-apply-hyper-modifier) + (defun . event-apply-shift-modifier) + (defun . event-apply-control-modifier) + (defun . event-apply-meta-modifier) + (defun . event-apply-modifier) + clone-buffer-hook clone-indirect-buffer-hook + (defun . clone-process) + (defun . clone-buffer) + (defun . clone-indirect-buffer) + (defun . clone-indirect-buffer-other-window) + normal-erase-is-backspace + (defun . normal-erase-is-backspace-setup-frame) + (defun . normal-erase-is-backspace-mode) + vis-mode-saved-buffer-invisibility-spec visible-mode + (defun . visible-mode) + (defun . apply-partially) + bad-packages-alist + (defun . bad-package-check) + (provide . simple)) + ("/usr/share/emacs/23.0.93/lisp/abbrev.elc" only-global-abbrevs abbrev-mode + (defun . abbrev-mode) + abbrev-mode edit-abbrevs-map + (defun . kill-all-abbrevs) + (defun . copy-abbrev-table) + (defun . insert-abbrevs) + (defun . list-abbrevs) + (defun . abbrev-table-name) + (defun . prepare-abbrev-list-buffer) + (defun . edit-abbrevs-mode) + (defun . edit-abbrevs) + (defun . edit-abbrevs-redefine) + (defun . define-abbrevs) + (defun . read-abbrev-file) + (defun . quietly-read-abbrev-file) + (defun . write-abbrev-file) + (defun . add-mode-abbrev) + (defun . add-global-abbrev) + (defun . add-abbrev) + (defun . inverse-add-mode-abbrev) + (defun . inverse-add-global-abbrev) + (defun . inverse-add-abbrev) + (defun . abbrev-prefix-mark) + (defun . expand-region-abbrevs) + (defun . abbrev-table-get) + (defun . abbrev-table-put) + (defun . abbrev-get) + (defun . abbrev-put) + (defun . abbrev-with-wrapper-hook) + abbrev-table-name-list + (defun . make-abbrev-table) + (defun . abbrev-table-p) + global-abbrev-table abbrev-minor-mode-table-alist fundamental-mode-abbrev-table abbrevs-changed abbrev-all-caps abbrev-start-location abbrev-start-location-buffer last-abbrev last-abbrev-text last-abbrev-location pre-abbrev-expand-hook + (defun . clear-abbrev-table) + (defun . define-abbrev) + (defun . abbrev--check-chars) + (defun . define-global-abbrev) + (defun . define-mode-abbrev) + (defun . abbrev--active-tables) + (defun . abbrev-symbol) + (defun . abbrev-expansion) + (defun . abbrev--before-point) + (defun . abbrev-insert) + abbrev-expand-functions + (defun . expand-abbrev) + (defun . unexpand-abbrev) + (defun . abbrev--write) + (defun . abbrev--describe) + (defun . insert-abbrev-table-description) + (defun . define-abbrev-table) + (defun . abbrev-table-menu) + (provide . abbrev)) + ("/usr/share/emacs/23.0.93/lisp/loaddefs.el" add-log-current-defun-function add-log-full-name add-log-mailing-address add-log-lisp-like-modes add-log-c-like-modes add-log-tex-like-modes ad-redefinition-action ad-default-compilation-action + (defun . outlinify-sticky) + (defun . ange-ftp-re-read-dir) + (defun . command-apropos) + autoarg-mode autoarg-kp-mode auto-insert-mode global-auto-revert-mode mouse-avoidance-mode display-battery-mode binhex-begin-line bookmark-map + (defun . bookmark-locate) + (defun . list-bookmarks) + (defun . edit-bookmarks) + menu-bar-bookmark-map + (defun . menu-bar-bookmark-map) + browse-url-browser-function browse-url-firefox-program browse-url-galeon-program + (defun . list-yahrzeit-dates) + calc-settings-file c-mode-syntax-table c++-mode-syntax-table objc-mode-syntax-table java-mode-syntax-table idl-mode-syntax-table pike-mode-syntax-table custom-print-functions comint-output-filter-functions comint-use-prompt-regexp-instead-of-fields comint-file-name-prefix compilation-mode-hook compilation-start-hook compilation-window-height compilation-process-setup-function compilation-buffer-name-function compilation-finish-function compilation-finish-functions compilation-ask-about-save compilation-search-path compile-command compilation-disable-input partial-completion-mode dynamic-completion-mode global-auto-composition-mode crisp-mode + (defun . brief-mode) + cua-mode custom-browse-sort-alphabetically custom-buffer-sort-alphabetically custom-menu-sort-alphabetically + (defun . customize-variable) + (defun . customize-variable-other-window) + customize-package-emacs-version-alist + (defun . customize-changed) + custom-file global-cwarn-mode + (defun . pending-delete-mode) + delete-selection-mode desktop-save-mode desktop-locals-to-save desktop-save-buffer desktop-buffer-mode-handlers desktop-minor-mode-handlers diff-switches diff-command dired-listing-switches dired-chown-program dired-ls-F-marks-symlinks dired-trivial-filenames dired-keep-marker-rename dired-keep-marker-copy dired-keep-marker-hardlink dired-keep-marker-symlink dired-dwim-target dired-copy-preserve-time dired-directory dnd-protocol-alist + (defun . zone-mode) + (defun . easy-mmode-define-minor-mode) + (defun . easy-mmode-define-global-mode) + (defun . define-global-minor-mode) + (defun . ebnf-despool) + edebug-all-defs edebug-all-forms + (defun . edebug-defun) + (defun . ediff3) + (defun . ediff) + (defun . ebuffers) + (defun . ebuffers3) + (defun . edirs) + (defun . edir-revisions) + (defun . edirs3) + (defun . edirs-merge) + (defun . edir-merge-revisions) + (defun . edir-merge-revisions-with-ancestor) + (defun . edirs-merge-with-ancestor) + (defun . ediff-merge) + (defun . ediff-merge-with-ancestor) + (defun . epatch) + (defun . epatch-buffer) + (defun . erevision) + menu-bar-ediff-misc-menu menu-bar-epatch-menu menu-bar-ediff-merge-menu menu-bar-ediff-menu + (defun . eregistry) + edmacro-eight-bits eldoc-minor-mode-string eldoc-documentation-function menu-bar-emerge-menu epa-global-mail-mode + (defun . epg-import-keys-from-server) + (defun . erc-select) + erc-ctcp-query-DCC-hook erc-track-minor-mode + (defun . eshell-report-bug) + tags-file-name tags-case-fold-search tags-table-list tags-compression-info-list tags-add-tables find-tag-hook find-tag-default-function eudc-tools-menu + (defun . ffap) + find-ls-option find-ls-subdir-switches find-grep-options find-name-arg ff-special-constructs + (defun . ff-find-related-file) + flyspell-mode + (defun . gdba) + gdb-enable-debug generic-mode-list + (defun . gnus-batch-kill) + (defun . gnus-set-sorted-intersection) + (defun . goto-address-at-mouse) + grep-window-height grep-command grep-find-command grep-setup-hook grep-regexp-alist grep-program find-program xargs-program grep-find-use-xargs grep-history grep-find-history + (defun . find-grep) + help-at-pt-display-when-idle three-step-help global-hi-lock-mode + (defun . highlight-lines-matching-regexp) + (defun . highlight-regexp) + (defun . highlight-phrase) + (defun . unhighlight-regexp) + hs-special-modes-alist global-highlight-changes-mode hippie-expand-try-functions-list hippie-expand-verbose hippie-expand-dabbrev-skip-space hippie-expand-dabbrev-as-symbol hippie-expand-no-restriction hippie-expand-max-buffers hippie-expand-ignore-buffers hippie-expand-only-buffers global-hl-line-mode holiday-general-holidays general-holidays holiday-oriental-holidays oriental-holidays holiday-local-holidays local-holidays holiday-other-holidays other-holidays hebrew-holidays-1 hebrew-holidays-2 hebrew-holidays-3 hebrew-holidays-4 holiday-hebrew-holidays hebrew-holidays holiday-christian-holidays christian-holidays holiday-islamic-holidays islamic-holidays holiday-bahai-holidays bahai-holidays holiday-solar-holidays solar-holidays + (defun . holiday-list) + icomplete-mode ido-mode + (defun . image-dired) + (defun . tumme) + image-file-name-extensions image-file-name-regexps auto-image-file-mode imenu-sort-function imenu-generic-expression imenu-create-index-function imenu-prev-index-position-function imenu-extract-index-name-function imenu-name-lookup-function imenu-default-goto-function inferior-lisp-filter-regexp inferior-lisp-program inferior-lisp-load-command inferior-lisp-prompt inferior-lisp-mode-hook + (defun . run-lisp) + Info-split-threshold ispell-personal-dictionary ispell-menu-map ispell-menu-xemacs ispell-menu-map-needed ispell-skip-region-alist ispell-tex-skip-alists ispell-html-skip-alists iswitchb-mode jka-compr-inhibit keypad-setup keypad-numlock-setup keypad-shifted-setup keypad-numlock-shifted-setup kkc-after-update-conversion-functions default-korean-keyboard + (defun . landmark-repeat) + (defun . landmark) + latex-inputenc-coding-alist latin1-display latin1-display-ucs-per-lynx ledit-save-files ledit-go-to-lisp-string ledit-go-to-liszt-string linum-format global-linum-mode locate-ls-subdir-switches lpr-windows-system lpr-lp-system printer-name lpr-switches lpr-command ls-lisp-support-shell-wildcards + (defun . phases-of-moon) + mail-hist-keep-history mail-use-rfc822 mail-abbrevs-mode mail-complete-style + (defun . manual-entry) + minibuffer-depth-indicate-mode minibuffer-electric-default-mode multi-isearch-next-buffer-function multi-isearch-next-buffer-current-function multi-isearch-current-buffer mouse-sel-mode msb-mode + (defun . string-to-list) + (defun . string-to-vector) + (defun . nested-alist-p) + mouse-wheel-mode + (defun . ipconfig) + (defun . indent-for-comment) + (defun . set-comment-column) + (defun . kill-comment) + (defun . indent-new-comment-line) + comment-use-syntax comment-column comment-start comment-start-skip comment-end-skip comment-end comment-indent-function comment-insert-comment-function comment-style comment-padding comment-multi-line comment-auto-fill-only-comments disabled-command-function disabled-command-hook + (defun . run-octave) + (defun . org-publish-project) + show-paren-mode pc-selection-mode + (defun . pcomplete/gdb) + (defun . pcomplete/pushd) + (defun . pcomplete/time) + cvs-dired-action cvs-dired-use-hook + (defun . cvs-dired-noselect) + cvs-global-menu + (defun . edit-picture) + (defun . run-prolog) + bdf-directory-list ps-page-dimensions-database ps-paper-type ps-print-color-p quickurl-reread-hook-postfix + (defun . irc) + rcirc-track-minor-mode + (defun . regexp-builder) + recentf-mode + (defun . close-rectangle) + (defun . replace-rectangle) + global-reveal-mode rmail-dont-reply-to-names rmail-default-dont-reply-to-names rmail-ignored-headers rmail-displayed-headers rmail-retry-ignored-headers rmail-highlighted-headers rmail-primary-inbox-list rmail-secondary-file-directory rmail-secondary-file-regexp rmail-mode-hook rmail-show-message-hook rmail-file-coding-system rmail-insert-mime-forwarded-message-function rmail-user-mail-address-regexp savehist-mode scroll-all-mode mail-from-style mail-specify-envelope-from mail-self-blind mail-interactive send-mail-function mail-header-separator mail-archive-file-name mail-default-reply-to mail-alias-file mail-personal-alias-file mail-setup-hook mail-aliases mail-yank-prefix mail-indentation-spaces mail-citation-hook mail-citation-prefix-regexp mail-signature mail-signature-file mail-default-directory mail-default-headers mail-bury-selects-summary mail-send-nonascii mail-mailing-lists sendmail-coding-system default-sendmail-coding-system server-mode + (defun . xml-mode) + (defun . shell-script-mode) + shell-dumb-shell-regexp skeleton-filter-function + (defun . speedbar) + strokes-mode + (defun . t-mouse-mode) + gpm-mouse-mode table-cell-map-hook table-load-hook table-point-entered-cell-hook table-point-left-cell-hook tex-shell-file-name tex-directory tex-first-line-header-regexp tex-main-file tex-offer-save tex-run-command latex-run-command slitex-run-command tex-start-options tex-start-commands latex-block-names tex-bibtex-command tex-dvi-print-command tex-alt-dvi-print-command tex-dvi-view-command tex-show-queue-command tex-default-mode tex-open-quote tex-close-quote + (defun . TeX-mode) + (defun . plain-TeX-mode) + (defun . LaTeX-mode) + texinfo-open-quote texinfo-close-quote + (defun . thumbs) + display-time-day-and-date display-time-mode + (defun . subtract-time) + tpu-edt-mode + (defun . tpu-edt) + trace-buffer tramp-mode tramp-syntax tramp-file-name-regexp-unified tramp-file-name-regexp-separate tramp-file-name-regexp-url tramp-file-name-regexp tramp-root-regexp tramp-completion-file-name-regexp-unified tramp-completion-file-name-regexp-separate tramp-completion-file-name-regexp-url tramp-completion-file-name-regexp tramp-completion-file-name-handler-alist + (defun . tramp-run-real-handler) + (defun . tramp-completion-run-real-handler) + (defun . tramp-completion-file-name-handler) + (defun . tramp-register-file-name-handler) + (defun . tramp-register-completion-file-name-handler) + type-break-mode type-break-interval type-break-good-rest-interval type-break-good-break-interval type-break-keystroke-threshold url-handler-mode + (defun . url-http-file-readable-p) + url-https-default-port url-https-asynchronous-p + (defun . url-https-expand-file-name) + (defun . url-rlogin) + (defun . url-telnet) + (defun . url-tn3270) + url-debug + (defun . url-basepath) + vc-checkout-hook vc-checkin-hook vc-before-checkin-hook + (defun . vc-resolve-conflicts) + (defun . vc-revert-buffer) + (defun . vc-arch-registered) + vc-bzr-admin-dirname vc-bzr-admin-checkout-format-file + (defun . vc-bzr-registered) + (defun . vc-cvs-registered) + (defun . vc-git-registered) + (defun . vc-hg-registered) + vc-mtn-admin-dir vc-mtn-admin-format + (defun . vc-mtn-registered) + vc-rcs-master-templates + (defun . vc-rcs-registered) + vc-sccs-master-templates + (defun . vc-sccs-registered) + (defun . vc-sccs-search-project-dir) + (defun . vc-svn-registered) + view-remove-frame-by-deleting view-mode warning-prefix-function warning-series warning-fill-prefix warning-type-format + (defun . which-func-mode) + which-function-mode global-whitespace-mode global-whitespace-newline-mode widget-keymap winner-mode woman-locale xterm-mouse-mode + (provide . loaddefs)) + ("/usr/share/emacs/23.0.93/lisp/startup.elc" command-line-processed initial-buffer-choice inhibit-startup-screen inhibit-splash-screen inhibit-startup-message startup-screen-inhibit-startup-screen inhibit-startup-echo-area-message inhibit-default-init inhibit-startup-buffer-menu command-switch-alist command-line-args-left argv command-line-functions command-line-default-directory command-line-x-option-alist command-line-ns-option-alist before-init-hook after-init-hook emacs-startup-hook term-setup-hook inhibit-startup-hooks keyboard-type window-setup-hook initial-major-mode init-file-user site-run-file mail-host-address user-mail-address auto-save-list-file-prefix emacs-quick-startup emacs-basic-display init-file-debug init-file-had-error normal-top-level-add-subdirs-inode-list debian-emacs-flavor no-blinking-cursor pure-space-overflow pure-space-overflow-message tutorial-directory + (defun . normal-top-level-add-subdirs-to-load-path) + (defun . normal-top-level-add-to-load-path) + (defun . normal-top-level) + (defun . precompute-menubar-bindings) + tty-long-option-alist tty-long-option-alist tool-bar-images-pixel-height tool-bar-originally-present handle-args-function-alist window-system-initialization-alist + (defun . tty-handle-args) + (defun . command-line) + initial-scratch-message fancy-startup-text fancy-about-text fancy-splash-image splash-screen-keymap + (defun . fancy-splash-insert) + (defun . fancy-splash-head) + (defun . fancy-startup-tail) + (defun . exit-splash-screen) + (defun . fancy-startup-screen) + (defun . fancy-about-screen) + (defun . fancy-splash-frame) + (defun . use-fancy-splash-screens-p) + (defun . normal-splash-screen) + (defun . normal-mouse-startup-screen) + (defun . normal-no-mouse-startup-screen) + (defun . normal-about-screen) + (defun . startup-echo-area-message) + (defun . display-startup-echo-area-message) + (defun . display-startup-screen) + (defun . display-about-screen) + (defun . about-emacs) + (defun . display-splash-screen) + (defun . command-line-1) + (defun . command-line-normalize-file-name)) + ("/usr/share/emacs/23.0.93/lisp/button.elc" + (defface . button) + button-map button-buffer-map + (defun . button-category-symbol) + (defun . define-button-type) + (defun . button-type-put) + (defun . button-type-get) + (defun . button-type-subtype-p) + (defun . button-start) + (defun . button-end) + (defun . button-get) + (defun . button-put) + (defun . button-activate) + (defun . button-label) + (defun . button-type) + (defun . button-has-type-p) + (defun . make-button) + (defun . insert-button) + (defun . make-text-button) + (defun . insert-text-button) + (defun . button-at) + (defun . next-button) + (defun . previous-button) + (defun . push-button) + (defun . forward-button) + (defun . backward-button) + (provide . button)) + ("/usr/share/emacs/23.0.93/lisp/minibuffer.elc" + (defun . completion-boundaries) + (defun . completion--some) + (defun . complete-with-action) + (defun . completion-table-dynamic) + (defun . lazy-completion-table) + (defun . completion-table-with-context) + (defun . completion-table-with-terminator) + (defun . completion-table-with-predicate) + (defun . completion-table-in-turn) + (defun . complete-in-turn) + (defun . dynamic-completion-table) + (defun . minibuffer-message) + (defun . minibuffer-completion-contents) + (defun . delete-minibuffer-contents) + completion-auto-help completion-styles-alist completion-styles + (defun . completion-try-completion) + (defun . completion-all-completions) + (defun . minibuffer--bitset) + (defun . completion--do-completion) + (defun . minibuffer-complete) + completion-all-sorted-completions + (defun . completion--flush-all-sorted-completions) + (defun . completion-all-sorted-completions) + (defun . minibuffer-force-complete) + minibuffer-confirm-exit-commands + (defun . minibuffer-complete-and-exit) + (defun . completion--try-word-completion) + (defun . minibuffer-complete-word) + (defun . completion--insert-strings) + completion-common-substring completion-setup-hook + (defface . completions-first-difference) + (defface . completions-common-part) + (defun . completion-hilit-commonality) + (defun . display-completion-list) + (defun . minibuffer-completion-help) + (defun . exit-minibuffer) + (defun . self-insert-and-exit) + minibuffer-local-must-match-filename-map + (defun . minibuffer--double-dollars) + (defun . completion--make-envvar-table) + completion--embedded-envvar-re completion--embedded-envvar-re + (defun . completion--embedded-envvar-table) + (defun . completion--file-name-table) + (defun . read-file-name-internal) + read-file-name-function read-file-name-predicate read-file-name-completion-ignore-case insert-default-directory + (defun . read-file-name) + (defun . internal-complete-buffer-except) + (defun . completion-emacs21-try-completion) + (defun . completion-emacs21-all-completions) + (defun . completion-emacs22-try-completion) + (defun . completion-emacs22-all-completions) + (defun . completion--merge-suffix) + (defun . completion-basic-try-completion) + (defun . completion-basic-all-completions) + completion-pcm--delim-wild-regex + (defun . completion-pcm--prepare-delim-re) + completion-pcm-word-delimiters + (defun . completion-pcm--pattern-trivial-p) + (defun . completion-pcm--string->pattern) + (defun . completion-pcm--pattern->regex) + (defun . completion-pcm--all-completions) + (defun . completion-pcm--hilit-commonality) + (defun . completion-pcm--find-all-completions) + (defun . completion-pcm-all-completions) + (defun . completion-pcm--merge-completions) + (defun . completion-pcm--pattern->string) + (defun . completion-pcm--filename-try-filter) + (defun . completion-pcm--merge-try) + (defun . completion-pcm-try-completion) + (provide . minibuffer)) + ("/usr/share/emacs/23.0.93/lisp/faces.elc" face-name-history face-font-selection-order face-font-family-alternatives face-font-registry-alternatives + (defun . face-list) + (defun . make-face) + (defun . make-empty-face) + (defun . copy-face) + (defun . internal-find-face) + (defun . internal-get-face) + (defun . facep) + (defun . check-face) + (defun . face-id) + (defun . face-equal) + (defun . face-differs-from-default-p) + (defun . face-nontrivial-p) + face-x-resources + (defun . set-face-attribute-from-resource) + (defun . set-face-attributes-from-resources) + (defun . make-face-x-resource-internal) + (defun . face-name) + (defun . face-all-attributes) + (defun . face-attribute) + (defun . face-attribute-merged-with) + (defun . face-attribute-specified-or) + (defun . face-foreground) + (defun . face-background) + (defun . face-stipple) + (defun . face-background-pixmap) + (defun . face-underline-p) + (defun . face-inverse-video-p) + (defun . face-bold-p) + (defun . face-italic-p) + (defun . face-documentation) + (defun . set-face-documentation) + (defun . face-doc-string) + (defun . set-face-doc-string) + (defun . set-face-attribute) + (defun . make-face-bold) + (defun . make-face-unbold) + (defun . make-face-italic) + (defun . make-face-unitalic) + (defun . make-face-bold-italic) + (defun . set-face-font) + (defun . set-face-background) + (defun . set-face-foreground) + (defun . set-face-stipple) + (defun . set-face-underline-p) + (defun . set-face-underline) + (defun . set-face-inverse-video-p) + (defun . set-face-bold-p) + (defun . set-face-italic-p) + (defun . set-face-background-pixmap) + (defun . invert-face) + (defun . read-face-name) + (defun . face-valid-attribute-values) + face-attribute-name-alist + (defun . face-descriptive-attribute-name) + (defun . face-read-string) + (defun . face-read-integer) + (defun . read-face-attribute) + (defun . read-face-font) + (defun . read-all-face-attributes) + (defun . modify-face) + (defun . read-face-and-attribute) + list-faces-sample-text + (defun . list-faces-display) + (defun . describe-face) + (defun . face-attr-construct) + (defun . face-spec-set-match-display) + (defun . face-spec-choose) + (defun . face-spec-reset-face) + (defun . face-spec-set) + (defun . face-spec-recalc) + (defun . face-spec-set-2) + (defun . face-attr-match-p) + (defun . face-spec-match-p) + (defun . face-default-spec) + (defun . face-user-default-spec) + (defun . defined-colors) + (defun . x-defined-colors) + (defun . color-defined-p) + (defun . x-color-defined-p) + (defun . color-values) + (defun . x-color-values) + (defun . display-color-p) + (defun . x-display-color-p) + (defun . display-grayscale-p) + (defun . read-color) + (defun . face-at-point) + (defun . foreground-color-at-point) + (defun . background-color-at-point) + frame-background-mode inhibit-frame-set-background-mode + (defun . frame-set-background-mode) + (defun . x-handle-named-frame-geometry) + (defun . x-handle-reverse-video) + (defun . x-create-frame-with-faces) + (defun . face-set-after-frame-default) + (defun . tty-handle-reverse-video) + (defun . tty-create-frame-with-faces) + (defun . tty-find-type) + (defun . tty-run-terminal-initialization) + (defun . tty-set-up-initial-frame-faces) + (defun . frame-update-faces) + (defun . frame-update-face-colors) + (defface . default) + (defface . bold) + (defface . italic) + (defface . bold-italic) + (defface . underline) + (defface . fixed-pitch) + (defface . variable-pitch) + (defface . shadow) + (defface . link) + (defface . link-visited) + (defface . highlight) + (defface . region) + (defface . secondary-selection) + (defface . trailing-whitespace) + (defface . escape-glyph) + (defface . nobreak-space) + (defface . mode-line) + (defface . mode-line-inactive) + (defface . mode-line-highlight) + (defface . mode-line-emphasis) + (defface . mode-line-buffer-id) + (defface . header-line) + (defface . vertical-border) + (defface . minibuffer-prompt) + (defface . fringe) + (defface . scroll-bar) + (defface . border) + (defface . cursor) + (defface . mouse) + (defface . tool-bar) + (defface . menu) + x-font-regexp x-font-regexp-head x-font-regexp-weight x-font-regexp-slant x-font-regexp-weight-subnum x-font-regexp-weight-subnum x-font-regexp-slant-subnum x-font-regexp-slant-subnum x-font-regexp-swidth-subnum x-font-regexp-swidth-subnum x-font-regexp-adstyle-subnum x-font-regexp-adstyle-subnum + (defun . x-resolve-font-name) + (defun . x-frob-font-weight) + (defun . x-frob-font-slant) + (defun . internal-frob-font-weight) + (defun . internal-frob-font-slant) + (defun . x-make-font-bold) + (defun . x-make-font-demibold) + (defun . x-make-font-unbold) + (defun . x-make-font-italic) + (defun . x-make-font-oblique) + (defun . x-make-font-unitalic) + (defun . x-make-font-bold-italic) + (provide . faces)) + ("/usr/share/emacs/23.0.93/lisp/cus-face.elc" + (defun . custom-facep) + (defun . custom-declare-face) + custom-face-attributes + (defun . custom-face-attributes-get) + (defun . custom-set-faces) + (defun . custom-theme-set-faces) + (defun . custom-theme-reset-faces) + (defun . custom-reset-faces) + (provide . cus-face)) + ("/usr/share/emacs/23.0.93/lisp/files.elc" delete-auto-save-files directory-abbrev-alist make-backup-files backup-inhibited backup-by-copying backup-by-copying-when-linked backup-by-copying-when-mismatch backup-by-copying-when-privileged-mismatch backup-enable-predicate buffer-offer-save find-file-existing-other-name find-file-visit-truename revert-without-query buffer-file-number buffer-file-numbers-unique buffer-file-read-only temporary-file-directory small-temporary-file-directory null-device file-name-invalid-regexp file-precious-flag break-hardlink-on-save version-control dired-kept-versions delete-old-versions kept-old-versions kept-new-versions require-final-newline mode-require-final-newline auto-save-default auto-save-file-name-transforms save-abbrevs find-file-run-dired find-directory-functions find-file-not-found-functions find-file-not-found-hooks find-file-hooks find-file-hook write-file-functions write-file-hooks local-write-file-hooks write-contents-functions write-contents-hooks enable-local-variables local-enable-local-variables enable-local-eval view-read-only file-name-history + (defun . ange-ftp-completion-hook-function) + (defun . convert-standard-filename) + (defun . read-directory-name) + (defun . pwd) + cd-path + (defun . parse-colon-path) + (defun . cd-absolute) + (defun . cd) + (defun . load-file) + (defun . locate-file) + (defun . locate-file-completion-table) + (defun . locate-file-completion) + locate-dominating-stop-dir-regexp + (defun . locate-dominating-file) + (defun . executable-find) + (defun . load-library) + (defun . file-remote-p) + (defun . file-local-copy) + (defun . file-truename) + (defun . file-chase-links) + (defun . make-temp-file) + (defun . recode-file-name) + confirm-nonexistent-file-or-buffer + (defun . confirm-nonexistent-file-or-buffer) + (defun . read-buffer-to-switch) + (defun . switch-to-buffer-other-window) + (defun . switch-to-buffer-other-frame) + (defun . display-buffer-other-frame) + find-file-default + (defun . minibuffer-with-setup-hook) + (defun . find-file-read-args) + (defun . find-file) + (defun . find-file-other-window) + (defun . find-file-other-frame) + (defun . find-file-existing) + (defun . find-file-read-only) + (defun . find-file-read-only-other-window) + (defun . find-file-read-only-other-frame) + (defun . find-alternate-file-other-window) + (defun . find-alternate-file) + (defun . create-file-buffer) + (defun . generate-new-buffer) + automount-dir-prefix abbreviated-home-dir + (defun . abbreviate-file-name) + find-file-not-true-dirname-list + (defun . find-buffer-visiting) + find-file-wildcards find-file-suppress-same-file-warnings large-file-warning-threshold + (defun . abort-if-file-too-large) + (defun . find-file-noselect) + (defun . find-file-noselect-1) + (defun . insert-file-contents-literally) + (defun . insert-file-1) + (defun . insert-file-literally) + find-file-literally + (defun . find-file-literally) + after-find-file-from-revert-buffer + (defun . after-find-file) + (defun . report-errors) + (defun . normal-mode) + auto-mode-case-fold auto-mode-alist + (defun . conf-mode-maybe) + interpreter-mode-alist inhibit-first-line-modes-regexps inhibit-first-line-modes-suffixes auto-mode-interpreter-regexp magic-mode-alist magic-fallback-mode-alist magic-mode-regexp-match-limit + (defun . set-auto-mode) + (defun . set-auto-mode-0) + (defun . set-auto-mode-1) + ignored-local-variables hack-local-variables-hook safe-local-variable-values safe-local-eval-forms file-local-variables-alist before-hack-local-variables-hook + (defun . hack-local-variables-confirm) + (defun . hack-local-variables-prop-line) + (defun . hack-local-variables-filter) + (defun . hack-local-variables) + (defun . safe-local-variable-p) + (defun . risky-local-variable-p) + (defun . hack-one-local-variable-quotep) + (defun . hack-one-local-variable-constantp) + (defun . hack-one-local-variable-eval-safep) + (defun . hack-one-local-variable) + dir-locals-class-alist dir-locals-directory-cache + (defun . dir-locals-get-class-variables) + (defun . dir-locals-collect-mode-variables) + (defun . dir-locals-collect-variables) + (defun . dir-locals-set-directory-class) + (defun . dir-locals-set-class-variables) + dir-locals-file + (defun . dir-locals-find-file) + (defun . dir-locals-read-from-file) + (defun . hack-dir-local-variables) + change-major-mode-with-file-name + (defun . set-visited-file-name) + (defun . write-file) + (defun . backup-buffer) + (defun . backup-buffer-copy) + (defun . file-name-sans-versions) + (defun . file-ownership-preserved-p) + (defun . file-name-sans-extension) + (defun . file-name-extension) + make-backup-file-name-function backup-directory-alist + (defun . normal-backup-enable-predicate) + (defun . make-backup-file-name) + (defun . make-backup-file-name-1) + (defun . backup-file-name-p) + (defun . backup-extract-version) + (defun . find-backup-file-name) + (defun . file-nlinks) + (defun . file-relative-name) + (defun . save-buffer) + (defun . delete-auto-save-file-if-necessary) + auto-save-hook before-save-hook after-save-hook save-buffer-coding-system + (defun . basic-save-buffer) + (defun . basic-save-buffer-1) + (defun . basic-save-buffer-2) + (defun . diff-buffer-with-file) + save-some-buffers-action-alist buffer-save-without-query + (defun . save-some-buffers) + (defun . not-modified) + (defun . toggle-read-only) + (defun . insert-file) + (defun . append-to-file) + (defun . file-newest-backup) + (defun . rename-uniquely) + (defun . make-directory) + revert-buffer-function revert-buffer-insert-file-contents-function buffer-stale-function before-revert-hook after-revert-hook + (defun . revert-buffer) + (defun . recover-this-file) + (defun . recover-file) + (defun . recover-session) + (defun . recover-session-finish) + (defun . kill-buffer-ask) + (defun . kill-some-buffers) + (defun . kill-matching-buffers) + (defun . auto-save-mode) + (defun . rename-auto-save-file) + (defun . make-auto-save-file-name) + (defun . auto-save-file-name-p) + (defun . wildcard-to-regexp) + list-directory-brief-switches list-directory-verbose-switches + (defun . file-expand-wildcards) + (defun . list-directory) + (defun . shell-quote-wildcard-pattern) + insert-directory-program directory-free-space-program directory-free-space-args + (defun . get-free-disk-space) + directory-listing-before-filename-regexp insert-directory-ls-version + (defun . insert-directory) + (defun . insert-directory-adj-pos) + (defun . insert-directory-safely) + kill-emacs-query-functions confirm-kill-emacs + (defun . save-buffers-kill-emacs) + (defun . save-buffers-kill-terminal) + (defun . file-name-non-special) + (defun . file-modes-char-to-who) + (defun . file-modes-char-to-right) + (defun . file-modes-rights-to-number) + (defun . file-modes-symbolic-to-number) + (defun . read-file-modes) + trash-directory + (defun . move-file-to-trash)) + ("/usr/share/emacs/23.0.93/lisp/bindings.elc" + (defun . make-mode-line-mouse-map) + (defun . mode-line-toggle-read-only) + (defun . mode-line-toggle-modified) + (defun . mode-line-widen) + (defun . mode-line-abbrev-mode) + (defun . mode-line-auto-fill-mode) + mode-line-input-method-map mode-line-coding-system-map + (defun . mode-line-change-eol) + mode-line-eol-desc-cache + (defun . mode-line-eol-desc) + mode-line-client mode-line-mule-info + (defun . mode-line-frame-control) + mode-line-frame-identification mode-line-process mode-line-modified mode-line-remote mode-line-position mode-line-modes mode-line-mode-menu mode-line-major-mode-keymap mode-line-minor-mode-keymap mode-line-column-line-number-mode-map mode-line-buffer-identification-keymap + (defun . propertized-buffer-identification) + mode-line-buffer-identification + (defun . unbury-buffer) + (defun . mode-line-unbury-buffer) + (defun . mode-line-bury-buffer) + (defun . mode-line-other-buffer) + (defun . mode-line-next-buffer) + (defun . mode-line-previous-buffer) + (defun . bound-and-true-p) + (defun . mode-line-minor-mode-help) + minor-mode-alist + (provide . base64) + (provide . md5) + (provide . overlay) + (provide . text-properties) + (defun . complete-symbol) + narrow-map goto-map search-map + (defun . mode-specific-command-prefix) + mode-specific-map ctl-x-r-map abbrev-map) + ("/usr/share/emacs/23.0.93/lisp/format.elc" format-alist + (defun . format-encode-run-method) + (defun . format-decode-run-method) + (defun . format-annotate-function) + (defun . format-decode) + (defun . format-decode-buffer) + (defun . format-decode-region) + (defun . format-encode-buffer) + (defun . format-encode-region) + (defun . format-write-file) + (defun . format-find-file) + (defun . format-insert-file) + (defun . format-read) + (defun . format-replace-strings) + (defun . format-delq-cons) + (defun . format-make-relatively-unique) + (defun . format-common-tail) + (defun . format-proper-list-p) + (defun . format-reorder) + (defun . format-deannotate-region) + (defun . format-subtract-regions) + (defun . format-property-increment-region) + (defun . format-insert-annotations) + (defun . format-annotate-value) + (defun . format-annotate-region) + (defun . format-annotate-location) + (defun . format-annotate-single-property-change) + (defun . format-annotate-atomic-property-change) + (provide . format)) + ("/usr/share/emacs/23.0.93/lisp/env.elc" read-envvar-name-history + (defun . read-envvar-name) + setenv-history + (defun . substitute-env-vars) + (defun . setenv-internal) + (defun . setenv) + (defun . getenv) + (provide . env)) + ("/usr/share/emacs/23.0.93/lisp/international/mule-conf.el" + (defun . define-iso-single-byte-charset) + (provide . code-pages)) + ("/usr/share/emacs/23.0.93/lisp/international/mule.elc" mule-version mule-version-date private-char-area-1-min private-char-area-1-max private-char-area-2-min private-char-area-2-max emacs-mule-charset-table + (defun . convert-define-charset-argument) + (defun . define-charset) + (defun . load-with-code-conversion) + (defun . charset-info) + (defun . charset-id) + (defun . charset-bytes) + (defun . get-charset-property) + (defun . put-charset-property) + (defun . charset-description) + (defun . charset-dimension) + (defun . charset-chars) + (defun . charset-iso-final-char) + (defun . charset-short-name) + (defun . charset-long-name) + (defun . charset-list) + (defun . char-valid-p) + (defun . generic-char-p) + (defun . make-char-internal) + ascii-case-table coding-system-iso-2022-flags + (defun . define-coding-system) + (defun . coding-system-doc-string) + (defun . coding-system-mnemonic) + (defun . coding-system-type) + (defun . coding-system-charset-list) + (defun . coding-system-category) + (defun . coding-system-get) + (defun . coding-system-eol-type-mnemonic) + (defun . coding-system-lessp) + (defun . coding-system-equal) + (defun . add-to-coding-system-list) + (defun . coding-system-list) + char-coding-system-table + (defun . transform-make-coding-system-args) + (defun . make-coding-system) + (defun . merge-coding-systems) + (defun . autoload-coding-system) + buffer-file-coding-system-explicit + (defun . set-buffer-file-coding-system) + (defun . revert-buffer-with-coding-system) + (defun . set-file-name-coding-system) + default-terminal-coding-system + (defun . set-terminal-coding-system) + default-keyboard-coding-system + (defun . set-keyboard-coding-system) + keyboard-coding-system + (defun . set-buffer-process-coding-system) + (defun . set-clipboard-coding-system) + (defun . set-selection-coding-system) + last-next-selection-coding-system + (defun . set-next-selection-coding-system) + (defun . set-coding-priority) + ctext-non-standard-encodings-alist ctext-non-standard-encodings ctext-non-standard-encodings-regexp + (defun . ctext-post-read-conversion) + (defun . ctext-non-standard-encodings-table) + (defun . ctext-pre-write-conversion) + auto-coding-alist auto-coding-regexp-alist + (defun . auto-coding-regexp-alist-lookup) + auto-coding-functions set-auto-coding-for-load + (defun . auto-coding-alist-lookup) + (defun . find-auto-coding) + (defun . set-auto-coding) + (defun . after-insert-file-set-coding) + (defun . find-new-buffer-file-coding-system) + (defun . modify-coding-system-alist) + (defun . decode-coding-inserted-region) + (defun . recode-region) + (defun . make-translation-table) + (defun . make-translation-table-from-vector) + (defun . make-translation-table-from-alist) + (defun . define-translation-table) + (defun . translate-region) + (defun . with-category-table) + (defun . define-translation-hash-table) + (defun . sgml-xml-auto-coding-function) + (defun . sgml-html-meta-auto-coding-function) + (defun . xml-find-file-coding-system) + (provide . mule)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/map-ynp.elc" + (defun . map-y-or-n-p)) + ("/usr/share/emacs/23.0.93/lisp/custom.elc" + (require . widget) + custom-define-hook custom-dont-initialize custom-current-group-alist + (defun . custom-initialize-default) + (defun . custom-initialize-set) + (defun . custom-initialize-safe-set) + (defun . custom-initialize-safe-default) + (defun . custom-initialize-reset) + (defun . custom-initialize-changed) + (defun . custom-declare-variable) + (defun . defcustom) + (defun . defface) + (defun . custom-current-group) + (defun . custom-declare-group) + (defun . defgroup) + (defun . custom-add-to-group) + (defun . custom-group-of-mode) + (defun . custom-handle-all-keywords) + (defun . custom-handle-keyword) + (defun . custom-add-dependencies) + (defun . custom-add-option) + (defun . custom-add-frequent-value) + (defun . custom-add-link) + (defun . custom-add-version) + (defun . custom-add-package-version) + (defun . custom-add-load) + (defun . custom-autoload) + (defun . custom-variable-p) + (defun . custom-note-var-changed) + custom-load-recursion + (defun . custom-load-symbol) + custom-local-buffer + (defun . custom-set-default) + (defun . custom-set-minor-mode) + (defun . custom-quote) + (defun . customize-mark-to-save) + (defun . customize-mark-as-set) + (defun . custom-reevaluate-setting) + custom-known-themes + (defun . custom-theme-p) + (defun . custom-check-theme) + (defun . custom-push-theme) + (defun . custom-set-variables) + (defun . custom-theme-set-variables) + (defun . deftheme) + (defun . custom-declare-theme) + (defun . custom-make-theme-feature) + custom-theme-directory + (defun . provide-theme) + (defun . load-theme) + custom-enabling-themes + (defun . enable-theme) + custom-enabled-themes + (defun . custom-theme-enabled-p) + (defun . disable-theme) + (defun . custom-variable-theme-value) + (defun . custom-theme-recalc-variable) + (defun . custom-theme-recalc-face) + (defun . custom-theme-reset-variables) + (defun . custom-reset-variables) + read-quoted-char-radix + (provide . custom)) + ("/usr/share/emacs/23.0.93/lisp/widget.elc" + (defun . define-widget-keywords) + (defun . define-widget) + (defun . widget-plist-member) + (provide . widget)) + ("/usr/share/emacs/23.0.93/lisp/version.el" emacs-copyright emacs-version emacs-major-version emacs-minor-version emacs-build-time emacs-build-system + (defun . emacs-version) + (defun . version)) + ("/usr/share/emacs/23.0.93/lisp/subr.elc" custom-declare-variable-list + (defun . custom-declare-variable-early) + (defun . declare-function) + (defun . not) + (defun . noreturn) + (defun . 1value) + (defun . def-edebug-spec) + (defun . lambda) + (defun . push) + (defun . pop) + (defun . when) + (defun . unless) + --dolist-tail-- + (defun . dolist) + --dotimes-limit-- + (defun . dotimes) + (defun . declare) + (defun . ignore-errors) + (defun . ignore) + (defun . error) + (defun . frame-configuration-p) + (defun . functionp) + (defun . caar) + (defun . cadr) + (defun . cdar) + (defun . cddr) + (defun . last) + (defun . butlast) + (defun . nbutlast) + (defun . delete-dups) + (defun . number-sequence) + (defun . copy-tree) + (defun . assoc-default) + (defun . assoc-ignore-case) + (defun . assoc-ignore-representation) + (defun . member-ignore-case) + (defun . assq-delete-all) + (defun . rassq-delete-all) + (defun . remove) + (defun . remq) + (defun . kbd) + (defun . undefined) + (defun . suppress-keymap) + (defun . define-key-after) + (defun . map-keymap-sorted) + (defun . keymap-canonicalize) + (defun . keyboard-translate) + (defun . global-set-key) + (defun . local-set-key) + (defun . global-unset-key) + (defun . local-unset-key) + key-substitution-in-progress + (defun . substitute-key-definition) + (defun . substitute-key-definition-key) + global-map esc-map ctl-x-map ctl-x-4-map + (defun . ctl-x-4-prefix) + ctl-x-5-map + (defun . ctl-x-5-prefix) + listify-key-sequence-1 listify-key-sequence-1 + (defun . listify-key-sequence) + (defun . eventp) + (defun . event-modifiers) + (defun . event-basic-type) + (defun . mouse-movement-p) + (defun . mouse-event-p) + (defun . event-start) + (defun . event-end) + (defun . event-click-count) + (defun . posn-window) + (defun . posn-area) + (defun . posn-point) + (defun . posn-set-point) + (defun . posn-x-y) + (defun . posn-col-row) + (defun . posn-actual-col-row) + (defun . posn-timestamp) + (defun . posn-string) + (defun . posn-image) + (defun . posn-object) + (defun . posn-object-x-y) + (defun . posn-object-width-height) + (defun . window-dot) + (defun . set-window-dot) + (defun . read-input) + (defun . show-buffer) + (defun . eval-current-buffer) + (defun . string-to-int) + (defun . insert-string) + (defun . makehash) + (defun . baud-rate) + (defun . focus-frame) + (defun . unfocus-frame) + executing-macro x-lost-selection-hooks x-sent-selection-hooks messages-buffer-max-lines last-input-char last-command-char + (defun . send-string) + (defun . send-region) + (defun . string=) + (defun . string<) + (defun . move-marker) + (defun . rplaca) + (defun . rplacd) + (defun . beep) + (defun . indent-to-column) + (defun . backward-delete-char) + (defun . search-forward-regexp) + (defun . search-backward-regexp) + (defun . int-to-string) + (defun . store-match-data) + (defun . chmod) + (defun . mkdir) + (defun . point-at-eol) + (defun . point-at-bol) + (defun . user-original-login-name) + (defun . make-local-hook) + (defun . add-hook) + (defun . remove-hook) + (defun . add-to-list) + (defun . add-to-ordered-list) + (defun . add-to-history) + delay-mode-hooks delayed-mode-hooks after-change-major-mode-hook + (defun . run-mode-hooks) + (defun . delay-mode-hooks) + (defun . derived-mode-p) + minor-mode-list + (defun . add-minor-mode) + (defun . symbol-file) + (defun . locate-library) + (defun . eval-at-startup) + (defun . load-history-regexp) + (defun . load-history-filename-element) + (defun . eval-after-load) + (defun . do-after-load-evaluation) + (defun . eval-next-after-load) + (defun . process-lines) + (defun . open-network-stream) + (defun . process-kill-without-query) + (defun . process-get) + (defun . process-put) + read-quoted-char-radix + (defun . read-quoted-char) + (defun . read-passwd) + (defun . read-number) + (defun . sit-for) + (defun . atomic-change-group) + (defun . prepare-change-group) + (defun . activate-change-group) + (defun . accept-change-group) + (defun . cancel-change-group) + (defun . redraw-modeline) + (defun . force-mode-line-update) + (defun . momentary-string-display) + (defun . copy-overlay) + (defun . remove-overlays) + suspend-hook suspend-resume-hook temp-buffer-show-hook temp-buffer-setup-hook buffer-file-type user-emacs-directory + (defun . locate-user-emacs-file) + (defun . find-tag-default) + (defun . play-sound) + (defun . shell-quote-argument) + (defun . string-or-null-p) + (defun . booleanp) + (defun . field-at-pos) + (defun . remove-yank-excluded-properties) + (defun . insert-for-yank) + (defun . insert-for-yank-1) + (defun . insert-buffer-substring-no-properties) + (defun . insert-buffer-substring-as-yank) + (defun . start-process-shell-command) + (defun . start-file-process-shell-command) + (defun . call-process-shell-command) + (defun . process-file-shell-command) + (defun . with-current-buffer) + (defun . with-selected-window) + (defun . with-selected-frame) + (defun . with-temp-file) + (defun . with-temp-message) + (defun . with-temp-buffer) + (defun . with-output-to-string) + (defun . with-local-quit) + (defun . while-no-input) + (defun . condition-case-no-debug) + (defun . with-demoted-errors) + (defun . combine-after-change-calls) + (defun . with-case-table) + (defun . save-match-data) + (defun . match-string) + (defun . match-string-no-properties) + (defun . match-substitute-replacement) + (defun . looking-back) + (defun . looking-at-p) + (defun . string-match-p) + (defun . subregexp-context-p) + split-string-default-separators + (defun . split-string) + (defun . combine-and-quote-strings) + (defun . split-string-and-unquote) + (defun . subst-char-in-string) + (defun . replace-regexp-in-string) + (defun . add-to-invisibility-spec) + (defun . remove-from-invisibility-spec) + (defun . with-syntax-table) + (defun . make-syntax-table) + (defun . syntax-after) + (defun . syntax-class) + (defun . text-clone-maintain) + (defun . text-clone-create) + (defun . define-mail-user-agent) + (defun . progress-reporter-update) + (defun . make-progress-reporter) + (defun . progress-reporter-force-update) + (defun . progress-reporter-do-update) + (defun . progress-reporter-done) + (defun . dotimes-with-progress-reporter) + version-separator version-regexp-alist + (defun . version-to-list) + (defun . version-list-<) + (defun . version-list-=) + (defun . version-list-<=) + (defun . version-list-not-zero) + (defun . version<) + (defun . version<=) + (defun . version=)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/backquote.elc" + (provide . backquote) + (defun . backquote-list*-function) + (defun . backquote-list*-macro) + (defun . backquote-list*) + backquote-backquote-symbol backquote-unquote-symbol backquote-splice-symbol + (defun . backquote) + (defun . \`) + (defun . backquote-delay-process) + (defun . backquote-process) + (defun . backquote-listify)) + ("/usr/share/emacs/23.0.93/lisp/emacs-lisp/byte-run.elc" + (defun . macro-declaration-function) + (defun . defsubst) + (defun . make-obsolete) + (defun . define-obsolete-function-alias) + (defun . make-obsolete-variable) + (defun . define-obsolete-variable-alias) + (defun . dont-compile) + (defun . eval-when-compile) + (defun . eval-and-compile) + (defun . with-no-warnings))) diff --git a/emacs/nxhtml/tests/in/bug370417.php b/emacs/nxhtml/tests/in/bug370417.php new file mode 100644 index 0000000..b73534d --- /dev/null +++ b/emacs/nxhtml/tests/in/bug370417.php @@ -0,0 +1,10 @@ +<html> + <body> + <p> + <?php + echo "foo"; +echo "bar"; + ?> + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/bug381979-2-bad-traceb.txt b/emacs/nxhtml/tests/in/bug381979-2-bad-traceb.txt new file mode 100644 index 0000000..514b00a --- /dev/null +++ b/emacs/nxhtml/tests/in/bug381979-2-bad-traceb.txt @@ -0,0 +1,24 @@ +Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p nil) + <(1 nil) + (and mumamo-last-new-chunk first-check-from (< first-check-from (overlay-end mumamo-last-new-chunk))) + (if (and mumamo-last-new-chunk first-check-from (< first-check-from ...)) (progn (setq mumamo-last-new-chunk ...))) + (when (and mumamo-last-new-chunk first-check-from (< first-check-from ...)) (setq mumamo-last-new-chunk (overlay-get mumamo-last-new-chunk ...))) + (progn (setq mumamo-last-new-chunk (overlay-get new-chunk-at-change-min ...)) (when (and mumamo-last-new-chunk first-check-from ...) (setq mumamo-last-new-chunk ...))) + (if new-chunk-at-change-min (progn (setq mumamo-last-new-chunk ...) (when ... ...))) + (when new-chunk-at-change-min (setq mumamo-last-new-chunk (overlay-get new-chunk-at-change-min ...)) (when (and mumamo-last-new-chunk first-check-from ...) (setq mumamo-last-new-chunk ...))) + (progn (when new-chunk-at-change-min (setq mumamo-last-new-chunk ...) (when ... ...))) + (if (mumamo-make-new-chunks) (progn (when new-chunk-at-change-min ... ...))) + (when (mumamo-make-new-chunks) (when new-chunk-at-change-min (setq mumamo-last-new-chunk ...) (when ... ...))) + (progn (when (mumamo-make-new-chunks) (when new-chunk-at-change-min ... ...)) (setq mumamo-last-chunk-change-pos nil)) + (if mumamo-last-chunk-change-pos (progn (when ... ...) (setq mumamo-last-chunk-change-pos nil))) + (when mumamo-last-chunk-change-pos (when (mumamo-make-new-chunks) (when new-chunk-at-change-min ... ...)) (setq mumamo-last-chunk-change-pos nil)) + (let* ((change-min ...) (change-max ...) (new-chunk-at-change-min ...) (new-chunk-at-change-min-start ...) (this-new-syntax-min-max ...) (this-new-syntax-min ...) (in-new-min-border ...) (here ...) (first-check-from ...)) (when mumamo-last-chunk-change-pos (when ... ...) (setq mumamo-last-chunk-change-pos nil)) (let* (... ... ... ... narpos this-new-values this-new-chunk prev-new-chunk first-change-pos interrupted ... ... ... ... ...) (when ... ...) (unless this-new-chunk ...) (setq mumamo-find-chunks-level ...) (when this-new-chunk ... ...) (when end-param ...))) + (save-restriction (widen) (let* (... ... ... ... ... ... ... ... ...) (when mumamo-last-chunk-change-pos ... ...) (let* ... ... ... ... ... ...))) + mumamo-find-chunks(1 "mumamo-set-major-post-command") + (let* ((ovl ...) (major ...) (in-pre-hook ...)) (if (not major) (lwarn ... :error "major=%s" major) (unless ... ...))) + mumamo-set-major-post-command() + (if font-lock-mode (mumamo-set-major-post-command)) + mumamo-post-command-1() + eval((mumamo-post-command-1)) + eval-expression((mumamo-post-command-1) nil) + call-interactively(eval-expression nil nil) diff --git a/emacs/nxhtml/tests/in/bug381979-2.php b/emacs/nxhtml/tests/in/bug381979-2.php new file mode 100644 index 0000000..fc543c5 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug381979-2.php @@ -0,0 +1,6 @@ +<?php +$a = array( + 'foo' => 'bar', + 'gaz' => 'gazonk', +); +?> \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug381979-svnlib.inc b/emacs/nxhtml/tests/in/bug381979-svnlib.inc new file mode 100644 index 0000000..6fc755b --- /dev/null +++ b/emacs/nxhtml/tests/in/bug381979-svnlib.inc @@ -0,0 +1,744 @@ +<?php +// $Id$ +/** + * @file + * A few generic functions for interfacing with Subversion via command line. + * The API of these functions has been inspired by the SVN PECL extension + * (http://www.php.net/manual/en/ref.svn.php), but works differently in places. + * On the one hand, this is due to the incompleteness of the functions in here, + * and on the other hand there are a few artificial restrictions and + * complications in the PECL extension's API that we can really do without. + * + * @note + * These functions can be run *without* Drupal. + * + * Copyright 2008 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020) + * Copyright 2006-2008 by Gavin Mogan ("halkeye", http://drupal.org/user/56779) + */ + +// file_directory_temp() is normally provided by Drupal, but as this file is +// supposed to be independent from Drupal code, here's a fallback definition. +if (!function_exists('file_directory_temp')) { + /** + * Determine the default temporary directory. + * + * @return A string containing a temp directory. + */ + function file_directory_temp() { + return sys_get_temp_dir(); + } +} + +/** + * If subsequent function calls from this file act on a private repository + * that requires authentication, this function will store username and password + * for the duration of the current process (in a static variable, that is). + * Other functions in this file make use of this login information. + */ +function svnlib_set_authentication_info($username, $password) { + _svnlib_authentication_info( + array('username' => $username, 'password' => $password) + ); +} + +/** + * Unset any username and password that was previously passed + * to subversion_set_authentication_info(), so that subsequent repository + * access will happen anonymously again. + */ +function svnlib_unset_authentication_info() { + _svnlib_authentication_info(FALSE); +} + +/** + * Append the option for our custom config dir to a $cmd array, + * and also username and password if those have been set before. + */ +function _svnlib_add_common_options(&$cmd) { + $auth_info = _svnlib_authentication_info(); + if (isset($auth_info)) { + $cmd = array_merge($cmd, array( + '--username', escapeshellarg($auth_info['username']), + '--password', escapeshellarg($auth_info['password']), + )); + } + $cmd[] = '--config-dir '. escapeshellarg(dirname(__FILE__) .'/configdir'); +} + +/** + * Write or retrieve the authentication info state, stored in a static variable. + * + * @param $info + * NULL to retrieve the info, FALSE to unset it, or an array with array keys + * 'username' and 'password' to remember it for later retrieval. + */ +function _svnlib_authentication_info($info = NULL) { + static $auth_info = NULL; + + if (!isset($info)) { + return $auth_info; + } + else { + $auth_info = ($info === FALSE) ? NULL : $info; + return $auth_info; + } +} + +/** + * By default, Subversion will be invoked with the 'svn' binary which is + * alright as long as the binary is in the PATH. If it's not, you can call + * this function to set a different path to the binary (which will be used + * until this process finishes, or until a new path is set). + */ +function svnlib_set_svn_binary($svn_binary) { + _svnlib_svn_binary($svn_binary); +} + +/** + * Write or retrieve the path of the svn binary, stored in a static variable. + * + * @param $svn_binary + * NULL to retrieve the info, or the path to the binary to remember it + * for later retrieval. + */ +function _svnlib_svn_binary($svn_binary = NULL) { + static $binary = 'svn'; + + if (!isset($svn_binary)) { + return $binary; + } + $binary = $svn_binary; + return $binary; +} + +/** + * Retrieve the version of the svn binary, and return an array with the keys + * 'major', 'minor' and 'patch', each containing the integer for the respective + * part of the version number. If invoking the SVN executable fails, an empty + * array is returned. + */ +function svnlib_version() { + static $version; + + if (isset($version)) { + return $version; + } + $return_code = 0; + exec(_svnlib_svn_binary() .' --version', $output, $return_code); + + if ($return_code != 0) { + $version = array(); + return $version; + } + $line = reset($output); // The first line contains the version number. + + if (!preg_match('/\b([\d]+)\.([\d]+)(?:\.([\d]+))?/', $line, $matches)) { + $version = array(); + return $version; + } + $version = array( + 'major' => (int) $matches[1], + 'minor' => (int) $matches[2], + 'patch' => empty($matches[3]) ? 0 : (int) $matches[3], + ); + return $version; +} + +/** + * Append an appropriate output pipe to a $cmd array, which causes STDERR + * to be written to a random file. + * + * @return + * An array with the temporary files that will be created when $cmd + * is executed. In its current form, the return array only contains + * the filename for STDERR output as 'stderr' array element. + */ +function _svnlib_add_output_pipes(&$cmd) { + $tempdir = file_directory_temp(); + $tempfiles = array( + 'stderr' => $tempdir .'/drupal_versioncontrol_svn.stderr.'. mt_rand() .'.txt', + ); + $cmd[] = '2> '. $tempfiles['stderr']; + return $tempfiles; +} + +/** + * Delete temporary files that have been created by a command which included + * output pipes from _svnlib_add_output_pipes(). + */ +function _svnlib_delete_temporary_files($tempfiles) { + @unlink($tempfiles['stderr']); +} + +/** + * Read the STDERR output for a command that was executed. + * The output must have been written to a temporary file which was given + * by _svnlib_add_output_pipes(). The temporary file is deleted after it + * has been read. After calling the function, the error message can be + * retrieved by calling svnlib_last_error_message() or discarded by calling + * svnlib_unset_error_message(). + */ +function _svnlib_set_error_message($tempfiles) { + _svnlib_error_message(file_get_contents($tempfiles['stderr'])); + @unlink($tempfiles['stderr']); +} + +/** + * Retrieve the STDERR output from the last invocation of 'svn' that exited + * with a non-zero status code. After fetching the error message, it will be + * unset again until a subsequent 'svn' invocation fails as well. If no message + * is set, this function returns NULL. + * + * For better security, it is advisable to run the returned error message + * through check_plain() or similar string checker functions. + */ +function svnlib_last_error_message() { + $message = _svnlib_error_message(); + _svnlib_error_message(FALSE); + return $message; +} + +/** + * Write or retrieve an error message, stored in a static variable. + * + * @param $info + * NULL to retrieve the message, FALSE to unset it, or a string containing + * the new message to remember it for later retrieval. + */ +function _svnlib_error_message($message = NULL) { + static $error_message = NULL; + + if (!isset($message)) { + return $error_message; + } + else { + $error_message = ($message === FALSE) ? NULL : $message; + return $error_message; + } +} + +/** + * Return commit log messages of a repository URL. This function is equivalent + * to 'svn log -v -r $revision_range $repository_url'. + * + * @param $repository_url + * The URL of the repository (e.g. 'file:///svnroot/my-repo') or an item + * inside that repository (e.g. 'file:///svnroot/my-repo/subdir/hello.php'). + * @param $revision_range + * The revision specification that will be passed to 'svn log' as the + * '-r' parameter. Examples: '35' for a specific revision, 'HEAD:35' for all + * revisions since (and including) r35, or the default parameter 'HEAD:1' + * for all revisions of the given URL. If you specify the more recent + * revision first (e.g. 'HEAD:1') then it will also be first in the + * result array, whereas if you specify the older revision first ('1:HEAD') + * then you'll get a result array with an ascending sort, the most + * recent revision being the last array element. + * @param $url_revision + * The revision of the URL that should be listed. + * This needs to be a single revision, e.g. '35' or 'HEAD'. + * For example, if a file was deleted in revision 36, you need to pass '35' + * as parameter to get its log, otherwise Subversion won't find the file. + * + * @return + * An array of detailed information about the revisions that exist + * in the given URL at the specified revision or revision range. + * Each revision detail array has the revision number as array key. + * If the 'svn log' invocation exited with an error, this function + * returns NULL and the error message can be retrieved by calling + * svnlib_last_error_message(). + */ +function svnlib_log($repository_url, $revision_range = 'HEAD:1', $url_revision = 'HEAD') { + $cmd = array( + escapeshellarg(escapeshellcmd(_svnlib_svn_binary())), + 'log', + '-r', $revision_range, + '--non-interactive', + '--xml', + '-v', + ); + _svnlib_add_common_options($cmd); + $cmd[] = escapeshellarg($repository_url .'@'. $url_revision); + $tempfiles = _svnlib_add_output_pipes($cmd); + + $return_code = 0; + exec(implode(' ', $cmd), $output, $return_code); + if ($return_code != 0) { + _svnlib_set_error_message($tempfiles); + return NULL; // no such revision(s) found + } + $log = implode("\n", $output); + _svnlib_delete_temporary_files($tempfiles); + + return _svnlib_parse_log($log); +} + +/* + * Parse the output of 'svn log' into an array of log entries. + * The output looks something like this (0 to N possible "logentry" elements): +<?xml version="1.0"?> +<log> + <logentry revision="272"> + <author>jpetso</author> + <date>2007-04-12T15:01:00.247137Z</date> + <paths> + <path action="M">/trunk/lila/kde/scalable/apps/ktorrent.svg</path> + <path action="A">/trunk/lila/kde/scalable/devices/laptop.svg</path> + <path copyfrom-path="/trunk/lila/kde/scalable/devices/pda_black.svg" + copyfrom-rev="270" + action="A">/trunk/lila/kde/scalable/devices/pda_blue.svg</path> + <path action="R">/trunk/lila/kde/scalable/devices/ipod_unmount.svg</path> + <path action="D">/trunk/lila/kde/ChangeLog</path> + </paths> + <msg>New laptop icon from the GNOME set, more moderate + colors in ktorrent.svg, and bits of devices stuff. + </msg> + </logentry> +</log> +*/ +function _svnlib_parse_log($log) { + $revisions = array(); + $xml = new SimpleXMLElement($log); + + foreach ($xml->logentry as $logentry) { + $revision = array(); + $revision['rev'] = intval((string) $logentry['revision']); + $revision['author'] = (string) $logentry->author; + $revision['msg'] = rtrim((string) $logentry->msg); // no trailing linebreaks + $revision['time_t'] = strtotime((string) $logentry->date); + $paths = array(); + + foreach ($logentry->paths->path as $logpath) { + $path = array( + 'path' => (string) $logpath, + 'action' => (string) $logpath['action'], + ); + if (!empty($logpath['copyfrom-path'])) { + $path['copyfrom'] = array( + 'path' => (string) $logpath['copyfrom-path'], + 'rev' => (string) $logpath['copyfrom-rev'], + ); + } + $paths[$path['path']] = $path; + } + $revision['paths'] = $paths; + $revisions[$revision['rev']] = $revision; + } + return $revisions; +} + +/** + * Return the contents of a directory (specified as repository URL, + * optionally at a certain revision) as an array of items. This function + * is equivalent to 'svn ls $repository_url@$revision'. + * + * @param $repository_url + * The URL of the repository (e.g. 'file:///svnroot/my-repo') or an item + * inside that repository (e.g. 'file:///svnroot/my-repo/subdir'). + * @param $url_revision + * The revision of the URL that should be listed. + * This needs to be a single revision, e.g. '35' or 'HEAD'. + * For example, if a file was deleted in revision 36, you need to pass '35' + * as parameter to get its listing, otherwise Subversion won't find the file. + * @param $recursive + * FALSE to retrieve just the direct child items of the current directory, + * or TRUE to descend into each subdirectory and retrieve all descendant + * items recursively. If $recursive is true then each directory item + * in the result array will have an additional array element 'children' + * which contains the list entries below this directory, as array keys + * in the result array. + * + * If @p $repository_url refers to a file then the @p $recursive parameter + * has no effect on the 'svn ls' output and, by consequence, on the + * return value. + * + * @return + * A array of items. If @p $repository_url refers to a file then the array + * contains a single entry with this file, whereas if @p $repository_url + * refers to a directory then the array contains all items inside this + * directory (but not the directory itself). + * If the 'svn ls' invocation exited with an error, this function + * returns NULL and the error message can be retrieved by calling + * svnlib_last_error_message(). + */ +function svnlib_ls($repository_url, $url_revision = 'HEAD', $recursive = FALSE) { + $cmd = array( + escapeshellarg(escapeshellcmd(_svnlib_svn_binary())), + 'ls', + '--non-interactive', + '--xml', + ); + if ($recursive) { + $cmd[] = '-R'; + } + _svnlib_add_common_options($cmd); + $cmd[] = escapeshellarg($repository_url .'@'. $url_revision); + $tempfiles = _svnlib_add_output_pipes($cmd); + + $return_code = 0; + exec(implode(' ', $cmd), $output, $return_code); + if ($return_code != 0) { + _svnlib_set_error_message($tempfiles); + return NULL; // no such item or revision found + } + $lists = implode("\n", $output); + _svnlib_delete_temporary_files($tempfiles); + + return _svnlib_parse_ls($lists, $recursive); +} + +/* + * Parse the output of 'svn ls' into an array of item entries. + * The output looks something like this (0 to N possible "entry" elements): +<?xml version="1.0"?> +<lists> + <list path="file:///home/jakob/repos/svn/lila-theme/tags/svg-utils-0-1/utils/svg-utils/svgcolor-xml"> + <entry kind="dir"> + <name>lila</name> + <commit revision="257"> + <author>jpetso</author> + <date>2006-11-29T01:27:47.192716Z</date> + </commit> + </entry> + <entry kind="file"> + <name>lila/lila-blue.xml</name> + <size>918</size> + <commit revision="9"> + <author>dgt84</author> + <date>2004-05-04T21:32:13.000000Z</date> + </commit> + </entry> + </list> +</lists> +*/ +function _svnlib_parse_ls($lists, $recursive) { + $items = array(); + $current_item_stack = array(); // will help us determine hierarchical structures + $xml = new SimpleXMLElement($lists); + + foreach ($xml->list->entry as $entry) { + $item = array(); + $item['created_rev'] = intval((string) $entry->commit['revision']); + $item['last_author'] = (string) $entry->commit->author; + $item['time_t'] = strtotime((string) $entry->commit->date); + $relative_path = (string) $entry->name; + $item['name'] = basename($relative_path); + $item['type'] = (string) $entry['kind']; + + if ($item['type'] == 'file') { + $item['size'] = intval((string) $entry->size); + } + + // When listing recursively, we want to capture the item hierarchy. + if ($recursive) { + if ($item['type'] == 'dir') { + $item['children'] = array(); + } + if (strpos($relative_path, '/') !== FALSE) { // don't regard top-level items + $parent_path = dirname($relative_path); + if (isset($items[$parent_path]) && !in_array($relative_path, $items[$parent_path]['children'])) { + $items[$parent_path]['children'][] = $relative_path; + } + } + } + $items[$relative_path] = $item; + } + return $items; +} + +/** + * Returns detail information about a directory or file item in the repository. + * In most cases, svnlib_info() is the better svnlib_ls(), as it retrieves not + * only item names but also repository root and the path of each item + * inside the repository. + * + * You can also use svnlib_info() to retrieve a former item path if the item + * has been moved or copied: just pass the current URL and revision together + * with a past or future revision number as @p $target_revision, and you get + * the path of the item at that time. + * + * This function is equivalent to + * 'svn info -r $target_revision $repository_url@$url_revision'. + * + * @param $repository_urls + * The URL of the item (e.g. 'file:///svnroot/my-repo/subdir/hello.php') + * or the repository itself (e.g. 'file:///svnroot/my-repo'), as string. + * Alternatively, you can also pass an array of multiple URLs. + * @param $url_revision + * The revision of the URL that should be listed. + * This needs to be a single revision, e.g. '35' or 'HEAD'. + * For example, if a file was deleted in revision 36, you need to pass '35' + * as parameter to get its info, otherwise Subversion won't find the file. + * In case multiple URLs are passed, this revision applies to each of them. + * @param $depth + * Specifies if info for descendant items should be retrieved as well, and + * if so, which of those. The default 'empty' will not retrieve any children, + * 'files' will retrieve all immediate file children, 'immediates' will + * retrieve file and directory children, and 'infinity' will retrieve all + * descendant items there are, recursively. If $depth is 'infinity' then each + * directory item in the result array will have an additional array element + * named 'children' which contains the paths below this directory, the paths + * corresponding to array keys in the result array. + * + * If @p $repository_url refers to a file then the @p $depth parameter + * has no effect on the 'svn info' output and, by consequence, on the + * return value. + * + * @param $target_revision + * The revision specification that will be passed to 'svn info' as the + * '-r' parameter. This needs to be a single revision, e.g. '35' or 'HEAD'. + * This is handy to track item copies and renames, see the general function + * description on how to do that. If you leave this at NULL, the info will be + * retrieved at the state of the $url_revision. + * + * @return + * A array of items that contain information about the items that correspond + * the specified URL(s). If @p $repository_url refers to a directory and + * @p $depth is 'infinity', the array also includes information about all + * descendants of the items that correspond to the specified URL(s). + * If the 'svn info' invocation exited with an error, this function + * returns NULL and the error message can be retrieved by calling + * svnlib_last_error_message(). + */ +function svnlib_info($repository_urls, $url_revision = 'HEAD', $depth = 'empty', $target_revision = NULL) { + if (!is_array($repository_urls)) { // it's a single URL as a string! + $repository_urls = array($repository_urls); + } + + $cmd = array( + escapeshellarg(escapeshellcmd(_svnlib_svn_binary())), + 'info', + '--non-interactive', + '--xml', + ); + + if ($depth == 'infinity') { + $cmd[] = '-R'; // "--depth infinity" is not in 1.4, but '-R' (recursive) is + } + elseif ($depth != 'empty') { + $version = svnlib_version(); + if ($version['major'] >= 1 && $version['minor'] >= 5) { + $cmd[] = '--depth '. $depth; + } + else { // 1.4 and earlier compatibility workaround + foreach ($repository_urls as $repository_url) { + // Make sure the item is a directory, otherwise it has no children + // anyways (and the relative path fetched by ls will lead to incorrect + // results as it duplicates the basename that is already in the URL). + $repository_url_items = svnlib_info($repository_url, $url_revision, 'empty', $target_revision); + $repository_url_item = reset($repository_url_items); + if ($repository_url_item['type'] != 'dir') { + continue; + } + // Fetch child items with svn ls, that's what 1.4 can actually do. + $items = svnlib_ls($repository_url, $url_revision); + foreach ($items as $relative_path => $item) { + if ($depth == 'files' && $item['type'] = 'dir') { + continue; // 'immediates' fetches all children, 'files' only files + } + $repository_urls[] = $repository_url .'/'. $relative_path; + } + } + } + } + // else { + // "--depth empty" is the default, leave it out for svn <= 1.4 compatibility + // } + + if (isset($target_revision)) { + $cmd[] = '-r'; + $cmd[] = $target_revision; + } + _svnlib_add_common_options($cmd); + foreach ($repository_urls as $repository_url) { + $cmd[] = escapeshellarg($repository_url .'@'. $url_revision); + } + $tempfiles = _svnlib_add_output_pipes($cmd); + + $return_code = 0; + exec(implode(' ', $cmd), $output, $return_code); + if ($return_code != 0) { + _svnlib_set_error_message($tempfiles); + return NULL; // no such item or revision found + } + $info = implode("\n", $output); + _svnlib_delete_temporary_files($tempfiles); + + $recursive = ($depth == 'infinity'); + return _svnlib_parse_info($info, $recursive); +} + +/* + * Parse the output of 'svn info' into an array of item entries. + * The output looks something like this (same URL as in the 'svn ls' example, + * also 0 to N possible "entry" elements): +<?xml version="1.0"?> +<info> + <entry kind="dir" path="svgcolor-xml" revision="275"> + <url>file:///home/jakob/repos/svn/lila-theme/tags/svg-utils-0-1/utils/svg-utils/svgcolor-xml</url> + <repository> + <root>file:///home/jakob/repos/svn/lila-theme</root> + <uuid>fd53868f-e4f1-0310-84ca-8663aff3ef64</uuid> + </repository> + <commit revision="257"> + <author>jpetso</author> + <date>2006-11-29T01:27:47.192716Z</date> + </commit> + </entry> + <entry kind="dir" path="lila" revision="275"> + <url>file:///home/jakob/repos/svn/lila-theme/tags/svg-utils-0-1/utils/svg-utils/svgcolor-xml/lila</url> + <repository> + <root>file:///home/jakob/repos/svn/lila-theme</root> + <uuid>fd53868f-e4f1-0310-84ca-8663aff3ef64</uuid> + </repository> + <commit revision="257"> + <author>jpetso</author> + <date>2006-11-29T01:27:47.192716Z</date> + </commit> + </entry> + <entry kind="file" path="lila/lila-blue.xml" revision="275"> + <url>file:///home/jakob/repos/svn/lila-theme/tags/svg-utils-0-1/utils/svg-utils/svgcolor-xml/lila/lila-blue.xml</url> + <repository> + <root>file:///home/jakob/repos/svn/lila-theme</root> + <uuid>fd53868f-e4f1-0310-84ca-8663aff3ef64</uuid> + </repository> + <commit revision="9"> + <author>dgt84</author> + <date>2004-05-04T21:32:13.000000Z</date> + </commit> + </entry> +</info> +*/ +function _svnlib_parse_info($info, $recursive) { + $items = array(); + $xml = new SimpleXMLElement($info); + + foreach ($xml->entry as $entry) { + $item = array(); + $item['url'] = (string) $entry->url; + $item['repository_root'] = (string) $entry->repository->root; + $item['repository_uuid'] = (string) $entry->repository->uuid; + + if ($item['url'] == $item['repository_root']) { + $item['path'] = '/'; + } + else { + $item['path'] = substr($item['url'], strlen($item['repository_root'])); + } + + if (isset($items[$item['path']])) { + // Duplicate item, we had this one before already. Nevertheless, we can + // perhaps make use of it in order to enhance the hierarchical structure. + $item = $items[$item['path']]; + } + else { + $item['type'] = (string) $entry['kind']; + $relative_path = (string) $entry['path']; + $item['rev'] = intval((string) $entry['revision']); // current state of the item + $item['created_rev'] = intval((string) $entry->commit['revision']); // last edit + $item['last_author'] = (string) $entry->commit->author; + $item['time_t'] = strtotime((string) $entry->commit->date); + + if ($recursive && $item['type'] == 'dir') { + $item['children'] = array(); + } + } + + // For "--depth infinity", provide the caller with further hierarchy info. + if ($recursive && $item['path'] != '/') { + $parent_path = dirname($item['path']); + if (isset($items[$parent_path]) && !in_array($item['path'], $items[$parent_path]['children'])) { + $items[$parent_path]['children'][] = $item['path']; + } + } + $items[$item['path']] = $item; + } + return $items; +} + + +/** + * Copy the contents of a file in a repository to a given destination. + * This function is equivalent to + * 'svn cat $repository_url@$url_revision > $destination'. + * + * @param $destination + * The path of the file that should afterwards contain the file contents. + * @param $repository_url + * The URL of the file, e.g. 'file:///svnroot/my-repo/subdir/hello.php'. + * @param $url_revision + * The revision of the URL that should be queried for the property. + * This needs to be a single revision, e.g. '35' or 'HEAD'. + * + * @return + * TRUE if the file was created successfully. If the 'svn cat' invocation + * exited with an error, this function returns FALSE and the error message + * can be retrieved by calling svnlib_last_error_message(). + */ +function svnlib_cat($destination, $repository_url, $url_revision = 'HEAD') { + $cmd = array( + escapeshellarg(escapeshellcmd(_svnlib_svn_binary())), + 'cat', + '--non-interactive', + ); + _svnlib_add_common_options($cmd); + $cmd[] = escapeshellarg($repository_url .'@'. $url_revision); + $cmd[] = '> '. $destination; + $tempfiles = _svnlib_add_output_pipes($cmd); + + $return_code = 0; + exec(implode(' ', $cmd), $output, $return_code); + if ($return_code != 0) { + @unlink($destination); + _svnlib_set_error_message($tempfiles); + return FALSE; // no such item or revision found + } + _svnlib_delete_temporary_files($tempfiles); + return TRUE; +} + +/** + * Return a specific SVN property of the given file or directory in the + * repository. This function is equivalent to + * 'svn propget $property_name $repository_url@$url_revision'. + * + * @param $property_name + * The name of the property, e.g. 'svn:mime-type' or 'svn:executable'. + * @param $repository_url + * The URL of the item (e.g. 'file:///svnroot/my-repo/subdir/hello.php') + * or the repository itself (e.g. 'file:///svnroot/my-repo'), as string. + * @param $url_revision + * The revision of the URL that should be queried for the property. + * This needs to be a single revision, e.g. '35' or 'HEAD'. + * + * @return + * A string containing the specified property for the item in the given + * revision, an empty string if this property is not set. If the + * 'svn propget' invocation exited with an error, this function + * returns NULL and the error message can be retrieved by calling + * svnlib_last_error_message(). + */ +function svnlib_propget($property_name, $repository_url, $url_revision = 'HEAD') { + $cmd = array( + escapeshellarg(escapeshellcmd(_svnlib_svn_binary())), + 'propget', + $property_name, + '--non-interactive', + ); + _svnlib_add_common_options($cmd); + $cmd[] = escapeshellarg($repository_url .'@'. $url_revision); + $tempfiles = _svnlib_add_output_pipes($cmd); + + $return_code = 0; + exec(implode(' ', $cmd), $output, $return_code); + if ($return_code != 0) { + _svnlib_set_error_message($tempfiles); + return NULL; // no such item or revision found + } + $property = trim(implode('', $output)); + _svnlib_delete_temporary_files($tempfiles); + + if (empty($property)) { + return ''; + } + return $property; +} diff --git a/emacs/nxhtml/tests/in/bug384115-bt2.txt b/emacs/nxhtml/tests/in/bug384115-bt2.txt new file mode 100644 index 0000000..0fc787d --- /dev/null +++ b/emacs/nxhtml/tests/in/bug384115-bt2.txt @@ -0,0 +1,11 @@ +Debugger entered--Lisp error: (file-error "Cannot open load file" "../../../../../../elisp/package.d/nxhtml/nxhtml/nxhtml-menu") + (nxhtml-global-minor-mode 1) + (let* ((util-dir ...) (related-dir ...) (nxhtml-dir ...)) (add-to-list (quote load-path) nxhtml-dir) (add-to-list (quote load-path) related-dir) (add-to-list (quote load-path) util-dir) (add-to-list (quote load-path) nxhtml-install-dir) (message "... nXhtml loading %.1f seconds elapsed ..." (- ... nxhtml-load-time-start)) (load (expand-file-name "nxhtml-loaddefs" nxhtml-install-dir)) (message "... nXhtml loading %.1f seconds elapsed ..." (- ... nxhtml-load-time-start)) (nxhtml-global-minor-mode 1) (message "... nXhtml loading %.1f seconds elapsed ..." (- ... nxhtml-load-time-start)) (when (fboundp ...) (load ...) (rncpp-patch-xhtml-loader)) (message "... nXhtml loading %.1f seconds elapsed ..." (- ... nxhtml-load-time-start)) (load (expand-file-name "nxhtml/nxhtml-autoload" nxhtml-install-dir))) + (if (featurep (quote nxhtml-autostart)) nil (provide (quote nxhtml-autostart)) (if (< emacs-major-version 23) (load ...) (let ... ...)) (let* (... ... ...) (add-to-list ... nxhtml-dir) (add-to-list ... related-dir) (add-to-list ... util-dir) (add-to-list ... nxhtml-install-dir) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (load ...) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (nxhtml-global-minor-mode 1) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (when ... ... ...) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (load ...)) (message "... nXhtml loading %.1f seconds elapsed ..." (- ... nxhtml-load-time-start)) (nxhtml-list-loaded-features) (message "Nxml/Nxhtml Autostart.el loaded in %.1f seconds" (- ... nxhtml-load-time-start))) + (unless (featurep (quote nxhtml-autostart)) (provide (quote nxhtml-autostart)) (if (< emacs-major-version 23) (load ...) (let ... ...)) (let* (... ... ...) (add-to-list ... nxhtml-dir) (add-to-list ... related-dir) (add-to-list ... util-dir) (add-to-list ... nxhtml-install-dir) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (load ...) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (nxhtml-global-minor-mode 1) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (when ... ... ...) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (load ...)) (message "... nXhtml loading %.1f seconds elapsed ..." (- ... nxhtml-load-time-start)) (nxhtml-list-loaded-features) (message "Nxml/Nxhtml Autostart.el loaded in %.1f seconds" (- ... nxhtml-load-time-start))) + eval-buffer(#<buffer *load*> nil "/Users/dave/elisp/package.d/nxhtml/autostart.el" nil t) ; Reading at buffer position 7076 + load-with-code-conversion("/Users/dave/elisp/package.d/nxhtml/autostart.el" "/Users/dave/elisp/package.d/nxhtml/autostart.el" nil t) + load("/Users/dave/elisp/package.d/nxhtml/autostart.el" nil t) + command-line-1(("-l" "/Users/dave/elisp/package.d/nxhtml/nxhtmlmaint.el" "-l" "/Users/dave/elisp/package.d/nxhtml/autostart.el" "-f" "nxhtmlmaint-byte-compile-all")) + command-line() + normal-top-level() diff --git a/emacs/nxhtml/tests/in/bug388729-messages.txt b/emacs/nxhtml/tests/in/bug388729-messages.txt new file mode 100644 index 0000000..4075487 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug388729-messages.txt @@ -0,0 +1,292 @@ +("/Applications/Emacs.app/Contents/MacOS/Emacs" "-Q" "--debug-init" "--load" "/Users/isho/.emacs.d/nxhtml/autostart.el") +For information about GNU Emacs and the GNU system, type C-h C-a. +Nxml/Nxhtml Autostart.el loading ... +Loading /Users/isho/.emacs.d/nxhtml/autostart22.el (source)... +Loading /Applications/Emacs.app/Contents/Resources/site-lisp/nxml-mode/rng-auto.el (source)...done +Loading /Users/isho/.emacs.d/nxhtml/autostart22.el (source)...done +... nXhtml loading 0.1 seconds elapsed ... +Loading /Users/isho/.emacs.d/nxhtml/nxhtml-loaddefs.el (source)...done +... nXhtml loading 0.1 seconds elapsed ... +Loading /Users/isho/.emacs.d/nxhtml/nxhtml/nxhtml-menu.el (source)... +Loading regexp-opt...done +Loading easy-mmode...done +Loading advice...done +after advising ido +Loading cl-macs...done +Loading url-methods...done +html-site-current (information): No current site set +Loading derived...done +Loading byte-opt...done + +Finished loading /Users/isho/.emacs.d/nxhtml/util/mumamo.el + +Loading /Users/isho/.emacs.d/nxhtml/nxhtml/nxhtml-menu.el (source)...done +... nXhtml loading 1.3 seconds elapsed ... +Loading /Users/isho/.emacs.d/nxhtml/etc/schema/schema-path-patch.el (source)...done +xhtml-loader.rnc was ok +(No changes need to be saved) +... nXhtml loading 1.4 seconds elapsed ... +Loading /Users/isho/.emacs.d/nxhtml/nxhtml/nxhtml-autoload.el (source)... +nxhtml-autoload starting ... (hm, should maybe be renamed ...) +majmodpri-apply-priorities running... +majmodpri-sort-lists running ... (done) +majmodpri-apply-priorities: No file buffers to change modes in +majmodpri-apply-priorities running ... (done) +majmodpri-sort-lists running ... (done) +nxhtml-autoload finished +majmodpri-sort-lists running ... (done) +Loading /Users/isho/.emacs.d/nxhtml/nxhtml/nxhtml-autoload.el (source)...done +... nXhtml loading 1.7 seconds elapsed ... +=== Loaded at nxhtml/autostart.el end: +(feature 'html-imenu)=t +(feature 'html-quote)=t +(feature 'html-site)=t +(feature 'html-upl)=t +(feature 'mumamo)=t +(feature 'nxhtml-menu)=t +(feature 'nxhtml-mode)=t +(feature 'rngalt)=t +(feature 'tidy-xhtml)=t +Nxml/Nxhtml Autostart.el loaded in 1.9 seconds +nxhtml_test.php has auto save data; consider M-x recover-this-file +Loading /Users/isho/.emacs.d/nxhtml/util/mumamo-fun.el (source)...done +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from mumamo-get-chunk-save-buffer-state, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=nil +MU:(find-next-chunk-values nil nil nil) +MU:find-next-chunk-values:here a, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:(when (>= 45 1) +MU:find-next-chunk-values:here d, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:curr-chunk-funs=(mumamo-chunk-xml-pi mumamo-chunk-inlined-style mumamo-chunk-inlined-script mumamo-chunk-style= mumamo-chunk-onjs=) +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-xml-pi pos=1, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-xml-pi, r=(5 nil php-mode (10 nil) nil mumamo-search-fw-exc-end-xml-pi mumamo-find-borders-xml-pi) +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-inlined-style pos=1, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-inlined-style, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-inlined-script pos=1, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-inlined-script, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-style= pos=1, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-style=, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-onjs= pos=1, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-onjs=, r=nil +MU:find-next-chunk-values:here A, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:here B, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:here E +MU:find-next-chunk-values:curr-is-closed=t +MU:find-next-chunk-values=> current=(1 5 html-mode 10 nil nil (mumamo-chunk-xml-pi mumamo-chunk-inlined-style mumamo-chunk-inlined-script mumamo-chunk-style= mumamo-chunk-onjs=) nil t), next=(php-mode mumamo-search-fw-exc-end-xml-pi mumamo-find-borders-xml-pi none 1) +MU:find-chunks:mumamo-old-tail=nil, major=nil, mumamo-last-chunk=nil +MU: +-------------------- +MU: +-------------------- +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from mumamo-turn-on-actions, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=4, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=nil from mumamo-turn-on-actions, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:(find-next-chunk-values #<overlay from 1 to 5 in nxhtml_test.php> nil nil) +MU:find-next-chunk-values:here a, curr-min=5, after-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-next-chunk-values:(when (>= 45 6) +MU:find-next-chunk-values:Calling (curr-end-fun=mumamo-search-fw-exc-end-xml-pi 4 45)=>44 +MU:find-next-chunk-values:here c, curr-min=5, after-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-next-chunk-values:here c2, curr-min=5, after-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-next-chunk-values:before end-in-code: 5 mumamo-search-fw-exc-end-xml-pi php-mode +Loading /Users/isho/.emacs.d/nxhtml/related/php-mode.el (source)... +majmodpri-sort-lists running ... (done) +Loading /Users/isho/.emacs.d/nxhtml/related/php-mode.el (source)...done +MU: +-------------------- +MU:find-next-chunk-values:curr-end-fun-end after end-in-code=44 +MU:find-next-chunk-values:here d, curr-min=5, after-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-next-chunk-values:curr-chunk-funs=nil +MU:find-next-chunk-values:here A, curr-min=5, after-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-next-chunk-values:here B, curr-min=5, after-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-next-chunk-values:here C, curr-min=5, after-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-next-chunk-values:here D +MU:find-next-chunk-values:here E +MU:find-next-chunk-values:curr-is-closed=t +MU:find-next-chunk-values=> current=(5 44 php-mode nil nil nil nil #<overlay from 1 to 5 in nxhtml_test.php> t), next=(nil nil nil nil -1) +MU:find-chunks:mumamo-old-tail=nil, major=nil, mumamo-last-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:(find-next-chunk-values #<overlay from 5 to 44 in nxhtml_test.php> nil nil) +MU:find-next-chunk-values:here a, curr-min=44, after-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-next-chunk-values:(when (>= 45 45) +MU:find-next-chunk-values:here d, curr-min=44, after-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-next-chunk-values:curr-chunk-funs=(mumamo-chunk-xml-pi mumamo-chunk-inlined-style mumamo-chunk-inlined-script mumamo-chunk-style= mumamo-chunk-onjs=) +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-xml-pi pos=45, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-xml-pi, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-inlined-style pos=45, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-inlined-style, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-inlined-script pos=45, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-inlined-script, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-style= pos=45, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-style=, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-onjs= pos=45, max=45 +MU:find-next-chunk-values:fn=mumamo-chunk-onjs=, r=nil +MU:find-next-chunk-values:here A, curr-min=44, after-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-next-chunk-values:here B, curr-min=44, after-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-next-chunk-values:here C, curr-min=44, after-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-next-chunk-values:here D +MU:find-next-chunk-values:here E +MU:find-next-chunk-values:curr-is-closed=nil +MU:find-next-chunk-values=> current=(44 nil html-mode nil nil nil (mumamo-chunk-xml-pi mumamo-chunk-inlined-style mumamo-chunk-inlined-script mumamo-chunk-style= mumamo-chunk-onjs=) #<overlay from 5 to 44 in nxhtml_test.php> nil), next=(nil nil nil nil 1) +MU:find-chunks:mumamo-old-tail=nil, major=nil, mumamo-last-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from mumamo-set-major-post-command, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=45, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from mumamo-fontify-region-1, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=45, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from mumamo-fontify-region-1 2, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=45, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from syntax-ppss, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=45, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from mumamo-fontify-region-1 2, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=45, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 5 to 44 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=10 from syntax-ppss, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=10, ok-pos=45, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=10, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 5 to 44 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=44 from mumamo-fontify-region-1 2, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=44, ok-pos=45, this-new-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=44, this-new-chunk=#<overlay from 44 to 45 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 44 to 45 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=2 from mumamo-set-major-post-command, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=2, ok-pos=45, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=2, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=3 from mumamo-set-major-post-command, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=3, ok-pos=45, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=3, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=4 from mumamo-set-major-post-command, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=4, ok-pos=45, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=4, this-new-chunk=#<overlay from 1 to 5 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 5 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from mumamo-set-major-post-command, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=45, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 5 to 44 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from mumamo-idle-set-major-mode, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=45, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 5 to 44 in nxhtml_test.php>, point-max=45, last=#<overlay from 44 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 5 to 44 in nxhtml_test.php> +MU:c-after-change: major-mode=php-mode c-nonsymbol-token-regexp=!=\|##\|%\(?::%:\|[:=]\)\|&[&=]\|\*[/=]\|\+[+=]\|-[=>-]\|\.\.\.\|/[*/=]\|:[:>]\|<\(?:<=\|[:<=]\)\|==\|>\(?:>=\|[=>]\)\|\?\?\(?:!\?\?!\|=\?\?=\|[!()=-]\)\|\^=\||[=|]\|[]!#%&(-,./:-?[{-~^-] +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from syntax-ppss-flush-cache, level=0 +MU:find-chunks:first-check-from=4, chunk-at-change-min=#<overlay from 5 to 5 in nxhtml_test.php> +MU:find-chunks:at start mumamo-old-tail=#<overlay from 1 to 5 in nxhtml_test.php>, mumamo-last-chunk=nil +MU:(find-next-chunk-values nil 4 nil) +MU:find-next-chunk-values:here a, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:(when (>= 6 1) +MU:find-next-chunk-values:here d, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:curr-chunk-funs=(mumamo-chunk-xml-pi mumamo-chunk-inlined-style mumamo-chunk-inlined-script mumamo-chunk-style= mumamo-chunk-onjs=) +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-xml-pi pos=1, max=6 +MU:find-next-chunk-values:fn=mumamo-chunk-xml-pi, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-inlined-style pos=1, max=6 +MU:find-next-chunk-values:fn=mumamo-chunk-inlined-style, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-inlined-script pos=1, max=6 +MU:find-next-chunk-values:fn=mumamo-chunk-inlined-script, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-style= pos=1, max=6 +MU:find-next-chunk-values:fn=mumamo-chunk-style=, r=nil +MU:find-next-chunk-values:before (r (funcall fn pos pos max)), fn=mumamo-chunk-onjs= pos=1, max=6 +MU:find-next-chunk-values:fn=mumamo-chunk-onjs=, r=nil +MU:find-next-chunk-values:here A, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:here B, curr-min=1, after-chunk=nil +MU:find-next-chunk-values:here E +MU:find-next-chunk-values:curr-is-closed=nil +MU:find-next-chunk-values=> current=(1 nil html-mode nil nil nil (mumamo-chunk-xml-pi mumamo-chunk-inlined-style mumamo-chunk-inlined-script mumamo-chunk-style= mumamo-chunk-onjs=) nil nil), next=(nil nil nil nil 1) +MU:find-chunks:mumamo-old-tail=#<overlay from 1 to 5 in nxhtml_test.php>, major=html-mode, mumamo-last-chunk=nil +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php>, point-max=6, last=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 6 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from mumamo-set-major-post-command, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=6, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php>, point-max=6, last=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 6 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from mumamo-fontify-region-1, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=6, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php>, point-max=6, last=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 6 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from mumamo-fontify-region-1 2, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=6, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php>, point-max=6, last=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 6 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=1 from syntax-ppss, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:using old at end=1, ok-pos=6, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=1, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php>, point-max=6, last=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 6 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from mumamo-idle-set-major-mode, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=6, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 1 to 6 in nxhtml_test.php>, point-max=6, last=#<overlay from 1 to 6 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 6 in nxhtml_test.php> +Mark set +MU:c-after-change: major-mode=html-mode c-nonsymbol-token-regexp=nil +Loading debug...done +Entering debugger... +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from mumamo-fontify-region-1, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=45, this-new-chunk=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 1 to 45 in nxhtml_test.php>, point-max=45, last=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 45 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from mumamo-fontify-region-1 2, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=45, this-new-chunk=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 1 to 45 in nxhtml_test.php>, point-max=45, last=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 45 in nxhtml_test.php> +MU:!!!!!!!!!!!!!!!!!!!find-chunks end=5 from syntax-ppss, level=0 +MU:find-chunks:first-check-from=nil, chunk-at-change-min=nil +MU:find-chunks:at start mumamo-old-tail=nil, mumamo-last-chunk=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks:using old at end=5, ok-pos=45, this-new-chunk=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks:Exit.end-param=5, this-new-chunk=#<overlay from 1 to 45 in nxhtml_test.php>, point-max=45, last=#<overlay from 1 to 45 in nxhtml_test.php> +MU:find-chunks=>#<overlay from 1 to 45 in nxhtml_test.php> +Quit +File `/Users/isho/Desktop/backtrace.txt' exists; overwrite? (y or n) +Wrote /Users/isho/Desktop/backtrace.txt +File `~/Desktop/messages.txt' exists; overwrite? (y or n) diff --git a/emacs/nxhtml/tests/in/bug388729-nxhtml_test.php b/emacs/nxhtml/tests/in/bug388729-nxhtml_test.php new file mode 100644 index 0000000..5b049b9 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug388729-nxhtml_test.php @@ -0,0 +1,2 @@ + +<?php echo "this could be anything"; ?> diff --git a/emacs/nxhtml/tests/in/bug393137-new.html.erb b/emacs/nxhtml/tests/in/bug393137-new.html.erb new file mode 100644 index 0000000..4023506 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug393137-new.html.erb @@ -0,0 +1,18 @@ + <h1>New post</h1> + +<% form_for(@post) do |f| %> + <%= f.error_messages %> +<p> + <%= f.label :title %><br /> +<% a = f.text_field :title %> +</p> +<p> + <%= f.label :body %><br /> +<%#= f.text_area :body %> +</p> +<p> + <%= f.submit 'Create' %> +</p> +<% end %> + +<%= link_to 'Back', posts_path %> diff --git a/emacs/nxhtml/tests/in/bug400415-foo.php b/emacs/nxhtml/tests/in/bug400415-foo.php new file mode 100644 index 0000000..8e40934 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug400415-foo.php @@ -0,0 +1,9 @@ +<?php + +class Foo { + public function foo() { + $foo = <<<EOT_SQL + I am a heredoc +EOT_SQL + } +} diff --git a/emacs/nxhtml/tests/in/bug400415-foo2.php b/emacs/nxhtml/tests/in/bug400415-foo2.php new file mode 100644 index 0000000..bb4fbad --- /dev/null +++ b/emacs/nxhtml/tests/in/bug400415-foo2.php @@ -0,0 +1,9 @@ +<?php + +class Foo { + public function foo() { + $foo = <<<EOT_SQL + I am a heredoc +EOT_SQL; + } +} diff --git a/emacs/nxhtml/tests/in/bug409183.html b/emacs/nxhtml/tests/in/bug409183.html new file mode 100644 index 0000000..0089fc3 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug409183.html @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:xi="http://www.w3.org/2001/XInclude" + xmlns:py="http://genshi.edgewall.org/" + py:strip="True"> + <head> + <title></title> + </head> + <body> + <py:match path="head" once="True">Something</py:match> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/bug416505-Body.mxml b/emacs/nxhtml/tests/in/bug416505-Body.mxml new file mode 100644 index 0000000..e42e09f --- /dev/null +++ b/emacs/nxhtml/tests/in/bug416505-Body.mxml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?> +<mx:Canvas + xmlns:mx="http://www.adobe.com/2006/mxml" + xmlns:c="imo.utils.*" + xmlns:imocp="imo.components.*" + xmlns:fl="http://github.com/lancecarlson/flails" + xmlns:commons="imo.components.commons.*" + creationComplete="resetMenus()" + horizontalScrollPolicy="off" verticalScrollPolicy="off"> + + <mx:Script> + <![CDATA[ + import imo.components.tooltips.MediaFileToolTip; + + import mx.core.UIComponent; + import mx.events.DragEvent; + import mx.managers.DragManager; + + public static const LEFT_STATES:Array = []; + public static const RIGHT_STATES:Array = []; + + [Deprecated] + public function changeState(state:String):void { + containers.currentState = state; + } + + private function tabMouseDown(e:MouseEvent):void{ + resetMenus(e.target.parent); + containers.currentState = e.target.label; + } + + private function resetMenus(which:Object = null):void { + if (which == null) { + leftMenu.selectedIndex = -1; + rightMenu.selectedIndex = -1; + } else { + which.selectedIndex = -1; + } + } + + private function onDragEnter( event:DragEvent ):void{ + containers.currentState = "queue"; + DragManager.acceptDragDrop( UIComponent(event.target) ); + } + + private function updateMenu(page:Object):void{ + if (page.hasOwnProperty("menu")) { + this[page.menu + "Menu"].selectedIndex = page.menuIndex; + } else { + resetMenus(); + } + } + ]]> + </mx:Script> + + <!--<commons:TransparentBorderCanvas styleName="sideCanvas" x="-10" width="30" height="210" + horizontalScrollPolicy="off" verticalScrollPolicy="off" + customBorderThickness="2" borderAlpha=".6" cornerRadius="10">--> + <mx:Canvas styleName="sideCanvas" horizontalScrollPolicy="off" verticalScrollPolicy="off" x="-8" width="30" height="174" > + <mx:TabBar id="leftMenu" + styleName="sideMenu" + dataProvider="{LEFT_STATES.reverse()}" + rotation="90" + x="24" + y="4" + width="163" + buttonMode="true" + mouseDown="tabMouseDown(event);" + toggleOnClick="true"/> + </mx:Canvas> + <!--</commons:TransparentBorderCanvas>--> + + <imocp:MainContainer x="29" y="0" id="containers" width="376" height="473"/> + <mx:Canvas x="412" styleName="sideCanvas" horizontalScrollPolicy="off" verticalScrollPolicy="off" width="40" height="155"> + <mx:TabBar x="22" y="5" id="rightMenu" mouseDown="tabMouseDown(event);" + styleName="rightSideMenu" + dataProvider="{RIGHT_STATES.reverse()}" + rotation="90" + width="142" + buttonMode="true" + dragEnter="onDragEnter(event)" + toggleOnClick="true"/> + </mx:Canvas> + <!--</commons:TransparentBorderCanvas>--> +</mx:Canvas> diff --git a/emacs/nxhtml/tests/in/bug416505-nxhtml.el b/emacs/nxhtml/tests/in/bug416505-nxhtml.el new file mode 100644 index 0000000..867bf53 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug416505-nxhtml.el @@ -0,0 +1,45 @@ +;; NXHTML +;;(load (concat vendor-path "/nxhtml/autostart.el")) + +(defconst mumamo-actionscript-tag-start-regex + (rx "<mx:Script>" (0+ space) "<![CDATA[")) + +(defconst mumamo-actionscript-tag-end-regex + (rx "]]>" (0+ space) "</mx:Script>")) + +;; (defun mumamo-search-bw-exc-start-inlined-actionscript (pos min) +;; (let ((exc-start (mumamo-chunk-start-bw-re pos min mumamo-actionscript-tag-start-regex))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'espresso-mode)))) + +;; (defun mumamo-search-bw-exc-end-inlined-actionscript (pos min) +;; (mumamo-chunk-end-bw-re pos min mumamo-actionscript-tag-end-regex)) + +;; (defun mumamo-search-fw-exc-start-inlined-actionscript-old (pos max) +;; (mumamo-chunk-start-fw-re pos max mumamo-actionscript-tag-start-regex)) + +(defun mumamo-search-fw-exc-start-inlined-actionscript (pos max) + (let ((where (mumamo-chunk-start-fw-re pos max mumamo-actionscript-tag-start-regex))) + (when where + (list where 'js-mode)))) + +(defun mumamo-search-fw-exc-end-inlined-actionscript (pos max) + (mumamo-chunk-end-fw-re pos max mumamo-actionscript-tag-end-regex)) + +(defun mumamo-chunk-inlined-actionscript (pos min max) + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-inlined-actionscript + ;; 'mumamo-search-bw-exc-end-inlined-actionscript + ;; 'mumamo-search-fw-exc-start-inlined-actionscript-old + ;; 'mumamo-search-fw-exc-end-inlined-actionscript) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-actionscript + 'mumamo-search-fw-exc-end-inlined-actionscript)) + +(define-mumamo-multi-major-mode mxml-actionscript-mumamo-mode + "Turn on multiple major modes for MXML with main mode `nxml-mode'. +This covers inlined style and script for mxml." + ("nXml Family" nxml-mode (mumamo-chunk-inlined-actionscript))) + +(add-to-list 'auto-mode-alist '("\\.mxml$" . mxml-actionscript-mumamo-mode)) diff --git a/emacs/nxhtml/tests/in/bug452676.php b/emacs/nxhtml/tests/in/bug452676.php new file mode 100644 index 0000000..d47c8ee --- /dev/null +++ b/emacs/nxhtml/tests/in/bug452676.php @@ -0,0 +1,12 @@ + +<?php + +class Foo { + public $foo = array( + 'long' => <<<'LONG' +lorem ipsum +LONG +); + + public $bar = 1; + CancelOk diff --git a/emacs/nxhtml/tests/in/bug463136.php b/emacs/nxhtml/tests/in/bug463136.php new file mode 100644 index 0000000..6ed29f7 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug463136.php @@ -0,0 +1,5 @@ + +<body> + <?php +echo "test"; +echo "test2"; \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug492366-test.php b/emacs/nxhtml/tests/in/bug492366-test.php new file mode 100644 index 0000000..be84c75 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug492366-test.php @@ -0,0 +1,21 @@ +<?php +function render() +{ + $html =<<<HTML + <head> + </head> + <body> + <div id="some_id" class="some_class"></div> + <div id="some_id" class="some_class"></div> + <form method="post" id="" action=""> + </form> + <form method="get" id="id2" action="do.php"> + </form> + </body> +HTML; + +echo $html; +} + +render(); + ?> diff --git a/emacs/nxhtml/tests/in/bug495770-heredoc_demo.pl b/emacs/nxhtml/tests/in/bug495770-heredoc_demo.pl new file mode 100644 index 0000000..562e695 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug495770-heredoc_demo.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl +# heredoc_demo.pl doom@kzsu.stanford.edu +# December 10, 2009 + +use warnings; +use strict; +$|=1; +use Data::Dumper; + +use File::Path qw( mkpath ); +use File::Basename qw( fileparse basename dirname ); +use File::Copy qw( copy move ); +use Fatal qw( open close mkpath copy move ); +use Cwd qw( cwd abs_path ); + +use Env qw(HOME); + +our $VERSION = 0.01; +my $prog = basename($0); + +use Getopt::Std; +my %opt = (); +getopts('d', \%opt); +my $DEBUG = $opt{d} || 1; # TODO set default to 0 when in production + +my ($title, $incantation, $god); + +my $skull=<<"END_SQL"; + SELECT id, god, incantation + FROM spell, pantheon + WHERE pantheon.id = spell.pantheon AND + pantheon.name = 'lovecraft' +END_SQL + +my $phfftp=<<"END_HTML"; +<HTML><HEAD><TITLE>$title</TITLE></HEAD> +<BODY> +<H2>$title</H2> +<P>Speak not the dread words of $incantation +lest ye invoke the $god.</P> +</BODY></HTML> +END_HTML + +print $skull, "\n"; +print $phfftp, "\n"; + +__END__ + +=head1 NAME + +heredoc_demo.pl - (( TODO insert brief description )) + +=head1 SYNOPSIS + + heredoc_demo.pl -[options] [arguments] + + Options: + -d debug + +=head1 OPTIONS + +=over 8 + +=item B<-d> + +Turn on debug messages. + +=back + +=head1 DESCRIPTION + +B<heredoc_demo.pl> is a script which + +(( TODO insert explaination + This is stub documentation created by template.el. )) + +=head1 AUTHOR + +Joseph Brenner, E<lt>doom@kzsu.stanford.eduE<gt> + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2009 by Joseph Brenner + +This program is free software; you can redistribute it and/or modify it +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. + +See http://dev.perl.org/licenses/ for more information. + +=head1 BUGS + +None reported... yet. + +=cut diff --git a/emacs/nxhtml/tests/in/bug505554-nxhtml-download-messages.txt b/emacs/nxhtml/tests/in/bug505554-nxhtml-download-messages.txt new file mode 100644 index 0000000..fef35a6 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug505554-nxhtml-download-messages.txt @@ -0,0 +1,98 @@ +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +Updated "/home/ranko/.emacs.d/nxhtml/autostart.el" +Invalid face reference: hi-gold [4 times] +Reading [application/octet-stream]... 2k of 2k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +Updated "/home/ranko/.emacs.d/nxhtml/autostart22.el" +Invalid face reference: hi-gold +Reading [application/octet-stream]... 77 bytes of 66 bytes (117%) +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/emacs22.cmd" was ok +Reading [application/octet-stream]... 158k of 158k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +Updated "/home/ranko/.emacs.d/nxhtml/nxhtml-loaddefs.el" +Reading [application/octet-stream]... 16k of 16k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +Updated "/home/ranko/.emacs.d/nxhtml/nxhtmlmaint.el" +Reading [text/plain]... 1k of 1k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/README.txt" was ok +Reading [application/octet-stream]... 18k of 18k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +Downloaded "/home/ranko/.emacs.d/nxhtml/web-autoload.el" +Reading [application/octet-stream]... 95k of 95k (100%) [2 times] +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/web-vcs-temp.tmp +Downloaded "/home/ranko/.emacs.d/nxhtml/web-vcs.el" +Contacting host: bazaar.launchpad.net:80 +Reading [application/octet-stream]... 5k of 5k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/alts/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/alts/find-recursive-orig.el" was ok +Reading [application/octet-stream]... 23k of 23k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/alts/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/alts/javascript-mozlab.el" was ok +Reading [application/octet-stream]... 97k of 97k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/alts/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/alts/smarty-mode-vdebout.el" was ok +Contacting host: bazaar.launchpad.net:80 [2 times] +Reading [image/jpeg]... 25k of 25k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/etc/img/pause/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/img/pause/pause.jpg" was ok +Reading [image/jpeg]... 26k of 26k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/etc/img/pause/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/img/pause/pause2.jpg" was ok +Contacting host: bazaar.launchpad.net:80 +Reading [application/octet-stream]... 1k of 1k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/schema/genshi-old.rnc" was ok +Reading [text/xml]... 150 bytes of 139 bytes (108%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/schema/genshi-schemas.xml" was ok +Reading [application/octet-stream]... 2k of 2k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +Updated "/home/ranko/.emacs.d/nxhtml/etc/schema/genshi.rnc" +Reading [application/octet-stream]... 2k of 2k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/schema/mjt.rnc" was ok +Reading [text/x-diff]... 1k of 1k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/schema/nxml-erb.patch" was ok +Reading [application/octet-stream]... 1k of 1k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +Downloaded "/home/ranko/.emacs.d/nxhtml/etc/schema/old-genshi.rnc" +Reading [application/octet-stream]... 2k of 2k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +Downloaded "/home/ranko/.emacs.d/nxhtml/etc/schema/old-qtmstr-xhtml.rnc" +Reading [application/octet-stream]... 367 bytes of 356 bytes (103%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +Downloaded "/home/ranko/.emacs.d/nxhtml/etc/schema/old-xinclude.rnc" +Reading [application/octet-stream]... 2k of 2k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/schema/qtmstr-xhtml-old.rnc" was ok +Reading [application/octet-stream]... 2k of 2k (100%) +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +Updated "/home/ranko/.emacs.d/nxhtml/etc/schema/qtmstr-xhtml.rnc" +Reading [application/octet-stream]... 3k of 3k (100%) +Reading... done. +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +File "/home/ranko/.emacs.d/nxhtml/etc/schema/schema-path-patch.el" was ok +Reading [application/octet-stream]... 890 bytes of 879 bytes (101%) +Wrote /home/ranko/.emacs.d/nxhtml/etc/schema/web-vcs-temp.tmp +Updated "/home/ranko/.emacs.d/nxhtml/etc/schema/xinclude.rnc" +let*: Args out of range: 5023, 5047 +Mark set [2 times] +Saved text from "Contacting host: bazaar.launchpad.net:80" +call-interactively: End of buffer +(New file) diff --git a/emacs/nxhtml/tests/in/bug505554-sample.html.erb b/emacs/nxhtml/tests/in/bug505554-sample.html.erb new file mode 100644 index 0000000..0380560 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug505554-sample.html.erb @@ -0,0 +1,11 @@ +<h1><%= t('views.common.login') %></h1> + +<% form_tag session_path do -%> +<p><%= label_tag(t('views.common.username')) %><br /> +<%= text_field_tag 'login', @login %></p> + +<p><%= label_tag(t('views.common.password')) %><br/> +<%= password_field_tag 'password', nil %></p> + +<p><%= submit_tag(t('views.common.login_verb')) %></p> +<% end -%> diff --git a/emacs/nxhtml/tests/in/bug505726-foo.html b/emacs/nxhtml/tests/in/bug505726-foo.html new file mode 100644 index 0000000..c738117 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug505726-foo.html @@ -0,0 +1,10 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" dir="ltr"> +<head> +</head> + +<body> + <script type="text/javascript"> + </script> +</body> +</html> diff --git a/emacs/nxhtml/tests/in/bug509586.ghtml b/emacs/nxhtml/tests/in/bug509586.ghtml new file mode 100644 index 0000000..275fd21 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug509586.ghtml @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC +"-//W3C//DTD XHTML 1.0 Strict//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/"> + <head> + <title>Title</title> + </head> + <!-- To test this open this file in `genshi-nxhtml-mumamo-mode' and + add evaluate this: --> + <!-- (setq exec-path (cons "c:/python26/" exec-path)) --> + <!-- (add-hook 'python-mode-hook 'turn-on-eldoc-mode) --> + <body> + ${} + </body> +</html> diff --git a/emacs/nxhtml/tests/in/bug523065.jsp b/emacs/nxhtml/tests/in/bug523065.jsp new file mode 100644 index 0000000..a696515 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug523065.jsp @@ -0,0 +1,9 @@ +In JSP page, if we have a line like <% // some comments %>, then the "%>" is ignored by nxhtml. +However if we write it like this: +<% // some comments +%> +or +<% +// some comments +%> +then the page is parsed correctly diff --git a/emacs/nxhtml/tests/in/bug523065.php b/emacs/nxhtml/tests/in/bug523065.php new file mode 100644 index 0000000..5d64278 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug523065.php @@ -0,0 +1,6 @@ + + <?php /* ?> + This is a comment + */ + ?> + This is html diff --git a/emacs/nxhtml/tests/in/bug529133-statemachine.py b/emacs/nxhtml/tests/in/bug529133-statemachine.py new file mode 100644 index 0000000..26ba642 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug529133-statemachine.py @@ -0,0 +1,1491 @@ +# $Id: statemachine.py 6188 2009-10-28 14:08:17Z milde $ +# Author: David Goodger <goodger@python.org> +# Copyright: This module has been placed in the public domain. + +""" +A finite state machine specialized for regular-expression-based text filters, +this module defines the following classes: + +- `StateMachine`, a state machine +- `State`, a state superclass +- `StateMachineWS`, a whitespace-sensitive version of `StateMachine` +- `StateWS`, a state superclass for use with `StateMachineWS` +- `SearchStateMachine`, uses `re.search()` instead of `re.match()` +- `SearchStateMachineWS`, uses `re.search()` instead of `re.match()` +- `ViewList`, extends standard Python lists. +- `StringList`, string-specific ViewList. + +Exception classes: + +- `StateMachineError` +- `UnknownStateError` +- `DuplicateStateError` +- `UnknownTransitionError` +- `DuplicateTransitionError` +- `TransitionPatternNotFound` +- `TransitionMethodNotFound` +- `UnexpectedIndentationError` +- `TransitionCorrection`: Raised to switch to another transition. +- `StateCorrection`: Raised to switch to another state & transition. + +Functions: + +- `string2lines()`: split a multi-line string into a list of one-line strings + + +How To Use This Module +====================== +(See the individual classes, methods, and attributes for details.) + +1. Import it: ``import statemachine`` or ``from statemachine import ...``. + You will also need to ``import re``. + +2. Derive a subclass of `State` (or `StateWS`) for each state in your state + machine:: + + class MyState(statemachine.State): + + Within the state's class definition: + + a) Include a pattern for each transition, in `State.patterns`:: + + patterns = {'atransition': r'pattern', ...} + + b) Include a list of initial transitions to be set up automatically, in + `State.initial_transitions`:: + + initial_transitions = ['atransition', ...] + + c) Define a method for each transition, with the same name as the + transition pattern:: + + def atransition(self, match, context, next_state): + # do something + result = [...] # a list + return context, next_state, result + # context, next_state may be altered + + Transition methods may raise an `EOFError` to cut processing short. + + d) You may wish to override the `State.bof()` and/or `State.eof()` implicit + transition methods, which handle the beginning- and end-of-file. + + e) In order to handle nested processing, you may wish to override the + attributes `State.nested_sm` and/or `State.nested_sm_kwargs`. + + If you are using `StateWS` as a base class, in order to handle nested + indented blocks, you may wish to: + + - override the attributes `StateWS.indent_sm`, + `StateWS.indent_sm_kwargs`, `StateWS.known_indent_sm`, and/or + `StateWS.known_indent_sm_kwargs`; + - override the `StateWS.blank()` method; and/or + - override or extend the `StateWS.indent()`, `StateWS.known_indent()`, + and/or `StateWS.firstknown_indent()` methods. + +3. Create a state machine object:: + + sm = StateMachine(state_classes=[MyState, ...], + initial_state='MyState') + +4. Obtain the input text, which needs to be converted into a tab-free list of + one-line strings. For example, to read text from a file called + 'inputfile':: + + input_string = open('inputfile').read() + input_lines = statemachine.string2lines(input_string) + +5. Run the state machine on the input text and collect the results, a list:: + + results = sm.run(input_lines) + +6. Remove any lingering circular references:: + + sm.unlink() +""" + +__docformat__ = 'restructuredtext' + +import sys +import re +import types +import unicodedata + + +class StateMachine: + + """ + A finite state machine for text filters using regular expressions. + + The input is provided in the form of a list of one-line strings (no + newlines). States are subclasses of the `State` class. Transitions consist + of regular expression patterns and transition methods, and are defined in + each state. + + The state machine is started with the `run()` method, which returns the + results of processing in a list. + """ + + def __init__(self, state_classes, initial_state, debug=0): + """ + Initialize a `StateMachine` object; add state objects. + + Parameters: + + - `state_classes`: a list of `State` (sub)classes. + - `initial_state`: a string, the class name of the initial state. + - `debug`: a boolean; produce verbose output if true (nonzero). + """ + + self.input_lines = None + """`StringList` of input lines (without newlines). + Filled by `self.run()`.""" + + self.input_offset = 0 + """Offset of `self.input_lines` from the beginning of the file.""" + + self.line = None + """Current input line.""" + + self.line_offset = -1 + """Current input line offset from beginning of `self.input_lines`.""" + + self.debug = debug + """Debugging mode on/off.""" + + self.initial_state = initial_state + """The name of the initial state (key to `self.states`).""" + + self.current_state = initial_state + """The name of the current state (key to `self.states`).""" + + self.states = {} + """Mapping of {state_name: State_object}.""" + + self.add_states(state_classes) + + self.observers = [] + """List of bound methods or functions to call whenever the current + line changes. Observers are called with one argument, ``self``. + Cleared at the end of `run()`.""" + + def unlink(self): + """Remove circular references to objects no longer required.""" + for state in self.states.values(): + state.unlink() + self.states = None + + def run(self, input_lines, input_offset=0, context=None, + input_source=None, initial_state=None): + """ + Run the state machine on `input_lines`. Return results (a list). + + Reset `self.line_offset` and `self.current_state`. Run the + beginning-of-file transition. Input one line at a time and check for a + matching transition. If a match is found, call the transition method + and possibly change the state. Store the context returned by the + transition method to be passed on to the next transition matched. + Accumulate the results returned by the transition methods in a list. + Run the end-of-file transition. Finally, return the accumulated + results. + + Parameters: + + - `input_lines`: a list of strings without newlines, or `StringList`. + - `input_offset`: the line offset of `input_lines` from the beginning + of the file. + - `context`: application-specific storage. + - `input_source`: name or path of source of `input_lines`. + - `initial_state`: name of initial state. + """ + self.runtime_init() + if isinstance(input_lines, StringList): + self.input_lines = input_lines + else: + self.input_lines = StringList(input_lines, source=input_source) + self.input_offset = input_offset + self.line_offset = -1 + self.current_state = initial_state or self.initial_state + if self.debug: + print >>sys.stderr, ( + '\nStateMachine.run: input_lines (line_offset=%s):\n| %s' + % (self.line_offset, '\n| '.join(self.input_lines))) + transitions = None + results = [] + state = self.get_state() + try: + if self.debug: + print >>sys.stderr, ('\nStateMachine.run: bof transition') + context, result = state.bof(context) + results.extend(result) + while 1: + try: + try: + self.next_line() + if self.debug: + source, offset = self.input_lines.info( + self.line_offset) + print >>sys.stderr, ( + '\nStateMachine.run: line (source=%r, ' + 'offset=%r):\n| %s' + % (source, offset, self.line)) + context, next_state, result = self.check_line( + context, state, transitions) + except EOFError: + if self.debug: + print >>sys.stderr, ( + '\nStateMachine.run: %s.eof transition' + % state.__class__.__name__) + result = state.eof(context) + results.extend(result) + break + else: + results.extend(result) + except TransitionCorrection, exception: + self.previous_line() # back up for another try + transitions = (exception.args[0],) + if self.debug: + print >>sys.stderr, ( + '\nStateMachine.run: TransitionCorrection to ' + 'state "%s", transition %s.' + % (state.__class__.__name__, transitions[0])) + continue + except StateCorrection, exception: + self.previous_line() # back up for another try + next_state = exception.args[0] + if len(exception.args) == 1: + transitions = None + else: + transitions = (exception.args[1],) + if self.debug: + print >>sys.stderr, ( + '\nStateMachine.run: StateCorrection to state ' + '"%s", transition %s.' + % (next_state, transitions[0])) + else: + transitions = None + state = self.get_state(next_state) + except: + if self.debug: + self.error() + raise + self.observers = [] + return results + + def get_state(self, next_state=None): + """ + Return current state object; set it first if `next_state` given. + + Parameter `next_state`: a string, the name of the next state. + + Exception: `UnknownStateError` raised if `next_state` unknown. + """ + if next_state: + if self.debug and next_state != self.current_state: + print >>sys.stderr, \ + ('\nStateMachine.get_state: Changing state from ' + '"%s" to "%s" (input line %s).' + % (self.current_state, next_state, + self.abs_line_number())) + self.current_state = next_state + try: + return self.states[self.current_state] + except KeyError: + raise UnknownStateError(self.current_state) + + def next_line(self, n=1): + """Load `self.line` with the `n`'th next line and return it.""" + try: + try: + self.line_offset += n + self.line = self.input_lines[self.line_offset] + except IndexError: + self.line = None + raise EOFError + return self.line + finally: + self.notify_observers() + + def is_next_line_blank(self): + """Return 1 if the next line is blank or non-existant.""" + try: + return not self.input_lines[self.line_offset + 1].strip() + except IndexError: + return 1 + + def at_eof(self): + """Return 1 if the input is at or past end-of-file.""" + return self.line_offset >= len(self.input_lines) - 1 + + def at_bof(self): + """Return 1 if the input is at or before beginning-of-file.""" + return self.line_offset <= 0 + + def previous_line(self, n=1): + """Load `self.line` with the `n`'th previous line and return it.""" + self.line_offset -= n + if self.line_offset < 0: + self.line = None + else: + self.line = self.input_lines[self.line_offset] + self.notify_observers() + return self.line + + def goto_line(self, line_offset): + """Jump to absolute line offset `line_offset`, load and return it.""" + try: + try: + self.line_offset = line_offset - self.input_offset + self.line = self.input_lines[self.line_offset] + except IndexError: + self.line = None + raise EOFError + return self.line + finally: + self.notify_observers() + + def get_source(self, line_offset): + """Return source of line at absolute line offset `line_offset`.""" + return self.input_lines.source(line_offset - self.input_offset) + + def get_source_spot(self, line_offset=None): + """Return dict with source position of current or given line""" + if line_offset is None: + line_offset = self.line_offset + else: + line_offset -= self.input_offset + (source, offset) = self.input_lines.info(line_offset) + return {'source': source, 'line': offset + 1} + + def abs_line_offset(self): + """Return line offset of current line, from beginning of file.""" + return self.line_offset + self.input_offset + + def abs_line_number(self): + """Return line number of current line (counting from 1).""" + return self.line_offset + self.input_offset + 1 + + def insert_input(self, input_lines, source): + self.input_lines.insert(self.line_offset + 1, '', + source='internal padding after ' + source) + self.input_lines.insert(self.line_offset + 1, '', + source='internal padding before '+ source) + self.input_lines.insert(self.line_offset + 2, + StringList(input_lines, source)) + + def get_text_block(self, flush_left=0): + """ + Return a contiguous block of text. + + If `flush_left` is true, raise `UnexpectedIndentationError` if an + indented line is encountered before the text block ends (with a blank + line). + """ + try: + block = self.input_lines.get_text_block(self.line_offset, + flush_left) + self.next_line(len(block) - 1) + return block + except UnexpectedIndentationError, error: + block, source, lineno = error.args + self.next_line(len(block) - 1) # advance to last line of block + raise + + def check_line(self, context, state, transitions=None): + """ + Examine one line of input for a transition match & execute its method. + + Parameters: + + - `context`: application-dependent storage. + - `state`: a `State` object, the current state. + - `transitions`: an optional ordered list of transition names to try, + instead of ``state.transition_order``. + + Return the values returned by the transition method: + + - context: possibly modified from the parameter `context`; + - next state name (`State` subclass name); + - the result output of the transition, a list. + + When there is no match, ``state.no_match()`` is called and its return + value is returned. + """ + if transitions is None: + transitions = state.transition_order + state_correction = None + if self.debug: + print >>sys.stderr, ( + '\nStateMachine.check_line: state="%s", transitions=%r.' + % (state.__class__.__name__, transitions)) + for name in transitions: + pattern, method, next_state = state.transitions[name] + match = pattern.match(self.line) + if match: + if self.debug: + print >>sys.stderr, ( + '\nStateMachine.check_line: Matched transition ' + '"%s" in state "%s".' + % (name, state.__class__.__name__)) + return method(match, context, next_state) + else: + if self.debug: + print >>sys.stderr, ( + '\nStateMachine.check_line: No match in state "%s".' + % state.__class__.__name__) + return state.no_match(context, transitions) + + def add_state(self, state_class): + """ + Initialize & add a `state_class` (`State` subclass) object. + + Exception: `DuplicateStateError` raised if `state_class` was already + added. + """ + statename = state_class.__name__ + if statename in self.states: + raise DuplicateStateError(statename) + self.states[statename] = state_class(self, self.debug) + + def add_states(self, state_classes): + """ + Add `state_classes` (a list of `State` subclasses). + """ + for state_class in state_classes: + self.add_state(state_class) + + def runtime_init(self): + """ + Initialize `self.states`. + """ + for state in self.states.values(): + state.runtime_init() + + def error(self): + """Report error details.""" + type, value, module, line, function = _exception_data() + print >>sys.stderr, '%s: %s' % (type, value) + print >>sys.stderr, 'input line %s' % (self.abs_line_number()) + print >>sys.stderr, ('module %s, line %s, function %s' + % (module, line, function)) + + def attach_observer(self, observer): + """ + The `observer` parameter is a function or bound method which takes two + arguments, the source and offset of the current line. + """ + self.observers.append(observer) + + def detach_observer(self, observer): + self.observers.remove(observer) + + def notify_observers(self): + for observer in self.observers: + try: + info = self.input_lines.info(self.line_offset) + except IndexError: + info = (None, None) + observer(*info) + + +class State: + + """ + State superclass. Contains a list of transitions, and transition methods. + + Transition methods all have the same signature. They take 3 parameters: + + - An `re` match object. ``match.string`` contains the matched input line, + ``match.start()`` gives the start index of the match, and + ``match.end()`` gives the end index. + - A context object, whose meaning is application-defined (initial value + ``None``). It can be used to store any information required by the state + machine, and the retured context is passed on to the next transition + method unchanged. + - The name of the next state, a string, taken from the transitions list; + normally it is returned unchanged, but it may be altered by the + transition method if necessary. + + Transition methods all return a 3-tuple: + + - A context object, as (potentially) modified by the transition method. + - The next state name (a return value of ``None`` means no state change). + - The processing result, a list, which is accumulated by the state + machine. + + Transition methods may raise an `EOFError` to cut processing short. + + There are two implicit transitions, and corresponding transition methods + are defined: `bof()` handles the beginning-of-file, and `eof()` handles + the end-of-file. These methods have non-standard signatures and return + values. `bof()` returns the initial context and results, and may be used + to return a header string, or do any other processing needed. `eof()` + should handle any remaining context and wrap things up; it returns the + final processing result. + + Typical applications need only subclass `State` (or a subclass), set the + `patterns` and `initial_transitions` class attributes, and provide + corresponding transition methods. The default object initialization will + take care of constructing the list of transitions. + """ + + patterns = None + """ + {Name: pattern} mapping, used by `make_transition()`. Each pattern may + be a string or a compiled `re` pattern. Override in subclasses. + """ + + initial_transitions = None + """ + A list of transitions to initialize when a `State` is instantiated. + Each entry is either a transition name string, or a (transition name, next + state name) pair. See `make_transitions()`. Override in subclasses. + """ + + nested_sm = None + """ + The `StateMachine` class for handling nested processing. + + If left as ``None``, `nested_sm` defaults to the class of the state's + controlling state machine. Override it in subclasses to avoid the default. + """ + + nested_sm_kwargs = None + """ + Keyword arguments dictionary, passed to the `nested_sm` constructor. + + Two keys must have entries in the dictionary: + + - Key 'state_classes' must be set to a list of `State` classes. + - Key 'initial_state' must be set to the name of the initial state class. + + If `nested_sm_kwargs` is left as ``None``, 'state_classes' defaults to the + class of the current state, and 'initial_state' defaults to the name of + the class of the current state. Override in subclasses to avoid the + defaults. + """ + + def __init__(self, state_machine, debug=0): + """ + Initialize a `State` object; make & add initial transitions. + + Parameters: + + - `statemachine`: the controlling `StateMachine` object. + - `debug`: a boolean; produce verbose output if true (nonzero). + """ + + self.transition_order = [] + """A list of transition names in search order.""" + + self.transitions = {} + """ + A mapping of transition names to 3-tuples containing + (compiled_pattern, transition_method, next_state_name). Initialized as + an instance attribute dynamically (instead of as a class attribute) + because it may make forward references to patterns and methods in this + or other classes. + """ + + self.add_initial_transitions() + + self.state_machine = state_machine + """A reference to the controlling `StateMachine` object.""" + + self.debug = debug + """Debugging mode on/off.""" + + if self.nested_sm is None: + self.nested_sm = self.state_machine.__class__ + if self.nested_sm_kwargs is None: + self.nested_sm_kwargs = {'state_classes': [self.__class__], + 'initial_state': self.__class__.__name__} + + def runtime_init(self): + """ + Initialize this `State` before running the state machine; called from + `self.state_machine.run()`. + """ + pass + + def unlink(self): + """Remove circular references to objects no longer required.""" + self.state_machine = None + + def add_initial_transitions(self): + """Make and add transitions listed in `self.initial_transitions`.""" + if self.initial_transitions: + names, transitions = self.make_transitions( + self.initial_transitions) + self.add_transitions(names, transitions) + + def add_transitions(self, names, transitions): + """ + Add a list of transitions to the start of the transition list. + + Parameters: + + - `names`: a list of transition names. + - `transitions`: a mapping of names to transition tuples. + + Exceptions: `DuplicateTransitionError`, `UnknownTransitionError`. + """ + for name in names: + if name in self.transitions: + raise DuplicateTransitionError(name) + if name not in transitions: + raise UnknownTransitionError(name) + self.transition_order[:0] = names + self.transitions.update(transitions) + + def add_transition(self, name, transition): + """ + Add a transition to the start of the transition list. + + Parameter `transition`: a ready-made transition 3-tuple. + + Exception: `DuplicateTransitionError`. + """ + if name in self.transitions: + raise DuplicateTransitionError(name) + self.transition_order[:0] = [name] + self.transitions[name] = transition + + def remove_transition(self, name): + """ + Remove a transition by `name`. + + Exception: `UnknownTransitionError`. + """ + try: + del self.transitions[name] + self.transition_order.remove(name) + except: + raise UnknownTransitionError(name) + + def make_transition(self, name, next_state=None): + """ + Make & return a transition tuple based on `name`. + + This is a convenience function to simplify transition creation. + + Parameters: + + - `name`: a string, the name of the transition pattern & method. This + `State` object must have a method called '`name`', and a dictionary + `self.patterns` containing a key '`name`'. + - `next_state`: a string, the name of the next `State` object for this + transition. A value of ``None`` (or absent) implies no state change + (i.e., continue with the same state). + + Exceptions: `TransitionPatternNotFound`, `TransitionMethodNotFound`. + """ + if next_state is None: + next_state = self.__class__.__name__ + try: + pattern = self.patterns[name] + if not hasattr(pattern, 'match'): + pattern = re.compile(pattern) + except KeyError: + raise TransitionPatternNotFound( + '%s.patterns[%r]' % (self.__class__.__name__, name)) + try: + method = getattr(self, name) + except AttributeError: + raise TransitionMethodNotFound( + '%s.%s' % (self.__class__.__name__, name)) + return (pattern, method, next_state) + + def make_transitions(self, name_list): + """ + Return a list of transition names and a transition mapping. + + Parameter `name_list`: a list, where each entry is either a transition + name string, or a 1- or 2-tuple (transition name, optional next state + name). + """ + stringtype = type('') + names = [] + transitions = {} + for namestate in name_list: + if type(namestate) is stringtype: + transitions[namestate] = self.make_transition(namestate) + names.append(namestate) + else: + transitions[namestate[0]] = self.make_transition(*namestate) + names.append(namestate[0]) + return names, transitions + + def no_match(self, context, transitions): + """ + Called when there is no match from `StateMachine.check_line()`. + + Return the same values returned by transition methods: + + - context: unchanged; + - next state name: ``None``; + - empty result list. + + Override in subclasses to catch this event. + """ + return context, None, [] + + def bof(self, context): + """ + Handle beginning-of-file. Return unchanged `context`, empty result. + + Override in subclasses. + + Parameter `context`: application-defined storage. + """ + return context, [] + + def eof(self, context): + """ + Handle end-of-file. Return empty result. + + Override in subclasses. + + Parameter `context`: application-defined storage. + """ + return [] + + def nop(self, match, context, next_state): + """ + A "do nothing" transition method. + + Return unchanged `context` & `next_state`, empty result. Useful for + simple state changes (actionless transitions). + """ + return context, next_state, [] + + +class StateMachineWS(StateMachine): + + """ + `StateMachine` subclass specialized for whitespace recognition. + + There are three methods provided for extracting indented text blocks: + + - `get_indented()`: use when the indent is unknown. + - `get_known_indented()`: use when the indent is known for all lines. + - `get_first_known_indented()`: use when only the first line's indent is + known. + """ + + def get_indented(self, until_blank=0, strip_indent=1): + """ + Return a block of indented lines of text, and info. + + Extract an indented block where the indent is unknown for all lines. + + :Parameters: + - `until_blank`: Stop collecting at the first blank line if true + (1). + - `strip_indent`: Strip common leading indent if true (1, + default). + + :Return: + - the indented block (a list of lines of text), + - its indent, + - its first line offset from BOF, and + - whether or not it finished with a blank line. + """ + offset = self.abs_line_offset() + indented, indent, blank_finish = self.input_lines.get_indented( + self.line_offset, until_blank, strip_indent) + if indented: + self.next_line(len(indented) - 1) # advance to last indented line + while indented and not indented[0].strip(): + indented.trim_start() + offset += 1 + return indented, indent, offset, blank_finish + + def get_known_indented(self, indent, until_blank=0, strip_indent=1): + """ + Return an indented block and info. + + Extract an indented block where the indent is known for all lines. + Starting with the current line, extract the entire text block with at + least `indent` indentation (which must be whitespace, except for the + first line). + + :Parameters: + - `indent`: The number of indent columns/characters. + - `until_blank`: Stop collecting at the first blank line if true + (1). + - `strip_indent`: Strip `indent` characters of indentation if true + (1, default). + + :Return: + - the indented block, + - its first line offset from BOF, and + - whether or not it finished with a blank line. + """ + offset = self.abs_line_offset() + indented, indent, blank_finish = self.input_lines.get_indented( + self.line_offset, until_blank, strip_indent, + block_indent=indent) + self.next_line(len(indented) - 1) # advance to last indented line + while indented and not indented[0].strip(): + indented.trim_start() + offset += 1 + return indented, offset, blank_finish + + def get_first_known_indented(self, indent, until_blank=0, strip_indent=1, + strip_top=1): + """ + Return an indented block and info. + + Extract an indented block where the indent is known for the first line + and unknown for all other lines. + + :Parameters: + - `indent`: The first line's indent (# of columns/characters). + - `until_blank`: Stop collecting at the first blank line if true + (1). + - `strip_indent`: Strip `indent` characters of indentation if true + (1, default). + - `strip_top`: Strip blank lines from the beginning of the block. + + :Return: + - the indented block, + - its indent, + - its first line offset from BOF, and + - whether or not it finished with a blank line. + """ + offset = self.abs_line_offset() + indented, indent, blank_finish = self.input_lines.get_indented( + self.line_offset, until_blank, strip_indent, + first_indent=indent) + self.next_line(len(indented) - 1) # advance to last indented line + if strip_top: + while indented and not indented[0].strip(): + indented.trim_start() + offset += 1 + return indented, indent, offset, blank_finish + + +class StateWS(State): + + """ + State superclass specialized for whitespace (blank lines & indents). + + Use this class with `StateMachineWS`. The transitions 'blank' (for blank + lines) and 'indent' (for indented text blocks) are added automatically, + before any other transitions. The transition method `blank()` handles + blank lines and `indent()` handles nested indented blocks. Indented + blocks trigger a new state machine to be created by `indent()` and run. + The class of the state machine to be created is in `indent_sm`, and the + constructor keyword arguments are in the dictionary `indent_sm_kwargs`. + + The methods `known_indent()` and `firstknown_indent()` are provided for + indented blocks where the indent (all lines' and first line's only, + respectively) is known to the transition method, along with the attributes + `known_indent_sm` and `known_indent_sm_kwargs`. Neither transition method + is triggered automatically. + """ + + indent_sm = None + """ + The `StateMachine` class handling indented text blocks. + + If left as ``None``, `indent_sm` defaults to the value of + `State.nested_sm`. Override it in subclasses to avoid the default. + """ + + indent_sm_kwargs = None + """ + Keyword arguments dictionary, passed to the `indent_sm` constructor. + + If left as ``None``, `indent_sm_kwargs` defaults to the value of + `State.nested_sm_kwargs`. Override it in subclasses to avoid the default. + """ + + known_indent_sm = None + """ + The `StateMachine` class handling known-indented text blocks. + + If left as ``None``, `known_indent_sm` defaults to the value of + `indent_sm`. Override it in subclasses to avoid the default. + """ + + known_indent_sm_kwargs = None + """ + Keyword arguments dictionary, passed to the `known_indent_sm` constructor. + + If left as ``None``, `known_indent_sm_kwargs` defaults to the value of + `indent_sm_kwargs`. Override it in subclasses to avoid the default. + """ + + ws_patterns = {'blank': ' *$', + 'indent': ' +'} + """Patterns for default whitespace transitions. May be overridden in + subclasses.""" + + ws_initial_transitions = ('blank', 'indent') + """Default initial whitespace transitions, added before those listed in + `State.initial_transitions`. May be overridden in subclasses.""" + + def __init__(self, state_machine, debug=0): + """ + Initialize a `StateSM` object; extends `State.__init__()`. + + Check for indent state machine attributes, set defaults if not set. + """ + State.__init__(self, state_machine, debug) + if self.indent_sm is None: + self.indent_sm = self.nested_sm + if self.indent_sm_kwargs is None: + self.indent_sm_kwargs = self.nested_sm_kwargs + if self.known_indent_sm is None: + self.known_indent_sm = self.indent_sm + if self.known_indent_sm_kwargs is None: + self.known_indent_sm_kwargs = self.indent_sm_kwargs + + def add_initial_transitions(self): + """ + Add whitespace-specific transitions before those defined in subclass. + + Extends `State.add_initial_transitions()`. + """ + State.add_initial_transitions(self) + if self.patterns is None: + self.patterns = {} + self.patterns.update(self.ws_patterns) + names, transitions = self.make_transitions( + self.ws_initial_transitions) + self.add_transitions(names, transitions) + + def blank(self, match, context, next_state): + """Handle blank lines. Does nothing. Override in subclasses.""" + return self.nop(match, context, next_state) + + def indent(self, match, context, next_state): + """ + Handle an indented text block. Extend or override in subclasses. + + Recursively run the registered state machine for indented blocks + (`self.indent_sm`). + """ + indented, indent, line_offset, blank_finish = \ + self.state_machine.get_indented() + sm = self.indent_sm(debug=self.debug, **self.indent_sm_kwargs) + results = sm.run(indented, input_offset=line_offset) + return context, next_state, results + + def known_indent(self, match, context, next_state): + """ + Handle a known-indent text block. Extend or override in subclasses. + + Recursively run the registered state machine for known-indent indented + blocks (`self.known_indent_sm`). The indent is the length of the + match, ``match.end()``. + """ + indented, line_offset, blank_finish = \ + self.state_machine.get_known_indented(match.end()) + sm = self.known_indent_sm(debug=self.debug, + **self.known_indent_sm_kwargs) + results = sm.run(indented, input_offset=line_offset) + return context, next_state, results + + def first_known_indent(self, match, context, next_state): + """ + Handle an indented text block (first line's indent known). + + Extend or override in subclasses. + + Recursively run the registered state machine for known-indent indented + blocks (`self.known_indent_sm`). The indent is the length of the + match, ``match.end()``. + """ + indented, line_offset, blank_finish = \ + self.state_machine.get_first_known_indented(match.end()) + sm = self.known_indent_sm(debug=self.debug, + **self.known_indent_sm_kwargs) + results = sm.run(indented, input_offset=line_offset) + return context, next_state, results + + +class _SearchOverride: + + """ + Mix-in class to override `StateMachine` regular expression behavior. + + Changes regular expression matching, from the default `re.match()` + (succeeds only if the pattern matches at the start of `self.line`) to + `re.search()` (succeeds if the pattern matches anywhere in `self.line`). + When subclassing a `StateMachine`, list this class **first** in the + inheritance list of the class definition. + """ + + def match(self, pattern): + """ + Return the result of a regular expression search. + + Overrides `StateMachine.match()`. + + Parameter `pattern`: `re` compiled regular expression. + """ + return pattern.search(self.line) + + +class SearchStateMachine(_SearchOverride, StateMachine): + """`StateMachine` which uses `re.search()` instead of `re.match()`.""" + pass + + +class SearchStateMachineWS(_SearchOverride, StateMachineWS): + """`StateMachineWS` which uses `re.search()` instead of `re.match()`.""" + pass + + +class ViewList: + + """ + List with extended functionality: slices of ViewList objects are child + lists, linked to their parents. Changes made to a child list also affect + the parent list. A child list is effectively a "view" (in the SQL sense) + of the parent list. Changes to parent lists, however, do *not* affect + active child lists. If a parent list is changed, any active child lists + should be recreated. + + The start and end of the slice can be trimmed using the `trim_start()` and + `trim_end()` methods, without affecting the parent list. The link between + child and parent lists can be broken by calling `disconnect()` on the + child list. + + Also, ViewList objects keep track of the source & offset of each item. + This information is accessible via the `source()`, `offset()`, and + `info()` methods. + """ + + def __init__(self, initlist=None, source=None, items=None, + parent=None, parent_offset=None): + self.data = [] + """The actual list of data, flattened from various sources.""" + + self.items = [] + """A list of (source, offset) pairs, same length as `self.data`: the + source of each line and the offset of each line from the beginning of + its source.""" + + self.parent = parent + """The parent list.""" + + self.parent_offset = parent_offset + """Offset of this list from the beginning of the parent list.""" + + if isinstance(initlist, ViewList): + self.data = initlist.data[:] + self.items = initlist.items[:] + elif initlist is not None: + self.data = list(initlist) + if items: + self.items = items + else: + self.items = [(source, i) for i in range(len(initlist))] + assert len(self.data) == len(self.items), 'data mismatch' + + def __str__(self): + return str(self.data) + + def __repr__(self): + return '%s(%s, items=%s)' % (self.__class__.__name__, + self.data, self.items) + + def __lt__(self, other): return self.data < self.__cast(other) + def __le__(self, other): return self.data <= self.__cast(other) + def __eq__(self, other): return self.data == self.__cast(other) + def __ne__(self, other): return self.data != self.__cast(other) + def __gt__(self, other): return self.data > self.__cast(other) + def __ge__(self, other): return self.data >= self.__cast(other) + def __cmp__(self, other): return cmp(self.data, self.__cast(other)) + + def __cast(self, other): + if isinstance(other, ViewList): + return other.data + else: + return other + + def __contains__(self, item): return item in self.data + def __len__(self): return len(self.data) + + # The __getitem__()/__setitem__() methods check whether the index + # is a slice first, since indexing a native list with a slice object + # just works. + + def __getitem__(self, i): + if isinstance(i, types.SliceType): + assert i.step in (None, 1), 'cannot handle slice with stride' + return self.__class__(self.data[i.start:i.stop], + items=self.items[i.start:i.stop], + parent=self, parent_offset=i.start or 0) + else: + return self.data[i] + + def __setitem__(self, i, item): + if isinstance(i, types.SliceType): + assert i.step in (None, 1), 'cannot handle slice with stride' + if not isinstance(item, ViewList): + raise TypeError('assigning non-ViewList to ViewList slice') + self.data[i.start:i.stop] = item.data + self.items[i.start:i.stop] = item.items + assert len(self.data) == len(self.items), 'data mismatch' + if self.parent: + self.parent[(i.start or 0) + self.parent_offset + : (i.stop or len(self)) + self.parent_offset] = item + else: + self.data[i] = item + if self.parent: + self.parent[i + self.parent_offset] = item + + def __delitem__(self, i): + try: + del self.data[i] + del self.items[i] + if self.parent: + del self.parent[i + self.parent_offset] + except TypeError: + assert i.step is None, 'cannot handle slice with stride' + del self.data[i.start:i.stop] + del self.items[i.start:i.stop] + if self.parent: + del self.parent[(i.start or 0) + self.parent_offset + : (i.stop or len(self)) + self.parent_offset] + + def __add__(self, other): + if isinstance(other, ViewList): + return self.__class__(self.data + other.data, + items=(self.items + other.items)) + else: + raise TypeError('adding non-ViewList to a ViewList') + + def __radd__(self, other): + if isinstance(other, ViewList): + return self.__class__(other.data + self.data, + items=(other.items + self.items)) + else: + raise TypeError('adding ViewList to a non-ViewList') + + def __iadd__(self, other): + if isinstance(other, ViewList): + self.data += other.data + else: + raise TypeError('argument to += must be a ViewList') + return self + + def __mul__(self, n): + return self.__class__(self.data * n, items=(self.items * n)) + + __rmul__ = __mul__ + + def __imul__(self, n): + self.data *= n + self.items *= n + return self + + def extend(self, other): + if not isinstance(other, ViewList): + raise TypeError('extending a ViewList with a non-ViewList') + if self.parent: + self.parent.insert(len(self.data) + self.parent_offset, other) + self.data.extend(other.data) + self.items.extend(other.items) + + def append(self, item, source=None, offset=0): + if source is None: + self.extend(item) + else: + if self.parent: + self.parent.insert(len(self.data) + self.parent_offset, item, + source, offset) + self.data.append(item) + self.items.append((source, offset)) + + def insert(self, i, item, source=None, offset=0): + if source is None: + if not isinstance(item, ViewList): + raise TypeError('inserting non-ViewList with no source given') + self.data[i:i] = item.data + self.items[i:i] = item.items + if self.parent: + index = (len(self.data) + i) % len(self.data) + self.parent.insert(index + self.parent_offset, item) + else: + self.data.insert(i, item) + self.items.insert(i, (source, offset)) + if self.parent: + index = (len(self.data) + i) % len(self.data) + self.parent.insert(index + self.parent_offset, item, + source, offset) + + def pop(self, i=-1): + if self.parent: + index = (len(self.data) + i) % len(self.data) + self.parent.pop(index + self.parent_offset) + self.items.pop(i) + return self.data.pop(i) + + def trim_start(self, n=1): + """ + Remove items from the start of the list, without touching the parent. + """ + if n > len(self.data): + raise IndexError("Size of trim too large; can't trim %s items " + "from a list of size %s." % (n, len(self.data))) + elif n < 0: + raise IndexError('Trim size must be >= 0.') + del self.data[:n] + del self.items[:n] + if self.parent: + self.parent_offset += n + + def trim_end(self, n=1): + """ + Remove items from the end of the list, without touching the parent. + """ + if n > len(self.data): + raise IndexError("Size of trim too large; can't trim %s items " + "from a list of size %s." % (n, len(self.data))) + elif n < 0: + raise IndexError('Trim size must be >= 0.') + del self.data[-n:] + del self.items[-n:] + + def remove(self, item): + index = self.index(item) + del self[index] + + def count(self, item): return self.data.count(item) + def index(self, item): return self.data.index(item) + + def reverse(self): + self.data.reverse() + self.items.reverse() + self.parent = None + + def sort(self, *args): + tmp = zip(self.data, self.items) + tmp.sort(*args) + self.data = [entry[0] for entry in tmp] + self.items = [entry[1] for entry in tmp] + self.parent = None + + def info(self, i): + """Return source & offset for index `i`.""" + try: + return self.items[i] + except IndexError: + if i == len(self.data): # Just past the end + return self.items[i - 1][0], None + else: + raise + + def source(self, i): + """Return source for index `i`.""" + return self.info(i)[0] + + def offset(self, i): + """Return offset for index `i`.""" + return self.info(i)[1] + + def disconnect(self): + """Break link between this list and parent list.""" + self.parent = None + + +class StringList(ViewList): + + """A `ViewList` with string-specific methods.""" + + def trim_left(self, length, start=0, end=sys.maxint): + """ + Trim `length` characters off the beginning of each item, in-place, + from index `start` to `end`. No whitespace-checking is done on the + trimmed text. Does not affect slice parent. + """ + self.data[start:end] = [line[length:] + for line in self.data[start:end]] + + def get_text_block(self, start, flush_left=0): + """ + Return a contiguous block of text. + + If `flush_left` is true, raise `UnexpectedIndentationError` if an + indented line is encountered before the text block ends (with a blank + line). + """ + end = start + last = len(self.data) + while end < last: + line = self.data[end] + if not line.strip(): + break + if flush_left and (line[0] == ' '): + source, offset = self.info(end) + raise UnexpectedIndentationError(self[start:end], source, + offset + 1) + end += 1 + return self[start:end] + + def get_indented(self, start=0, until_blank=0, strip_indent=1, + block_indent=None, first_indent=None): + """ + Extract and return a StringList of indented lines of text. + + Collect all lines with indentation, determine the minimum indentation, + remove the minimum indentation from all indented lines (unless + `strip_indent` is false), and return them. All lines up to but not + including the first unindented line will be returned. + + :Parameters: + - `start`: The index of the first line to examine. + - `until_blank`: Stop collecting at the first blank line if true. + - `strip_indent`: Strip common leading indent if true (default). + - `block_indent`: The indent of the entire block, if known. + - `first_indent`: The indent of the first line, if known. + + :Return: + - a StringList of indented lines with mininum indent removed; + - the amount of the indent; + - a boolean: did the indented block finish with a blank line or EOF? + """ + indent = block_indent # start with None if unknown + end = start + if block_indent is not None and first_indent is None: + first_indent = block_indent + if first_indent is not None: + end += 1 + last = len(self.data) + while end < last: + line = self.data[end] + if line and (line[0] != ' ' + or (block_indent is not None + and line[:block_indent].strip())): + # Line not indented or insufficiently indented. + # Block finished properly iff the last indented line blank: + blank_finish = ((end > start) + and not self.data[end - 1].strip()) + break + stripped = line.lstrip() + if not stripped: # blank line + if until_blank: + blank_finish = 1 + break + elif block_indent is None: + line_indent = len(line) - len(stripped) + if indent is None: + indent = line_indent + else: + indent = min(indent, line_indent) + end += 1 + else: + blank_finish = 1 # block ends at end of lines + block = self[start:end] + if first_indent is not None and block: + block.data[0] = block.data[0][first_indent:] + if indent and strip_indent: + block.trim_left(indent, start=(first_indent is not None)) + return block, indent or 0, blank_finish + + def get_2D_block(self, top, left, bottom, right, strip_indent=1): + block = self[top:bottom] + indent = right + for i in range(len(block.data)): + block.data[i] = line = block.data[i][left:right].rstrip() + if line: + indent = min(indent, len(line) - len(line.lstrip())) + if strip_indent and 0 < indent < right: + block.data = [line[indent:] for line in block.data] + return block + + def pad_double_width(self, pad_char): + """ + Pad all double-width characters in self by appending `pad_char` to each. + For East Asian language support. + """ + if hasattr(unicodedata, 'east_asian_width'): + east_asian_width = unicodedata.east_asian_width + else: + return # new in Python 2.4 + for i in range(len(self.data)): + line = self.data[i] + if isinstance(line, unicode): + new = [] + for char in line: + new.append(char) + if east_asian_width(char) in 'WF': # 'W'ide & 'F'ull-width + new.append(pad_char) + self.data[i] = ''.join(new) + + def replace(self, old, new): + """Replace all occurrences of substring `old` with `new`.""" + for i in range(len(self.data)): + self.data[i] = self.data[i].replace(old, new) + + +class StateMachineError(Exception): pass +class UnknownStateError(StateMachineError): pass +class DuplicateStateError(StateMachineError): pass +class UnknownTransitionError(StateMachineError): pass +class DuplicateTransitionError(StateMachineError): pass +class TransitionPatternNotFound(StateMachineError): pass +class TransitionMethodNotFound(StateMachineError): pass +class UnexpectedIndentationError(StateMachineError): pass + + +class TransitionCorrection(Exception): + + """ + Raise from within a transition method to switch to another transition. + + Raise with one argument, the new transition name. + """ + + +class StateCorrection(Exception): + + """ + Raise from within a transition method to switch to another state. + + Raise with one or two arguments: new state name, and an optional new + transition name. + """ + + +def string2lines(astring, tab_width=8, convert_whitespace=0, + whitespace=re.compile('[\v\f]')): + """ + Return a list of one-line strings with tabs expanded, no newlines, and + trailing whitespace stripped. + + Each tab is expanded with between 1 and `tab_width` spaces, so that the + next character's index becomes a multiple of `tab_width` (8 by default). + + Parameters: + + - `astring`: a multi-line string. + - `tab_width`: the number of columns between tab stops. + - `convert_whitespace`: convert form feeds and vertical tabs to spaces? + """ + if convert_whitespace: + astring = whitespace.sub(' ', astring) + return [s.expandtabs(tab_width).rstrip() for s in astring.splitlines()] + +def _exception_data(): + """ + Return exception information: + + - the exception's class name; + - the exception object; + - the name of the file containing the offending code; + - the line number of the offending code; + - the function name of the offending code. + """ + type, value, traceback = sys.exc_info() + while traceback.tb_next: + traceback = traceback.tb_next + code = traceback.tb_frame.f_code + return (type.__name__, value, code.co_filename, traceback.tb_lineno, + code.co_name) diff --git a/emacs/nxhtml/tests/in/bug531328.rhtml b/emacs/nxhtml/tests/in/bug531328.rhtml new file mode 100644 index 0000000..b7e4b98 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug531328.rhtml @@ -0,0 +1 @@ +<% foo %> <% bar %> diff --git a/emacs/nxhtml/tests/in/bug532500.rhtml b/emacs/nxhtml/tests/in/bug532500.rhtml new file mode 100644 index 0000000..308613b --- /dev/null +++ b/emacs/nxhtml/tests/in/bug532500.rhtml @@ -0,0 +1,7 @@ + <tr> + <td><%= f.label((t('app.views.large_surveys_admin.new.gift'))) %></td> + <td><%= check_box_tag('gift', + 'checked', + !@large_survey.coupon_pool_id.nil?, + {:onclick => "$('coupon_pool').toggle()"}) %></td> + </tr> diff --git a/emacs/nxhtml/tests/in/bug532759.djhtml b/emacs/nxhtml/tests/in/bug532759.djhtml new file mode 100644 index 0000000..e655dd2 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug532759.djhtml @@ -0,0 +1,17 @@ +{% if athlete_list %} + <p>Here are the athletes: {{ athlete_list }}.</p> +{% else %} + <p>No athletes are available.</p> + {% if coach_list %} + <p>Here are the coaches: {{ coach_list }}.</p> + {% endif %} +{% endif %} +{% block content %} + + {% if morning %} + <p>Hello World!</p> + {% else %} + <p>Goodbye World!</p> + {% endif %} + + {% endblock %} diff --git a/emacs/nxhtml/tests/in/bug546027.html b/emacs/nxhtml/tests/in/bug546027.html new file mode 100644 index 0000000..f0c0eac --- /dev/null +++ b/emacs/nxhtml/tests/in/bug546027.html @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> + +<<<<<<< .working +the code from my version bla bla bla... +======= +the version from the repo bla bla bla... +>>>>>>> .merge-right.r3379 + + </body> +</html> diff --git a/emacs/nxhtml/tests/in/bug552789-loremipsum.php b/emacs/nxhtml/tests/in/bug552789-loremipsum.php new file mode 100644 index 0000000..67a3908 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug552789-loremipsum.php @@ -0,0 +1,10 @@ +<html> + <body> + Lorem ipsum dolor sit amet, <?php echo 'consectetur adipisicing elit, sed do eiusmod'?> tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim + veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea + commodo consequat. Duis aute irure dolor in reprehenderit in voluptate + velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa qui officia deserunt + mollit anim id est laborum. + </body> +</html> \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/bug552789.php b/emacs/nxhtml/tests/in/bug552789.php new file mode 100644 index 0000000..eb3e856 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug552789.php @@ -0,0 +1,20 @@ + +<p> + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. + <?php + fun(); + ?> + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. + Some text to wrap. +</p> diff --git a/emacs/nxhtml/tests/in/bug556832-error-test.py b/emacs/nxhtml/tests/in/bug556832-error-test.py new file mode 100644 index 0000000..e998eda --- /dev/null +++ b/emacs/nxhtml/tests/in/bug556832-error-test.py @@ -0,0 +1,23 @@ +# -*- Python -*- + + +""" +=============== +This is a title +=============== + +This is some general description +""" + + +class SomeClass(object): + """ + This is a class description. + """ + + def __init__(self, fileName): + """The constructor.""" + pass + + def oneMethod(): + pass diff --git a/emacs/nxhtml/tests/in/bug557700-2.erb b/emacs/nxhtml/tests/in/bug557700-2.erb new file mode 100644 index 0000000..c05eec3 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug557700-2.erb @@ -0,0 +1,5 @@ +var x = 1; +<% @ruby_var.each do |v| %> + alert(v); + <% end %> + var y = 2; diff --git a/emacs/nxhtml/tests/in/bug557700-3.erb b/emacs/nxhtml/tests/in/bug557700-3.erb new file mode 100644 index 0000000..13d57d8 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug557700-3.erb @@ -0,0 +1,3 @@ +var x = 1; +var y = <%= v %>; + var z = 4; diff --git a/emacs/nxhtml/tests/in/bug557700-4.erb b/emacs/nxhtml/tests/in/bug557700-4.erb new file mode 100644 index 0000000..148e9b4 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug557700-4.erb @@ -0,0 +1,11 @@ +var x = 1; +for (i in l) { +alert(i); +} +<% var.each do |v| %> +alert(<%= v %>); +<% end %> +var z = 4; +for (i in l) { +alert(i); +} diff --git a/emacs/nxhtml/tests/in/bug557700-5.erb b/emacs/nxhtml/tests/in/bug557700-5.erb new file mode 100644 index 0000000..cfabef7 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug557700-5.erb @@ -0,0 +1,4 @@ +<% if true %> +alert(<%= v %>); +alert(<%= w %>); +<% end %> diff --git a/emacs/nxhtml/tests/in/bug557700-6.erb b/emacs/nxhtml/tests/in/bug557700-6.erb new file mode 100644 index 0000000..453f3e0 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug557700-6.erb @@ -0,0 +1,11 @@ +var x = "<%= x %>"; +var y = 5; + +Second line is treated as if it was a string. + +Problem with multiple lines inside ruby if: + +<% if b %> + var x = 1; +alert(1); +<% end %> diff --git a/emacs/nxhtml/tests/in/bug557700.erb b/emacs/nxhtml/tests/in/bug557700.erb new file mode 100644 index 0000000..e15c22e --- /dev/null +++ b/emacs/nxhtml/tests/in/bug557700.erb @@ -0,0 +1,3 @@ +var x = 1; +<%= ruby_code %> + var z = 3; diff --git a/emacs/nxhtml/tests/in/bug559772-TextHelper.php b/emacs/nxhtml/tests/in/bug559772-TextHelper.php new file mode 100644 index 0000000..0d3bffb --- /dev/null +++ b/emacs/nxhtml/tests/in/bug559772-TextHelper.php @@ -0,0 +1,205 @@ +<?php + +/* + * This file is part of the symfony package. + * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com> + * (c) 2004 David Heinemeier Hansson + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * TextHelper. + * + * @package symfony + * @subpackage helper + * @author Fabien Potencier <fabien.potencier@symfony-project.com> + * @author David Heinemeier Hansson + * @version SVN: $Id: TextHelper.php 3699 2007-04-02 11:47:32Z fabien $ + */ + +/** + * Truncates +text+ to the length of +length+ and replaces the last three characters with the +truncate_string+ + * if the +text+ is longer than +length+. + */ +function truncate_text($text, $length = 30, $truncate_string = '...', $truncate_lastspace = false) +{ + if ($text == '') + { + return ''; + } + + if (strlen($text) > $length) + { + $truncate_text = substr($text, 0, $length - strlen($truncate_string)); + if ($truncate_lastspace) + { + $truncate_text = preg_replace('/\s+?(\S+)?$/', '', $truncate_text); + } + + return $truncate_text.$truncate_string; + } + else + { + return $text; + } +} + +/** + * Highlights the +phrase+ where it is found in the +text+ by surrounding it like + * <strong class="highlight">I'm a highlight phrase</strong>. The highlighter can be specialized by + * passing +highlighter+ as single-quoted string with \1 where the phrase is supposed to be inserted. + * N.B.: The +phrase+ is sanitized to include only letters, digits, and spaces before use. + */ +function highlight_text($text, $phrase, $highlighter = '<strong class="highlight">\\1</strong>') +{ + if ($text == '') + { + return ''; + } + + if ($phrase == '') + { + return $text; + } + + return preg_replace('/('.preg_quote($phrase, '/').')/i', $highlighter, $text); +} + +/** + * Extracts an excerpt from the +text+ surrounding the +phrase+ with a number of characters on each side determined + * by +radius+. If the phrase isn't found, nil is returned. Ex: + * excerpt("hello my world", "my", 3) => "...lo my wo..." + */ +function excerpt_text($text, $phrase, $radius = 100, $excerpt_string = '...') +{ + if ($text == '' || $phrase == '') + { + return ''; + } + + $found_pos = strpos(strtolower($text), strtolower($phrase)); + if ($found_pos !== false) + { + $start_pos = max($found_pos - $radius, 0); + $end_pos = min($found_pos + strlen($phrase) + $radius, strlen($text)); + + $prefix = ($start_pos > 0) ? $excerpt_string : ''; + $postfix = $end_pos < strlen($text) ? $excerpt_string : ''; + + return $prefix.substr($text, $start_pos, $end_pos - $start_pos).$postfix; + } +} + +/** + * Word wrap long lines to line_width. + */ +function wrap_text($text, $line_width = 80) +{ + return preg_replace('/(.{1,'.$line_width.'})(\s+|$)/s', "\\1\n", preg_replace("/\n/", "\n\n", $text)); +} + +/* + # Returns +text+ transformed into html using very simple formatting rules + # Surrounds paragraphs with <tt><p></tt> tags, and converts line breaks into <tt><br /></tt> + # Two consecutive newlines(<tt>\n\n</tt>) are considered as a paragraph, one newline (<tt>\n</tt>) is + # considered a linebreak, three or more consecutive newlines are turned into two newlines +*/ +function simple_format_text($text, $options = array()) +{ + $css = (isset($options['class'])) ? ' class="'.$options['class'].'"' : ''; + + $text = sfToolkit::pregtr($text, array("/(\r\n|\r)/" => "\n", // lets make them newlines crossplatform + "/\n{3,}/" => "\n\n", // zap dupes + "/\n\n/" => "</p>\\0<p$css>", // turn two newlines into paragraph + "/([^\n])\n([^\n])/" => "\\1\n<br />\\2")); // turn single newline into <br/> + + return '<p'.$css.'>'.$text.'</p>'; // wrap the first and last line in paragraphs before we're done +} + +/** + * Turns all urls and email addresses into clickable links. The +link+ parameter can limit what should be linked. + * Options are :all (default), :email_addresses, and :urls. + * + * Example: + * auto_link("Go to http://www.symfony-project.com and say hello to fabien.potencier@example.com") => + * Go to <a href="http://www.symfony-project.com">http://www.symfony-project.com</a> and + * say hello to <a href="mailto:fabien.potencier@example.com">fabien.potencier@example.com</a> + */ +function auto_link_text($text, $link = 'all', $href_options = array()) +{ + if ($link == 'all') + { + return _auto_link_urls(_auto_link_email_addresses($text), $href_options); + } + else if ($link == 'email_addresses') + { + return _auto_link_email_addresses($text); + } + else if ($link == 'urls') + { + return _auto_link_urls($text, $href_options); + } +} + +/* + * Turns all links into words, like "<a href="something">else</a>" to "else". + */ +function strip_links_text($text) +{ + return preg_replace('/<a.*>(.*)<\/a>/m', '\\1', $text); +} + +if (!defined('SF_AUTO_LINK_RE')) +{ + define('SF_AUTO_LINK_RE', '~ + ( # leading text + <\w+.*?>| # leading HTML tag, or + [^=!:\'"/]| # leading punctuation, or + ^ # beginning of line + ) + ( + (?:https?://)| # protocol spec, or + (?:www\.) # www.* + ) + ( + [-\w]+ # subdomain or domain + (?:\.[-\w]+)* # remaining subdomains or domain + (?::\d+)? # port + (?:/(?:(?:[\~\w\+%-]|(?:[,.;:][^\s$]))+)?)* # path + (?:\?[\w\+%&=.;-]+)? # query string + (?:\#[\w\-]*)? # trailing anchor + ) + ([[:punct:]]|\s|<|$) # trailing text + ~x'); +} + +/** + * Turns all urls into clickable links. + */ +function _auto_link_urls($text, $href_options = array()) +{ + $href_options = _tag_options($href_options); + return preg_replace_callback( + SF_AUTO_LINK_RE, + create_function('$matches', ' + if (preg_match("/<a\s/i", $matches[1])) + { + return $matches[0]; + } + else + { + return $matches[1].\'<a href="\'.($matches[2] == "www." ? "http://www." : $matches[2]).$matches[3].\'"'.$href_options.'>\'.$matches[2].$matches[3].\'</a>\'.$matches[4]; + } + ') + , $text); +} + +/** + * Turns all email addresses into clickable links. + */ +function _auto_link_email_addresses($text) +{ + return preg_replace('/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/', '<a href="mailto:\\1">\\1</a>', $text); +} diff --git a/emacs/nxhtml/tests/in/bug565595.mako b/emacs/nxhtml/tests/in/bug565595.mako new file mode 100644 index 0000000..3444765 --- /dev/null +++ b/emacs/nxhtml/tests/in/bug565595.mako @@ -0,0 +1,12 @@ +<%! + import sys +%> +<html> + <head> + <title>Test</title> + </head> + <body> + </body> + +</html> + diff --git a/emacs/nxhtml/tests/in/bug568178.pl b/emacs/nxhtml/tests/in/bug568178.pl new file mode 100644 index 0000000..a454f4b --- /dev/null +++ b/emacs/nxhtml/tests/in/bug568178.pl @@ -0,0 +1,4 @@ +print SOCKET << HTML or warn "Cannot write to socket: $!"; +<input type="text">html continues... + +HTML diff --git a/emacs/nxhtml/tests/in/bug568178.sh b/emacs/nxhtml/tests/in/bug568178.sh new file mode 100644 index 0000000..ca5e2af --- /dev/null +++ b/emacs/nxhtml/tests/in/bug568178.sh @@ -0,0 +1,9 @@ +bteq << 'SQL part' | grep '\\$'| read start_dt_ya start_dt end_dt_ya end_dt +-- SQL code here +select '$',start_date- '1 year', start_date .... +SQL part + +bteq <<SQL | grep '\\$'| read start_dt_ya start_dt end_dt_ya end_dt +-- SQL code here +select '$',start_date- '1 year', start_date .... +SQL diff --git a/emacs/nxhtml/tests/in/bug569742-master-end.html b/emacs/nxhtml/tests/in/bug569742-master-end.html new file mode 100644 index 0000000..8e0419c --- /dev/null +++ b/emacs/nxhtml/tests/in/bug569742-master-end.html @@ -0,0 +1,37 @@ + +From EmacsWiki: + +I have chunk problems with 1.99. This works, it detects the PHP and JS chunks properly: + +<? + + +$stuff = <<<EOTHTML + + <script type="text/javascript"> + + //<![CDATA[ + + var stuff; + + //]]> + </script> + +EOTHTML; + + +However if I donât close the inner chunk before EOTHTML, because I want to add some conditional code after it in PHP then it thinks the part of the buffer after EOTHTML is still in JS mode which is not good: + +<? + + +$stuff = <<<EOTHTML + + <script type="text/javascript"> + + //<![CDATA[ + + var stuff; + +EOTHTML; + diff --git a/emacs/nxhtml/tests/in/ch-2008-07-25-test.html.erb b/emacs/nxhtml/tests/in/ch-2008-07-25-test.html.erb new file mode 100644 index 0000000..92b76fa --- /dev/null +++ b/emacs/nxhtml/tests/in/ch-2008-07-25-test.html.erb @@ -0,0 +1,37 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<% @meta_keywords ||= nil -%> +<% @meta_description ||= nil -%> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> + <% unless @meta_keywords.blank? -%> + <meta name="keywords" content="<%= @meta_keywords %>" /> + <% end -%> + <% unless @meta_description.blank? -%> + <meta name="description" content="<%= @meta_description %>" /> + <% end -%> + <title><%= @page_title.blank? ? "Mysite" : "#{@page_title} : Mysite" %></title> + <%= stylesheet_link_tag 'global', 'sem', :media => 'all' %> + </head> + <body> + <div id="shadow"> + <div id="container"> + + <div id="main" class="content"> + <%= yield %> + </div> + <table> + This text is in the wrong place, but you have to apply a + schema to get it marked as invalid. + <%= yield %> + </table> + + </div> <%# container %> + </div> <%# shadow %> + </body> + <% if live_site? %> + <%= render(:partial => 'shared/google_analytics') %> + <% end %> +</html> diff --git a/emacs/nxhtml/tests/in/chunks-in-chunks1.php b/emacs/nxhtml/tests/in/chunks-in-chunks1.php new file mode 100644 index 0000000..007bc66 --- /dev/null +++ b/emacs/nxhtml/tests/in/chunks-in-chunks1.php @@ -0,0 +1,19 @@ +$a = <<<EOTHTML + +<p>stuff</p> + +EOTHTML; + + +$b = <<<EOT + + <h2><a href="/">stuff</a></h2> + +EOT; + +$c = <<<EOT + +<button onclick="a()">test</button> + + +EOT; diff --git a/emacs/nxhtml/tests/in/chunks.html b/emacs/nxhtml/tests/in/chunks.html new file mode 100644 index 0000000..62a3bf8 --- /dev/null +++ b/emacs/nxhtml/tests/in/chunks.html @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + <script type="text/javascript"> + // <![CDATA[ + alert ("here"); + /* + -------------------------------------------------------------------------- + Do not edit past this point unless you know what you are doing. + -------------------------------------------------------------------------- + ===== BUG: THIS LINE IS BLACK ========== + ===== BUG: THIS LINE IS BLACK ========== + */ + + addEvent(window, 'load', spamSpan); + + function spamSpan() { + var allSpamSpans = getElementsByClass(spamSpanMainClass, document, 'span'); + for (var i = 0; i < allSpamSpans.length; i++) { + // get data + var user = getSpanValue(spamSpanUserClass, allSpamSpans[i]); + var domain = getSpanValue(spamSpanDomainClass, allSpamSpans[i]); + var anchorText = getSpanValue(spamSpanAnchorTextClass, allSpamSpans[i]); + // prepare parameter data + var paramValues = new Array(); + for (var j = 0; j < spamSpanParams.length; j++) { + var paramSpanValue = getSpanValue(spamSpanParams[j], allSpamSpans[i]); + if (paramSpanValue) { + paramValues.push(spamSpanParams[j] + '=' + + encodeURIComponent(paramSpanValue)); + } + } + // create new anchor tag + var at = String.fromCharCode(32*2); + var email = cleanSpan(user) + at + cleanSpan(domain); + var anchorTagText = document.createTextNode(anchorText ? anchorText : email); + var mto = String.fromCharCode(109,97,105,108,116,111,58); + var hrefAttr = mto + email; + hrefAttr += paramValues.length ? '?' + paramValues.join('&') : ''; + var anchorTag = document.createElement('a'); + anchorTag.className = spamSpanMainClass; + anchorTag.setAttribute('href', hrefAttr); + anchorTag.appendChild(anchorTagText); + // replace the span with anchor + allSpamSpans[i].parentNode.replaceChild(anchorTag, allSpamSpans[i]); + } + } + // ]]> + </script> + <style type="text/css" media="all"> + /* <![CDATA[ */ + body { + margin-left: 1px; + /* ]]> */ + </style> + + </head> + <body> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/cr-lf.el b/emacs/nxhtml/tests/in/cr-lf.el new file mode 100644 index 0000000..0a7d06b --- /dev/null +++ b/emacs/nxhtml/tests/in/cr-lf.el @@ -0,0 +1,2 @@ +;; This is just a test of cr-lf handling. Save this file with DOS +;; cr-lf line endings and open it again. diff --git a/emacs/nxhtml/tests/in/csr-080710-2.html b/emacs/nxhtml/tests/in/csr-080710-2.html new file mode 100644 index 0000000..bccc2f7 --- /dev/null +++ b/emacs/nxhtml/tests/in/csr-080710-2.html @@ -0,0 +1,23 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Title</title> + <style type="text/css"> + body { background: #ccc; } + p { + color: white; + + } + </style> + </head> + <body> + <div id="container"> + <script type="text/javascript"> + var a = "aaa"; + + function test () { + + } + </script> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/csr-080710.html b/emacs/nxhtml/tests/in/csr-080710.html new file mode 100644 index 0000000..be99b8b --- /dev/null +++ b/emacs/nxhtml/tests/in/csr-080710.html @@ -0,0 +1,24 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title></title> + <link rel="Stylesheet" type="text/css" href="/style/style.css" media="all" /> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <style type="text/css" media="all"> + + </style> + </head> + <body> + <div id="container"> + <script type="text/javascript"> + var a = "aaa"; + + function test () { + + } + </script> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/cvd-080805-ac.php b/emacs/nxhtml/tests/in/cvd-080805-ac.php new file mode 100644 index 0000000..b951c75 --- /dev/null +++ b/emacs/nxhtml/tests/in/cvd-080805-ac.php @@ -0,0 +1,21 @@ +<?php + +Zend_Loader::loadClass('Account','application/models'); +Zend_Loader::loadClass('Device','application/models'); +Zend_Loader::loadClass('Carrier','application/models'); +Zend_Loader::loadClass('DistributionChannel','application/models'); + +/** Zend_Controller_Action */ +require_once 'Zend_Global_Controller_Action.php'; + +class AccountController extends Zend_Global_Controller_Action +{ + public function indexAction($errors = array()) + { + + $this->view->assign('errors',$errors); + $this->view->assign('body','account_index.htm'); +echo $this->view->render('main_doc.htm'); + + } +} diff --git a/emacs/nxhtml/tests/in/cvd-080805-cc.php b/emacs/nxhtml/tests/in/cvd-080805-cc.php new file mode 100644 index 0000000..4394387 --- /dev/null +++ b/emacs/nxhtml/tests/in/cvd-080805-cc.php @@ -0,0 +1,18 @@ +<?php + +Zend_Loader::loadClass("Category","application/models"); +Zend_Loader::loadClass("CategoryDisplayName","application/models"); + +/** Zend_Controller_Action */ +require_once 'Zend_Global_Controller_Action.php'; + +class CategoryController extends Zend_Global_Controller_Action +{ + public function indexAction($notices = array(), $errors = array()) + { + + $request = $this->GetRequest(); + blah, etc. + } +} + diff --git a/emacs/nxhtml/tests/in/drechsler-080517-simple.xml b/emacs/nxhtml/tests/in/drechsler-080517-simple.xml new file mode 100644 index 0000000..01b738d --- /dev/null +++ b/emacs/nxhtml/tests/in/drechsler-080517-simple.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<data> +</data> diff --git a/emacs/nxhtml/tests/in/el-070424-duh.xml b/emacs/nxhtml/tests/in/el-070424-duh.xml new file mode 100644 index 0000000..4e8b09a --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070424-duh.xml @@ -0,0 +1,6 @@ +<outermost> + <inner1><inner2> + <inner3>Duh</inner3> + </inner2> + </inner1> +</outermost> diff --git a/emacs/nxhtml/tests/in/el-070511-simple.html b/emacs/nxhtml/tests/in/el-070511-simple.html new file mode 100644 index 0000000..d56f53f --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070511-simple.html @@ -0,0 +1,102 @@ +<!-- Since this file is not xhtml, nxhtml won't indent it correctly. + Therefore, turn on html mode before editing this file: + M-x html-mode --> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> + <HEAD> + <TITLE>TDDB64 Avancerad programmering och interaktivitet pÃ¥ WWW</TITLE> + <META content="text/html; charset=windows-1252" http-equiv=Content-Type> + <META content="Microsoft FrontPage 4.0" name=GENERATOR> + + + <SCRIPT language="javascript" type="text/javascript"> + + </SCRIPT> + + + </HEAD> + + <BODY bgColor="#ffffff"> + <P> + <TABLE border=0 cellPadding=1 cellSpacing=0 width="100%"> + <TR> + <TD align=CENTER bgColor="#ddffdd" width="15%"> + <IMG align=MIDDLE alt="IDA " border=0 hspace=4 src="http://www.ida.liu.se/~TDDB06/labs/dhtml/simple_files/Ida-logo-tr-mini.gif"> </TD> + <TD width="1%"> + <TD width="84%"> + + <B><A href="http://www.ida.liu.se/">Dept. of Computer and + Information Science</A>, <A href="http://www.liu.se/">Linköping + University</A></B> </TD> + </TR> + <TR> + <TD align=CENTER bgColor="#ddffdd" vAlign=top width="15%"><BR><BR> + + + <!-- --> + <!-- The Menue list starts here --> + <!-- --> + <DL> + <DT><B><A href="http://www.ida.liu.se/~TDDB06/index.shtm">Home</A></B> + <DT><B><A href="http://www.ida.liu.se/~TDDB06/faq.shtml">FAQ</A></B> + <DT><B><A + href="http://www.ida.liu.se/~TDDB06/labs/index.shtml">Labs</A></B> + <DT><B><A + href="http://www.ida.liu.se/~TDDB06/fo2000.shtml">Lectures</A></B> + <DT><B><A + href="http://www.ida.liu.se/~TDDB06/news2000.shtml">News</A></B> + <DT><B><A + href="http://www.lith.liu.se:4019/schema/schema?period=period+3+99-00&kurs=DDB06">Schedule</A></B> + + <DT><B><A + href="http://www.ida.liu.se/~TDDB06/resources.shtml">Resources</A></B> + <DT><B><A href="http://www.ida.liu.se/~TDDB06/staff.shtml">Staff</A></B> + + <DT><B><A href="http://www.ida.liu.se/~TDDB06/other.shtml">Other</A></B> + + <DT><B><A href="http://www.ida.liu.se/~TDDB06/"></A></B> + <DT><B><A href="http://www.ida.liu.se/~TDDB06/"></A></B> + <DT><B><A href="http://www.ida.liu.se/~TDDB06/"></A></B> + <DT><B><A href="http://www.ida.liu.se/~TDDB06/"></A></B> + <DT><B><A href="http://www.ida.liu.se/~TDDB06/"></A></B></DT> + + </DL> + <!-- --> + <!-- The Menue list ends here --> + <!-- --> + + + </TD> + <TD width="1%"> + <TD width="84%"> + + + + <!-- --> + <!-- The page content starts here --> + <!-- --> + <img src="http://www.ida.liu.se/~TDDB06/const.gif" alt="JavaDude"> + This page is not under construction. It is supposed to look like this. + + <H1>TDDB64 Web Programming and Interactivity</H1>This + course covers an overview of WWW, HTML, basic Java programming, and + advanced Java programming. The course consists of a number of + <EM>lectures, programming assignments,</EM> and a <EM>programming + project,</EM> where the students practice advanced Java and WWW + implementation techniques. + <!-- --> + <!-- The page content starts here --> + <!-- --> + + + + </TD></TR> + </TABLE> + <HR> + <p> + <a href="http://validator.w3.org/check?uri=referer"><img + src="http://www.w3.org/Icons/valid-html40" + alt="Valid HTML 4.0 Transitional" height="31" width="88"></a> + </p> + +</BODY></HTML> diff --git a/emacs/nxhtml/tests/in/el-070602-index.php b/emacs/nxhtml/tests/in/el-070602-index.php new file mode 100644 index 0000000..f971b1a --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070602-index.php @@ -0,0 +1,54 @@ +<?php + /* We must use this header to be correct and for the css validator to + find our stylesheet without us having to provide a fully qualified + path (address) to it. */ +header("Content-type:application/xhtml+xml; charset=utf-8"); +echo '<'.'?xml version="1.0" encoding="utf-8"?'.'>'; +?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Lab 2 - Layout Control - Task 1 - XHTML/CSS version</title> + <link rel="stylesheet" type="text/css" href="stylesheet.css"/> + </head> + <body> + <div id="container"> + <div id="header">Top area</div> + <div id="left-menu"> + <ul> + <li><a style="hej" href="index.php">Home</a></li> + <li><a href="index.php?page=a">First Main Page</a></li> + <li><a href="index.php?page=b">Second Main Page</a></li> + </ul> + </div> + <div id="main"> + <?php + if (isset($_GET['page'])) { + $thepage = $_GET['page']; + + if ($thepage != 'a' && $thepage != 'b') { + print('You hacker you!'); + } + else { + require('main-div-'.$thepage.'.html'); + } + } + else { + require('main-div-a.html'); + } + ?> + </div> + <div id="footer"> + <p> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="valid-xhtml10.png" alt="Valid XHTML 1.0 Strict"></img> + </a> + <a href="http://jigsaw.w3.org/css-validator/check?uri=referer"> + <img src="vcss.png" alt="Valid CSS!"></img> + </a> + </p> + </div> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/el-070604.html b/emacs/nxhtml/tests/in/el-070604.html new file mode 100644 index 0000000..882e982 --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070604.html @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>Dummy</title> + <link rel="stylesheet" type="text/css" href="<?php echo get_stylesheet();?>"/> + </head> + <body> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/el-070604.php b/emacs/nxhtml/tests/in/el-070604.php new file mode 100644 index 0000000..45f7d7c --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070604.php @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>Dummy</title> + <link rel="stylesheet" type="text/css" href="<?php echo get_stylesheet();?>"/> + </head> + <body> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/el-070722-comment-error.php b/emacs/nxhtml/tests/in/el-070722-comment-error.php new file mode 100644 index 0000000..ff3bdf5 --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070722-comment-error.php @@ -0,0 +1,6 @@ +<?php +/* this is a comment + and it seems to work ok... +*/ +?> + diff --git a/emacs/nxhtml/tests/in/el-070722-index-2.el b/emacs/nxhtml/tests/in/el-070722-index-2.el new file mode 100644 index 0000000..05b18f1 --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070722-index-2.el @@ -0,0 +1,7 @@ +(defun temp-el-070722 () + (remove-text-properties 1 25 '(syntax-table nil)) + (syntax-ppss-flush-cache -1) + (setq syntax-ppss-last nil) + (goto-char (point-min)) + (let ((parse-sexp-lookup-properties t)) (syntax-ppss 24)) + ) diff --git a/emacs/nxhtml/tests/in/el-070722-index-2.php b/emacs/nxhtml/tests/in/el-070722-index-2.php new file mode 100644 index 0000000..ff4dbf9 --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070722-index-2.php @@ -0,0 +1,48 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Lab 2 - Layout Control - Task 2 - XHTML/CSS version</title> + <link rel="stylesheet" type="text/css" href="stylesheet.css"/> + </head> + <body> + <div id="container"> + <div id="header">Top area</div> + <div id="left-menu"> + <ul> + <li><a href="index.php">Home</a></li> + <li><a href="index.php?page=a">First Main Page</a></li> + <li><a href="index.php?page=b">Second Main Page</a></li> + </ul> + </div> + <div id="main"> + <?php + if (isset($_GET["page"])) { + $thepage = $_GET['page']; + + if ($thepage != 'a' && $thepage != 'b') { + print('You hacker you!'); + } + else { + require('main-div-'.$thepage.'.html'); + } + } + else { + require('main-div-a.html'); + } + ?> + </div> + <div id="right-menu">Right area</div> + <div id="footer"> + <p> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="valid-xhtml10.png" alt="Valid XHTML 1.0 Strict"></img> + </a> + <a href="http://jigsaw.w3.org/css-validator/check?uri=referer"> + <img src="vcss.png" alt="Valid CSS!"></img> + </a> + </p> + </div> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/el-070722-index-noheader.php b/emacs/nxhtml/tests/in/el-070722-index-noheader.php new file mode 100644 index 0000000..34271ba --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070722-index-noheader.php @@ -0,0 +1,48 @@ +<?php +/* We must use this header to be correct and for the css validator to + find our stylesheet without us having to provide a fully qualified + path (address) to it. */ +header("Content-type:application/xhtml+xml; charset=utf-8"); +echo '<'.'?xml version="1.0" encoding="utf-8"?'.'>'; +?> + <body> + <div id="container"> + <div id="header">Top area</div> + <div id="left-menu"> + <ul> + <li><a href="index.php">Home</a></li> + <li><a href="index.php?page=a">First Main Page</a></li> + <li><a href="index.php?page=b">Second Main Page</a></li> + </ul> + </div> + <div id="main"> + <?php + if (isset($_GET["page"])) { + $thepage = $_GET['page']; + + if ($thepage != 'a' && $thepage != 'b') { + print('You hacker you!'); + } + else { + require('main-div-'.$thepage.'.html'); + } + } + else { + require('main-div-a.html'); + } + ?> + </div> + <div id="right-menu">Right area</div> + <div id="footer"> + <p> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="valid-xhtml10.png" alt="Valid XHTML 1.0 Strict"></img> + </a> + <a href="http://jigsaw.w3.org/css-validator/check?uri=referer"> + <img src="vcss.png" alt="Valid CSS!"></img> + </a> + </p> + </div> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/el-070722-index.php b/emacs/nxhtml/tests/in/el-070722-index.php new file mode 100644 index 0000000..1418da2 --- /dev/null +++ b/emacs/nxhtml/tests/in/el-070722-index.php @@ -0,0 +1,55 @@ +<?php +/* We must use this header to be correct and for the css validator to + find our stylesheet without us having to provide a fully qualified + path (address) to it. */ +header("Content-type:application/xhtml+xml; charset=utf-8"); +echo '<'.'?xml version="1.0" encoding="utf-8"?'.'>'; +?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Lab 2 - Layout Control - Task 2 - XHTML/CSS version</title> + <link rel="stylesheet" type="text/css" href="stylesheet.css"/> + </head> + <body> + <div id="container"> + <div id="header">Top area</div> + <div id="left-menu"> + <ul> + <li><a href="index.php">Home</a></li> + <li><a href="index.php?page=a">First Main Page</a></li> + <li><a href="index.php?page=b">Second Main Page</a></li> + </ul> + </div> + <div id="main"> + <?php + if (isset($_GET["page"])) { + $thepage = $_GET['page']; + + if ($thepage != 'a' && $thepage != 'b') { + print('You hacker you!'); + } + else { + require('main-div-'.$thepage.'.html'); + } + } + else { + require('main-div-a.html'); + } + ?> + </div> + <div id="right-menu">Right area</div> + <div id="footer"> + <p> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="valid-xhtml10.png" alt="Valid XHTML 1.0 Strict"></img> + </a> + <a href="http://jigsaw.w3.org/css-validator/check?uri=referer"> + <img src="vcss.png" alt="Valid CSS!"></img> + </a> + </p> + </div> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/el-071217-foo.html b/emacs/nxhtml/tests/in/el-071217-foo.html new file mode 100644 index 0000000..32b7412 --- /dev/null +++ b/emacs/nxhtml/tests/in/el-071217-foo.html @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <frameset cols="50%, 50%"> + <frame src="about:blank" /> + <frame src="about:blank" /> + </frameset> +</html> +<!-- A comment --> diff --git a/emacs/nxhtml/tests/in/emacswiki-080119.php b/emacs/nxhtml/tests/in/emacswiki-080119.php new file mode 100644 index 0000000..e4215a1 --- /dev/null +++ b/emacs/nxhtml/tests/in/emacswiki-080119.php @@ -0,0 +1,15 @@ +<?php + + /* There was a problem reported 2008-01-19 on + http://www.emacswiki.org/cgi-bin/wiki/NxhtmlMode. The word + INCLUDE was highlighted with a different color. However this + should now work and the word APP_INCLUDE below should all be in + font-lock-warning-face. + + FIXME: When deleting the first star the first time only the first + part of the comment is affected. + */ + +define("APP_INCLUDE", "/home/app/include/"); include_once(APP_INCLUDE . "file.php"); + +?> diff --git a/emacs/nxhtml/tests/in/emacswiki-erb-bug.el b/emacs/nxhtml/tests/in/emacswiki-erb-bug.el new file mode 100644 index 0000000..4e565ef --- /dev/null +++ b/emacs/nxhtml/tests/in/emacswiki-erb-bug.el @@ -0,0 +1,36 @@ +;;; This file is from a link on EmacsWiki to http://paste.lisp.org/display/59495 +;; +;; As far as I can see this is a ruby-mode bug, not a mumamo bug. + +;;; The problem is that when a ruby ERB template is loaded with an +;;; after-hook that modifies the font-lock keywords, nxhtml causes +;;; font-lock not to occur on strings and comments. What's more is +;;; this affects regular ruby-mode as well, not just within mumamo. + +(require 'ruby-mode) + +;; Extra keyword fontification for ruby +(defun emacswiki-erb-bug-keywords () + (font-lock-add-keywords nil + '(("\\<\\(FIX\\|TODO\\|FIXME\\|HACK\\|REFACTOR\\):" + 1 font-lock-warning-face t)))) + +;; Adding the extra keywords at the beginning of ruby-mode-hook breaks +;; ruby-mode fontification (use the test case at the bottom): +(add-hook 'ruby-mode-hook 'emacswiki-erb-bug-keywords) +;; removing this hook makes it not break anymore: +(remove-hook 'ruby-mode-hook 'emacswiki-erb-bug-keywords) +;; However adding the extra keywords at the end of the hook works fine: +(add-hook 'ruby-mode-hook 'emacswiki-erb-bug-keywords t) + + +;; run this to test: +(progn + (find-file "bar.rb") + (insert "# Comments should be font-locked, but are not. +class Bar + def baz + \"strings should also be font-locked but are not.\" + end +end")) + diff --git a/emacs/nxhtml/tests/in/err-line38.html b/emacs/nxhtml/tests/in/err-line38.html new file mode 100644 index 0000000..3a5182f --- /dev/null +++ b/emacs/nxhtml/tests/in/err-line38.html @@ -0,0 +1,768 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>News and Notes about nXhtml</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> + </head> + <body> + <div id="container"> + + <div id="rgtcol"> + <p id="nxhtml-home"> + <a href="nxhtml.html">To nXhtml main page</a> + </p> + + <h1>News and Notes about nXhtml</h1> + + <dl> + + <dt id="hadron-bugs" style="margin-top:1em;">Thanks for testing!</dt> + <dd> + <p> + I want to thanks the testers, especially Hadron Quark + and Eric Lilja, for helping me by testing and pointing + out bugs and weaknesses, most related to editing of PHP. + </p> + <p> + It is quite a big job trying to get rid of smaller annoying bugs and bigger ones. + In my mailbox folder for nXhtml I have more than 500 old messages currently. + </p> + </dd> + + <dt id="state-of-the-art" style="margin-top:1em; + background-color: #00fa9a; + background-color: #20b2aa; + padding: 0.5em; + ">The State of the Art</dt> + <dd style="background-color: #54ff9f; padding: 0.5em"> + <p> + I have more and more come to realize that there are two + main parts of nXhtml which are in quite different + degrees of maturity. The reason for the difference is + mainly that one of them, <strong>mumamo-mode</strong>, requires + very tight integration with Emacs in a way that + currently is not completely possible. Some things must + be changed in Emacs for this. There are also things to + discover in the interactions with other minor modes for + example. + </p> + <p> + That said I still think mumamo-mode is mature enough for + serious use (though it sometimes conflicts with some other modules). + </p> + <p> + The other part, <strong>nxhtml-mode</strong>, is more mature, + since it stands more by itself and since it builds on + the very stable nxml-mode. I would not say nxhtml-mode + is finished, but it is stable and useful. + </p> + </dd> + + <dt id="magic-problems" style="margin-top:1em;">Magic major mode selection</dt> + <dd> + <p> + Sometimes the major mode that Emacs opens a file in is + not what you expect. This can happen with files like PHP + files. The reason might be that magic-mode-alist have + choosen a mode based on the content of the file. The way + this is done does not take files with mixes a mix of for + example XHTML and PHP into account. + </p> + <p> + You may try setting magic-mode-alist to nil if this is a + problem for you. + </p> + <p> + <em> + This is now no longer necessary since the introduction + of magic-fallback-mode-alist in CVS Emacs on 2007-05-16. + (If you have an Emacs newer than that, of course.) + </em> + </p> + </dd> + + <dt id="underline-bug" style="margin-top:1em;">Long Red Underlines</dt> + <dd> + <p> + Because of a bug in Emacs 22.1 you can sometimes (at the + end of a line) get long red lines instead of just a + single underlined character. Many users (me included) + find this quite a bit disturbing. I have therefore added + a command to quickly hide/show the underlines. This is + on <em>C-c C-w</em>. + </p> + <p> + This is particular useful for example in the case where + you edit a PHP file and are bound to get a lot of XHTML + validation errors. + </p> + </dd> + + <dt id="php-attribute-values" style="margin-top:1em;">Attribute values computed by PHP</dt> + <dd> + <p> + If you want to have attribute values computed by PHP + here is a way how to structure that to avoid breaking + completion and validation in the XHTML part unnessecary: + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="<?php foo("bar");?>"/> + </p> + <p> + Unfortunately that still breaks XHTML validation since + < is not allowed in strings. In the long run I + believe the XML validator has to be broken up so that it + avoids parsing the string here (in PHP files). + </p> + <p> + For now I have implemented a workaround. + If you are using constructs like those above then turn on <em>nxhtml-strval-mode</em>. + This will temporarily replace the above with + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="«?php foo("bar");?»"/> + </p> + <p> + However on the screen you will still see the original + string and when writing to file the correct characters + will be used. + </p> + </dd> + + <dt id="pi-note" style="margin-top:1em;">A note for PHP and its cousins</dt> + <dd> + <p> + The rules for a process instruction in XML, like <?php + ... ?> says that the text can contain any text except + <em>?></em>. So if you want to output that string + from PHP then break it up so it does not look as ?> in + the source file. + </p> + <p> + It might be good to break up the beginning part of the + process instructions too. And please note that to use + XHTML validation or completion you should avoid using + < in strings, since it is not allowed there. + </p> + </dd> + + <dt id="pi-note" style="margin-top:1em;">Perl Mode slow with Mumamo Mode</dt> + <dd> + <p> + Perl mode used with MuMaMo mode sometimes makes the + fontification slow for big files. I do not know the + reason, but I am trying to find a solution for this. If + you encounter this problem, just turn off mumamo-mode in + that buffer. + </p> + </dd> + + <dt id="tab-width-problems" style="margin-top:1em;">Tab width</dt> + <dd> + <p> + Do you have <em>tab-width</em> to something different than 8 + (the default)? Then please change this to 8. I have got + reports of problem with indentation when it is not 8. + </p> + </dd> + + <dt id="mmm-compat" style="margin-top:1em;">Why the chunks are not compatible with mmm</dt> + <dd> + <p> + Some people have asked why the way to specify chunks in + mumamo-mode is not compatible with the old mmm-mode. The + answer is that I was not sure that the way used in + mmm-mode for specifying the chunks was flexible enough. + </p> + <p> + And I am sure that even the way used in mumamo-mode is + not good enough for all cases, but I let it be the way + it is until I have a better understanding of the + problem. Suggestions and comments are welcome! + </p> + </dd> + + </dl> + + <h1>nXhtml Changes</h1> + + <dl> + <dt>0.89</dt> + <dd> + <ul> + <li> + Corrected autostart for nXhtml when not used together with EmacsW32. + </li> + </ul> + </dd> + <dt>0.90</dt> + <dd> + <ul> + <li> + Improved display of XML path. + </li> + <li> + Discontinued xmple-mode. + </li> + <li> + New major modes nxhtml-part-mode/nxml-part-mode replaces + minor mode xmlpe-mode. (While moving the code to + nxhtml-part.el I also fixed a bug in Xmple minor mode that + made Emacs take 99% of the CPU.) + </li> + </ul> + </dd> + <dt>0.91</dt> + <dd> + <ul> + <li> + Fixed some calls to perl which prevented uploading of + a site of you did not have perl in the same location + as me. + </li> + <li> + Glued together things so that editing PHP files works + as I intended. (This means that Emacs switches between + php-mode and nxhtml-part-mode automatically when + moving point. And that you can use completion.) + </li> + <li> + Starting working on the documentation for nXhtml. + New layout to the documentation files. + Examples with images. + </li> + </ul> + </dd> + <dt>0.92</dt> + <dd> + <ul> + <li> + Fixes to make the switching between php and xhtml + style editing work better. + </li> + </ul> + </dd> + <dt>0.93</dt> + <dd> + <ul> + <li> + Better error handling when switching to editing + embedded JavaScript and CSS. + </li> + <li> + Removed PHP spec from embedded switching since they + interfered with the automatic switching between php + and xhtml. + </li> + <li> + Gives an error message if web host is not defined in + site when trying to use View Uploaded File and + cousins. + </li> + <li> + Gives a ready message when finished uploading a single + file. + </li> + <li> + When using Mode Switching at <? ... ?> mode + switching could occur in wrong buffer. Fixed together + with some other buffer problems. + </li> + </ul> + </dd> + <dt>0.94</dt> + <dd> + <ul> + <li> + Add http://www.w3.org/ to the help sites for CSS. + </li> + <li> + Included a CSS mode. + </li> + <li> + Added a menu entry for bug reporting. + </li> + <li> + Renamed menu bar entry from XHTML to nXhtml for clarity. + (But nXml menu bar entry is still called XML.) + </li> + <li> + Added work around for globalized minor modes in the + cases of MLinks, XML Path and mode switching at <? ... ?>. + </li> + </ul> + </dd> + <dt>0.95</dt> + <dd> + <ul> + <li> + Added workaround for the problem with the first + keyboard key after automatically switching of mode at + <? ... ?>. + </li> + </ul> + </dd> + <dt>0.96</dt> + <dd> + <ul> + <li> + Added support for multiple major modes with mumamo.el. + </li> + <li> + More conventient handling of links. They can now be + opened in the same window, 'other window' or in a new + frame. + </li> + </ul> + </dd> + <dt>0.97</dt> + <dd> + <ul> + <li> + Schema was not setup after starting new page so + completion did not work. Fixed. + </li> + <li> + Added http://xhtml.com/ to help sites for XHTML. + </li> + <li> + Added the concept of <em>XML validation headers</em>. + These are just text parsed by the nXml validation + parser to get a start state before starting parsing a + buffer. This allows the use of the nXml completion in + buffers where there are no XML header. Such a header + is often lacking for example in PHP code since the + XHTML header is often generated dynamically. + </li> + <li> + Because of the change above <em>nxhtml-part-mode</em> + is no longer needed and is therefore declared + obsolete. + </li> + <li> + Corrected a bug in mlinks.el that prevented opening an + HTML link in a other window or a new frame. + </li> + <li> + Added support for JSP, eRuby and some support for perl + in mumamo.el. + </li> + </ul> + </dd> + <dt>0.98</dt> + <dd id="v0.98"> + <ul> + <li> + Mumamo was not found when nXhtml was installed with + just the zip file. Corrected. (nXhtml is also + installed when you install EmacsW32.) + </li> + <li> + Enhancement to mumamo error handling when a bad mode + specifier for an embedded mode is found. + </li> + <li> + Introduced a bug for empty XHTML documents in + 0.97. Corrected. + </li> + <li> + Corrected a bug for chunks 1 character long. + </li> + <li> + There is what I consider is a bug in Emacs 22.1 in the + handling of global minor mode that are not distributed + with Emacs. If they are turned on by customization, + but loaded after Emacs have loaded the customizations + (usually in .emacs) then they are not turned on + correctly. Added work-around for this. + </li> + <li> + <em>Extra XHTML Validation Header</em>: + <ul> + <li> + <em>Extra XHTML Validation Header</em> state was not saved when moving between chunks. Fixed. + </li> + <li> + Tried to make the concept of <em>Extra XHTML Validation Header</em> + more clear. Added this visually to the buffer. + </li> + <li> + <em>Extra XHTML Validation Headers</em> can now be turned on + automatically based on file name. + </li> + </ul> + </li> + <li> + <em>nXhtml menu:</em> + <ul> + <li> + Reorganized the nXhtml menu. + </li> + <li> + Added <em>customization</em> groups for help libraries to nXhtml. + </li> + <li> + Added an entry for customization of nXhtml to the menus. + </li> + <li> + Added <em>Tidy</em> to the menus again. + </li> + </ul> + </li> + <li> + Corrected bug in <em>XML Path</em> (nxml-where) for single tags. + Other small fixes to nxhtml-where. + </li> + <li> + Documentation enhancements. + Added <em>The Quick Guide</em>. + </li> + </ul> + </dd> + <dt>0.99</dt> + <dd id="v0.99"> + <ul> + <li> + Fixed a serious bug in the cooperation between nxhtml-mode and mumamo-mode. + </li> + <li> + Turn on mumamo-mode by file name (mumamo-global-mode). + </li> + <li> + Extra XHTML Validation Header: + <ul> + <li> + The Extra XHTML Validation Header state were not saved when changing major mode in MuMaMo. Corrected. + </li> + <li> + Added more alternatives to the Extra XHTML Validation Header list. + This should make it easier to use completion with for example PHP. + </li> + <li> + Added default value for the Extra XHTML Validation Header. + </li> + <li> + Tried to make the use of Extra XHTML Validation Header more automatic and therefore useful. + Also tried to make it play better with setting schema file. + (There is no need normally to set schema file by hand.) + </li> + <li> + To turn this on by default customize nxhtml-global-validation-header-mode. + </li> + </ul> + </li> + <li> + Possible to hide validation warnings without turning + on validation (which would make completion in the + XHTML part impossible). + </li> + <li> + Some fixes to php-mode: + <ul> + <li>Using the character # for comments now works for most cases.</li> + <li>Now uses the fontification faces in a more standard way which calms down the look.</li> + <li>Initialization bug fixes.</li> + <li>Renamed php-mode-user-hook to php-mode-hook to follow standard.</li> + </ul> + </li> + <li> + Indentation fixes: + <ul> + <li> + Various corrections to indentation in mumamo. + </li> + <li> + Added the possibility to use TAB to indent regions + (indent-region-mode). + </li> + <li> + Warn about bad indentation in mixed PHP/HTML code + when using php-mode only. + </li> + </ul> + </li> + <li> + Fontification now fontifies all text first in main + major mode and thereafter applies submodes. (This + avoids some problems with around a submode chunk.) + </li> + <li> + Reorganized the nXhtml menu: + <ul> + <li> + There is now a minor mode for the nXhtml + menu. This makes it possible to easier use common + features when in buffers not in nxhtml-mode. + </li> + <li> + The nXhtml menu does not disappear when moving + into a chunk where the major mode is not + nxhtml-mode. The changes also makes it easy to + access uploading functions functions etc from + other modes than nxhtml-mode since the + <em>nXhtml</em> may also be shown in them. + </li> + <li> + The nXhtml menu can be turned on globally by default. + Customize nxhtml-menu-mode for that. + </li> + </ul> + </li> + </ul> + </dd> + <dt>1.00</dt> + <dd id="v1.00"> + <ul> + <li> + Reached version number 1.00 - which you maybe believe + means the bugs should be gone? Sorry, it is just that + I ran out of version numbers ;-) However it looks like + much fewer bugs at least. + </li> + <li> + Fixed problems mostly related to global turn on of different features in nXhtml. + </li> + <li> + Small fixes to indentation. + <ul> + <li> + nxhtml-mode could get confused by php tags. + </li> + <li> + nxhtml-mode did not indent <!DOCTYPE in a sensible way. + </li> + <li> + Electric keys now works in embedded php when using mumamo-mode. + </li> + </ul> + </li> + <li> + Tidy was very misbehaving since the output buffer was + not erased between different files. But I have got no + bug reports on this ;-) + </li> + <li> + Fixed a bug in validation that should up when using muamo-mode. + </li> + <li> + Fixed bug in <script ...> and <style ...> chunk dividing. + </li> + <li> + Added support for OpenLaszlo. + </li> + <li> + Corrections to mlinks-mode (visible mostly as links in + XHTML buffers): + <ul> + <li> + Links disappeared when a new file was + opened. Corrected. + </li> + <li> + Links were not correctly updated at changes in the + buffer when mumamo-mode was used. Fixed. + </li> + </ul> + </li> + <li> + The welcome message for nXhtml could be shown too + early sometimes when loading, before nXhtml actually + knew if it should be shown or not. Tried to fix it. + </li> + </ul> + </dd> + <dt>1.01</dt> + <dd id="v1.01"> + <ul> + <li> + Reported wrong version number for nXhtml in the menus. Fixed. + </li> + <li> + <em>If you use the zip file to install nXhtml please + notice that it has now a top level nxml.</em> Sorry for not + having zipped it like that before! + </li> + <li> + The url links in <em>Welcome to nXhtml</em> was a bit + incorrect and did not work on all OS:es. Fixed. + </li> + <li> + Added customization of popup completion to the 'nxhtml + customization group so they are easier to find. + </li> + <li> + MuMaMo + <ul> + <li> + Struggled a bit with the load sequences of the elisp + libraries used by nXhtml when using MuMaMo. + </li> + <li> + Tried to get the global turn on of mumam-mode to work + in all cases. + </li> + <li> + The screen was blinking when changing overlays after + changes in the buffer. Tried to fix this. + </li> + <li> + Minor fixes do syntax highlighting, like taking care of single ':s. + </li> + <li> + Fixes to the support for JSP and eRuby. + </li> + <li> + Made the support for perl here documents a bit better. + Large perl documents are however still quite slow when + using mumamo-mode. I do not know the reason yet. + </li> + <li> + Refontification could miss some parts when buffer + changes caused chunk division changes. Complex, + tried to fix it, but I am a bit unsure that it + always works. + </li> + <li> + Cleaned up mumamo.el a bit. + </li> + <li> + Rewrote mumamo-test.el and functions called from it in + mumamo.el a bit to make tracebacks from errors more + useful. Changed keybindings in mumamo-test.el from + global to a minor mode <em>mumamo-test-mode</em>. + Renamed mumamo-notest.el to mumamo-test.el. Added it + to the zipped distribution of nXhtml. + </li> + </ul> + </li> + <li> + Fixed a bug related to links and buffer changes. + </li> + </ul> + </dd> + <dt>1.02</dt> + <dd id="v1.02"> + <ul> + <li> + Fixed a refontification bug that occured after changes. + </li> + </ul> + </dd> + <dt>1.03</dt> + <dd id="v1.03"> + <ul> + <li> + Added the possibility to call GIMP. + </li> + <li> + Reworked the messages for fontification errors to try + to catch an error that shows up sometimes. Tried to + avoid disturbing normal use in spite of that error. + </li> + <li> + Reverted to using a short delay before switching major + mode when moving between buffers. + </li> + </ul> + </dd> + <dt>1.04</dt> + <dd id="v1.04"> + <ul> + <li> + Completion in empty buffers with a completion header + did not work. Fixed. + </li> + <li> + Multiple major modes: + <ul> + <li> + Better error tracing for some functions. + </li> + <li> + Position was garbled when a ;-char was inserted in php-mode chunk. Fixed. + </li> + </ul> + </li> + <li> + Extra XHTML Validation Header: + <ul> + <li> + View File did not work correctly when an extra + XHTML validation header was used. Corrected. + </li> + <li> + Extra XHTML validation headers are no longer + turned on by default in any buffers. + </li> + </ul> + </li> + <li> + Tried to fix a problem when using newline-and-indent. + When this was in a mode derived from C the indentation + sometimes became 0. + </li> + <li> + Added a workaround for <a + href="#php-attribute-values">Attribute values computed + by PHP</a> + </li> + <li> + Ruby + <ul> + <li> + Multiple major mode turned on by default for .rhtml files when this mode is global. + </li> + <li> + Multiple major mode is no longer turned on when rub-mode is turned on. + </li> + </ul> + </li> + <li> + Added .nosearch to subdirectories with no elisp files. + </li> + <li> + Added support for Firefox add-on It's All Text. + </li> + <li> + Added the possibility to easily view the output of scripts on the server (if they require no parameters). + You can now do that from the nXhtml menu. + Previously only html files on the server could be viewed that way. + Image files can also be viewed this way. + </li> + <li> + Upgraded htmlize.el to version 1.34 + </li> + <li> + Added functions for unfilling. + </li> + <li> + Added keybindings and menu entries for longlines-mode, fill-paragraph and unfill-paragraph. + </li> + <li> + Added image-mode to those that are encompassed by + nxhtml-global-minor-mode so that images can be + uploaded more easily. + </li> + <li> + Added <em>edit with GIMP</em> and <em>upload</em> to the popup menu for links. + This avoids the need to load the linked files in Emacs first. + </li> + <li> + Fixed incorrect checks for mlinks-mode in menu building. + </li> + </ul> + </dd> + </dl> + </div> + </div> + + <hr class="footer"/> + <p class="footer"> + Copyright © 2007 OurComments.org + -- + Latest update 2007-05-06 + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/eval-in-html.el b/emacs/nxhtml/tests/in/eval-in-html.el new file mode 100644 index 0000000000000000000000000000000000000000..33bb9e9b3f7e7d1282697bf4a938aad7f7fd856f GIT binary patch literal 22420 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 literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/tests/in/fontif-err.html b/emacs/nxhtml/tests/in/fontif-err.html new file mode 100644 index 0000000..6f71efa --- /dev/null +++ b/emacs/nxhtml/tests/in/fontif-err.html @@ -0,0 +1,339 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>nXhtml Notes and Changes</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> + </head> + <body> + <div id="container"> + + <div id="rgtcol"> + <p id="nxhtml-home"> + <a href="nxhtml.html">To nXhtml main page</a> + </p> + + <h1>nXhtml Notes and Bugs</h1> + + <dl> +<!-- <dt id="bugs-affect-mode-switching">Two Emacs 22 beta bugs affects PHP mode switching</dt> --> +<!-- <dd> --> +<!-- <p> --> +<!-- <a href="nxhtml.html#php">PHP / nXhtml automatic mode switching</a> is affected: --> +<!-- </p> --> +<!-- <ul> --> +<!-- <li> --> +<!-- Because of a bug in Emacs 22 beta you may have to turn --> +<!-- off and on the switch <em>Mode Switching at <? --> +<!-- ... ?></em> in the menus to get the automatic mode --> +<!-- switching to start. --> +<!-- <em>(Work around added in 0.94)</em> --> +<!-- </li> --> +<!-- <li> --> +<!-- There is the same problem with showing XML path. --> +<!-- <em>(Work around added in 0.94)</em> --> +<!-- </li> --> +<!-- <li> --> +<!-- It also affects MLinks. --> +<!-- <em>(Work around added in 0.94)</em> --> +<!-- </li> --> +<!-- <li> --> +<!-- Because of another bug in Emacs 22 beta immediately --> +<!-- after mode the automatic mode switching the keyboard --> +<!-- uses the key bindings from the <em>wrong mode for the --> +<!-- first key</em>. Type any key on the keyboard, that --> +<!-- cures it. --> +<!-- <em>(Work around added in 0.95)</em> --> +<!-- </li> --> +<!-- </ul> --> +<!-- </dd> --> + <dt id="new-mode-switching" style="margin-top:1em;">I have rewritten the PHP mode switching</dt> + <dd> + <p> + Because of some (fair) critique I have gotten about the way mode switching between php-mode and nxhtml-mode works + I have rewritten that part. + The new mode switching also includes embedded css, javascript, eRuby and JSP. + </p> + </dd> + <dt id="hadron-bugs" style="margin-top:1em;">A lot of bugs corrected for version 0.98</dt> + <dd> + <p> + I want to thanks Hadron Quark for helping me by testing + and pointing out bugs and weaknesses, most related to + editing of PHP. I have included fixes for many of them + in version 0.98 and more may follow. + </p> + </dd> + </dl> + + <h1>nXhtml Changes</h1> + + <dl> + <dt>0.89</dt> + <dd> + <ul> + <li> + Corrected autostart for nXhtml when not used together with EmacsW32. + </li> + </ul> + </dd> + <dt>0.90</dt> + <dd> + <ul> + <li> + Improved display of XML path. + </li> + <li> + Discontinued xmple-mode. + </li> + <li> + New major modes nxhtml-part-mode/nxml-part-mode replaces + minor mode xmlpe-mode. (While moving the code to + nxhtml-part.el I also fixed a bug in Xmple minor mode that + made Emacs take 99% of the CPU.) + </li> + </ul> + </dd> + <dt>0.91</dt> + <dd> + <ul> + <li> + Fixed some calls to perl which prevented uploading of + a site of you did not have perl in the same location + as me. + </li> + <li> + Glued together things so that editing PHP files works + as I intended. (This means that Emacs switches between + php-mode and nxhtml-part-mode automatically when + moving point. And that you can use completion.) + </li> + <li> + Starting working on the documentation for nXhtml. + New layout to the documentation files. + Examples with images. + </li> + </ul> + </dd> + <dt>0.92</dt> + <dd> + <ul> + <li> + Fixes to make the switching between php and xhtml + style editing work better. + </li> + </ul> + </dd> + <dt>0.93</dt> + <dd> + <ul> + <li> + Better error handling when switching to editing + embedded JavaScript and CSS. + </li> + <li> + Removed PHP spec from embedded switching since they + interfered with the automatic switching between php + and xhtml. + </li> + <li> + Gives an error message if web host is not defined in + site when trying to use View Uploaded File and + cousins. + </li> + <li> + Gives a ready message when finished uploading a single + file. + </li> + <li> + When using Mode Switching at <? ... ?> mode + switching could occur in wrong buffer. Fixed together + with some other buffer problems. + </li> + </ul> + </dd> + <dt>0.94</dt> + <dd> + <ul> + <li> + Add http://www.w3.org/ to the help sites for CSS. + </li> + <li> + Included a CSS mode. + </li> + <li> + Added a menu entry for bug reporting. + </li> + <li> + Renamed menu bar entry from XHTML to nXhtml for clarity. + (But nXml menu bar entry is still called XML.) + </li> + <li> + Added work around for globalized minor modes in the + cases of MLinks, XML Path and mode switching at <? ... ?>. + </li> + </ul> + </dd> + <dt>0.95</dt> + <dd> + <ul> + <li> + Added workaround for the problem with the first + keyboard key after automatically switching of mode at + <? ... ?>. + </li> + </ul> + </dd> + <dt>0.96</dt> + <dd> + <ul> + <li> + Added support for multiple major modes with mumamo.el. + </li> + <li> + More conventient handling of links. They can now be + opened in the same window, 'other window' or in a new + frame. + </li> + </ul> + </dd> + <dt>0.97</dt> + <dd> + <ul> + <li> + Schema was not setup after starting new page so + completion did not work. Fixed. + </li> + <li> + Added http://xhtml.com/ to help sites for XHTML. + </li> + <li> + Added the concept of <em>XML validation headers</em>. + These are just text parsed by the nXml validation + parser to get a start state before starting parsing a + buffer. This allows the use of the nXml completion in + buffers where there are no XML header. Such a header + is often lacking for example in PHP code since the + XHTML header is often generated dynamically. + </li> + <li> + Because of the change above <em>nxhtml-part-mode</em> + is no longer needed and is therefore declared + obsolete. + </li> + <li> + Corrected a bug in mlinks.el that prevented opening an + HTML link in a other window or a new frame. + </li> + <li> + Added support for JSP, eRuby and some support for perl + in mumamo.el. + </li> + </ul> + </dd> + <dt>0.98</dt> + <dd id="0.98"> + <ul> + <li> + Mumamo was not found when nXhtml was installed with + just the zip file. Corrected. (nXhtml is also + installed when you install EmacsW32.) + </li> + <li> + Enhancement to mumamo error handling when a bad mode + specifier for an embedded mode is found. + </li> + <li> + Introduced a bug for empty XHTML documents in + 0.97. Corrected. + </li> + <li> + Corrected a bug for chunks 1 character long. + </li> + <li> + There is a bug in Emacs 22 in the handling of global + minor mode that are not distributed with Emacs. If + they are turned on by customization, but loaded after + Emacs have loaded the customizations (usually in + .emacs) then they are not turned on correctly. Added + work-around for this. + </li> + <li> + <em>Extra XHTML Validation Header</em>: + <ul> + <li> + <em>Extra XHTML Validation Header</em> state was not saved when moving between chunks. Fixed. + </li> + <li> + Tried to make the concept of <em>Extra XHTML Validation Header</em> + more clear. Added this visually to the buffer. + </li> + <li> + <em>Extra XHTML Validation Headers</em> can now be turned on + automatically based on file name. + </li> + </ul> + </li> + <li> + <em>nXhtml menu:</em> + <ul> + <li> + Reorganized the nXhtml menu. + </li> + <li> + Added <em>customization</em> groups for help libraries to nXhtml. + </li> + <li> + Added an entry for customization of nXhtml to the menus. + </li> + <li> + Added <em>Tidy</em> to the menus again. + </li> + </ul> + </li> + <li> + Corrected bug in <em>XML Path</em> (nxml-where) for single tags. + Other small fixes to nxhtml-where. + </li> + <li> + Documentation enhancements. + Added <em>The Quick Guide</em>. + </li> + <li> + </li> + </ul> + </dd> + <dt>0.99</dt> + <dd id="0.99"> + <ul> + <li> + Corrections to indentation. + </li> + <li> + Turn on mumamo-mode by file name. + </li> + <li> + The Extra XHTML Validation Header state were not saved when changing major mode in MuMaMo. Corrected. + </li> + <li> + Added more alternatives to the Extra XHTML Validation Header list. + This should make it easier to use completion with for example PHP. + </li> + <li> + Added default value for the Extra XHTML Validation Header. + </li> + </ul> + </dd> + </dl> + </div> + </div> + + <hr class="footer"/> + <p class="footer"> + Copyright © 2007 OurComments.org + -- + Latest update 2007-04-11 + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/fontif-err.php b/emacs/nxhtml/tests/in/fontif-err.php new file mode 100644 index 0000000..6f71efa --- /dev/null +++ b/emacs/nxhtml/tests/in/fontif-err.php @@ -0,0 +1,339 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>nXhtml Notes and Changes</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> + </head> + <body> + <div id="container"> + + <div id="rgtcol"> + <p id="nxhtml-home"> + <a href="nxhtml.html">To nXhtml main page</a> + </p> + + <h1>nXhtml Notes and Bugs</h1> + + <dl> +<!-- <dt id="bugs-affect-mode-switching">Two Emacs 22 beta bugs affects PHP mode switching</dt> --> +<!-- <dd> --> +<!-- <p> --> +<!-- <a href="nxhtml.html#php">PHP / nXhtml automatic mode switching</a> is affected: --> +<!-- </p> --> +<!-- <ul> --> +<!-- <li> --> +<!-- Because of a bug in Emacs 22 beta you may have to turn --> +<!-- off and on the switch <em>Mode Switching at <? --> +<!-- ... ?></em> in the menus to get the automatic mode --> +<!-- switching to start. --> +<!-- <em>(Work around added in 0.94)</em> --> +<!-- </li> --> +<!-- <li> --> +<!-- There is the same problem with showing XML path. --> +<!-- <em>(Work around added in 0.94)</em> --> +<!-- </li> --> +<!-- <li> --> +<!-- It also affects MLinks. --> +<!-- <em>(Work around added in 0.94)</em> --> +<!-- </li> --> +<!-- <li> --> +<!-- Because of another bug in Emacs 22 beta immediately --> +<!-- after mode the automatic mode switching the keyboard --> +<!-- uses the key bindings from the <em>wrong mode for the --> +<!-- first key</em>. Type any key on the keyboard, that --> +<!-- cures it. --> +<!-- <em>(Work around added in 0.95)</em> --> +<!-- </li> --> +<!-- </ul> --> +<!-- </dd> --> + <dt id="new-mode-switching" style="margin-top:1em;">I have rewritten the PHP mode switching</dt> + <dd> + <p> + Because of some (fair) critique I have gotten about the way mode switching between php-mode and nxhtml-mode works + I have rewritten that part. + The new mode switching also includes embedded css, javascript, eRuby and JSP. + </p> + </dd> + <dt id="hadron-bugs" style="margin-top:1em;">A lot of bugs corrected for version 0.98</dt> + <dd> + <p> + I want to thanks Hadron Quark for helping me by testing + and pointing out bugs and weaknesses, most related to + editing of PHP. I have included fixes for many of them + in version 0.98 and more may follow. + </p> + </dd> + </dl> + + <h1>nXhtml Changes</h1> + + <dl> + <dt>0.89</dt> + <dd> + <ul> + <li> + Corrected autostart for nXhtml when not used together with EmacsW32. + </li> + </ul> + </dd> + <dt>0.90</dt> + <dd> + <ul> + <li> + Improved display of XML path. + </li> + <li> + Discontinued xmple-mode. + </li> + <li> + New major modes nxhtml-part-mode/nxml-part-mode replaces + minor mode xmlpe-mode. (While moving the code to + nxhtml-part.el I also fixed a bug in Xmple minor mode that + made Emacs take 99% of the CPU.) + </li> + </ul> + </dd> + <dt>0.91</dt> + <dd> + <ul> + <li> + Fixed some calls to perl which prevented uploading of + a site of you did not have perl in the same location + as me. + </li> + <li> + Glued together things so that editing PHP files works + as I intended. (This means that Emacs switches between + php-mode and nxhtml-part-mode automatically when + moving point. And that you can use completion.) + </li> + <li> + Starting working on the documentation for nXhtml. + New layout to the documentation files. + Examples with images. + </li> + </ul> + </dd> + <dt>0.92</dt> + <dd> + <ul> + <li> + Fixes to make the switching between php and xhtml + style editing work better. + </li> + </ul> + </dd> + <dt>0.93</dt> + <dd> + <ul> + <li> + Better error handling when switching to editing + embedded JavaScript and CSS. + </li> + <li> + Removed PHP spec from embedded switching since they + interfered with the automatic switching between php + and xhtml. + </li> + <li> + Gives an error message if web host is not defined in + site when trying to use View Uploaded File and + cousins. + </li> + <li> + Gives a ready message when finished uploading a single + file. + </li> + <li> + When using Mode Switching at <? ... ?> mode + switching could occur in wrong buffer. Fixed together + with some other buffer problems. + </li> + </ul> + </dd> + <dt>0.94</dt> + <dd> + <ul> + <li> + Add http://www.w3.org/ to the help sites for CSS. + </li> + <li> + Included a CSS mode. + </li> + <li> + Added a menu entry for bug reporting. + </li> + <li> + Renamed menu bar entry from XHTML to nXhtml for clarity. + (But nXml menu bar entry is still called XML.) + </li> + <li> + Added work around for globalized minor modes in the + cases of MLinks, XML Path and mode switching at <? ... ?>. + </li> + </ul> + </dd> + <dt>0.95</dt> + <dd> + <ul> + <li> + Added workaround for the problem with the first + keyboard key after automatically switching of mode at + <? ... ?>. + </li> + </ul> + </dd> + <dt>0.96</dt> + <dd> + <ul> + <li> + Added support for multiple major modes with mumamo.el. + </li> + <li> + More conventient handling of links. They can now be + opened in the same window, 'other window' or in a new + frame. + </li> + </ul> + </dd> + <dt>0.97</dt> + <dd> + <ul> + <li> + Schema was not setup after starting new page so + completion did not work. Fixed. + </li> + <li> + Added http://xhtml.com/ to help sites for XHTML. + </li> + <li> + Added the concept of <em>XML validation headers</em>. + These are just text parsed by the nXml validation + parser to get a start state before starting parsing a + buffer. This allows the use of the nXml completion in + buffers where there are no XML header. Such a header + is often lacking for example in PHP code since the + XHTML header is often generated dynamically. + </li> + <li> + Because of the change above <em>nxhtml-part-mode</em> + is no longer needed and is therefore declared + obsolete. + </li> + <li> + Corrected a bug in mlinks.el that prevented opening an + HTML link in a other window or a new frame. + </li> + <li> + Added support for JSP, eRuby and some support for perl + in mumamo.el. + </li> + </ul> + </dd> + <dt>0.98</dt> + <dd id="0.98"> + <ul> + <li> + Mumamo was not found when nXhtml was installed with + just the zip file. Corrected. (nXhtml is also + installed when you install EmacsW32.) + </li> + <li> + Enhancement to mumamo error handling when a bad mode + specifier for an embedded mode is found. + </li> + <li> + Introduced a bug for empty XHTML documents in + 0.97. Corrected. + </li> + <li> + Corrected a bug for chunks 1 character long. + </li> + <li> + There is a bug in Emacs 22 in the handling of global + minor mode that are not distributed with Emacs. If + they are turned on by customization, but loaded after + Emacs have loaded the customizations (usually in + .emacs) then they are not turned on correctly. Added + work-around for this. + </li> + <li> + <em>Extra XHTML Validation Header</em>: + <ul> + <li> + <em>Extra XHTML Validation Header</em> state was not saved when moving between chunks. Fixed. + </li> + <li> + Tried to make the concept of <em>Extra XHTML Validation Header</em> + more clear. Added this visually to the buffer. + </li> + <li> + <em>Extra XHTML Validation Headers</em> can now be turned on + automatically based on file name. + </li> + </ul> + </li> + <li> + <em>nXhtml menu:</em> + <ul> + <li> + Reorganized the nXhtml menu. + </li> + <li> + Added <em>customization</em> groups for help libraries to nXhtml. + </li> + <li> + Added an entry for customization of nXhtml to the menus. + </li> + <li> + Added <em>Tidy</em> to the menus again. + </li> + </ul> + </li> + <li> + Corrected bug in <em>XML Path</em> (nxml-where) for single tags. + Other small fixes to nxhtml-where. + </li> + <li> + Documentation enhancements. + Added <em>The Quick Guide</em>. + </li> + <li> + </li> + </ul> + </dd> + <dt>0.99</dt> + <dd id="0.99"> + <ul> + <li> + Corrections to indentation. + </li> + <li> + Turn on mumamo-mode by file name. + </li> + <li> + The Extra XHTML Validation Header state were not saved when changing major mode in MuMaMo. Corrected. + </li> + <li> + Added more alternatives to the Extra XHTML Validation Header list. + This should make it easier to use completion with for example PHP. + </li> + <li> + Added default value for the Extra XHTML Validation Header. + </li> + </ul> + </dd> + </dl> + </div> + </div> + + <hr class="footer"/> + <p class="footer"> + Copyright © 2007 OurComments.org + -- + Latest update 2007-04-11 + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/genshi-HelloWorldPage.ghtml b/emacs/nxhtml/tests/in/genshi-HelloWorldPage.ghtml new file mode 100644 index 0000000..f54fc5f --- /dev/null +++ b/emacs/nxhtml/tests/in/genshi-HelloWorldPage.ghtml @@ -0,0 +1,10 @@ +<div xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/"> + + <!-- sadf --> + + <div py:if="test"> + Hello from hello! + Test ${name} + </div> +</div> diff --git a/emacs/nxhtml/tests/in/genshi-auto-mode.html b/emacs/nxhtml/tests/in/genshi-auto-mode.html new file mode 100644 index 0000000..f54fc5f --- /dev/null +++ b/emacs/nxhtml/tests/in/genshi-auto-mode.html @@ -0,0 +1,10 @@ +<div xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/"> + + <!-- sadf --> + + <div py:if="test"> + Hello from hello! + Test ${name} + </div> +</div> diff --git a/emacs/nxhtml/tests/in/genshi.ghtml b/emacs/nxhtml/tests/in/genshi.ghtml new file mode 100644 index 0000000..bf0848d --- /dev/null +++ b/emacs/nxhtml/tests/in/genshi.ghtml @@ -0,0 +1,23 @@ +<?python + title = "A Genshi Template" + fruits = ["apple", "orange", "kiwi"] +?> +<html xmlns:py="http://genshi.edgewall.org/"> + <head> + <title py:content="title">This is replaced.</title> + </head> + <body> + <p>These are some of my favorite fruits:</p> + <ul> + <li py:for="fruit in fruits"> + I like ${fruit}s + </li> + </ul> +{% python + from genshi.builder import tag + def greeting(name): + return 'Hello, %s!' % name +%} +${greeting('world')} + </body> +</html> diff --git a/emacs/nxhtml/tests/in/goesele-091110-testnote-orig.mm b/emacs/nxhtml/tests/in/goesele-091110-testnote-orig.mm new file mode 100644 index 0000000..a9f78ca --- /dev/null +++ b/emacs/nxhtml/tests/in/goesele-091110-testnote-orig.mm @@ -0,0 +1,16 @@ +<map version="0.9.0"> +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> +<node CREATED="1257868981125" ID="ID_1727486195" MODIFIED="1257869002408" TEXT="Testnote"> +<richcontent TYPE="NOTE"><html> + <head> + + </head> + <body> + <p> + A note + </p> + </body> +</html> +</richcontent> +</node> +</map> diff --git a/emacs/nxhtml/tests/in/goesele-091110-testnote-temp.mm b/emacs/nxhtml/tests/in/goesele-091110-testnote-temp.mm new file mode 100644 index 0000000..a9f78ca --- /dev/null +++ b/emacs/nxhtml/tests/in/goesele-091110-testnote-temp.mm @@ -0,0 +1,16 @@ +<map version="0.9.0"> +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> +<node CREATED="1257868981125" ID="ID_1727486195" MODIFIED="1257869002408" TEXT="Testnote"> +<richcontent TYPE="NOTE"><html> + <head> + + </head> + <body> + <p> + A note + </p> + </body> +</html> +</richcontent> +</node> +</map> diff --git a/emacs/nxhtml/tests/in/goesele-091110-testnote.mm b/emacs/nxhtml/tests/in/goesele-091110-testnote.mm new file mode 100644 index 0000000..a9f78ca --- /dev/null +++ b/emacs/nxhtml/tests/in/goesele-091110-testnote.mm @@ -0,0 +1,16 @@ +<map version="0.9.0"> +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> +<node CREATED="1257868981125" ID="ID_1727486195" MODIFIED="1257869002408" TEXT="Testnote"> +<richcontent TYPE="NOTE"><html> + <head> + + </head> + <body> + <p> + A note + </p> + </body> +</html> +</richcontent> +</node> +</map> diff --git a/emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org b/emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org new file mode 100644 index 0000000..4e7cb67 --- /dev/null +++ b/emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org @@ -0,0 +1,5 @@ +* Testnote + + :CLOCK: + my clock + :END: diff --git a/emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org.mm b/emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org.mm new file mode 100644 index 0000000..befbd1d --- /dev/null +++ b/emacs/nxhtml/tests/in/goesele-091110-testnote.mm.org.mm @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<map version="0.9.0"> +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> +<node text="Testnote"> +<richcontent TYPE="NOTE"><html> +<head> +</head> +<body> +--org-mode: :CLOCK:<br /> +--org-mode: my clock<br /> +--org-mode: :END:<br /> +</body> +</html> +</richcontent> +</node> +</map> diff --git a/emacs/nxhtml/tests/in/haml1.haml b/emacs/nxhtml/tests/in/haml1.haml new file mode 100644 index 0000000..85f2324 --- /dev/null +++ b/emacs/nxhtml/tests/in/haml1.haml @@ -0,0 +1,132 @@ +!!! XML +!!! + +%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"} + +%title + = @title + \= @title + +%script{:type => "text/javascript", + :src => "javascripts/script_#{2 + 7}"} + +%gee + %whiz + Wow this is cool! +%p + <div id="blah">Blah!</div> +%one + %two + %three Hey there + +%html(xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en") + +%a(title=@title href=href) Stuff +%a{:title => @title, :href => href} Stuff + +%script(type="text/javascript" + src="javascripts/script_#{2 + 7}") + +%html{html_attrs('fr-fr')} + +%input{:selected => true} +%input(selected) +%input(selected=true) + +%div#things + %span#rice Chicken Fried + %p.beans{ :food => 'true' } The magical fruit + %h1.class.otherclass#id La La La + +#content .articles + .article.title Doogie Howser Comes Out + .article.date 2006-11-05 + .article.entry + Neil Patrick Harris would like to dispel any rumors that he is straight + +%br/ +%meta{'http-equiv' => 'Content-Type', :content => 'text/html'}/ + +%br +%meta{'http-equiv' => 'Content-Type', :content => 'text/html'} + +%blockquote< + %div + Foo! + +%img +%img> +%img + +%img +%pre>< + foo + bar +%img + +%peanutbutterjelly + / This is the peanutbutterjelly element + I like sandwiches! + +/ + %p This doesn't render... + %div + %h1 Because it's commented out! + +/[if IE] + %a{ :href => 'http://www.mozilla.com/en-US/firefox/' } + %h1 Get Firefox + +%p foo +-# This is a comment +%p bar + +- foo = "hello" +- foo << " there" +- foo << " you!" +%p= foo + +- (42...47).each do |i| + %p= i +%p See, I can count! + +%p + - case 2 + - when 1 + = "1!" + - when 2 + = "2?" + - when 3 + = "3." + +%p This is #{h quality} cake! +%p= "This is the #{h quality} cake!" + +%p + Look at \\#{h word} lack of backslash: \#{foo} + And yon presence thereof: \{foo} + +:javascript + $(document).ready(function() { + alert(#{@message.to_json}); + }); + +&= "I like cheese & crackers" + += "I feel <strong>!" +!= "I feel <strong>!" +compiles to +I feel <strong>! +I feel <strong>! + +%p + :markdown + Textile + ======= + + Hello, *World* + +- flavor = "raspberry" +#content + :textile + I *really* prefer _#{h flavor}_ jam. diff --git a/emacs/nxhtml/tests/in/heredoc.php b/emacs/nxhtml/tests/in/heredoc.php new file mode 100644 index 0000000..39e82e5 --- /dev/null +++ b/emacs/nxhtml/tests/in/heredoc.php @@ -0,0 +1,61 @@ + +<?php + +/* Testing fill paragraph and friends, fill me fill me fill me fill me + fill me fill me fill me fill me fill me fill me fill me fill me + fill me fill me + + However coloring it differently than the top level (or level 1) php + chunks may help detect nesting errors. */ + +$name = "Joe Smith"; +$occupation = "Programmer"; +echo <<<EOF + + This is a heredoc text-mode section. + For more information talk to $name, your local $occupation. + +EOF; + +$toprint = <<< HTMLEOF +<!-- heredoc html-mode section --> +<style type="text/css"> +.bugfix { color: red; } +</style> + +<script type="text/javascript" language="javascript"> + + function onEndCrop( coords, dimensions ) { + alert("Test"); + } +</script> + + +<a href="javascript:void window.open('');" title="Something"> + <img src="/administrator/images/imprimir.png" + style="color:red;" + border="0" + alt="<?php echo _CMN_PDF;?>" + onmouseover="this.src='images/imprimir_on.png';swap('imprimir',1);" + onmouseout="this.src='images/imprimir.png'; swap('imprimir',0);" + class="bot" id="imprimir"/> + </a> + +<?php + +/* This inner php chunk is not very useful (except for presentation of + MuMaMo chunk dividing capabilities and deficiences...), since php + normally seems to run only one pass... + + However coloring it differently than the top level (or level 1) php + chunks may help detect nesting errors. */ + +echo <<<ONEMORELEVEL +Just for testing the chunk background color... +ONEMORELEVEL; +?> + +HTMLEOF; +echo strtolower($toprint); + +?> diff --git a/emacs/nxhtml/tests/in/heredoc.pl b/emacs/nxhtml/tests/in/heredoc.pl new file mode 100644 index 0000000..8620357 --- /dev/null +++ b/emacs/nxhtml/tests/in/heredoc.pl @@ -0,0 +1,11 @@ +$text = 'Text from a Perl string.'; +print <<HTML; +<html> +<head> +<title>Here-Doc Example</title> +</head> +<body> +<h1>Here-Doc Example</h1> +<p>$text</p> +</body> +HTML diff --git a/emacs/nxhtml/tests/in/heredoc.py b/emacs/nxhtml/tests/in/heredoc.py new file mode 100644 index 0000000..aaa847f --- /dev/null +++ b/emacs/nxhtml/tests/in/heredoc.py @@ -0,0 +1,11 @@ +sender = 'Buffy the Vampire Slayer' +recipient = 'Spike' + +print("""\ +Dear %(recipient)s, + +I wish you to leave Sunnydale and never return. + +Not Quite Love, +%(sender)s +""" % locals()) diff --git a/emacs/nxhtml/tests/in/heredoc.rb b/emacs/nxhtml/tests/in/heredoc.rb new file mode 100644 index 0000000..ab7b54f --- /dev/null +++ b/emacs/nxhtml/tests/in/heredoc.rb @@ -0,0 +1,8 @@ +now = Time.now +puts <<-EOF + It's #{now.hour} o'clock John, where are your kids? + EOF +now = Time.now +puts <<EOF + It's #{now.hour} o'clock John, where are your kids? +EOF diff --git a/emacs/nxhtml/tests/in/heredoc.sh b/emacs/nxhtml/tests/in/heredoc.sh new file mode 100644 index 0000000..5893ac7 --- /dev/null +++ b/emacs/nxhtml/tests/in/heredoc.sh @@ -0,0 +1,4 @@ +tr a-z A-Z <<EOF + + +EOF diff --git a/emacs/nxhtml/tests/in/hg-2008-03-22-ajax.xhtml b/emacs/nxhtml/tests/in/hg-2008-03-22-ajax.xhtml new file mode 100644 index 0000000..22b3ec1 --- /dev/null +++ b/emacs/nxhtml/tests/in/hg-2008-03-22-ajax.xhtml @@ -0,0 +1,38 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta name="generator" content= + "HTML Tidy for Linux/x86 (vers 6 November 2007), see www.w3.org" /> + <title></title> + </head> + <body> + <script language="JavaScript" type="text/javascript"> + //<![CDATA[ +function test() { + var xmlhttp = new XMLHttpRequest(); + xmlhttp.onreadystatechange=function() { + if (xmlhttp.readystate==4) { + if (xmlhttp.status==200) { + alert(xmlhttp.responseText); + }else { + alert(xmlhttp.status); + } + #ffff00; + } + xmlhttp.open("post","/hello/cardCpu/queryList"); + var body = "label="+encodeURIComponent("±£ÍÍ"); + alert(body) + xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); + xmlhttp.send(body); + } +} +//]]> + </script> + <hr /> + <address><a href="mailto:agile@agile">agile.guo</a></address> + <!-- Created: Thu Sep 14 22:01:37 CST 2006 --> + <!-- hhmts start --> + Last modified: Thu Sep 14 22:01:42 CST 2006 <!-- hhmts end --> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/hq-070510-test.php b/emacs/nxhtml/tests/in/hq-070510-test.php new file mode 100644 index 0000000..8c57717 --- /dev/null +++ b/emacs/nxhtml/tests/in/hq-070510-test.php @@ -0,0 +1,12 @@ + +<?php +require_once("include/utils.php"); +?> + +<div class="linkcontainer"> +<?php +$_SESSION["linksfile"]="csv/links.csv"; +include("displaylinks.php"); +?> +</div> + diff --git a/emacs/nxhtml/tests/in/hq-070510-test.php.html b/emacs/nxhtml/tests/in/hq-070510-test.php.html new file mode 100644 index 0000000..57736a3 --- /dev/null +++ b/emacs/nxhtml/tests/in/hq-070510-test.php.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + <head> + <title>hq-070510-test.php</title> + <meta name="generator" content="emacs 22.1.1; htmlfontify 0.20"> +<style type="text/css"><!-- +body { background: rgb(255, 255, 255); color: rgb(0, 0, 0); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.default { background: rgb(255, 255, 255); color: rgb(0, 0, 0); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.default a { background: rgb(255, 255, 255); color: rgb(0, 0, 0); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: underline; } +span.constant { color: rgb(95, 158, 160); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.constant a { color: rgb(95, 158, 160); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: underline; } +span.variable-name { color: rgb(184, 134, 11); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.variable-name a { color: rgb(184, 134, 11); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: underline; } +span.function-name { color: rgb(0, 0, 255); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.function-name a { color: rgb(0, 0, 255); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: underline; } +span.string { color: rgb(188, 143, 143); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.string a { color: rgb(188, 143, 143); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: underline; } +span.default { background: rgb(255, 255, 255); color: rgb(0, 0, 0); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.default a { background: rgb(255, 255, 255); color: rgb(0, 0, 0); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: underline; } +span.keyword { color: rgb(160, 32, 240); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: none; } +span.keyword a { color: rgb(160, 32, 240); background: rgb(255, 255, 255); font-style: normal; font-weight: 500; font-stretch: normal; font-family: outline-courier new; font-size: 9pt; text-decoration: underline; } + --></style> + + </head> + <body> + +<pre> + +<<span class="keyword">?php</span> +<span class="default">require_once(</span><span class="string">"include/utils.php"</span>); +?> + +<<span class="function-name">div</span> <span class="variable-name">class</span>=<span class="string">"linkcontainer"</span>> +<<span class="keyword">?php</span> +$<span class="constant">_SESSION</span>[<span class="string">"linksfile"</span>]=<span class="string">"csv/links.csv"</span>; +<span class="default">include(</span><span class="string">"displaylinks.php"</span>); +?> +</<span class="function-name">div</span>> + + +</pre> + + </body> +</html> diff --git a/emacs/nxhtml/tests/in/hq-070524-bug.php b/emacs/nxhtml/tests/in/hq-070524-bug.php new file mode 100644 index 0000000..24bd8e8 --- /dev/null +++ b/emacs/nxhtml/tests/in/hq-070524-bug.php @@ -0,0 +1,10 @@ +<?php + + Echo "why is this text red"; + + /* It looks like there is some sync problem with php-mode + here. Adding a ( before the string makes the string + beeing fontified as a string. + */ + +?> diff --git a/emacs/nxhtml/tests/in/hq-071006-index.php b/emacs/nxhtml/tests/in/hq-071006-index.php new file mode 100644 index 0000000..78b60e8 --- /dev/null +++ b/emacs/nxhtml/tests/in/hq-071006-index.php @@ -0,0 +1,38 @@ +<?php + +// some basic library functions +include_once 'lib.php'; + +$book = new Mybook($api_key, $secret); + +if (isset($_POST['to'])) { + $prints_id = (int)$_POST['to']; + $prints = do_step($user, $prints_id); +} else { + if (isset($_GET['to'])) { + $prints_id = (int)$_GET['to']; + } else { + $prints_id = $user; + } + $prints = get_prints($prints_id); +} + +?> +<div style="padding: 10px;"> + <h2>Hi <mb:name firstnameonly="true" uid="<?php=$user?>" useyou="false"/>!</h2><br/> + <a href="<?= $book->get_add_url() ?>">Put prints in your profile</a>. + <form method="post" action="http://my-domain.com/footprints/"> +<?php + if ($prints_id != $user) { + echo '<input type="hidden" name="to" value="' . $prints_id . '"/>'; + } else { + echo '<br/>'; + } +?> + <input value="step" type="submit"/> + </form> + <hr/> + These are <mb:name uid="<?= $prints_id ?>" possessive="true"/> Footprints:<br/> + <?php echo render_prints($prints, 10); ?> + <div style="clear: both;"/> +</div> diff --git a/emacs/nxhtml/tests/in/html-syntactic-err-l164.html b/emacs/nxhtml/tests/in/html-syntactic-err-l164.html new file mode 100644 index 0000000..275ae67 --- /dev/null +++ b/emacs/nxhtml/tests/in/html-syntactic-err-l164.html @@ -0,0 +1,1474 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>News and Notes about nXhtml</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> + </head> + <body> + <div id="container"> + + <div id="rgtcol"> + <p id="nxhtml-home"> + <a href="nxhtml.html">To nXhtml main page</a> + </p> + + <h1>News and Notes about nXhtml</h1> + + <dl> + + <dt id="hadron-bugs" style="margin-top:1em;">Thanks for testing!</dt> + <dd> + <p> + I want to thanks the testers (who have been many now), + especially to my first testers Hadron Quark and Eric + Lilja, for helping me by testing and pointing out bugs + and weaknesses, most of them related to editing of PHP. + </p> + <p> + Without testers all kind of problems I just can't + imagine myself would still be there in nXhtml. For + example Hadron told me once that he got the error + <i>(wrong-type-argument stringp nil)</i>. Eh, I replied, are + you sure. Yes he was. I tried the same file as him. No + error. + </p> + <p> + The error happened during fontification so the error + message above was all we had. A real black box for + me. Or perhaps black magic? After much confusion and + some hard work we finally found out what it was and I + implemented a better way to catch such errors. If Hadron + would have given up the problem would still have been + there. Some problems are just impossible to solve + without good cooperation. So, again, thanks Hadron. + </p> + <p> + BTW, I will perhaps add some even better way to Emacs to + catch these errors so other can benefit from our + insights too, but that requires some time and effort + which I can't afford right now. + </p> + </dd> + + <dt id="state-of-the-art" style="margin-top:1em; + background-color: #00fa9a; + background-color: #20b2aa; + padding: 0.5em; + ">The State of the Art</dt> + <dd style="background-color: #54ff9f; padding: 0.5em"> + <p> + I have more and more come to realize that there are two + main parts of nXhtml which are in a bit different + degrees of maturity. The reason for the difference is + mainly that one of them, <strong>mumamo-mode</strong>, + requires very tight integration with Emacs in a way that + currently is difficult. There are also things to + discover, for example in the interactions with other + minor modes. Each minor mode actually have to be tested + with mumamo-mode. (Instruction for library authors are + in mumamo-mode.el) + </p> + <p> + That said I still think <strong>mumamo-mode</strong> is + mature enough for serious use. At least the + <i>fontification now works ok</i> I believe. Other + parts that also depends on the major mode used, + like <i>filling and indentation have some quirks</i>. To + make those work more reliably in all cases a bit more + standardisation across different major modes is + needed. (It is perhaps possible to work around those + problems in mumamo-mode, but the long term benefits of + doing that are probably small.) + </p> + <p> + The other part, <strong>nxhtml-mode</strong>, is more mature, + since it stands more by itself and since it builds on + the very stable nxml-mode. I would not say nxhtml-mode + is (ever) finished, but it is stable and useful. + </p> + </dd> + + <dt id="magic-problems" style="margin-top:1em;">Magic major mode selection</dt> + <dd> + <p> + Sometimes the major mode that Emacs opens a file in is + not what you expect. This can happen with files like PHP + files. The reason might be that magic-mode-alist have + choosen a mode based on the content of the file. The way + this is done does not take files with mixes a mix of for + example XHTML and PHP into account. + </p> + <p> + You may try setting magic-mode-alist to nil if this is a + problem for you. + </p> + <p> + <em> + This is now no longer necessary since the introduction + of magic-fallback-mode-alist in CVS Emacs on 2007-05-16. + (If you have an Emacs newer than that, of course.) + </em> + </p> + </dd> + + <dt id="underline-bug" style="margin-top:1em;">Long Red Underlines</dt> + <dd> + <p> + Because of a bug in Emacs 22.1 you can sometimes (at the + end of a line) get long red lines instead of just a + single underlined character. Many users (me included) + find this quite a bit disturbing. I have therefore added + a command to quickly hide/show the underlines. This is + on <em>C-c C-w</em>. + </p> + <p> + This is particular useful for example in the case where + you edit a PHP file and are bound to get a lot of XHTML + validation errors. + </p> + </dd> + + <dt id="php-attribute-values" style="margin-top:1em;">Attribute values computed by PHP</dt> + <dd> + <p> + If you want to have attribute values computed by PHP + here is a way how to structure that to avoid breaking + completion and validation in the XHTML part unnessecary: + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="<?php foo("bar");?>"/> + </p> + <p> + Unfortunately that still breaks XHTML validation since + < is not allowed in strings. In the long run I + believe the XML validator has to be broken up so that it + avoids parsing the string here (in PHP files). + </p> + <p> + For now I have implemented a workaround. + If you are using constructs like those above then turn on <em>nxhtml-strval-mode</em>. + This will temporarily replace the above with + </p> + <p style="margin-left:2em"> + <img src="images/linux.png" title="«?php foo("bar");?»"/> + </p> + <p> + However on the screen you will still see the original + string and when writing to file the correct characters + will be used. + </p> + </dd> + + <dt id="pi-note" style="margin-top:1em;">A note for PHP and its cousins</dt> + <dd> + <p> + The rules for a process instruction in XML, like <?php + ... ?> says that the text can contain any text except + <em>?></em>. So if you want to output that string + from PHP then break it up so it does not look as ?> in + the source file. + </p> + <p> + It might be good to break up the beginning part of the + process instructions too. And please note that to use + XHTML validation or completion you should avoid using + < in strings, since it is not allowed there. + </p> + </dd> + +<!-- <dt id="pi-note" style="margin-top:1em;">Perl Mode slow with Mumamo Mode</dt> --> +<!-- <dd> --> +<!-- <p> --> +<!-- Perl mode used with MuMaMo mode sometimes makes the --> +<!-- fontification slow for big files. I do not know the --> +<!-- reason, but I am trying to find a solution for this. If --> +<!-- you encounter this problem, just turn off mumamo-mode in --> +<!-- that buffer. --> +<!-- </p> --> +<!-- </dd> --> + + <dt id="tab-width-problems" style="margin-top:1em;">Tab width</dt> + <dd> + <p> + Do you have <em>tab-width</em> to something different than 8 + (the default)? Then please change this to 8. I have got + reports of problem with indentation when it is not 8. + </p> + </dd> + + <dt id="mmm-compat" style="margin-top:1em;">Why the chunks are not compatible with mmm</dt> + <dd> + <p> + Some people have asked why the way to specify chunks in + mumamo-mode is not compatible with the old mmm-mode. The + answer is that I was not sure that the way used in + mmm-mode for specifying the chunks was flexible enough. + </p> + <p> + And I am sure that even the way used in mumamo-mode is + not good enough for all cases, but I let it be the way + it is until I have a better understanding of the + problem. Suggestions and comments are welcome! + </p> + </dd> + + </dl> + + <h1 id="change-history">nXhtml Changes</h1> + + <div> + <a href="#v0.89">v0.89</a> + <a href="#v0.90">v0.90</a> + <a href="#v0.91">v0.91</a> + <a href="#v0.92">v0.92</a> + <a href="#v0.93">v0.93</a> + <a href="#v0.94">v0.94</a> + <a href="#v0.95">v0.95</a> + <a href="#v0.96">v0.96</a> + <a href="#v0.97">v0.97</a> + <a href="#v0.98">v0.98</a> + <a href="#v0.99">v0.99</a> + <a href="#v1.00">v1.00</a> + <a href="#v1.01">v1.01</a> + <a href="#v1.02">v1.02</a> + <a href="#v1.03">v1.03</a> + <a href="#v1.04">v1.04</a> + <a href="#v1.10">v1.10</a> + <a href="#v1.11">v1.10</a> + <a href="#v1.12">v1.10</a> + <a href="#v1.13">v1.10</a> + <a href="#v1.14">v1.10</a> + </div> + + <dl> + <dt id="v0.89">0.89</dt> + <dd> + <ul> + <li> + Corrected autostart for nXhtml when not used together with EmacsW32. + </li> + </ul> + </dd> + <dt id="v0.90">0.90</dt> + <dd> + <ul> + <li> + Improved display of XML path. + </li> + <li> + Discontinued xmple-mode. + </li> + <li> + New major modes nxhtml-part-mode/nxml-part-mode replaces + minor mode xmlpe-mode. (While moving the code to + nxhtml-part.el I also fixed a bug in Xmple minor mode that + made Emacs take 99% of the CPU.) + </li> + </ul> + </dd> + <dt id="v0.91">0.91</dt> + <dd> + <ul> + <li> + Fixed some calls to perl which prevented uploading of + a site of you did not have perl in the same location + as me. + </li> + <li> + Glued together things so that editing PHP files works + as I intended. (This means that Emacs switches between + php-mode and nxhtml-part-mode automatically when + moving point. And that you can use completion.) + </li> + <li> + Starting working on the documentation for nXhtml. + New layout to the documentation files. + Examples with images. + </li> + </ul> + </dd> + <dt id="v0.92">0.92</dt> + <dd> + <ul> + <li> + Fixes to make the switching between php and xhtml + style editing work better. + </li> + </ul> + </dd> + <dt id="v0.93">0.93</dt> + <dd> + <ul> + <li> + Better error handling when switching to editing + embedded JavaScript and CSS. + </li> + <li> + Removed PHP spec from embedded switching since they + interfered with the automatic switching between php + and xhtml. + </li> + <li> + Gives an error message if web host is not defined in + site when trying to use View Uploaded File and + cousins. + </li> + <li> + Gives a ready message when finished uploading a single + file. + </li> + <li> + When using Mode Switching at <? ... ?> mode + switching could occur in wrong buffer. Fixed together + with some other buffer problems. + </li> + </ul> + </dd> + <dt id="v0.94">0.94</dt> + <dd> + <ul> + <li> + Add http://www.w3.org/ to the help sites for CSS. + </li> + <li> + Included a CSS mode. + </li> + <li> + Added a menu entry for bug reporting. + </li> + <li> + Renamed menu bar entry from XHTML to nXhtml for clarity. + (But nXml menu bar entry is still called XML.) + </li> + <li> + Added work around for globalized minor modes in the + cases of MLinks, XML Path and mode switching at <? ... ?>. + </li> + </ul> + </dd> + <dt id="v0.95">0.95</dt> + <dd> + <ul> + <li> + Added workaround for the problem with the first + keyboard key after automatically switching of mode at + <? ... ?>. + </li> + </ul> + </dd> + <dt id="v0.96">0.96</dt> + <dd> + <ul> + <li> + Added support for multiple major modes with mumamo.el. + </li> + <li> + More conventient handling of links. They can now be + opened in the same window, 'other window' or in a new + frame. + </li> + </ul> + </dd> + <dt id="v0.97">0.97</dt> + <dd> + <ul> + <li> + Schema was not setup after starting new page so + completion did not work. Fixed. + </li> + <li> + Added http://xhtml.com/ to help sites for XHTML. + </li> + <li> + Added the concept of <em>fictive XML validation + headers</em>. These are just text parsed by the nXml + validation parser to get a start state before starting + parsing a buffer. This allows the use of the nXml + completion in buffers where there are no XML header. + Such a header is often lacking for example in PHP code + since the XHTML header is often generated dynamically. + </li> + <li> + Because of the change above <em>nxhtml-part-mode</em> + is no longer needed and is therefore declared + obsolete. + </li> + <li> + Corrected a bug in mlinks.el that prevented opening an + HTML link in a other window or a new frame. + </li> + <li> + Added support for JSP, eRuby and some support for perl + in mumamo.el. + </li> + </ul> + </dd> + <dt id="v0.98">0.98</dt> + <dd> + <ul> + <li> + Mumamo was not found when nXhtml was installed with + just the zip file. Corrected. (nXhtml is also + installed when you install EmacsW32.) + </li> + <li> + Enhancement to mumamo error handling when a bad mode + specifier for an embedded mode is found. + </li> + <li> + Introduced a bug for empty XHTML documents in + 0.97. Corrected. + </li> + <li> + Corrected a bug for chunks 1 character long. + </li> + <li> + There is what I consider is a bug in Emacs 22.1 in the + handling of global minor mode that are not distributed + with Emacs. If they are turned on by customization, + but loaded after Emacs have loaded the customizations + (usually in .emacs) then they are not turned on + correctly. Added work-around for this. + </li> + <li> + <em>Fictive XHTML Validation Header</em>: + <ul> + <li> + <em>Fictive XHTML Validation Header</em> state was not saved when moving between chunks. Fixed. + </li> + <li> + Tried to make the concept of <em>Fictive XHTML Validation Header</em> + more clear. Added this visually to the buffer. + </li> + <li> + <em>Fictive XHTML Validation Headers</em> can now be turned on + automatically based on file name. + </li> + </ul> + </li> + <li> + <em>nXhtml menu:</em> + <ul> + <li> + Reorganized the nXhtml menu. + </li> + <li> + Added <em>customization</em> groups for help libraries to nXhtml. + </li> + <li> + Added an entry for customization of nXhtml to the menus. + </li> + <li> + Added <em>Tidy</em> to the menus again. + </li> + </ul> + </li> + <li> + Corrected bug in <em>XML Path</em> (nxml-where) for single tags. + Other small fixes to nxhtml-where. + </li> + <li> + Documentation enhancements. + Added <em>The Quick Guide</em>. + </li> + </ul> + </dd> + <dt id="v0.99">0.99</dt> + <dd> + <ul> + <li> + Fixed a serious bug in the cooperation between nxhtml-mode and mumamo-mode. + </li> + <li> + Turn on mumamo-mode by file name (mumamo-global-mode). + </li> + <li> + Fictive XHTML Validation Header: + <ul> + <li> + The Fictive XHTML Validation Header state were not saved when changing major mode in MuMaMo. Corrected. + </li> + <li> + Added more alternatives to the Fictive XHTML Validation Header list. + This should make it easier to use completion with for example PHP. + </li> + <li> + Added default value for the Fictive XHTML Validation Header. + </li> + <li> + Tried to make the use of Fictive XHTML Validation Header more automatic and therefore useful. + Also tried to make it play better with setting schema file. + (There is no need normally to set schema file by hand.) + </li> + <li> + To turn this on by default customize nxhtml-global-validation-header-mode. + </li> + </ul> + </li> + <li> + Possible to hide validation warnings without turning + on validation (which would make completion in the + XHTML part impossible). + </li> + <li> + Some fixes to php-mode: + <ul> + <li>Using the character # for comments now works for most cases.</li> + <li>Now uses the fontification faces in a more standard way which calms down the look.</li> + <li>Initialization bug fixes.</li> + <li>Renamed php-mode-user-hook to php-mode-hook to follow standard.</li> + </ul> + </li> + <li> + Indentation fixes: + <ul> + <li> + Various corrections to indentation in mumamo. + </li> + <li> + Added the possibility to use TAB to indent regions + (indent-region-mode). + </li> + <li> + Warn about bad indentation in mixed PHP/HTML code + when using php-mode only. + </li> + </ul> + </li> + <li> + Fontification now fontifies all text first in main + major mode and thereafter applies submodes. (This + avoids some problems with around a submode chunk.) + </li> + <li> + Reorganized the nXhtml menu: + <ul> + <li> + There is now a minor mode for the nXhtml + menu. This makes it possible to easier use common + features when in buffers not in nxhtml-mode. + </li> + <li> + The nXhtml menu does not disappear when moving + into a chunk where the major mode is not + nxhtml-mode. The changes also makes it easy to + access uploading functions functions etc from + other modes than nxhtml-mode since the + <em>nXhtml</em> may also be shown in them. + </li> + <li> + The nXhtml menu can be turned on globally by default. + Customize nxhtml-menu-mode for that. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.00">1.00</dt> + <dd> + <ul> + <li> + Reached version number 1.00 - which you maybe believe + means the bugs should be gone? Sorry, it is just that + I ran out of version numbers ;-) However it looks like + much fewer bugs at least. + </li> + <li> + Fixed problems mostly related to global turn on of different features in nXhtml. + </li> + <li> + Small fixes to indentation. + <ul> + <li> + nxhtml-mode could get confused by php tags. + </li> + <li> + nxhtml-mode did not indent <!DOCTYPE in a sensible way. + </li> + <li> + Electric keys now works in embedded php when using mumamo-mode. + </li> + </ul> + </li> + <li> + Tidy was very misbehaving since the output buffer was + not erased between different files. But I have got no + bug reports on this ;-) + </li> + <li> + Fixed a bug in validation that should up when using muamo-mode. + </li> + <li> + Fixed bug in <script ...> and <style ...> chunk dividing. + </li> + <li> + Added support for OpenLaszlo. + </li> + <li> + Corrections to mlinks-mode (visible mostly as links in + XHTML buffers): + <ul> + <li> + Links disappeared when a new file was + opened. Corrected. + </li> + <li> + Links were not correctly updated at changes in the + buffer when mumamo-mode was used. Fixed. + </li> + </ul> + </li> + <li> + The welcome message for nXhtml could be shown too + early sometimes when loading, before nXhtml actually + knew if it should be shown or not. Tried to fix it. + </li> + </ul> + </dd> + <dt id="v1.01">1.01</dt> + <dd> + <ul> + <li> + Reported wrong version number for nXhtml in the menus. Fixed. + </li> + <li> + <em>If you use the zip file to install nXhtml please + notice that it has now a top level nxml.</em> Sorry for not + having zipped it like that before! + </li> + <li> + The url links in <em>Welcome to nXhtml</em> was a bit + incorrect and did not work on all OS:es. Fixed. + </li> + <li> + Added customization of popup completion to the 'nxhtml + customization group so they are easier to find. + </li> + <li> + MuMaMo + <ul> + <li> + Struggled a bit with the load sequences of the elisp + libraries used by nXhtml when using MuMaMo. + </li> + <li> + Tried to get the global turn on of mumam-mode to work + in all cases. + </li> + <li> + The screen was blinking when changing overlays after + changes in the buffer. Tried to fix this. + </li> + <li> + Minor fixes do syntax highlighting, like taking care of single ':s. + </li> + <li> + Fixes to the support for JSP and eRuby. + </li> + <li> + Made the support for perl here documents a bit better. + Large perl documents are however still quite slow when + using mumamo-mode. I do not know the reason yet. + </li> + <li> + Refontification could miss some parts when buffer + changes caused chunk division changes. Complex, + tried to fix it, but I am a bit unsure that it + always works. + </li> + <li> + Cleaned up mumamo.el a bit. + </li> + <li> + Rewrote mumamo-test.el and functions called from it in + mumamo.el a bit to make tracebacks from errors more + useful. Changed keybindings in mumamo-test.el from + global to a minor mode <em>mumamo-test-mode</em>. + Renamed mumamo-notest.el to mumamo-test.el. Added it + to the zipped distribution of nXhtml. + </li> + </ul> + </li> + <li> + Fixed a bug related to links and buffer changes. + </li> + </ul> + </dd> + <dt id="v1.02">1.02</dt> + <dd> + <ul> + <li> + Fixed a refontification bug that occured after changes. + </li> + </ul> + </dd> + <dt id="v1.03">1.03</dt> + <dd> + <ul> + <li> + Added the possibility to call GIMP. + </li> + <li> + Reworked the messages for fontification errors to try + to catch an error that shows up sometimes. Tried to + avoid disturbing normal use in spite of that error. + </li> + <li> + Reverted to using a short delay before switching major + mode when moving between buffers. + </li> + </ul> + </dd> + <dt id="v1.04">1.04</dt> + <dd id="v1.04-dd"> + <ul> + <li> + Enhanced the documentation for nXhtml. Starting from + <i>C-h f nxhtml-mode</i> it should now be easier to + get an overview. + </li> + <li> + Bug fixes etc: + <ul id="v1.04-bugs"> + <li> + Completion on an empty page gave a faulty frameset page. Fixed. + </li> + <li> + Insert end tag did not work with a fictive + validation header. Fixed. + </li> + <li> + Insert end tag when all preceding tags where + closed gave a strange error message. Fixed. + </li> + <li> + Changed some key bindings to comply with + <i>(info "(elisp) Key Binding Conventions")</i> + </li> + <li> + Completion in empty buffers with a completion + header did not work. Fixed. + </li> + <li id="mumamo-bugs"> + Multiple major modes: + <ul> + <li> + Fixed a bug that prevented mumamo-global-mode from + beeing turned on in a file opened in + fundamental-mode. + </li> + <li> + Better error tracing for some functions, + including the call of major mode functions. + </li> + <li> + Position was garbled when a ;-char was inserted in php-mode chunk. Fixed. + </li> + <li> + A bad check for if mlinks-mode where available was fixed. + </li> + <li> + Some bugs concerning turning off mumamo-mode was fixed. + </li> + <li> + Fixed a bug in <i>perl here doc</i> chunks. Suddenly the + problem with slowness when using mumamo-mode in + perl buffers seems gone. (Note quite sure, but I + can't see any problems now.) + </li> + <li> + Fixed a bug in mumamo-mode when current buffer was + switched before the major mode had been set from + the current chunk. + </li> + <li> + Fixed a long standing bug in php fontification of + strings and comments. + </li> + <li> + Fixed a bug where <i>sgml-xml-mode</i> was not defined. + </li> + <li> + Fixed a bug related to get-text-property which + gives an error when buffer is narrowed. + </li> + <li> + Tried to refontify things outside of a narrowed part. Fixed. + </li> + <li> + Too little where refontified after changes. I hope I have fixed this. + </li> + </ul> + </li> + <li> + Fictive XHTML Validation Header: + <ul id="v1.04-fic-bugs"> + <li> + View File did not work correctly when a fictive + XHTML validation header was used. Corrected. + </li> + <li> + Fictive XHTML validation headers are no longer + turned on by default in any buffers. + </li> + </ul> + </li> + <li> + Indentation: + <ul> + <li> + Tried to fix a problem when using + newline-and-indent. When this was in a mode + derived from C the indentation sometimes became 0. + </li> + <li> + Speeded up the indentation of regions a bit when + using <i>mumamo-mode</i>. + </li> + <li> + Indentation: TAB now only indents a region if it + is visibly marked (see transient-mark-mode and + cua-mode). + </li> + <li> + Simplified the indentation code. + </li> + </ul> + </li> + <li> + Fixed a problem where string fontification got out + of phase so that wrong parts of buffer could be + fontified as a string. + </li> + <li> + Added a workaround for <a + href="#php-attribute-values">Attribute values + computed by PHP</a> + </li> + <li> + Added .nosearch to subdirectories with no elisp files. + </li> + <li> + Fixed incorrect checks for mlinks-mode in menu building. + </li> + <li> + File extensions where used in a case sensitive way + in some places. Fixed. + </li> + <li> + appmenu: Worked only in html files. Fixed. + </li> + <li> + html-site: Fixed the error <em>Error + (html-site-current): Can't find site: + your-site-name</em>. + </li> + <li> + Fixed a problem with longlines-mode in the support + for Firefox add-on It's All Text. (Note however + that there are some bugs in longlines-mode + itself.) Rewrote the support to be more + general. It is now in the file as-external.el, see + this file. + </li> + <li> + Fixed an encoding problem in + <i>tidy-buffer</i>. Output from tidy was not read + using the same coding system as tidy was using. + </li> + <li> + Fixed some problems with face definitions, possibly bugs (not sure). + </li> + <li> + Made the fontification faster when using mumamo-mode. + (It is still slower than single mode fontification of course.) + </li> + <li> + nxml-where.el: Made it aware of mumamo.el. + </li> + </ul> + </li> + <li> + Menu changes: + <ul> + <li> + Completion menu: Renamed to <i>Completion and + Validation</i> menu and reorganized a little bit to + make it more clear. + </li> + <li> + Renamed <i>view</i> to <i>browse</i> since this is + the normal emacs name for showing files in a web + browser. Also made corresponding changes to + function names. Put back the possibility to view + only the region in a web browser. + </li> + </ul> + </li> + <li> + Uploading: + <ul> + <li> + Added remote dired to the menus. + </li> + <li> + Fixed problems with file names starting with ~. + </li> + <li> + Fixed more problems with file names with spaces. + </li> + </ul> + </li> + <li> + nxml-where: + <ul> + <li> + nxml-where now uses a timeout for more smooth performance. + </li> + <li> + nxml-where can now recognizes both id and name attribute. + </li> + <li> + Hyphens are now accepted in tag names. + </li> + </ul> + </li> + <li> + Ruby + <ul> + <li> + Multiple major mode turned on by default for .rhtml files when this mode is global. + </li> + <li> + Multiple major mode is no longer turned on when rub-mode is turned on. + </li> + </ul> + </li> + <li> + Added support for switching major mode dependent on if + Emacs was called as an external editor. This makes it + possible for example to switch to relevant major and + minor modes when Firefox add-on It's All Text. + </li> + <li> + Added the possibility to easily view the output of scripts on the server (if they require no parameters). + You can now do that from the nXhtml menu. + Previously only html files on the server could be viewed that way. + Image files can also be viewed this way. + </li> + <li> + Filling: + <ul> + <li> + Added functions for unfilling. + </li> + <li> + Added keybindings and menu entries for longlines-mode, fill-paragraph and unfill-paragraph. + </li> + </ul> + </li> + <li> + Quoting: + Added HTML quoting of & and < in text areas. Bound to C-c C-q. + </li> + <li> + Images: + <ul> + <li> + Added image-mode to those that are encompassed by + nxhtml-global-minor-mode so that images can be + uploaded more easily. + </li> + <li> + Added <em>edit with GIMP</em> and <em>upload</em> to the popup menu for links. + This avoids the need to load the linked files in Emacs first. + </li> + </ul> + </li> + <li> + Added <em>nxml-untag-element</em>. + </li> + <li> + Added a modified version of wikipedia-mode.el. Seems likely to be useful if you are doing web editing. + </li> + <li> + Added html-imenu.el + </li> + <li> + MuMaMo: + <ul> + <li> + Removed the lighter <i>"MuMaMo"</i> for + mumamo-mode. Instead the active major mode now has + <b>"/m"</b> appended to mode-name (that is what you see + in the mode line). + </li> + <li> + The normal way to turn on <i>mumamo-mode</i> has + changed. There are now functions that you can use + in <i>auto-mode-alist</i> to directly set up the + buffer for mumamo-mode. The available functions + are in the + variable <i>mumamo-defined-turn-on-functions</i>. + <p> + You are not supposed to call mumamo-mode + yourself any more and mumamo-global-mode is + gone. So is also mumamo-chunk-family-by-mode and + mumamo-filenames-list. The functionality those + gave are all replaced by the new functions for + turning on mumamo mode. + </p> + </li> + <li> + Added support for buffer local values in + hooks. This is necessary for example to support + minor modes that are meant to be buffer local but + not major mode specific. Instructions for authors + of this kind of minor modes are in the file + mumamo.el. + </li> + <li> + Added support for Django. + </li> + <li> + Added support for Embperl. + </li> + <li> + Added support for PHP Smarty. The <i>{literal} + ... {/literal}</i> construct is not supported. + This mean that you can not use <style ..> or <script ..>. + </li> + <li> + Added support for imenu for the main major mode. + Turned on this by default in nxhtml-mode. + </li> + <li> + Made the temporary replacement of the + attr="<?php ... ?>" a bit better. They are + now more visible and also still mumamo chunks + during the temporary replacement. + </li> + <li> + Added support for <i>flymake-mode</i>. + Maybe add support for checking chunks? + </li> + <li> + Printing: Added htmlfontify.el and + hfyview.el. These makes if possible to print a + buffer fontified with <i>mumamo-mode</i> on in + colors (through your web browser). There is an + example of the capabilities of htmlfontify <a + href="htmlfontify-example.html">here</a> (made + with a little function in hfyview.el). + </li> + </ul> + </li> + <li> + PHP: + <ul> + <li> + Did a first merge with Aaron Hawleys fixes for php-mode.el. + </li> + </ul> + </li> + <li> + CSS: Upgraded to Stefan's latest css-mode.el. + </li> + <li> + Fictive XHTML Validation Headers: Changed the way they + are turned on. They may now be turned on when + mumamo-mode is turned on. + </li> + <li> + Some users want to use their own patched version of + nXml. Next version of Emacs will come with + nXml. Therefore, the loading routine for nXhtml now + checks if nXml is is already loaded. Thanks to Eric + Lilja for testing this. Eric also made me aware of + that if nXhtml was placed in the site-lisp directory + tree then things did not work as I expected. I think I + have corrected that by placing a <i>.nosearch</i> file + at the top of the nxml tree in nXhtml. + </li> + <li> + Restructured the directories. Moved some files out of + the <i>nxhtml</i> subdir. Some of them went into the + <i>util</i> subdir (those are written by me) and some + to the new subdir <i>related</i> (those that are + inherited from others, maybe changed by me - most + often to work with mumamo-mode). + </li> + <li> + Changed all licenses to be GNU GPL. + </li> + <li> + Additions to tidy support: It is now possible to use + the tidy support to tidy the XHTML part of php etc. + (Thanks to Hadron for this suggestion.) + </li> + <li> + Added <i>winsize.el</i> which allows interactive resizing of + windows. Also added <i>winsav.el</i> which adds the + capability to rotate window configurations and also to + save window configuration to file. + </li> + <li> + Made nXhtml work with CVS Emacs 23.0.50.1. + </li> + <li> + Added freemind.el to the parcel. After all FreeMind + supports web publishing too so why not have the Emacs + support here ... + </li> + </ul> + </dd> + <dt id="v1.10">1.10</dt> + <dd id="v1.10-dd"> + Just jumped the version number for the new release of + nXhtml. There are really significant changes in this + release, not only minor bug fixes. + </dd> + <dt id="v1.11">1.11</dt> + <dd id="v1.11-dd"> + Minor bug fixes to completion. Added fictive validation + header to completion alternatives when buffer is empty and + mumamo is used. + </dd> + <dt id="v1.12">1.12</dt> + <dd id="v1.12-dd"> + <ul> + <li> + Fixed a bug in image link insertion in nxhtml-mode, thanks Niels Giesen! + </li> + <li> + Restructured, reordered and documented mumamo.el. It is now two + separate files, mumamo.el and mumamo-fun.el. + </li> + <li> + Added move by chunk to the nXhtml menu. + </li> + </ul> + </dd> + <dt id="v1.13">1.13</dt> + <dd id="v1.13-dd"> + <ul> + <li> + Better handling of the case when no validation header + is needed and the user tries to turn it on. + </li> + <li> + Added .phtml as php file. + </li> + </ul> + </dd> + <dt id="v1.14">1.14</dt> + <dd id="v1.14-dd"> + <ul> + <li> + Completion of links in XHTML was broken. Fixed, thanks + to Niels Giesen. + </li> + </ul> + </dd> + <dt id="v1.15">1.15</dt> + <dd id="v1.15-dd"> + <ul> + <li> + Added `mumamo-map' keymap. + </li> + <li> + Added a keymap to all multi major modes. + </li> + <li> + Some more refinement to fictive validation headers. + </li> + </ul> + </dd> + <dt id="v1.16">1.16</dt> + <dd id="v1.16-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Changes to indentation: + <ul> + <li> + Removed indent-region-mode since that + functionality is now in indent-for-tab-command in + Emacs 22. + </li> + <li> + Removed some code that checked if indentation was 0. + </li> + <li> + Added indent-for-tab-command to mumamo-map. + </li> + </ul> + </li> + <li> + Reordering and renaming: + <ul> + <li> + Reordered and move some functions in mumamo.el et al. + Added new file nxhtml-mumamo.el. + </li> + <li> + Renamed <i>define-mumamo-turn-on</i> to + <i>define-mumamo-multi-major-mode</i>. + </li> + <li> + Removed the ending <i>-turn-on</i> from the + functions defined by the macro above. + </li> + <li> + Introduced <i>multi major mode</i> as a name for + the functions defined by the macro above. Those + works in many respects like major mode functions, + but they support multiple major modes in a buffer. + </li> + </ul> + </li> + <li> + Added support for noweb as multiple major mode. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.17">1.17</dt> + <dd id="v1.17-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Added support for flyspell. + </li> + </ul> + </li> + <li> + Bug fixes to the version of find-recursive.el that + ships with nXhtml. Thanks to Cezar Halmagean. + </li> + <li> + Added tabkey2.el which tries to make it easy to use + the Tab key for completion. (You must load it and turn + on tabkey2-mode to use it.) + </li> + <li> + Folding: + <ul> + <li> + Added <i>nxhtml-heading-element-name-regexp</i> as + default for nxml style folding. + </li> + <li> + Some changes to fold-dwim.el. + </li> + </ul> + </li> + <li> + AppMenu: + <ul> + <li> + Simplified: Removed the possibility to + automatically show minor and major mode menus. + There is now only one list, <i>appmenu-alist</i>. + </li> + <li> + Added menu item <i>At Current Point</i> for + bindings found in character and overlay keymaps at + point. Those you always forget. + </li> + </ul> + </li> + <li> + Physical line: + <ul> + <li> + Added physical-line.el to nXhtml. + </li> + <li> + Added new functions to move to beginning and end + of line to ourcomments-util.el that supports + physical-line.el. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.18">1.18</dt> + <dd id="v1.18-dd"> + <ul> + <li> + Better Tab completion in tabkey2.el. + </li> + </ul> + </dd> + <dt id="v1.19">1.19</dt> + <dd id="v1.19-dd"> + <ul> + <li> + Even better Tab completion in tabkey2.el. + </li> + </ul> + </dd> + <dt id="v1.20">1.20</dt> + <dd id="v1.20-dd"> + <ul> + <li> + Once again even better Tab completion in tabkey2.el. + </li> + <li> + Fixed bug in hiding of validation errors (they could + disappear totally). + </li> + <li> + Cleaned up menus in nXhtml. + </li> + </ul> + </dd> + <dt id="v1.21">1.21</dt> + <dd id="v1.21-dd"> + <ul> + <li> + Added a bit support for dired (upload, browse, browse + remote). + </li> + <li> + Fixed some strange menu problems (i hope). + </li> + </ul> + </dd> + <dt id="v1.22">1.22</dt> + <dd id="v1.22-dd"> + <ul> + <li> + Bug fix. + </li> + </ul> + </dd> + <dt id="v1.23">1.23</dt> + <dd id="v1.23-dd"> + <ul> + <li> + Bug fix. + </li> + </ul> + </dd> + <dt id="v1.24">1.24</dt> + <dd id="v1.24-dd"> + <ul> + <li> + Tried again to make hexcolor-mode more readable. + </li> + <li> + Mumamo: + <ul> + <li> + Added support for <i>hi-lock-mode</i>. At present + it might however be very puzzling. The hilight + added by hi-lock-mode may be hidden by the + overlays used by mumamo. Tip: you can always use + the face <span + style="font-size:1.5em;">hi-black-hb</span>. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.25">1.25</dt> + <dd id="v1.25-dd"> + <ul> + <li> + Mumamo: + <ul> + <li> + Handle hi-lock-mode in a more general way + using <i>font-lock-mode-hook</i>. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.26">1.26</dt> + <dd id="v1.26-dd"> + <ul> + <li> + nxhtml-mode: + <ul> + <li> + Removed the indent line patch for nxml-mode. + </li> + <li> + Better test for empty page during completion. + </li> + </ul> + </li> + <li> + tabkey2-mode: + <ul> + <li> + A lot of improvements. + </li> + </ul> + </li> + </ul> + </dd> + <dt id="v1.27">1.27</dt> + <dd id="v1.27-dd"> + <ul> + <li> + Fixed a bug in html-site when comparing file + names. File names where not made unique before + comparision. + </li> + <li> + Fixed documentation and reordered code in mumamo.el + and mumamo-fun.el. + </li> + <li> + Fixed a bug in mumamo concerning indentation. The + desired indentation function replacement where not + used. + </li> + <li> + Fixed tabkey2 bugs. + </li> + <li> + Changed javascript.el indentation to make it work with + mumamo.el. + </li> + <li> + Introduced the function + <i>mumamo-make-variable-buffer-permanent</i> as an aid for + minor mode authors. + </li> + <li> + Made nXhtml menu available in sub-chunks. + </li> + <li> + Included a slightly changed version of Steve Yegge's + js2.el + js2-fl-mode.el with support for + jit-lock-mode. This support has some flaws and maybe + js2 is not ready for use, I am not sure. However if you want + to use this instead of Karl Landströms javascript-mode + then please customize <i>mumamo-major-modes</i>. + </li> + </ul> + </dd> + </dl> + </div> + </div> + + <hr class="footer"/> + <p class="footer"> + Copyright © 2008 OurComments.org + -- + Latest update 2008-03-09 + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/ind-0-error.php b/emacs/nxhtml/tests/in/ind-0-error.php new file mode 100644 index 0000000..6bbdb24 --- /dev/null +++ b/emacs/nxhtml/tests/in/ind-0-error.php @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Lab 2 - Layout Control - Task 2 - XHTML/CSS version</title> + </head> + <body> + <?php + // comment + $thepage = $_GET['page']; + + if (empty($thepage)) { + require('main-div-a.html'); + } + else { + if ($thepage != 'a' && $thepage != 'b') { + print('You hacker you!'); + } + else { + require('main-div-'.$thepage.'.html'); + } + for (;;) { + } + } + ?> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/indent-bug-html-mode.html b/emacs/nxhtml/tests/in/indent-bug-html-mode.html new file mode 100644 index 0000000..bc77985 --- /dev/null +++ b/emacs/nxhtml/tests/in/indent-bug-html-mode.html @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<title>Indentation bug at <</title> +</head> +<body> +Try to indent the whole file several times. +The first time both the html and the php code is badly indented. +<div id="main"> +<?php +for ($i = 0; $i < 4711; ++$i) { +} +?> +</div> +</body> +</html> diff --git a/emacs/nxhtml/tests/in/java.java b/emacs/nxhtml/tests/in/java.java new file mode 100644 index 0000000..8ba2940 --- /dev/null +++ b/emacs/nxhtml/tests/in/java.java @@ -0,0 +1,13 @@ +public class FirstProgram + +{ + + public static void main(String[] args) + + { + + System.out.println("Hey! you are going to compile and run your first Java program"); + + } + +} diff --git a/emacs/nxhtml/tests/in/jcl-080802-index.html.erb b/emacs/nxhtml/tests/in/jcl-080802-index.html.erb new file mode 100644 index 0000000..8478b3d --- /dev/null +++ b/emacs/nxhtml/tests/in/jcl-080802-index.html.erb @@ -0,0 +1,16 @@ +<h2>Mensajes recibidos</h2> +<p class="small" style="color:red;margin: 10px"> + Solo se muestran los ultimos 10 mensajes, aquà hay que añadir + paginación y ¿lógica?. +</p> +<div id="received-messages" class="message-list"> + <% for message in @messages %> + <div id="received-message-<%= message.id -%>" class="received-message"> + <span class="header"><%= message.sender.roster_name %> escribió a fecha <%= message.created_at -%></span> + <div class="content"> + <%=h truncate(message.message, 100) %> + </div> + <%= link_to "Mostrar", message_path(message) %> +</div> +<% end %> +</div> diff --git a/emacs/nxhtml/tests/in/jcl-080802-messages_controller.rb b/emacs/nxhtml/tests/in/jcl-080802-messages_controller.rb new file mode 100644 index 0000000..6fb0555 --- /dev/null +++ b/emacs/nxhtml/tests/in/jcl-080802-messages_controller.rb @@ -0,0 +1,57 @@ +class MessagesController < BaseController + + before_filter :enable_chat + skip_before_filter :verify_authenticity_token + + # GET /messages + # GET /messages.xml + def index + @messages = ChatMessage.to_user(current_user).last_week.all + + respond_to do |format| + format.html # index.html.erb + format.xml { render :xml => @messages } + end + end + + # GET /messages/1 + # GET /messages/1.xml + def show + @message = ChatMessage.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.xml { render :xml => @message } + end + end + + # POST /messages + # POST /messages.xml + def create + @message = ChatMessage.new(:receiver_id => params[:receiver_id], + :message => params[:messageText], + :sender => current_user) + + if @message.save + send_message + end + + render :nothing => true + + end + + protected + + def send_message + formatted_message = render_to_string(:partial => "message_for_chat", :object => @message) + shooter_action_for_receiver = render_to_string :update do |page| + page.call "showMessage", @message.sender.to_param, formatted_message + end + shooter_action_for_sender = render_to_string :update do |page| + page.call "showMessage", @message.receiver.to_param, formatted_message + page.call "messageTextBox.reset" + end + Meteor.shoot 'futura-chat', shooter_action_for_sender, [@message.sender.login] + Meteor.shoot 'futura-chat', shooter_action_for_receiver, [@message.receiver.login] + end +end diff --git a/emacs/nxhtml/tests/in/jj-081226.html b/emacs/nxhtml/tests/in/jj-081226.html new file mode 100644 index 0000000..9599014 --- /dev/null +++ b/emacs/nxhtml/tests/in/jj-081226.html @@ -0,0 +1,26 @@ +<script type="text/javascript"> + // <![CDATA[ + // Set this to the URL you used to fetch recommendations, whether you + // fetched them on the client or the server. + var request_url="%(json_url)s"; + + // This function is used track click-throughs by fetching a web + // beacon + function trackClickThrough(elem) { + var img = new Image(); + img.src = '%(beacon_url)s' + + '?request_url=' + escape(request_url) + + '&click_through_url=' + escape(elem.href); + return true; + } + // ]]> +</script> +<p> + <!-- + Imagine this is one of the recommendations that was returned. + Just add an onclick handler that calls trackClickThrough. + --> + <a href="http://www.google.com" + onclick="return trackClickThrough(this);">Click me!</a> +</p> + diff --git a/emacs/nxhtml/tests/in/josh-091115-cancer_summary.xsl b/emacs/nxhtml/tests/in/josh-091115-cancer_summary.xsl new file mode 100644 index 0000000..043e9d2 --- /dev/null +++ b/emacs/nxhtml/tests/in/josh-091115-cancer_summary.xsl @@ -0,0 +1,490 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" + xmlns:set="http://exslt.org/sets"> + + <xsl:output method="html"/> + <xsl:output encoding="utf-8"/> + <xsl:output doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/> + <xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/> + + <xsl:template match="/"> + + <html> + <head> + <title>Cancer Summary: <xsl:value-of select="//individual/@name"/> <xsl:value-of select="//individual/@gender"/> <xsl:value-of select="//individual/@id"/></title> + + <link rel="shortcut icon" href="/resources/report_resources/apipe_dashboard/images/gc_favicon.png" type="image/png" /> + + <link rel="stylesheet" href="/resources/report_resources/apipe_dashboard/css/master.css" type="text/css" media="screen" /> + <link rel="stylesheet" href="/resources/report_resources/apipe_dashboard/css/tablesorter.css" type="text/css" media="screen" /> + <script type="text/javascript" src="/resources/report_resources/jquery/jquery.js"></script> + <script type="text/javascript" src="/resources/report_resources/jquery/jquery.tablesorter.min.js"></script> + <script type="text/javascript"> + $(document).ready(function() { + $("#tier_1_snps").tablesorter({ + // sort on first column, ascending + // sortList: [[0,0]] + }); + + $("#tier_1_insertions").tablesorter({ + // sort on first column, ascending + //sortList: [[0,0]] + }); + + $("#tier_1_deletions").tablesorter({ + // sort on first column, ascending + //sortList: [[0,0]] + }); + }); + </script> + <link rel="stylesheet" href="/resources/report_resources/cancer_card/css/zoom2.css" type="text/css" media="screen"></link> + <script type="text/javascript" src="/resources/report_resources/cancer_card/js/dom-drag.js"></script> + + <script type="text/javascript" src="/resources/report_resources/cancer_card/js/HotSpot2.js"></script> + <script type="text/javascript"> + addEvent(window, 'load', function() { + HotSpotController.init("zoomImage",300, '<xsl:value-of select="//individual/circos-images/@large"/>','ZTbutton'); }); + + function addEvent(obj, evType, fn) { + if (obj.addEventListener) { + obj.addEventListener(evType, fn, false); + return true; + } else if (obj.attachEvent) { + var r = obj.attachEvent("on" + evType, fn); + return r; + } else { + return false; + } + } + </script> + + <script type="text/javascript"> + $(document).ready(function() { + $("input[type=checkbox]").click(function() { + alert("Clicked: " + this.value); + }); + }); + </script> + + <style type="text/css" media="screen"> + table.info_table_group td { + padding-right: 10px; + } + + div.content_padding { + padding: 0 10px 20px 10px; + } + + h3.group_header { + border-bottom: 2px solid #CCC; + } + div.circos_graph { + float: left; + width: 920px; + } + + form.status_selector { + margin: 0; + padding: 0; + float: right; + font-size: 85%; + font-weight: normal; + } + + form.status_selector table { + margin: 0; + padding: 0; + } + + form.status_selector table td.lbl { + padding-right: 10px; + padding-left: 5px; + } + + + form.status_selector table td.table_lbl { + font-weight: bold; + padding-right: 8px; + padding-left: 3px; + } + </style> + </head> + + <body> + <div class="container"> + <div class="background"> + <div class="page_header"> + <table cellpadding="0" cellspacing="0" border="0"> + <tr> + <td> + <img src="/resources/report_resources/apipe_dashboard/images/gc_header_logo2.png" width="44" height="45" align="absmiddle" /> + </td> + <td> + <h1><xsl:value-of select="//individual/@name"/> <xsl:value-of select="//individual/@gender"/> <xsl:value-of select="//individual/@id"/> Cancer Summary</h1> + </td> + </tr> + </table> + </div> + <div class="page_padding"> + <!-- <h2 class="page_title icon_instrument_data">Flow Cell <xsl:value-of select="//flow-cell/@id"/> Status</h2> --> + <table cellpadding="0" cellspacing="0" border="0" class="info_table_group"> + <tr> + <td> + <h3 class="group_header">Clinical Data</h3> + <table border="0" cellpadding="0" cellspacing="0"> + <tr> + <td> + <table border="0" cellpadding="0" cellspacing="0" class="info_table" width="100%"> + <colgroup> + <col/> + <col width="100%"/> + </colgroup> + <tr><td class="label">Name:</td><td class="value"><xsl:value-of select="//individual/@name"/></td></tr> + <tr> + <td class="label">Gender:</td> + <td class="value"> + <xsl:choose> + <xsl:when test="string(//individual/@gender)"> + <xsl:value-of select="//individual/@gender"/> + </xsl:when> + <xsl:otherwise> + Not Provided + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr><td class="label">ID:</td><td class="value"><xsl:value-of select="//individual/@id"/></td></tr> + + </table> + </td> + <td> + <table border="0" cellpadding="0" cellspacing="0" class="info_table" width="100%" style="float: left;"> + <colgroup> + <col/> + <col width="100%"/> + </colgroup> + + <tr><td class="label">Year Diagnosed:</td><td class="value"><xsl:value-of select="//clinical-data/@diagnosis-year"/></td></tr> + <tr><td class="label">Diagnosed at Age:</td><td class="value"><xsl:value-of select="//clinical-data/@diagnosis-age"/></td></tr> + <xsl:choose> + <xsl:when test="//clinical-data/@alive = '1'"> + <tr><td class="label">Survived:</td><td class="value">Yes</td></tr> + </xsl:when> + <xsl:otherwise> + <tr><td class="label">Survived:</td><td class="value">No</td></tr> + <tr><td class="label">Days Survived:</td><td class="value"><xsl:value-of select="//clinical-data/@days-survived"/></td></tr> + </xsl:otherwise> + </xsl:choose> + </table> + </td> + <td> + <table border="0" cellpadding="0" cellspacing="0" class="info_table" width="100%" style="float: left;"> + <colgroup> + <col/> + <col width="100%"/> + </colgroup> + + <tr><td class="label">Treatment:</td><td class="value"><xsl:value-of select="//clinical-data/@treatment"/></td></tr> + <tr><td class="label">Outcome:</td><td class="value"><xsl:value-of select="//clinical-data/@outcome"/></td></tr> + <tr><td class="label">AMP:</td><td class="value"><xsl:value-of select="//clinical-data/@amp"/></td></tr> + + </table> + </td> + </tr> + </table> + </td> + <td> + <h3 class="group_header">Sequencing Stats</h3> + <table border="0" cellpadding="0" cellspacing="0" class="info_table" width="100%"> + <colgroup> + <col/> + <col width="100%"/> + </colgroup> + <tr><td class="label">Normal Coverage:</td><td class="value"><xsl:value-of select="//samples/sample/models/model/@normal-haploid-coverage"/>X</td></tr> + <tr><td class="label">Tumor Coverage:</td><td class="value"><xsl:value-of select="//samples/sample/models/model/@tumor-haploid-coverage"/>X</td></tr> + </table> + </td> + </tr> + </table> + <hr style="margin-bottom: 0;"/> + <h2 class="report_section" style="margin-bottom: 0; margin-top: 0">Circos Graph   <a id="ZTbutton" href="javascript: void(0);" style="font-size: 85%; font-weight: normal;">[toggle zoom]</a></h2> + <p id="ZTthumbnail"> + <img> + <xsl:attribute name="id">zoomImage</xsl:attribute> + <xsl:attribute name="src"><xsl:value-of select="//individual/circos-images/@small"/></xsl:attribute> + <xsl:attribute name="width">920</xsl:attribute> + <xsl:attribute name="height">920</xsl:attribute> + </img> + </p> + <h2 class="report_section" style="margin-bottom: 0">Tier 1 SNPs +<!-- <form class="status_selector"> + <input type="hidden" name="table" value="tier_1_snps"/> + <table cellpadding="0" cellspacing="0"> + <tr> + <td class="table_lbl">Show:</td> + <xsl:for-each select="set:distinct(//variants/snps/snp/@validation-status)"> + <td class="cb"> + <input type="checkbox"><xsl:attribute name="value"><xsl:value-of select="."/></xsl:attribute></input> + </td> + <td class="lbl"> + <xsl:value-of select="."/> + </td> + </xsl:for-each> + </tr> + </table> + </form> +--> + + </h2> + <table id="tier_1_snps" class="list tablesorter" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top: 0;"> + <xsl:choose> + <xsl:when test="count(//variants/snps/snp) > 0"> + + <thead> + <tr> + <th>validation status</th> + <th>chromosome</th> + <th class="last">start</th> + <th class="last">reference</th> + <th class="last">variant</th> + <th class="last">gene</th> + <th class="last">amino acid change</th> + <th class="last">trv type</th> + </tr> + </thead> + <tbody> + <xsl:for-each select="//variants/snps/snp"> + <xsl:sort select="@validation-status" data-type="text" order="ascending"/> + <xsl:sort select="@chromosome" data-type="number" order="ascending"/> + <tr> + <td class="validation_status"><xsl:value-of select="@validation-status"/></td> + <td><xsl:value-of select="@chromosome"/></td> + <td class="last"> + <xsl:variable name="start" select="@start"/><xsl:value-of select="format-number($start, '#,##0')"/> + </td> + <td class="last"><xsl:value-of select="@reference-allele"/></td> + <td class="last"><xsl:value-of select="@variant-allele"/></td> + <td class="last"><xsl:value-of select="@gene"/></td> + <td class="last"><xsl:value-of select="@amino-acid-change"/></td> + <td class="last"><xsl:value-of select="@trv-type"/></td> + </tr> + </xsl:for-each> + </tbody> + </xsl:when> + <xsl:otherwise> + <tr><td><span class="note">None found.</span></td></tr> + </xsl:otherwise> + </xsl:choose> + </table> + + <h2 class="report_section" style="margin-bottom: 0">Tier 1 Insertions</h2> + <table id="tier_1_insertions" class="list tablesorter" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top: 0;"> + <xsl:choose> + <xsl:when test="count(//variants/insertions/insertion) > 0"> + <thead> + <tr> + <th>validation status</th> + <th>chromosome</th> + <th class="last">start</th> + <th class="last">stop</th> + <th class="last">variant</th> + <th class="last">gene</th> + <th class="last">amino acid change</th> + <th class="last">trv type</th> + </tr> + </thead> + <tbody> + <xsl:for-each select="//variants/insertions/insertion"> + <xsl:sort select="@validation-status" data-type="text" order="ascending"/> + <xsl:sort select="@chromosome" data-type="number" order="ascending"/> + <tr> + <td class="validation_status"><xsl:value-of select="@validation-status"/></td> + <td><xsl:value-of select="@chromosome"/></td> + <td class="last"> + <xsl:variable name="start" select="@start"/><xsl:value-of select="format-number($start, '#,##0')"/> + </td> + <td class="last"> + <xsl:variable name="stop" select="@stop"/><xsl:value-of select="format-number($stop, '#,##0')"/> + </td> + <td class="last"><xsl:value-of select="@variant-allele"/></td> + <td class="last"><xsl:value-of select="@gene"/></td> + <td class="last"><xsl:value-of select="@amino-acid-change"/></td> + <td class="last"><xsl:value-of select="@trv-type"/></td> + </tr> + </xsl:for-each> + </tbody> + </xsl:when> + <xsl:otherwise> + <tr><td><span class="note">None found.</span></td></tr> + </xsl:otherwise> + </xsl:choose> + </table> + + <h2 class="report_section" style="margin-bottom: 0">Tier 1 Deletions</h2> + <table id="tier_1_deletions" class="list tablesorter" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top: 0;"> + <xsl:choose> + <xsl:when test="count(//variants/deletions/deletion) > 0"> + <thead> + <tr> + <th>validation status</th> + <th>chromosome</th> + <th class="last">start</th> + <th class="last">stop</th> + <th class="last">reference</th> + <th class="last">gene</th> + <th class="last">amino acid change</th> + <th class="last">trv type</th> + </tr> + </thead> + <tbody> + <xsl:for-each select="//variants/deletions/deletion"> + <xsl:sort select="@validation-status" data-type="text" order="ascending"/> + <xsl:sort select="@chromosome" data-type="number" order="ascending"/> + <tr> + <td class="validation_status"><xsl:value-of select="@validation-status"/></td> + <td><xsl:value-of select="@chromosome"/></td> + <td class="last"> + <xsl:variable name="start" select="@start"/><xsl:value-of select="format-number($start, '#,##0')"/> + </td> + <td class="last"> + <xsl:variable name="stop" select="@stop"/><xsl:value-of select="format-number($stop, '#,##0')"/> + </td> + <td class="last"><xsl:value-of select="@reference-allele"/></td> + <td class="last"><xsl:value-of select="@gene"/></td> + <td class="last"><xsl:value-of select="@amino-acid-change"/></td> + <td class="last"><xsl:value-of select="@trv-type"/></td> + </tr> + </xsl:for-each> + </tbody> + </xsl:when> + <xsl:otherwise> + <tr><td><span class="note">None found.</span></td></tr> + </xsl:otherwise> + </xsl:choose> + </table> + + <h2 class="report_section" style="margin-bottom: 0;">Structural Variations (translocations)</h2> + <table id="sv_translocations" class="list" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top: 0;"> + <xsl:choose> + <xsl:when test="count(//structural-variants/translocations/translocation) > 0"> + <thead> + <tr> + <th>validation status</th> + <th class="last">chromosome</th> + <th class="last">position</th> + <th> </th> + <th class="last">chromosome</th> + <th class="last">position</th> + </tr> + </thead> + <tbody> + <xsl:for-each select="//structural-variants/translocations/translocation"> + <xsl:sort select="@validation-status" data-type="text" order="ascending"/> + <xsl:sort select="start/@chromosome" data-type="number" order="ascending"/> + <tr> + <td class="validation_status"><xsl:value-of select="@validation-status"/></td> + <td class="last"><xsl:value-of select="start/@chromosome"/></td> + <td class="last"> + <xsl:variable name="start_position" select="start/@position"/><xsl:value-of select="format-number($start_position, '#,##0')"/> + </td> + + <td class="last"><span style="font-size: 100%; font-weight: bold;">→</span></td> + + <td class="last"><xsl:value-of select="stop/@chromosome"/></td> + <td class="last"> + <xsl:variable name="stop_position" select="stop/@position"/><xsl:value-of select="format-number($stop_position, '#,##0')"/> + </td> + </tr> + </xsl:for-each> + </tbody> + </xsl:when> + <xsl:otherwise> + <tr><td><span class="note">None found.</span></td></tr> + </xsl:otherwise> + </xsl:choose> + </table> + + <h2 class="report_section" style="margin-bottom: 0;">Structural Variations (insertions)</h2> + <table id="sv_insertions" class="list" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top: 0;"> + <tbody> + <xsl:choose> + <xsl:when test="count(//structural-variants/insertions/insertion) > 0"> + <thead> + <tr> + <th>validation status</th> + <th class="last">chromosome</th> + <th class="last">start</th> + <th class="last">stop</th> + <th class="last">size</th> + </tr> + </thead> + <xsl:for-each select="//structural-variants/insertions/insertion"> + <xsl:sort select="@validation-status" data-type="number" order="ascending"/> + <xsl:sort select="start/@chromosome" data-type="number" order="ascending"/> + <tr> + <td class="validation_status"><xsl:value-of select="@validation-status"/></td> + <td class="last"><xsl:value-of select="start/@chromosome"/></td> + <td class="last"> + <xsl:variable name="start_position" select="start/@position"/><xsl:value-of select="format-number($start_position, '#,##0')"/> + </td> + <td class="last"> + <xsl:variable name="stop_position" select="stop/@position"/><xsl:value-of select="format-number($stop_position, '#,##0')"/> + </td> + <xsl:variable name="size" select="@size"/><xsl:value-of select="format-number($size, '#,##0')"/> + + </tr> + </xsl:for-each> + </xsl:when> + <xsl:otherwise> + <tr><td><span class="note">None found.</span></td></tr> + </xsl:otherwise> + </xsl:choose> + </tbody> + </table> + + <h2 class="report_section" style="margin-bottom: 0;">Structural Variations (deletions)</h2> + <table id="sv_deletions" class="list" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top: 0;"> + <xsl:choose> + <xsl:when test="count(//structural-variants/deletions/deletion) > 0"> + <thead> + <tr> + <th>validation status</th> + <th class="last">chromosome</th> + <th class="last">start</th> + <th class="last">stop</th> + <th class="last">size</th> + </tr> + </thead> + <tbody> + <xsl:for-each select="//structural-variants/deletions/deletion"> + <xsl:sort select="@validation-status" data-type="number" order="ascending"/> + <xsl:sort select="start/@chromosome" data-type="number" order="ascending"/> + <tr> + <td class="validation_status"><xsl:value-of select="@validation-status"/></td> + <td class="last"><xsl:value-of select="start/@chromosome"/></td> + <td class="last"> + <xsl:variable name="start_position" select="start/@position"/><xsl:value-of select="format-number($start_position, '#,##0')"/> + </td> + <td class="last"> + <xsl:variable name="stop_position" select="stop/@position"/><xsl:value-of select="format-number($stop_position, '#,##0')"/> + </td> + <td class="last"> + <xsl:variable name="size" select="@size"/><xsl:value-of select="format-number($size, '#,##0')"/> + </td> + </tr> + </xsl:for-each> + </tbody> + </xsl:when> + <xsl:otherwise> + <tr><td><span class="note">None found.</span></td></tr> + </xsl:otherwise> + </xsl:choose> + </table> + </div> + </div> + </div> + </body> + </html> + + </xsl:template> + +</xsl:stylesheet> diff --git a/emacs/nxhtml/tests/in/jump-parse.html b/emacs/nxhtml/tests/in/jump-parse.html new file mode 100644 index 0000000..68b0cf4 --- /dev/null +++ b/emacs/nxhtml/tests/in/jump-parse.html @@ -0,0 +1,7 @@ +<h1>Listing People</h1> + +<table> +<% for person in @people %> +<tr> +</tr> +</table> diff --git a/emacs/nxhtml/tests/in/jump-parse.rhtml b/emacs/nxhtml/tests/in/jump-parse.rhtml new file mode 100644 index 0000000..1848b6c --- /dev/null +++ b/emacs/nxhtml/tests/in/jump-parse.rhtml @@ -0,0 +1,9 @@ +<h1>Listing People</h1> + +<table> + +<% <testnxmlparsed> for person in @people %> + +<tr> +</tr> +</table> diff --git a/emacs/nxhtml/tests/in/kp-080604.php b/emacs/nxhtml/tests/in/kp-080604.php new file mode 100644 index 0000000..a8b40c3 --- /dev/null +++ b/emacs/nxhtml/tests/in/kp-080604.php @@ -0,0 +1,4 @@ +<?php +require_once dirname(__FILE__) . '/foo.php'; +require_once dirname(__FILE__) . '/bar.php'; + diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-1.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-1.html new file mode 100644 index 0000000..8d2a355 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-1.html @@ -0,0 +1,13 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-2.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-2.html new file mode 100644 index 0000000..8203f63 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-2.html @@ -0,0 +1,174 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { % block pagestyle % } + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + { % endblock % } + </style> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.preload.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/swfobject.js"></script> + <script type="text/javascript"> + function image_loaded(info) { + /* now we know that the image is loaded, we can add in to the + * document and position it as we want */ + // create the element, set the ID and add in to the DOM, + // otherwise it won't have dimensions + var pointer = $('<img src="' + info.image + '" />'); + pointer.attr('id', 'pointer'); + var frame = $('#container'); + pointer.appendTo(frame); + + // put it into the center and make top & left be in the center + // of the image (cool hack) + pointer.css({ + position: 'absolute', + top: '50%', + left: '50%', + margin: (-pointer.height() / 2) + 'px 0 0 ' + + (-pointer.width() / 2) + 'px' + }); + + // continue with the animation now + play_animation(); + } + + function prepare_animation() { + /* prepares animation by preloading stuff */ + // hide all panels + $('a > img').css('visibility', 'hidden'); + // create the logo - 'pointer': preload and center it + $.preload(['logo'], { + base: '{ % media_url % }/homepage/img/intro/', + ext: '.png', + onFinish: image_loaded + }); + } + + function play_animation() { + /* plays the animations, adds callbacks */ + var frame = $('#container'); + var pointer = $('#pointer'); + + /* run the effects now: first fade in the pointer, then move it + * to the edge of the frame, then fade in the panels + */ + pointer.hide().fadeIn(2000) + .animate({ + top: pointer.height() / 2 + 10, + left: frame.width() - pointer.width() / 2 + }, 3000, undefined, function() { + var panels = $('a > img'); + // show panels, fade them in and add callbacks + panels.css({ visibility: 'visible', + opacity: '0'}) + .fadeTo(1000, 0.5) + .mouseover(fade_in) + .mouseout(fade_out); + }); + } + + function fade_in() { + /* fade in the panel */ + $(this).fadeTo(300, 1); + } + + function fade_out() { + /* fade out the panel */ + $(this).fadeTo(300, 0.5); + } + + // start JS magic when the page has loaded + $(document).ready(prepare_animation); + </script> + + </head> + +{% block body %} +<body> + +<div id="distance"></div> +<div id="container"> + <div id="flashcontent"> + + <table border="0"> + <tr> + <td colspan="3"><div style="height: 63px;" /></td> + </tr> + <tr> + <td><a href="/junkers/"><img src="{% media_url %}/homepage/img/intro/panel_junkers.jpg" alt="junkers" width="166" height="221" /></a></td> + <td><a href="/zeppelin/"><img src="{% media_url %}/homepage/img/intro/panel_zeppelin.jpg" alt="zeppelin" width="168" height="221" /></a></td> + <td><a href="/maximilian/"><img src="{% media_url %}/homepage/img/intro/panel_maximilian.jpg" alt="maximilian" width="162" height="221" /></a></td> + </tr> + <tr> + <td colspan="3"><div style="height: 66px;" /></td> + </tr> + </table> + </div> + + <script type="text/javascript"> + // <![CDATA[ + var so = new SWFObject("{% media_url % }/homepage/swf/intro_{ % translate "LANGUAGE_NAME" % }.swf", "intro", "500", "370", "9", "#FFF"); + so.addParam("allowScriptAccess", "always"); + so.write("flashcontent"); + // ]]> + </script> + +</div> +</div> + +</body> +{% endblock %} + +</html> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-2j.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-2j.html new file mode 100644 index 0000000..6017ba3 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-2j.html @@ -0,0 +1,174 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + { % endblock % } + </style> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.preload.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/swfobject.js"></script> + <script type="text/javascript"> + function image_loaded(info) { + /* now we know that the image is loaded, we can add in to the + * document and position it as we want */ + // create the element, set the ID and add in to the DOM, + // otherwise it won't have dimensions + var pointer = $('<img src="' + info.image + '" />'); + pointer.attr('id', 'pointer'); + var frame = $('#container'); + pointer.appendTo(frame); + + // put it into the center and make top & left be in the center + // of the image (cool hack) + pointer.css({ + position: 'absolute', + top: '50%', + left: '50%', + margin: (-pointer.height() / 2) + 'px 0 0 ' + + (-pointer.width() / 2) + 'px' + }); + + // continue with the animation now + play_animation(); + } + + function prepare_animation() { + /* prepares animation by preloading stuff */ + // hide all panels + $('a > img').css('visibility', 'hidden'); + // create the logo - 'pointer': preload and center it + $.preload(['logo'], { + base: '{ % media_url % }/homepage/img/intro/', + ext: '.png', + onFinish: image_loaded + }); + } + + function play_animation() { + /* plays the animations, adds callbacks */ + var frame = $('#container'); + var pointer = $('#pointer'); + + /* run the effects now: first fade in the pointer, then move it + * to the edge of the frame, then fade in the panels + */ + pointer.hide().fadeIn(2000) + .animate({ + top: pointer.height() / 2 + 10, + left: frame.width() - pointer.width() / 2 + }, 3000, undefined, function() { + var panels = $('a > img'); + // show panels, fade them in and add callbacks + panels.css({ visibility: 'visible', + opacity: '0'}) + .fadeTo(1000, 0.5) + .mouseover(fade_in) + .mouseout(fade_out); + }); + } + + function fade_in() { + /* fade in the panel */ + $(this).fadeTo(300, 1); + } + + function fade_out() { + /* fade out the panel */ + $(this).fadeTo(300, 0.5); + } + + // start JS magic when the page has loaded + $(document).ready(prepare_animation); + </script> + + </head> + +{% block body %} +<body> + +<div id="distance"></div> +<div id="container"> + <div id="flashcontent"> + + <table border="0"> + <tr> + <td colspan="3"><div style="height: 63px;" /></td> + </tr> + <tr> + <td><a href="/junkers/"><img src="{% media_url %}/homepage/img/intro/panel_junkers.jpg" alt="junkers" width="166" height="221" /></a></td> + <td><a href="/zeppelin/"><img src="{% media_url %}/homepage/img/intro/panel_zeppelin.jpg" alt="zeppelin" width="168" height="221" /></a></td> + <td><a href="/maximilian/"><img src="{% media_url %}/homepage/img/intro/panel_maximilian.jpg" alt="maximilian" width="162" height="221" /></a></td> + </tr> + <tr> + <td colspan="3"><div style="height: 66px;" /></td> + </tr> + </table> + </div> + + <script type="text/javascript"> + // <![CDATA[ + var so = new SWFObject("{% media_url % }/homepage/swf/intro_{ % translate "LANGUAGE_NAME" % }.swf", "intro", "500", "370", "9", "#FFF"); + so.addParam("allowScriptAccess", "always"); + so.write("flashcontent"); + // ]]> + </script> + +</div> +</div> + +</body> +{% endblock %} + +</html> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-3.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-3.html new file mode 100644 index 0000000..2026eb5 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-3.html @@ -0,0 +1,61 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + {% block pagestyle %} + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + {% endblock %} + </style> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.preload.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/swfobject.js"></script> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-4.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-4.html new file mode 100644 index 0000000..a350fc4 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-4.html @@ -0,0 +1,58 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + {% block pagestyle %} + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + {% endblock %} + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-5.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-5.html new file mode 100644 index 0000000..46fbf29 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-5.html @@ -0,0 +1,20 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-6.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-6.html new file mode 100644 index 0000000..9fc7fae --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-6.html @@ -0,0 +1,58 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { % block pagestyle % } + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + { % endblock % } + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-7.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-7.html new file mode 100644 index 0000000..4cd4359 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-7.html @@ -0,0 +1,56 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-8.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-8.html new file mode 100644 index 0000000..4b91efa --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-8.html @@ -0,0 +1,57 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { block pagestyle } + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-9.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-9.html new file mode 100644 index 0000000..03571e6 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-9.html @@ -0,0 +1,57 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + * { + margin: 0; + padding: 0; + } + { block pagestyle } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-a-notabs.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-a-notabs.html new file mode 100644 index 0000000..61b64e3 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-a-notabs.html @@ -0,0 +1,57 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-a.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-a.html new file mode 100644 index 0000000..b1c5245 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-a.html @@ -0,0 +1,57 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-b.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-b.html new file mode 100644 index 0000000..89ac466 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-b.html @@ -0,0 +1,55 @@ +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-c.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-c.html new file mode 100644 index 0000000..f797466 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-c.html @@ -0,0 +1,52 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-d.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-d.html new file mode 100644 index 0000000..f40fdf6 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-d.html @@ -0,0 +1,51 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-e.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-e.html new file mode 100644 index 0000000..62aafe7 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-e.html @@ -0,0 +1,50 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-f.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-f.html new file mode 100644 index 0000000..ac73f84 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-f.html @@ -0,0 +1,49 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-g.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-g.html new file mode 100644 index 0000000..9d302ce --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-g.html @@ -0,0 +1,39 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-h.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-h.html new file mode 100644 index 0000000..5a0a166 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-h.html @@ -0,0 +1,27 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + #pointer { + display: block; + margin: 0 auto; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-i.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-i.html new file mode 100644 index 0000000..66ed32f --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-i.html @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + padding: 0; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-j.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-j.html new file mode 100644 index 0000000..e1beacd --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-j.html @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + + <style type="text/css"> + + p { + margin: 0; + padding: 0; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing-k.html b/emacs/nxhtml/tests/in/kubica-080516-freezing-k.html new file mode 100644 index 0000000..9dc91e1 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing-k.html @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + + <style type="text/css"> + { xlock } + p { + margin: 0; + padding: 0; + } + + </style> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing.css b/emacs/nxhtml/tests/in/kubica-080516-freezing.css new file mode 100644 index 0000000..fdd782d --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing.css @@ -0,0 +1,36 @@ + {% block pagestyle %} + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + {% endblock %} diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing.html b/emacs/nxhtml/tests/in/kubica-080516-freezing.html new file mode 100644 index 0000000..15caa88 --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing.html @@ -0,0 +1,174 @@ +{% load transdigest helpers %} +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC + "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://dublincore.org/documents/dcq-html/"> + <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" /> + <link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" /> + <link rel="stylesheet" type="text/css" href="{% media_url %}/homepage/css/web0.5.css" media="screen" /> + + <title>{% block title %}{% translate "WELCOME_TO_POINTTEC" %}{% endblock %}</title> + <meta name="DC.title" content="Homepage of point TEC" /> + <meta name="DC.creator" content="Marek Kubica" /> + <meta name="DC.subject" content="Presentation of products" /> + <meta name="DC.publisher" content="point TEC" /> + <meta name="DC.rights" content="copyright by point TEC" /> + {% block htmlhead %} + + {% endblock %} + <style type="text/css"> + {% block pagestyle %} + * { + margin: 0; + padding: 0; + } + img { + border: 0 + } + + html, body { + height: 100%; + } + + #distance { + width: 1px; + height: 50%; + margin-bottom: -175px; + } + #container { + position: relative; + margin: 0 auto; + height: 370px; + width: 500px; + background-color: #ffffff; + } + /* the horizontal bars */ + #flashcontent * div { + background-color: #292926; + } + + #pointer { + display: block; + margin: 0 auto; + } + + {% endblock %} + </style> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/jquery.preload.js"></script> + <script type="text/javascript" src="{% media_url %}/homepage/js/swfobject.js"></script> + <script type="text/javascript"> + function image_loaded(info) { + /* now we know that the image is loaded, we can add in to the + * document and position it as we want */ + // create the element, set the ID and add in to the DOM, + // otherwise it won't have dimensions + var pointer = $('<img src="' + info.image + '" />'); + pointer.attr('id', 'pointer'); + var frame = $('#container'); + pointer.appendTo(frame); + + // put it into the center and make top & left be in the center + // of the image (cool hack) + pointer.css({ + position: 'absolute', + top: '50%', + left: '50%', + margin: (-pointer.height() / 2) + 'px 0 0 ' + + (-pointer.width() / 2) + 'px' + }); + + // continue with the animation now + play_animation(); + } + + function prepare_animation() { + /* prepares animation by preloading stuff */ + // hide all panels + $('a > img').css('visibility', 'hidden'); + // create the logo - 'pointer': preload and center it + $.preload(['logo'], { + base: '{% media_url %}/homepage/img/intro/', + ext: '.png', + onFinish: image_loaded + }); + } + + function play_animation() { + /* plays the animations, adds callbacks */ + var frame = $('#container'); + var pointer = $('#pointer'); + + /* run the effects now: first fade in the pointer, then move it + * to the edge of the frame, then fade in the panels + */ + pointer.hide().fadeIn(2000) + .animate({ + top: pointer.height() / 2 + 10, + left: frame.width() - pointer.width() / 2 + }, 3000, undefined, function() { + var panels = $('a > img'); + // show panels, fade them in and add callbacks + panels.css({ visibility: 'visible', + opacity: '0'}) + .fadeTo(1000, 0.5) + .mouseover(fade_in) + .mouseout(fade_out); + }); + } + + function fade_in() { + /* fade in the panel */ + $(this).fadeTo(300, 1); + } + + function fade_out() { + /* fade out the panel */ + $(this).fadeTo(300, 0.5); + } + + // start JS magic when the page has loaded + $(document).ready(prepare_animation); + </script> + + </head> + +{% block body %} +<body> + +<div id="distance"></div> +<div id="container"> + <div id="flashcontent"> + + <table border="0"> + <tr> + <td colspan="3"><div style="height: 63px;" /></td> + </tr> + <tr> + <td><a href="/junkers/"><img src="{% media_url %}/homepage/img/intro/panel_junkers.jpg" alt="junkers" width="166" height="221" /></a></td> + <td><a href="/zeppelin/"><img src="{% media_url %}/homepage/img/intro/panel_zeppelin.jpg" alt="zeppelin" width="168" height="221" /></a></td> + <td><a href="/maximilian/"><img src="{% media_url %}/homepage/img/intro/panel_maximilian.jpg" alt="maximilian" width="162" height="221" /></a></td> + </tr> + <tr> + <td colspan="3"><div style="height: 66px;" /></td> + </tr> + </table> + </div> + + <script type="text/javascript"> + // <![CDATA[ + var so = new SWFObject("{% media_url %}/homepage/swf/intro_{% translate "LANGUAGE_NAME" %}.swf", "intro", "500", "370", "9", "#FFF"); + so.addParam("allowScriptAccess", "always"); + so.write("flashcontent"); + // ]]> + </script> + +</div> +</div> + +</body> +{% endblock %} + +</html> diff --git a/emacs/nxhtml/tests/in/kubica-080516-freezing.txt b/emacs/nxhtml/tests/in/kubica-080516-freezing.txt new file mode 100644 index 0000000..dc3a6cf --- /dev/null +++ b/emacs/nxhtml/tests/in/kubica-080516-freezing.txt @@ -0,0 +1,10 @@ +The problem seems to have to do with the { block pagestyle } thing +below. If that is removed then the freezing does not happen. + + <style type="text/css"> + { block pagestyle } + p { + margin: 0; + +Try the files kubica-080516-freezing-i.html and dito j. The former +freezes Emacs, but the latter does not. diff --git a/emacs/nxhtml/tests/in/kwalo-080930.php b/emacs/nxhtml/tests/in/kwalo-080930.php new file mode 100644 index 0000000..b45be15 --- /dev/null +++ b/emacs/nxhtml/tests/in/kwalo-080930.php @@ -0,0 +1,23 @@ +<? + +class Baz +{ + // This class was written after the file was opened +} + +class Bar +{ + public function foo() + { + var_dump("foo"); + return null; + } +} + +class Foo +{ + public function bar() + { + var_dump("bar"); + } +} \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/latex-clojre-mumamo-test.lclj b/emacs/nxhtml/tests/in/latex-clojre-mumamo-test.lclj new file mode 100644 index 0000000..7d5a97c --- /dev/null +++ b/emacs/nxhtml/tests/in/latex-clojre-mumamo-test.lclj @@ -0,0 +1,17 @@ +\begin{section} +Test file for latex-clojure-mumamo-mode! + +\begin{subsection} +Define some vars here! +\begin{clojure} +(def zero 0) +\end{clojure} + +\begin{subsection} +Define some functions here! +\begin{clojure} +(defn id [arg] + arg) +\end{clojure} + +\end{section} diff --git a/emacs/nxhtml/tests/in/lg-080813-div.html b/emacs/nxhtml/tests/in/lg-080813-div.html new file mode 100644 index 0000000..c507cb7 --- /dev/null +++ b/emacs/nxhtml/tests/in/lg-080813-div.html @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + <meta http-equiv="Content-Type" content="text/html;" /> + <!-- There was a typo above, a missing " after content --> + </head> + <body> + <div> + <div> + <p><a href="">marked invalid</a></p> + </div> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/lg-080813-label.html b/emacs/nxhtml/tests/in/lg-080813-label.html new file mode 100644 index 0000000..8e790eb --- /dev/null +++ b/emacs/nxhtml/tests/in/lg-080813-label.html @@ -0,0 +1,15 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><title></title></head> + <body> + <p> + Since nXml do not have a schema for xhtml 1.0 transitional it + uses strict instead. Therefore it gaves false errors here. + </p> + <form action="" method="get"> + <label for="inputname">Label for field: </label> + <input type="text" name="inputname" id="inputname" /> + </form> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/long-lines.txt b/emacs/nxhtml/tests/in/long-lines.txt new file mode 100644 index 0000000..791bdcb --- /dev/null +++ b/emacs/nxhtml/tests/in/long-lines.txt @@ -0,0 +1 @@ +this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line this is a very long line diff --git a/emacs/nxhtml/tests/in/markdown.markdown b/emacs/nxhtml/tests/in/markdown.markdown new file mode 100644 index 0000000..a4cb19d --- /dev/null +++ b/emacs/nxhtml/tests/in/markdown.markdown @@ -0,0 +1,16 @@ + +This is a regular paragraph. + +<table> + <tr> + <td>Foo</td> + </tr> +</table> + +This is another regular paragraph. + +Those look alike should not be in html-mode: + + <http://example.com/> + <address@example.com> + diff --git a/emacs/nxhtml/tests/in/mason.mason b/emacs/nxhtml/tests/in/mason.mason new file mode 100644 index 0000000..089dc1d --- /dev/null +++ b/emacs/nxhtml/tests/in/mason.mason @@ -0,0 +1,46 @@ + +<%perl> + my $noun = 'World'; +my @time = localtime; +</%perl> +Hello <% $noun %>, +% if ( $time[2] < 12 ) { + good morning. + % } else { + good afternoon. + % } + + <%text> + Some text + </%text> + +<%doc> + Some doc +</%doc> + +<& simple_comp &> + + <%args> + $a + @b # a comment + %c + + # another comment + $d => 5 + $e => $d*2 + @f => ('foo', 'baz') + %g => (joe => 1, bob => 2) + </%args> + +<&| /path/to/comp &> this is the content </&> +<&| comp, arg1 => 'hi' &> filters can take arguments </&> +<&| comp &> content can include <% "tags" %> of all kinds </&> +something +<& simple_comp &> +<&| SELF:method1 &> subcomponents can be filters </&> +<&| compit &> + <&| comp1 &> + nesting is also + <&| comp2 &> OK </&> +xx +</&> diff --git a/emacs/nxhtml/tests/in/menu-err.txt b/emacs/nxhtml/tests/in/menu-err.txt new file mode 100644 index 0000000..6a2beb6 --- /dev/null +++ b/emacs/nxhtml/tests/in/menu-err.txt @@ -0,0 +1,10 @@ +Debugger entered--Lisp error: (error "No file on this line") + signal(error ("No file on this line")) + error("No file on this line") + dired-get-file-for-visit() + (if (derived-mode-p (quote dired-mode)) (dired-get-file-for-visit) buffer-file-name) + html-site-buffer-or-dired-file-name() + (setq file (html-site-buffer-or-dired-file-name)) + (if file nil (setq file (html-site-buffer-or-dired-file-name))) + (unless file (setq file (html-site-buffer-or-dired-file-name))) + nxhtml-buffer-possibly-local-viewable() diff --git a/emacs/nxhtml/tests/in/mjt-feed.html b/emacs/nxhtml/tests/in/mjt-feed.html new file mode 100644 index 0000000..50044d0 --- /dev/null +++ b/emacs/nxhtml/tests/in/mjt-feed.html @@ -0,0 +1,86 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<link rel="stylesheet" href="feedstyle.css" type="text/css" /> +<title>mjt google feeds</title> +<script type="text/javascript" src="http://mjtemplate.org/dist/mjt-0.6/mjt.js"></script> +<script type="text/javascript" src="./google-api-keys.js"></script> +<script type="text/javascript"> + load_google_api('http://www.google.com/jsapi?key='); +</script> +<script type="text/javascript"> + + google.load("feeds", "1"); + + function initialize() { + var top = mjt.run('top'); + + var feeduri = mjt.urlquery.feed; + if (typeof feeduri == 'undefined') + feeduri = "http://blog.freebase.com/?feed=atom"; + document.title = 'feed: ' + feeduri; + + var feed = new google.feeds.Feed(feeduri); + feed.load(function(result) { mjt.run('feed', top.showfeed, [result]); }); + } + google.setOnLoadCallback(initialize); +</script> +</head> +<body> +<div> +This is a toy feed reader using <a href="http://mjtemplate.org">Mjt</a> to +read Google's new <a href="http://code.google.com/apis/ajaxfeeds/documentation/">AJAX feed API</a>. +</div> +<div> +some feeds: +<a href="?feed=http://blog.freebase.com/%3Ffeed%3Datom">The Freebase Dev Blog</a> +| <a href="?feed=http://googleajaxsearchapi.blogspot.com/atom.xml">Google AJAX Search API Blog</a> +</div> +<!-- compare to <a href="http://code.google.com/apis/ajaxfeeds/documentation/helloworld.html">google example</a> --> +<div id="top" style="display:none;"> +<div class="feedform"> +<form action="feed.html"> +<div>xml feed uri: + <input type="text" size="70" name="feed" value="${mjt.urlquery.feed||''}" /> +<input type="submit" value="read" /> +</div> +</form> +</div> +<div mjt.def="showfeed(result)"> +<div mjt.choose=""> +<div mjt.when="result.status != '200' && result.error"> + error: <b>$result.error.message</b> +</div> +<div mjt.when="result.status.code == 200"> +<pre mjt.script=""> + document.title = 'feed: ' + result.feed.title; + </pre> +<h1 class="feedtitle"><a href="$result.feed.link">$result.feed.title</a></h1> +<div mjt.for="entry in result.feed.entries" class="entry"> +<div class="entryheader"> +<a href="$entry.link" class="entrytitle">$entry.title</a> +<span mjt.if="entry.categories instanceof Array && entry.categories.length>0"> + in: <span mjt.for="cat in (entry.categories||[])" class="category">$cat</span> +</span> +<div> + + <span class="author">${entry.author||''}</span> - + <span class="date">${entry.publishedDate||''}</span> +</div> +</div> +<!-- XXX security - does google sanitize? we sure don't... --> +<div class="content">${mjt.bless(entry.content)}</div> +</div> +</div> +<div mjt.otherwise=""> +<b>unknown response type from google feed api</b> +</div> +</div> +</div> +</div> +<!-- the feed view gets pasted here when ready --> +<div id="feed"></div> +</body> +</html> diff --git a/emacs/nxhtml/tests/in/mjt-imagesearch.html b/emacs/nxhtml/tests/in/mjt-imagesearch.html new file mode 100644 index 0000000..1ec9cd8 --- /dev/null +++ b/emacs/nxhtml/tests/in/mjt-imagesearch.html @@ -0,0 +1,46 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<title>mjt yahoo test</title> +<script type="text/javascript" src="http://mjtemplate.org/dist/mjt-0.6/mjt.js"></script> +<script type="text/javascript" src="http://mjtemplate.org/dist/mjt-0.6/src/yahooapi/yahooapi.js"></script> +</head> +<body onload="mjt.run('top')"> +<h2>Yahoo image search example</h2> +using +<a href="http://mjtemplate.org">mjt</a> +to interact with the +<a href="http://developer.yahoo.com/common/json.html">yahoo json api</a> +<div id="top" style="display:none;"> +<div mjt.task="o"> + mjt.yahooapi.ImageSearch(mjt.urlquery.query||'kathakali') + </div> +<form method="get" action=""> +<div> +<input type="text" name="query" value="${mjt.urlquery.query||''}" /> +<input type="submit" value="search" /> +</div> +</form> +<div mjt.choose="o.state"> +<div mjt.when="ready"> +<div mjt.for="img in o.result.Result"> +<h3>$img.Title</h3> +<img alt="image" src="#" mjt.src="$img.Thumbnail.Url" style="float:left" /> +<div>$img.Summary</div> +<hr style="clear:both" /> +</div> +</div> +<div mjt.when="wait"> + loading... + </div> +<div mjt.when="error"> +<div mjt.for="msg in o.messages"> + $msg.message + </div> +</div> +</div> +</div> +</body> +</html> diff --git a/emacs/nxhtml/tests/in/mjt-minimal.html b/emacs/nxhtml/tests/in/mjt-minimal.html new file mode 100644 index 0000000..6d8e30e --- /dev/null +++ b/emacs/nxhtml/tests/in/mjt-minimal.html @@ -0,0 +1,11 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<script type="text/javascript" src="http://mjtemplate.org/dist/mjt-0.6/mjt.js"></script> +<title>a minimal mjt example</title> +</head> +<body onload="mjt.run()" style="display:none"> + running mjt version ${mjt.VERSION} +</body></html> diff --git a/emacs/nxhtml/tests/in/mumamo-and-org.org b/emacs/nxhtml/tests/in/mumamo-and-org.org new file mode 100644 index 0000000..19d9b53 --- /dev/null +++ b/emacs/nxhtml/tests/in/mumamo-and-org.org @@ -0,0 +1,20 @@ +* Test of org and mumamo + + Below is a html chunk + +#+BEGIN_HTML +<p> + I have no idea of how to use this yet. +</p> +#+END_HTML + +#+BEGIN_SRC emacs-lisp-mode + (defun +#+END_SRC + +Where are the "..." in org-mumamo-mode??? + +** Some subnode + +Hm, org full header lines are broken, why? +Does not seem related to mumamo. diff --git a/emacs/nxhtml/tests/in/mumamo-and-org.org.mm b/emacs/nxhtml/tests/in/mumamo-and-org.org.mm new file mode 100644 index 0000000..041427f --- /dev/null +++ b/emacs/nxhtml/tests/in/mumamo-and-org.org.mm @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<map version="0.9.0"> +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> +<node text="Test of org and mumamo"> +<node style="bubble" background_color="#eeee00"> +<richcontent TYPE="NODE"><html> +<head> +<style type="text/css"> +<!-- +p { margin-top: 0 } +--> +</style> +</head> +<body> +<p><br /> Below is a html chunk</p><p><br /></p> + +<p> + I have not idea of how to use this yet. +</p> +<p><br /></p> +</body> +</html> +</richcontent> +<richcontent TYPE="NOTE"><html><head></head><body><p>-- This is more about "Test of org and mumamo" --</p></body></html></richcontent> +</node> +<node text="Some subnode"> +<node style="bubble" background_color="#eeee00"> +<richcontent TYPE="NODE"><html> +<head> +<style type="text/css"> +<!-- +p { margin-top: 0 } +--> +</style> +</head> +<body> +<p><br />Hm, header lines are broken, why?</p> +</body> +</html> +</richcontent> +<richcontent TYPE="NOTE"><html><head></head><body><p>-- This is more about "Some subnode" --</p></body></html></richcontent> +</node> +</node> +</node> +</map> diff --git a/emacs/nxhtml/tests/in/ng-080309-read-url.html b/emacs/nxhtml/tests/in/ng-080309-read-url.html new file mode 100644 index 0000000..9b20d66 --- /dev/null +++ b/emacs/nxhtml/tests/in/ng-080309-read-url.html @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> + <a href="rgr-080307.php" ></a> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/no-php-end-2.php b/emacs/nxhtml/tests/in/no-php-end-2.php new file mode 100644 index 0000000..ac7debb --- /dev/null +++ b/emacs/nxhtml/tests/in/no-php-end-2.php @@ -0,0 +1,18 @@ +<?php + +include_once(APP_AAA_INCLUDE."bb.php"); +include_once(APP_AAA_INCLUDE."cc.php"); +include_once(APP_AAA_INCLUDE."dd.php"); +include_once(APP_AAA_INCLUDE."ee.php"); +include_once(APP_AAA_INCLUDE."ff.php"); +include_once(APP_AAA_INCLUDE."gg.php"); + +class Test +{ + public $var1; + + function __construct() + { + $This->var1 = 5; + } +} \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/no-php-end-2.php-log.txt b/emacs/nxhtml/tests/in/no-php-end-2.php-log.txt new file mode 100644 index 0000000..e0d5e9f --- /dev/null +++ b/emacs/nxhtml/tests/in/no-php-end-2.php-log.txt @@ -0,0 +1,312 @@ +Illegal char in prolog +undo! +mumamo-jit-lock-after-change 1 2 0 + mumamo-jit-lock-after-change: font-lock-extend-after-change-region-function=nil +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (progn (let ((jit-lock-start (\, min)) (jit-lock-end (\, max))) (mumamo-with-buffer-prepared-for-jit-lock (run-hook-with-args (quote jit-lock-after-change-extend-region-functions) min max old-len)) (setq min jit-lock-start) (setq max jit-lock-end) (syntax-ppss-flush-cache min))))) +>>>>>>>>>> +mumamo-jit-lock-after-change r-min,max=(1 . 7),nil major-min,max=nxhtml-mode,nil +mumamo-jit-lock-after-change new-min,max=1,7 +mumamo-mark-for-refontification A min,max=1,7 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=1,7 point-min,max=1,329 +mumamo-jit-lock-after-change.unfontify-pos=1 +mumamo-jit-lock-function 1, ff=nil, just-changed=nil +++++++ mumamo-fontify-region 1 8 nil, skip=nil +here 1, here=1, end=8 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (progn (let (ppss ret) (setq ppss (parse-partial-sexp (\, syntax-start) (+ (\, syntax-end) 0))) (if (or (nth 3 ppss) (nth 4 ppss)) (progn nil t) t))))) +>>>>>>>>>> + fn=mumamo-chunk-xml-pi, r=(1 6 nil nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 1 to 329 in no-php-end-2.php> cv-min/cv-max 1/6 +mumamo-mark-for-refontification A min,max=7,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=7,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (1 6 nil nil nil nil) +mumamo-remove-chunk-overlays 1 6 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 1 nil, chunk-max: 6 nil +*** mumamo-fontify-region-1.here=1, chunk=#<overlay from 1 to 6 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=1, start=1, chunk-min=1,max=6 end=8 chunk-major=nxhtml-mode +mumamo-fontify-region-with 1 6 nil nxhtml-mode, ff=t +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 1 6 nil 1 6 nxhtml-mode +mumamo-do-fontify 1 6, chunk-syntax-min,max=1,6, new: 1 6 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (parse-partial-sexp (point-min) last-pos))) +>>>>>>>>>> +mumamo-do-fontify exit >>>>>>> 1 6 nil 1 6 nxhtml-mode +here 1, here=6, end=8 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=nil cv-min/cv-max 6/nil +mumamo-mark-for-refontification A min,max=8,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=8,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=6, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=6, start=1, chunk-min=6,max=329 end=8 chunk-major=php-mode +mumamo-fontify-region-with 6 8 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 6 8 nil 6 329 php-mode +mumamo-do-fontify 6 8, chunk-syntax-min,max=6,329, new: 6 8 +mumamo-do-fontify exit >>>>>>> 6 8 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=8,8 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=1,end=329, start=1, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 + +++++++ mumamo-fontify-region 8 329 nil, skip=nil +here 1, here=8, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=8, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=8, start=8, chunk-min=6,max=329 end=329 chunk-major=php-mode +mumamo-fontify-region-with 8 329 nil php-mode, ff=t +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 8 329 nil 6 329 php-mode +mumamo-do-fontify 8 329, chunk-syntax-min,max=6,329, new: 8 329 +mumamo-do-fontify exit >>>>>>> 8 329 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=329,329 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=8, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +mumamo-jit-lock-function 6, ff=nil, just-changed=nil + +++++++ mumamo-fontify-region 1 48 nil, skip=nil +here 1, here=1, end=48 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (progn (let (ppss ret) (setq ppss (parse-partial-sexp (\, syntax-start) (+ (\, syntax-end) 0))) (if (or (nth 3 ppss) (nth 4 ppss)) (progn nil t) t))))) +>>>>>>>>>> + fn=mumamo-chunk-xml-pi, r=(1 6 nil nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 1 to 6 in no-php-end-2.php> cv-min/cv-max 1/6 +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 1 nil, chunk-max: 6 nil +*** mumamo-fontify-region-1.here=1, chunk=#<overlay from 1 to 6 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=1, start=1, chunk-min=1,max=6 end=48 chunk-major=nxhtml-mode +mumamo-fontify-region-with 1 6 nil nxhtml-mode, ff=t +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 1 6 nil 1 6 nxhtml-mode +mumamo-do-fontify 1 6, chunk-syntax-min,max=1,6, new: 1 6 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (parse-partial-sexp (point-min) last-pos))) +>>>>>>>>>> +mumamo-do-fontify exit >>>>>>> 1 6 nil 1 6 nxhtml-mode +here 1, here=6, end=48 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-mark-for-refontification A min,max=48,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=48,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=6, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=6, start=1, chunk-min=6,max=329 end=48 chunk-major=php-mode +mumamo-fontify-region-with 6 48 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 6 48 nil 6 329 php-mode +mumamo-do-fontify 6 48, chunk-syntax-min,max=6,329, new: 6 48 +mumamo-do-fontify exit >>>>>>> 6 48 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=48,48 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=1,end=329, start=1, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 + +++++++ mumamo-fontify-region 48 329 nil, skip=nil +here 1, here=48, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=48, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=48, start=48, chunk-min=6,max=329 end=329 chunk-major=php-mode +mumamo-fontify-region-with 48 329 nil php-mode, ff=t +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 48 329 nil 6 329 php-mode +mumamo-do-fontify 48 329, chunk-syntax-min,max=6,329, new: 48 329 +mumamo-do-fontify exit >>>>>>> 48 329 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=329,329 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=48, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +mumamo-jit-lock-function 7, ff=nil, just-changed=nil + +++++++ mumamo-fontify-region 7 88 nil, skip=nil +here 1, here=7, end=88 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-mark-for-refontification A min,max=88,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=88,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=7, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=7, start=7, chunk-min=6,max=329 end=88 chunk-major=php-mode +mumamo-fontify-region-with 7 88 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 7 88 nil 6 329 php-mode +mumamo-do-fontify 7 88, chunk-syntax-min,max=6,329, new: 7 88 +mumamo-do-fontify exit >>>>>>> 7 88 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=88,88 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=7, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +++++++ mumamo-fontify-region 88 329 nil, skip=nil +here 1, here=88, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=88, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=88, start=88, chunk-min=6,max=329 end=329 chunk-major=php-mode +mumamo-fontify-region-with 88 329 nil php-mode, ff=t +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 88 329 nil 6 329 php-mode +mumamo-do-fontify 88 329, chunk-syntax-min,max=6,329, new: 88 329 +mumamo-do-fontify exit >>>>>>> 88 329 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=329,329 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=88, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +mumamo-jit-lock-function 8, ff=nil, just-changed=nil +++++++ mumamo-fontify-region 8 128 nil, skip=nil +here 1, here=8, end=128 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-mark-for-refontification A min,max=128,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=128,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=8, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=8, start=8, chunk-min=6,max=329 end=128 chunk-major=php-mode +mumamo-fontify-region-with 8 128 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 8 128 nil 6 329 php-mode +mumamo-do-fontify 8 128, chunk-syntax-min,max=6,329, new: 8 128 +mumamo-do-fontify exit >>>>>>> 8 128 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=128,128 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=8, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +++++++ mumamo-fontify-region 128 329 nil, skip=nil +here 1, here=128, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=128, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=128, start=128, chunk-min=6,max=329 end=329 chunk-major=php-mode +mumamo-fontify-region-with 128 329 nil php-mode, ff=t +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 128 329 nil 6 329 php-mode +mumamo-do-fontify 128 329, chunk-syntax-min,max=6,329, new: 128 329 +mumamo-do-fontify exit >>>>>>> 128 329 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=329,329 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=128, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +mumamo-jit-lock-function 20, ff=nil, just-changed=nil +++++++ mumamo-fontify-region 8 168 nil, skip=nil +here 1, here=8, end=168 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-mark-for-refontification A min,max=168,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=168,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=8, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=8, start=8, chunk-min=6,max=329 end=168 chunk-major=php-mode +mumamo-fontify-region-with 8 168 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 8 168 nil 6 329 php-mode +mumamo-do-fontify 8 168, chunk-syntax-min,max=6,329, new: 8 168 +mumamo-do-fontify exit >>>>>>> 8 168 nil 6 329 php-mode +mumamo-mark-for-refontification A min,max=168,168 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=8, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +++++++ mumamo-fontify-region 168 329 nil, skip=nil +here 1, here=168, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil diff --git a/emacs/nxhtml/tests/in/no-php-end-2.php-log2.txt b/emacs/nxhtml/tests/in/no-php-end-2.php-log2.txt new file mode 100644 index 0000000..1df7c4d --- /dev/null +++ b/emacs/nxhtml/tests/in/no-php-end-2.php-log2.txt @@ -0,0 +1,238 @@ +Illegal char in prolog +undo! +mumamo-jit-lock-after-change 1 2 0 + mumamo-jit-lock-after-change: font-lock-extend-after-change-region-function=nil +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (progn (let ((jit-lock-start (\, min)) (jit-lock-end (\, max))) (mumamo-with-buffer-prepared-for-jit-lock (run-hook-with-args (quote jit-lock-after-change-extend-region-functions) min max old-len)) (setq min jit-lock-start) (setq max jit-lock-end) (syntax-ppss-flush-cache min))))) +>>>>>>>>>> +mumamo-jit-lock-after-change r-min,max=(1 . 7),nil major-min,max=nxhtml-mode,nil +mumamo-jit-lock-after-change new-min,max=1,7 +mumamo-mark-for-refontification A min,max=1,7 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=1,7 point-min,max=1,329 +mumamo-jit-lock-after-change.unfontify-pos=1 +mumamo-jit-lock-function 1, ff=nil, just-changed=nil +++++++ mumamo-fontify-region 1 8 nil, skip=nil +here 1, here=1, end=8 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (progn (let (ppss ret) (setq ppss (parse-partial-sexp (\, syntax-start) (+ (\, syntax-end) 0))) (if (or (nth 3 ppss) (nth 4 ppss)) (progn nil t) t))))) +>>>>>>>>>> + fn=mumamo-chunk-xml-pi, r=(1 6 nil nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 1 to 329 in no-php-end-2.php> cv-min/cv-max 1/6 +new-is-closed=6 +mumamo-mark-for-refontification A min,max=7,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=7,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (1 6 nil nil nil nil) +mumamo-remove-chunk-overlays 1 6 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 1 nil, chunk-max: 6 nil +*** mumamo-fontify-region-1.here=1, chunk=#<overlay from 1 to 6 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=1, start=1, chunk-min=1,max=6 end=8 chunk-major=nxhtml-mode +mumamo-fontify-region-with 1 6 nil nxhtml-mode, ff=t +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 1 6 nil 1 6 nxhtml-mode +mumamo-do-fontify 1 6, chunk-syntax-min,max=1,6, new: 1 6 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (parse-partial-sexp (point-min) last-pos))) +>>>>>>>>>> +mumamo-do-fontify exit >>>>>>> 1 6 nil 1 6 nxhtml-mode +here 1, here=6, end=8 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=nil cv-min/cv-max 6/nil +(when (and end new-real-end (> new-real-end end)) +mumamo-mark-for-refontification A min,max=8,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=8,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=6, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=6, start=1, chunk-min=6,max=329 end=8 chunk-major=php-mode +mumamo-fontify-region-with 6 8 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 6 8 nil 6 329 php-mode +mumamo-do-fontify 6 8, chunk-syntax-min,max=6,329, new: 6 8 +mumamo-do-fontify exit >>>>>>> 6 8 nil 6 329 php-mode + +not sure +mumamo-mark-for-refontification A min,max=8,8 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=1,end=329, start=1, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +++++++ mumamo-fontify-region 8 329 nil, skip=nil +here 1, here=8, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=8, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=8, start=8, chunk-min=6,max=329 end=329 chunk-major=php-mode +mumamo-fontify-region-with 8 329 nil php-mode, ff=t +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 8 329 nil 6 329 php-mode +mumamo-do-fontify 8 329, chunk-syntax-min,max=6,329, new: 8 329 +mumamo-do-fontify exit >>>>>>> 8 329 nil 6 329 php-mode + + +not sure +mumamo-mark-for-refontification A min,max=329,329 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=8, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +mumamo-jit-lock-function 6, ff=nil, just-changed=nil +++++++ mumamo-fontify-region 1 48 nil, skip=nil +here 1, here=1, end=48 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (progn (let (ppss ret) (setq ppss (parse-partial-sexp (\, syntax-start) (+ (\, syntax-end) 0))) (if (or (nth 3 ppss) (nth 4 ppss)) (progn nil t) t))))) +>>>>>>>>>> + fn=mumamo-chunk-xml-pi, r=(1 6 nil nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 1 to 6 in no-php-end-2.php> cv-min/cv-max 1/6 +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 1 nil, chunk-max: 6 nil +*** mumamo-fontify-region-1.here=1, chunk=#<overlay from 1 to 6 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=1, start=1, chunk-min=1,max=6 end=48 chunk-major=nxhtml-mode +mumamo-fontify-region-with 1 6 nil nxhtml-mode, ff=t +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 1 6 nil 1 6 nxhtml-mode +mumamo-do-fontify 1 6, chunk-syntax-min,max=1,6, new: 1 6 +mumamo-with-major-mode-setup nxhtml-mode => html-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (parse-partial-sexp (point-min) last-pos))) +>>>>>>>>>> +mumamo-do-fontify exit >>>>>>> 1 6 nil 1 6 nxhtml-mode +here 1, here=6, end=48 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +(when (and end new-real-end (> new-real-end end)) +mumamo-mark-for-refontification A min,max=48,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=48,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=6, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=6, start=1, chunk-min=6,max=329 end=48 chunk-major=php-mode +mumamo-fontify-region-with 6 48 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 6 48 nil 6 329 php-mode +mumamo-do-fontify 6 48, chunk-syntax-min,max=6,329, new: 6 48 +mumamo-do-fontify exit >>>>>>> 6 48 nil 6 329 php-mode + + +not sure +mumamo-mark-for-refontification A min,max=48,48 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=1,end=329, start=1, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +++++++ mumamo-fontify-region 48 329 nil, skip=nil +here 1, here=48, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=48, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=48, start=48, chunk-min=6,max=329 end=329 chunk-major=php-mode +mumamo-fontify-region-with 48 329 nil php-mode, ff=t +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 48 329 nil 6 329 php-mode +mumamo-do-fontify 48 329, chunk-syntax-min,max=6,329, new: 48 329 +mumamo-do-fontify exit >>>>>>> 48 329 nil 6 329 php-mode + + +not sure +mumamo-mark-for-refontification A min,max=329,329 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=48, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +mumamo-jit-lock-function 7, ff=nil, just-changed=nil +++++++ mumamo-fontify-region 7 88 nil, skip=nil +here 1, here=7, end=88 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +(when (and end new-real-end (> new-real-end end)) +mumamo-mark-for-refontification A min,max=88,329 point-min,max=1,329 +mumamo-mark-for-refontification B min,max=88,329 point-min,max=1,329 +mumamo-create-chunk-from-chunk-values (6 nil php-mode nil nil nil) +mumamo-remove-chunk-overlays 6 329 +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (quote (if syntax-begin-function (progn syntax-begin-function) (when (and (not syntax-begin-function) (boundp (quote font-lock-beginning-of-syntax-function)) font-lock-beginning-of-syntax-function) font-lock-beginning-of-syntax-function)))) +>>>>>>>>>> + mumamo-major-mode-from-modespec php-mode => php-mode +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=7, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=7, start=7, chunk-min=6,max=329 end=88 chunk-major=php-mode +mumamo-fontify-region-with 7 88 nil php-mode, ff=nil +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 7 88 nil 6 329 php-mode +mumamo-do-fontify 7 88, chunk-syntax-min,max=6,329, new: 7 88 +mumamo-do-fontify exit >>>>>>> 7 88 nil 6 329 php-mode + + +not sure +mumamo-mark-for-refontification A min,max=88,88 point-min,max=1,329 +*** mumamo-fontify-region-1: here 3 ovl-start=6,end=329, start=7, chunks-to-remove=nil +*** mumamo-fontify-region-1: here 4 +++++++ mumamo-fontify-region 88 329 nil, skip=nil +here 1, here=88, end=329 + fn=mumamo-chunk-xml-pi, r=(6 nil php-mode nil nil) + fn=mumamo-chunk-inlined-style, r=(1 nil nil nil nil) + fn=mumamo-chunk-inlined-script, r=(1 nil nil nil nil) + fn=mumamo-chunk-style=, r=(nil nil nil) + fn=mumamo-chunk-onjs=, r=(nil nil nil) +old-chunk=#<overlay from 6 to 329 in no-php-end-2.php> cv-min/cv-max 6/nil +mumamo-fontify-region-1 FACE FACE FACE chunk-min: 6 font-lock-keyword-face, chunk-max: 329 nil +*** mumamo-fontify-region-1.here=88, chunk=#<overlay from 6 to 329 in no-php-end-2.php> +*** mumamo-fontify-region-1: here 2 here=88, start=88, chunk-min=6,max=329 end=329 chunk-major=php-mode +mumamo-fontify-region-with 88 329 nil php-mode, ff=t +mumamo-with-major-mode-setup php-mode => php-mode +mumamo-with-major-mode-setup <<<<<<<<<< body=(progn (\` (mumamo-do-fontify (\, start) (\, end) (\, verbose) (\, chunk-syntax-min) (\, chunk-syntax-max) major))) +>>>>>>>>>> +mumamo-do-fontify <<<<<<< 88 329 nil 6 329 php-mode +mumamo-do-fontify 88 329, chunk-syntax-min,max=6,329, new: 88 329 +mumamo-do-fontify exit >>>>>>> 88 329 nil 6 329 php-mode + + +not sure +mumamo-mark-for-refontification A min,max=329,329 point-min,max=1,329 +*** muma diff --git a/emacs/nxhtml/tests/in/no-php-end-3.php b/emacs/nxhtml/tests/in/no-php-end-3.php new file mode 100644 index 0000000..2e91d1a --- /dev/null +++ b/emacs/nxhtml/tests/in/no-php-end-3.php @@ -0,0 +1,18 @@ +<?php + +include_once(APP_AAA_INCLUDE."bb.php"); +include_once(APP_AAA_INCLUDE."cc.php"); +include_once(APP_AAA_INCLUDE."dd.php"); +include_once(APP_AAA_INCLUDE."ee.php"); +include_once(APP_AAA_INCLUDE."ff.php"); +include_once(APP_AAA_INCLUDE."gg.php"); + +class Test +{ + public $var1; + + function __construct() + { + $This->var1 = 5; + } +} diff --git a/emacs/nxhtml/tests/in/no-php-end-4.php b/emacs/nxhtml/tests/in/no-php-end-4.php new file mode 100644 index 0000000..2e91d1a --- /dev/null +++ b/emacs/nxhtml/tests/in/no-php-end-4.php @@ -0,0 +1,18 @@ +<?php + +include_once(APP_AAA_INCLUDE."bb.php"); +include_once(APP_AAA_INCLUDE."cc.php"); +include_once(APP_AAA_INCLUDE."dd.php"); +include_once(APP_AAA_INCLUDE."ee.php"); +include_once(APP_AAA_INCLUDE."ff.php"); +include_once(APP_AAA_INCLUDE."gg.php"); + +class Test +{ + public $var1; + + function __construct() + { + $This->var1 = 5; + } +} diff --git a/emacs/nxhtml/tests/in/no-php-end.php b/emacs/nxhtml/tests/in/no-php-end.php new file mode 100644 index 0000000..ecd9d9f --- /dev/null +++ b/emacs/nxhtml/tests/in/no-php-end.php @@ -0,0 +1,4 @@ +<?php + +$parent_id = 5; +var_dump($parent_id); diff --git a/emacs/nxhtml/tests/in/nojump-parse.html b/emacs/nxhtml/tests/in/nojump-parse.html new file mode 100644 index 0000000..d66369f --- /dev/null +++ b/emacs/nxhtml/tests/in/nojump-parse.html @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + <script type="text/javascript"> +<testnxmlparsed> + </script> diff --git a/emacs/nxhtml/tests/in/noweb1.now b/emacs/nxhtml/tests/in/noweb1.now new file mode 100644 index 0000000..1df9074 --- /dev/null +++ b/emacs/nxhtml/tests/in/noweb1.now @@ -0,0 +1,38 @@ +@ +\section{Hello world} + +Today I awakened and decided to write +some code, so I started to write a Hello World in \textsf C. + +<<hello.c>>= +/* + <<license>> +*/ +#include <stdio.h> + +int main(int argc, char *argv[]) { + printf("Hello World!\n"); + return 0; +} +@ +\noindent \ldots then I did the same in PHP. + +<<hello.sql>>= +SELECT * FROM Persons +WHERE FirstName LIKE '%a' +@ +<<hello.php>>= +<?php + /* + <<license>> + */ + echo "Hello world!\n"; +?> +@ +\section{License} +Later, same day some lawyer reminded me about licenses. +So, here it is: + +<<license>>= +This work is placed in the public domain. +@ diff --git a/emacs/nxhtml/tests/in/nutshell.mako b/emacs/nxhtml/tests/in/nutshell.mako new file mode 100644 index 0000000..3c7540e --- /dev/null +++ b/emacs/nxhtml/tests/in/nutshell.mako @@ -0,0 +1,27 @@ + % for row in rows: +<%inherit file="base.html"/> + +<% + rows = [[v for v in range(0,10)] for row in range(0,10)] +%> +<%! + rows = [[v for v in range(0,10)] for row in range(0,10)] +%> +aaa +<table> + ## This is a comment. + % for row in rows: + ${makerow(row)} + % endfor +</table> + +<%def name="makerow(row)"> + <tr> + % for name in row: + <td>${name}</td>\ + % endfor + </tr> +</%def> +<%doc> +This should be a comment too... +</%doc> diff --git a/emacs/nxhtml/tests/in/nxml-bug.html b/emacs/nxhtml/tests/in/nxml-bug.html new file mode 100644 index 0000000..3d2fe7b --- /dev/null +++ b/emacs/nxhtml/tests/in/nxml-bug.html @@ -0,0 +1,11 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><title></title></head> + <body> + <form action="" method="get"> + <label for="inputname">Label for field: </label> + <input type="text" name="inputname" id="inputname" /> + </form> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/nxml-indent-2.html b/emacs/nxhtml/tests/in/nxml-indent-2.html new file mode 100644 index 0000000..e30dba0 --- /dev/null +++ b/emacs/nxhtml/tests/in/nxml-indent-2.html @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>Kimpro Malmö & Sydsverige - AKTUELLT I MALMÖ</title> + <link href="textmall.css" rel="stylesheet" type="text/css" /> + <link href="layout.css" rel="stylesheet" type="text/css" /> + </head> + <body> + <div class="kolumn1"> + <span class="rubrik">Aktuellt våren 2008</span><br /> + <i>Välkommen till dansens magiska universum!</i><br /> + Här i kalendariet kan du se vad som händer i kimprosammanhang + just nu. De arrangemang med rosa botten är utöver våra + vanliga söndags-träffar i Malmö. Vill du veta mer om de olika + verksamheterna, ta en titt under <u><a href= + "index_verksamhet.html" target="index3s">Verksamhet</a>. + <b>OBS!</b> Notera att vi bytt danstid till kl 19-21! Detta + gäller endast en period nu i vår.<br /> + <br /></u><b>Mars</b> + <table width="370" cellspacing="5"> + <!-- + <tr> + <td class="kalendariecell_special"> + <img src="grafik/aktuelltbild_januari.jpg" border=0><br> + <i>Några av oss som dansar i Malmö</i><br> + +<span class="mellanrubrik"> +<br> +<b>OBS: Ny tid!</b><br></span> +Vi har ny tid för dansen på söndagar! 19-21 är nya tiden som gäller en tid framöver. <br> +<br> + +<br> +Sofia och Rebecka har arbetat tillsammans sedan år 2000. De träffades +på Nordens dåvarande enda cirkusgymnasium i Gävle och utbildade sig +sedan i Köpenhamn på AFUK, Akademiet för Utaemet Kreativitet - +Artistlinien, med parakrobatik som huvuddiciplin. Sedan följde en +treårig +utbildning" Centre des Arts du Cirque de Lomme-Et vous trouvez ca +drole!!!" i Lille, Frankrike. 2003 startade de nycirkusföretaget +"Stint" +tillsammans och de jobbar nu som frilansande cirkusartister främst i +Frankrike.<br> +<br> +Med Rebecka som överman och Sofia som underman kör de både liggande och +stående parakrobatik, spänningsövningar, huvud- och handhandbalanser. +Tillsammans har de jobbat ihop flera olika akter á 5 minuter. Däribland +hittar man kvinnlig styrka och pur pondus, komisk vardagstristess, +hisnande teknik och tyngdpunkt i relationerna mellan människor och +samhällets uppochned vända verklighet, ur ett verkligt uppochnedvänt +perspektiv. Sedan år 2006 har fokuset flyttats mer och mer åt +improvisationshållet, parakrobatikimprovisation i samarbete med fri +improviserad musik och kontaktimprovisation.<br> +<a href="http://www.stint.nu" target=blank><u>www.stint.nu</u></a><br> +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 24 Februari<br> +<span class="mellanrubrik"> +Musikjam!</span><br> +kl 19-21, 30 kr<br> +<br> +Denna söndag kommer inga inhyrda musiker till jammet, +utan då det är vi själva som står för musiken!<br> +<br> +Så alla som kan och vill -ta med er instrument eller +andra ljudframbringande prylar. Att använda sin röst går förståss +också bra.<br> +<br> +Vill man inte musisera så dansar man som vanligt. +(..och därför kostar det bara 30 kr, då vi inte har några musiker som +ska betalas)<br> +<br> +VÄLKOMNA! +</td> +</tr> + --> + <tr> + <td class="kalendariecell"> + Söndag 2 Mars<br /> + <span class="mellanrubrik">Nybörjarintroduktion & + Jam med Karin R och Jenny</span><br /> + Kl. 19-21, 30 kr. + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 9 Mars<br /> + <span class="mellanrubrik">Blind fold jam - jam med + ögonbindel!</span><br /> + ... med Sofi och Tove. Kl 19-21, 30 kr<br /> + På ett blind fold jam dansar man med ögonen förbundna, + för att öka känsligheten, lyssnandet och samspelet. Det + är också ett sätt att försöka komma förbi + föreställningar man (medvetet eller omedvetet) har runt + vem man väljer att dansa med. Det blir i slutändan en + spegling till en själv om de val man gör på dansgolvet, + där kroppen denna gång får bestämma i stället för + huvudet. Vi inleder som vanligt med en introduktion. + Tag gärna med egen ögonbindel!<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 16 Mars<br /> + <span class="mellanrubrik">Introduktion och + jam</span><br /> + 19-21, 30 kr<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 23 Mars<br /> + <span class="mellanrubrik">Ingenting här för då är vi + på NIM i Köpenhamn! + <!-- Introduktion och jam</span><br> --> + <!-- 19-21, 30 kr<br> --></span> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen den 30:e<br /> + <span class="mellanrubrik">Kort introduktion och + Livejam!!</span><br /> + 19-21, 50 kr<br /> + </td> + </tr> + </table> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/nxml-indent-3.html b/emacs/nxhtml/tests/in/nxml-indent-3.html new file mode 100644 index 0000000..e7c686f --- /dev/null +++ b/emacs/nxhtml/tests/in/nxml-indent-3.html @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title> + Kimpro Malmö & Sydsverige - AKTUELLT I MALMÖ + </title> + <link href="textmall.css" rel="stylesheet" type="text/css" /> + <link href="layout.css" rel="stylesheet" type="text/css" /> + </head> + <body> + <div class="kolumn1"> + <span class="rubrik">Aktuellt våren 2008</span><br /> + <i>Välkommen till dansens magiska universum!</i><br /> + Här i kalendariet kan du se vad som händer i kimprosammanhang + just nu. De arrangemang med rosa botten är utöver våra + vanliga söndags-träffar i Malmö. Vill du veta mer om de olika + verksamheterna, ta en titt under <u><a href= + "index_verksamhet.html" target="index3s">Verksamhet</a>. + <b>OBS!</b> Notera att vi bytt danstid till kl 19-21! Detta + gäller endast en period nu i vår.<br /> + <br /></u><b>Mars</b> + <table width="370" cellspacing="5"> + <!-- + <tr> + <td class="kalendariecell_special"> + <img src="grafik/aktuelltbild_januari.jpg" border=0><br> + <i>Några av oss som dansar i Malmö</i><br> + +<span class="mellanrubrik"> +<br> +<b>OBS: Ny tid!</b><br></span> +Vi har ny tid för dansen på söndagar! 19-21 är nya tiden som gäller en tid framöver. <br> +<br> + +<br> +Sofia och Rebecka har arbetat tillsammans sedan år 2000. De träffades +på Nordens dåvarande enda cirkusgymnasium i Gävle och utbildade sig +sedan i Köpenhamn på AFUK, Akademiet för Utaemet Kreativitet - +Artistlinien, med parakrobatik som huvuddiciplin. Sedan följde en +treårig +"Stint" +tillsammans och de jobbar nu som frilansande cirkusartister främst i +Frankrike.<br> +<br> +Med Rebecka som överman och Sofia som underman kör de både liggande och +stående parakrobatik, spänningsövningar, huvud- och handhandbalanser. +Tillsammans har de jobbat ihop flera olika akter á 5 minuter. Däribland +hittar man kvinnlig styrka och pur pondus, komisk vardagstristess, +hisnande teknik och tyngdpunkt i relationerna mellan människor och +samhällets uppochned vända verklighet, ur ett verkligt uppochnedvänt +perspektiv. Sedan år 2006 har fokuset flyttats mer och mer åt +improvisationshållet, parakrobatikimprovisation i samarbete med fri +improviserad musik och kontaktimprovisation.<br> +<a href="http://www.stint.nu" target=blank><u>www.stint.nu</u></a><br> +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 24 Februari<br> +<span class="mellanrubrik"> +Musikjam!</span><br> +kl 19-21, 30 kr<br> +<br> +Denna söndag kommer inga inhyrda musiker till jammet, +utan då det är vi själva som står för musiken!<br> +<br> +Så alla som kan och vill -ta med er instrument eller +andra ljudframbringande prylar. Att använda sin röst går förståss +också bra.<br> +<br> +Vill man inte musisera så dansar man som vanligt. +(..och därför kostar det bara 30 kr, då vi inte har några musiker som +ska betalas)<br> +<br> +VÄLKOMNA! +</td> +</tr> + --> + <tr> + <td class="kalendariecell"> + Söndag 2 Mars<br /> + <span class="mellanrubrik">Nybörjarintroduktion & + Jam med Karin R och Jenny</span><br /> + Kl. 19-21, 30 kr. + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 9 Mars<br /> + <span class="mellanrubrik">Blind fold jam - jam med + ögonbindel!</span><br /> + ... med Sofi och Tove. Kl 19-21, 30 kr<br /> + På ett blind fold jam dansar man med ögonen förbundna, + för att öka känsligheten, lyssnandet och samspelet. Det + är också ett sätt att försöka komma förbi + föreställningar man (medvetet eller omedvetet) har runt + vem man väljer att dansa med. Det blir i slutändan en + spegling till en själv om de val man gör på dansgolvet, + där kroppen denna gång får bestämma i stället för + huvudet. Vi inleder som vanligt med en introduktion. + Tag gärna med egen ögonbindel!<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 16 Mars<br /> + <span class="mellanrubrik">Introduktion och + jam</span><br /> + 19-21, 30 kr<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 23 Mars<br /> + <span class="mellanrubrik">Ingenting här för då är vi + på NIM i Köpenhamn! + <!-- Introduktion och jam</span><br> --> + <!-- 19-21, 30 kr<br> --></span> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen den 30:e<br /> + <span class="mellanrubrik">Kort introduktion och + Livejam!!</span><br /> + 19-21, 50 kr<br /> + </td> + </tr> + </table> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/nxml-indent-noerr1.html b/emacs/nxhtml/tests/in/nxml-indent-noerr1.html new file mode 100644 index 0000000..db82964 --- /dev/null +++ b/emacs/nxhtml/tests/in/nxml-indent-noerr1.html @@ -0,0 +1,192 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title> + Kimpro Malmö & Sydsverige - AKTUELLT I MALMÖ + </title> + <link href="textmall.css" rel="stylesheet" type="text/css" /> + <link href="layout.css" rel="stylesheet" type="text/css" /> + </head> + <body> + <div class="kolumn1"> + <span class="rubrik">Aktuellt våren 2008</span><br /> + <i>Välkommen till dansens magiska universum!</i><br /> + Här i kalendariet kan du se vad som händer i kimprosammanhang + just nu. De arrangemang med rosa botten är utöver våra + vanliga söndags-träffar i Malmö. Vill du veta mer om de olika + verksamheterna, ta en titt under <u><a href= + "index_verksamhet.html" target="index3s">Verksamhet</a>. + <b>OBS!</b> Notera att vi bytt danstid till kl 19-21! Detta + gäller endast en period nu i vår.<br /> + <br /></u><b>Mars</b> + <table width="370" cellspacing="5"> + <!-- + <tr> + <td class="kalendariecell_special"> + <img src="grafik/aktuelltbild_januari.jpg" border=0><br> + <i>Några av oss som dansar i Malmö</i><br> + +<span class="mellanrubrik"> +<br> +<b>OBS: Ny tid!</b><br></span> +Vi har ny tid för dansen på söndagar! 19-21 är nya tiden som gäller en tid framöver. <br> +<br> + +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 6 Januari<br> +<span class="mellanrubrik"> +Grundklass & Jam</span><br> +Årets första nybörjarintro! Kl. 17-19, 30 kr. +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 13 Januari<br> +<span class="mellanrubrik"> +Introduktion & Jam</span><br> +Kl. 17-19, 30 kr. +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 20 Januari<br> +<span class="mellanrubrik"> +Introduktion & Jam</span><br> +Kl. 17-19, 30 kr. +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 27 Januari<br> +<span class="mellanrubrik"> +Introduktion & Jam</span><br> +Kl. 17-19, 30 kr. +</td> +</tr> + +<tr> +<td class="kalendariecell_special"> +<b>23-24 februari</b><br> +<span class="mellanrubrik">WORKSHOP I AKROBATIK +FÖR KONTAKTIMPROVISATÖRER</span><br> +<br> +Två parakrobater, Sofia och Rebecka, bosatta i Frankrike kommer till +Malmö +för att hålla en workshop speciellt för Kimpro Malmö! +Workshopen kommer handla om hur man kan använda akrobatik i +kontaktimprovisation. Inga förkunskaper i akrobatik behövs.<br> +<br> +23-24/2, kl.13-16 båda dagarna.<br> +Kostnad: 350 kr.<br> +Betalas senast den 21/2 till plusgirokonto: 1136904-8, Nordea, +skriv: akro + namn.<br> +Plats: meddelas senare.<br> +Anmälan senast 19/2 till Clara, claravara00@yahoo.se<br> +<br> +Begränsat antal platser. Först till kvarn!<br> +<br> +<br> +Sofia och Rebecka har arbetat tillsammans sedan år 2000. De träffades +på Nordens dåvarande enda cirkusgymnasium i Gävle och utbildade sig +sedan i Köpenhamn på AFUK, Akademiet för Utaemet Kreativitet - +Artistlinien, med parakrobatik som huvuddiciplin. Sedan följde en +treårig +utbildning" Centre des Arts du Cirque de Lomme-Et vous trouvez ca +drole!!!" i Lille, Frankrike. 2003 startade de nycirkusföretaget +"Stint" +tillsammans och de jobbar nu som frilansande cirkusartister främst i +Frankrike.<br> +<br> +Med Rebecka som överman och Sofia som underman kör de både liggande och +stående parakrobatik, spänningsövningar, huvud- och handhandbalanser. +Tillsammans har de jobbat ihop flera olika akter á 5 minuter. Däribland +hittar man kvinnlig styrka och pur pondus, komisk vardagstristess, +hisnande teknik och tyngdpunkt i relationerna mellan människor och +samhällets uppochned vända verklighet, ur ett verkligt uppochnedvänt +perspektiv. Sedan år 2006 har fokuset flyttats mer och mer åt +improvisationshållet, parakrobatikimprovisation i samarbete med fri +improviserad musik och kontaktimprovisation.<br> +<a href="http://www.stint.nu" target=blank><u>www.stint.nu</u></a><br> +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 24 Februari<br> +<span class="mellanrubrik"> +Musikjam!</span><br> +kl 19-21, 30 kr<br> +<br> +Denna söndag kommer inga inhyrda musiker till jammet, +utan då det är vi själva som står för musiken!<br> +<br> +Så alla som kan och vill -ta med er instrument eller +andra ljudframbringande prylar. Att använda sin röst går förståss +också bra.<br> +<br> +Vill man inte musisera så dansar man som vanligt. +(..och därför kostar det bara 30 kr, då vi inte har några musiker som +ska betalas)<br> +<br> +VÄLKOMNA! +</td> +</tr> + --> + <tr> + <td class="kalendariecell"> + Söndag 2 Mars<br /> + <span class="mellanrubrik">Nybörjarintroduktion & + Jam med Karin R och Jenny</span><br /> + Kl. 19-21, 30 kr. + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 9 Mars<br /> + <span class="mellanrubrik">Blind fold jam - jam med + ögonbindel!</span><br /> + ... med Sofi och Tove. Kl 19-21, 30 kr<br /> + På ett blind fold jam dansar man med ögonen förbundna, + för att öka känsligheten, lyssnandet och samspelet. Det + är också ett sätt att försöka komma förbi + föreställningar man (medvetet eller omedvetet) har runt + vem man väljer att dansa med. Det blir i slutändan en + spegling till en själv om de val man gör på dansgolvet, + där kroppen denna gång får bestämma i stället för + huvudet. Vi inleder som vanligt med en introduktion. + Tag gärna med egen ögonbindel!<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 16 Mars<br /> + <span class="mellanrubrik">Introduktion och + jam</span><br /> + 19-21, 30 kr<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 23 Mars<br /> + <span class="mellanrubrik">Ingenting här för då är vi + på NIM i Köpenhamn! + <!-- Introduktion och jam</span><br> --> + <!-- 19-21, 30 kr<br> --></span> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen den 30:e<br /> + <span class="mellanrubrik">Kort introduktion och + Livejam!!</span><br /> + 19-21, 50 kr<br /> + </td> + </tr> + </table> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/nxml-indent.el b/emacs/nxhtml/tests/in/nxml-indent.el new file mode 100644 index 0000000..fc17d1b --- /dev/null +++ b/emacs/nxhtml/tests/in/nxml-indent.el @@ -0,0 +1 @@ +(nxml-scan-element-backward 6407 nil 2407) diff --git a/emacs/nxhtml/tests/in/nxml-indent.html b/emacs/nxhtml/tests/in/nxml-indent.html new file mode 100644 index 0000000..db82964 --- /dev/null +++ b/emacs/nxhtml/tests/in/nxml-indent.html @@ -0,0 +1,192 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title> + Kimpro Malmö & Sydsverige - AKTUELLT I MALMÖ + </title> + <link href="textmall.css" rel="stylesheet" type="text/css" /> + <link href="layout.css" rel="stylesheet" type="text/css" /> + </head> + <body> + <div class="kolumn1"> + <span class="rubrik">Aktuellt våren 2008</span><br /> + <i>Välkommen till dansens magiska universum!</i><br /> + Här i kalendariet kan du se vad som händer i kimprosammanhang + just nu. De arrangemang med rosa botten är utöver våra + vanliga söndags-träffar i Malmö. Vill du veta mer om de olika + verksamheterna, ta en titt under <u><a href= + "index_verksamhet.html" target="index3s">Verksamhet</a>. + <b>OBS!</b> Notera att vi bytt danstid till kl 19-21! Detta + gäller endast en period nu i vår.<br /> + <br /></u><b>Mars</b> + <table width="370" cellspacing="5"> + <!-- + <tr> + <td class="kalendariecell_special"> + <img src="grafik/aktuelltbild_januari.jpg" border=0><br> + <i>Några av oss som dansar i Malmö</i><br> + +<span class="mellanrubrik"> +<br> +<b>OBS: Ny tid!</b><br></span> +Vi har ny tid för dansen på söndagar! 19-21 är nya tiden som gäller en tid framöver. <br> +<br> + +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 6 Januari<br> +<span class="mellanrubrik"> +Grundklass & Jam</span><br> +Årets första nybörjarintro! Kl. 17-19, 30 kr. +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 13 Januari<br> +<span class="mellanrubrik"> +Introduktion & Jam</span><br> +Kl. 17-19, 30 kr. +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 20 Januari<br> +<span class="mellanrubrik"> +Introduktion & Jam</span><br> +Kl. 17-19, 30 kr. +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 27 Januari<br> +<span class="mellanrubrik"> +Introduktion & Jam</span><br> +Kl. 17-19, 30 kr. +</td> +</tr> + +<tr> +<td class="kalendariecell_special"> +<b>23-24 februari</b><br> +<span class="mellanrubrik">WORKSHOP I AKROBATIK +FÖR KONTAKTIMPROVISATÖRER</span><br> +<br> +Två parakrobater, Sofia och Rebecka, bosatta i Frankrike kommer till +Malmö +för att hålla en workshop speciellt för Kimpro Malmö! +Workshopen kommer handla om hur man kan använda akrobatik i +kontaktimprovisation. Inga förkunskaper i akrobatik behövs.<br> +<br> +23-24/2, kl.13-16 båda dagarna.<br> +Kostnad: 350 kr.<br> +Betalas senast den 21/2 till plusgirokonto: 1136904-8, Nordea, +skriv: akro + namn.<br> +Plats: meddelas senare.<br> +Anmälan senast 19/2 till Clara, claravara00@yahoo.se<br> +<br> +Begränsat antal platser. Först till kvarn!<br> +<br> +<br> +Sofia och Rebecka har arbetat tillsammans sedan år 2000. De träffades +på Nordens dåvarande enda cirkusgymnasium i Gävle och utbildade sig +sedan i Köpenhamn på AFUK, Akademiet för Utaemet Kreativitet - +Artistlinien, med parakrobatik som huvuddiciplin. Sedan följde en +treårig +utbildning" Centre des Arts du Cirque de Lomme-Et vous trouvez ca +drole!!!" i Lille, Frankrike. 2003 startade de nycirkusföretaget +"Stint" +tillsammans och de jobbar nu som frilansande cirkusartister främst i +Frankrike.<br> +<br> +Med Rebecka som överman och Sofia som underman kör de både liggande och +stående parakrobatik, spänningsövningar, huvud- och handhandbalanser. +Tillsammans har de jobbat ihop flera olika akter á 5 minuter. Däribland +hittar man kvinnlig styrka och pur pondus, komisk vardagstristess, +hisnande teknik och tyngdpunkt i relationerna mellan människor och +samhällets uppochned vända verklighet, ur ett verkligt uppochnedvänt +perspektiv. Sedan år 2006 har fokuset flyttats mer och mer åt +improvisationshållet, parakrobatikimprovisation i samarbete med fri +improviserad musik och kontaktimprovisation.<br> +<a href="http://www.stint.nu" target=blank><u>www.stint.nu</u></a><br> +</td> +</tr> +<tr> +<td class="kalendariecell"> +Söndag 24 Februari<br> +<span class="mellanrubrik"> +Musikjam!</span><br> +kl 19-21, 30 kr<br> +<br> +Denna söndag kommer inga inhyrda musiker till jammet, +utan då det är vi själva som står för musiken!<br> +<br> +Så alla som kan och vill -ta med er instrument eller +andra ljudframbringande prylar. Att använda sin röst går förståss +också bra.<br> +<br> +Vill man inte musisera så dansar man som vanligt. +(..och därför kostar det bara 30 kr, då vi inte har några musiker som +ska betalas)<br> +<br> +VÄLKOMNA! +</td> +</tr> + --> + <tr> + <td class="kalendariecell"> + Söndag 2 Mars<br /> + <span class="mellanrubrik">Nybörjarintroduktion & + Jam med Karin R och Jenny</span><br /> + Kl. 19-21, 30 kr. + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 9 Mars<br /> + <span class="mellanrubrik">Blind fold jam - jam med + ögonbindel!</span><br /> + ... med Sofi och Tove. Kl 19-21, 30 kr<br /> + På ett blind fold jam dansar man med ögonen förbundna, + för att öka känsligheten, lyssnandet och samspelet. Det + är också ett sätt att försöka komma förbi + föreställningar man (medvetet eller omedvetet) har runt + vem man väljer att dansa med. Det blir i slutändan en + spegling till en själv om de val man gör på dansgolvet, + där kroppen denna gång får bestämma i stället för + huvudet. Vi inleder som vanligt med en introduktion. + Tag gärna med egen ögonbindel!<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 16 Mars<br /> + <span class="mellanrubrik">Introduktion och + jam</span><br /> + 19-21, 30 kr<br /> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen 23 Mars<br /> + <span class="mellanrubrik">Ingenting här för då är vi + på NIM i Köpenhamn! + <!-- Introduktion och jam</span><br> --> + <!-- 19-21, 30 kr<br> --></span> + </td> + </tr> + <tr> + <td class="kalendariecell"> + Söndagen den 30:e<br /> + <span class="mellanrubrik">Kort introduktion och + Livejam!!</span><br /> + 19-21, 50 kr<br /> + </td> + </tr> + </table> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/only-html.html b/emacs/nxhtml/tests/in/only-html.html new file mode 100644 index 0000000..7b297dd --- /dev/null +++ b/emacs/nxhtml/tests/in/only-html.html @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> + For testing fontification. + </body> +</html> diff --git a/emacs/nxhtml/tests/in/only-php.php b/emacs/nxhtml/tests/in/only-php.php new file mode 100644 index 0000000..ef54982 --- /dev/null +++ b/emacs/nxhtml/tests/in/only-php.php @@ -0,0 +1,10 @@ +<?php +include 'header.php'; +if (dff) { + thank(); + // Bad indentation on next line? + } +for (;;) { + you(); +} +?> diff --git a/emacs/nxhtml/tests/in/pavel-071116.djhtml b/emacs/nxhtml/tests/in/pavel-071116.djhtml new file mode 100644 index 0000000..1476f3a --- /dev/null +++ b/emacs/nxhtml/tests/in/pavel-071116.djhtml @@ -0,0 +1,31 @@ + <html> +{% extends "base.html" %} +<head> +<title>Muzikanti z lekce 4</title> +</head> +<body> +<table> +some text not within django block +{# some comment else #} +{% for muzikant in people %} +<tr> +<td> +{{ muzikant.name }} +<b> +{% comment %} +something else +{% if muzikant.nemamezeru %}*{% endif %} {% endcomment %} +</b> +</td> +<td> +<i {% if muzikant.ma_duraz %} style="font-weight: bold;"{% else %}{% endif %}> +{{ muzikant.genre|rjust|lower }} +</i> +</td> +</tr> +{% endfor %} +</table> +{% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %} +<p>The current time is {{ my_current_time }}.</p> +</body> +</html> diff --git a/emacs/nxhtml/tests/in/php-parseable.php b/emacs/nxhtml/tests/in/php-parseable.php new file mode 100644 index 0000000..590e4f6 --- /dev/null +++ b/emacs/nxhtml/tests/in/php-parseable.php @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> + <img alt="ALT" src="<?php some_code("txt"); ?>" /> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/question43320.html b/emacs/nxhtml/tests/in/question43320.html new file mode 100644 index 0000000..3ec0721 --- /dev/null +++ b/emacs/nxhtml/tests/in/question43320.html @@ -0,0 +1,35 @@ +<table> +<tr> +<td> +<table> +<tr> +<td>Hello</td> +</tr> +<?php +for ($i=1;$i<5; $i++) { +if (1) { +} +if (1) { +if (1) { +if (1) { +?> +<tr> +<td> +<p>the brace below (should have 2 spaces in front of it!)</p> +</td> +</tr> +<?php +} +} +$foo = "test".bar; +for ($i=1;$i<5; $i++) { +if () { +} +} +} +} +?> +</table> +</td> +</tr> +</table> diff --git a/emacs/nxhtml/tests/in/question44504-folding.html b/emacs/nxhtml/tests/in/question44504-folding.html new file mode 100644 index 0000000..8ecb7ce --- /dev/null +++ b/emacs/nxhtml/tests/in/question44504-folding.html @@ -0,0 +1,28 @@ +<table> + + +<!--Mėnesio pasirinkimas --> + +<tr> + <td width='50' colspan='1' class='men-met'> + <input type='button' value=' < ' onClick='goLastMonth(<?php echo date("t", strtotime("$year1-$month1-$day1")).", ".$month . ", " . $year.", ".date("w", strtotime("$year-$month-$day1")); ?>)' /> + </td> + <td width='250' colspan='5' class='men-met'> + <span class='title'><?php echo $men . " " . $year; ?></span><br /> + </td> + <td width='50' colspan='1' align='right' class='men-met'> + <input type='button' value=' > ' onClick='goNextMonth(1, <?php echo $month . ", " . $year.", ".date("w", strtotime("$year2-$month2-$day1")); ?>)' /> + </td> +</tr> + +<!-- AntraÅ¡tė su savaitės dienom --> +<tr> + <td class='head' >Pir</td> + <td class='head' >Ant</td> + <td class='head' >Tre</td> + <td class='head' >Ket</td> + <td class='head' >Pen</td> + <td class='head' >Å eÅ¡</td> + <td class='head' style="color: red;" >Sek</td> +</tr> +</table> diff --git a/emacs/nxhtml/tests/in/question49234.sh b/emacs/nxhtml/tests/in/question49234.sh new file mode 100644 index 0000000..3596046 --- /dev/null +++ b/emacs/nxhtml/tests/in/question49234.sh @@ -0,0 +1,41 @@ +#!/bin/ksh +. /bin/shared/.mkt.cfg + + +STORE_TMP=/tmp/stores.txt +cd /spool/xml + +rm -f $STORE_TMP + +bteq << EOF +.SESSIONS 1 +.LOGON $UserId,$Password; + +.EXPORT DATA FILE "$STORE_TMP" +select division_id,store_id, +trim(store)||' '||trim(store_addr_line2_txt)||', '|| +trim(store_city) +from stores +where status_id='A' + and division_id in (517,1920,2445) +order by division_id,store_city,store_id; + +.EXIT 0 +EOF + +perl <<EOF > $1 +print qq(<?xml version="1.0" encoding="utf-8"?>\n<stores>); +open IN, '<$STORE_TMP'; +while (read IN,\$info, 12) { + my (\$div, \$s) = unpack 'x2 i i', \$info; # read binary nums + \$_ = <IN>; # Read store name + chop; # Remove newline + s/(\w+)/\u\L\$1/g; # Title case + s/&/&/g; # Fix ampersands + s/"/"/g; # Fix quotes + printf qq(<s d="%02d" i="%d" n="%s"/>\n),\$div,\$s,\$_; +} +print "</stores>"; +EOF + +rm $STORE_TMP diff --git a/emacs/nxhtml/tests/in/rgr-030809-indexbody.php b/emacs/nxhtml/tests/in/rgr-030809-indexbody.php new file mode 100644 index 0000000..0384b4d --- /dev/null +++ b/emacs/nxhtml/tests/in/rgr-030809-indexbody.php @@ -0,0 +1,57 @@ + +<h1><div class="pagetitle"><?php echoMessage("website.title");?></div></h1> + +<img class="indeximage1" src="images/indeximage1.jpg"/> + +<div class="textcontainer latestnewscontainer"> + + <div class="indexspecialevent"> + <?php $numrows=displaySpecialEvent("nextevent");?> + </div> + + <div class="pubquizpreview"> + <div> + <h3> + <?php echo createLink("pubquiz","pubquiz.comingnext");?> + </h3> + </div> + <div> + <?php previewEvents("pubquiz");?> + </div> + </div> + + <div class="latestnewstitle"> + <?php + echoMessage("index.latest.title"); + ?> + </div> + <div class="latestnewsbody"> + <?php echoMessage("index.latest.body");?> + <?php include("menu.php");?> + </div> +</div> + +<div class="textcontainer" title="English Books Hamburg"> + + <div> + <?php echoMessage("index.about1");?> + </div> + + <div> + <h2> + <?php echo createLink("general","index.whatsnew");?> + </h2> + </div> + + <div> + <img class="newsimage" src="images/newsimage1.jpg"/> + </div> + + <div> + <?php echoMessage("index.news.n1");?> + </div> + <div> + <?php echoMessage("index.news.about2");?> + </div> + +</div> diff --git a/emacs/nxhtml/tests/in/rgr-080307.php b/emacs/nxhtml/tests/in/rgr-080307.php new file mode 100644 index 0000000..0cc4616 --- /dev/null +++ b/emacs/nxhtml/tests/in/rgr-080307.php @@ -0,0 +1,2 @@ +<div src="hello"></div> +<img alt="angry" src="hello.gif"/> diff --git a/emacs/nxhtml/tests/in/rgr-080308-header-2.php b/emacs/nxhtml/tests/in/rgr-080308-header-2.php new file mode 100644 index 0000000..e53ee01 --- /dev/null +++ b/emacs/nxhtml/tests/in/rgr-080308-header-2.php @@ -0,0 +1,56 @@ +<?php require_once("utils.php"); ?> + +<?php echo '<?xml version="1.0" encoding="utf-8"/?/>'; ?> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + +<head> + + <link type="text/css" href="stylesheet.css" rel="stylesheet" title="Style Sheet" /> + <link type="text/css" href="custom.css" rel="stylesheet" title="Style Sheet" /> + + <title><?php echoMessage("website.title")?></title> + + <meta name="keywords" content="irish bar,irish pub,finnegans wake , hamburg"/> + <meta name="description" content="Finnegans Wake Irish Pub"/> + + <style type="text/css">@import url(calendar-win2k-1.css);</style> + <script type="text/javascript" src="jscalendar-1.0/calendar.js"></script> + <script type="text/javascript" src="jscalendar-1.0/lang/calendar-en.js"></script> + <script type="text/javascript" src="jscalendar-1.0/calendar-setup.js"></script> + + +</head> + +<body class="body" title="Irish Bar"> + + <div class="webcontainer"> + + <div class="headerbanner"> + <img src="images/banner.gif" alt="Irish Bar"/> + </div> + + <div class="logo"> + <img src="images/logo.gif" alt="Irish Pubs"/> + </div> + + <div> + <?php include("navigation.php");?> + </div> + + <?php + if(isDemo()){ + echo '<div class="demomode">'; + echoMessage("admin.demo"); + echo "</div>"; + } + + include("address.php"); + include("sportpreview.php"); + + ?> + + <div class="centercontainer" title="Irish Pubs Germany"> diff --git a/emacs/nxhtml/tests/in/rgr-080308-header.php b/emacs/nxhtml/tests/in/rgr-080308-header.php new file mode 100644 index 0000000..e53ee01 --- /dev/null +++ b/emacs/nxhtml/tests/in/rgr-080308-header.php @@ -0,0 +1,56 @@ +<?php require_once("utils.php"); ?> + +<?php echo '<?xml version="1.0" encoding="utf-8"/?/>'; ?> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + +<head> + + <link type="text/css" href="stylesheet.css" rel="stylesheet" title="Style Sheet" /> + <link type="text/css" href="custom.css" rel="stylesheet" title="Style Sheet" /> + + <title><?php echoMessage("website.title")?></title> + + <meta name="keywords" content="irish bar,irish pub,finnegans wake , hamburg"/> + <meta name="description" content="Finnegans Wake Irish Pub"/> + + <style type="text/css">@import url(calendar-win2k-1.css);</style> + <script type="text/javascript" src="jscalendar-1.0/calendar.js"></script> + <script type="text/javascript" src="jscalendar-1.0/lang/calendar-en.js"></script> + <script type="text/javascript" src="jscalendar-1.0/calendar-setup.js"></script> + + +</head> + +<body class="body" title="Irish Bar"> + + <div class="webcontainer"> + + <div class="headerbanner"> + <img src="images/banner.gif" alt="Irish Bar"/> + </div> + + <div class="logo"> + <img src="images/logo.gif" alt="Irish Pubs"/> + </div> + + <div> + <?php include("navigation.php");?> + </div> + + <?php + if(isDemo()){ + echo '<div class="demomode">'; + echoMessage("admin.demo"); + echo "</div>"; + } + + include("address.php"); + include("sportpreview.php"); + + ?> + + <div class="centercontainer" title="Irish Pubs Germany"> diff --git a/emacs/nxhtml/tests/in/rgr-080308-indexbody.php b/emacs/nxhtml/tests/in/rgr-080308-indexbody.php new file mode 100644 index 0000000..0384b4d --- /dev/null +++ b/emacs/nxhtml/tests/in/rgr-080308-indexbody.php @@ -0,0 +1,57 @@ + +<h1><div class="pagetitle"><?php echoMessage("website.title");?></div></h1> + +<img class="indeximage1" src="images/indeximage1.jpg"/> + +<div class="textcontainer latestnewscontainer"> + + <div class="indexspecialevent"> + <?php $numrows=displaySpecialEvent("nextevent");?> + </div> + + <div class="pubquizpreview"> + <div> + <h3> + <?php echo createLink("pubquiz","pubquiz.comingnext");?> + </h3> + </div> + <div> + <?php previewEvents("pubquiz");?> + </div> + </div> + + <div class="latestnewstitle"> + <?php + echoMessage("index.latest.title"); + ?> + </div> + <div class="latestnewsbody"> + <?php echoMessage("index.latest.body");?> + <?php include("menu.php");?> + </div> +</div> + +<div class="textcontainer" title="English Books Hamburg"> + + <div> + <?php echoMessage("index.about1");?> + </div> + + <div> + <h2> + <?php echo createLink("general","index.whatsnew");?> + </h2> + </div> + + <div> + <img class="newsimage" src="images/newsimage1.jpg"/> + </div> + + <div> + <?php echoMessage("index.news.n1");?> + </div> + <div> + <?php echoMessage("index.news.about2");?> + </div> + +</div> diff --git a/emacs/nxhtml/tests/in/rr-090524-header.php b/emacs/nxhtml/tests/in/rr-090524-header.php new file mode 100644 index 0000000..e966036 --- /dev/null +++ b/emacs/nxhtml/tests/in/rr-090524-header.php @@ -0,0 +1,76 @@ +<?php require_once("utils.php");?> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> + +<html> + +<?php + if ($_SESSION["CurrentLanguage"]==0){ + $_SESSION["CurrentLanguage"]=$Default_Lang; + } +?> + + <head> + + <meta http-equiv="Content-Type" content="text/html;charset=utf-8" > + + <style type="text/css">@import url(calendar-win2k-1.css);</style> + <script type="text/javascript" src="jscalendar-1.0/calendar.js"></script> + <script type="text/javascript" src="jscalendar-1.0/lang/calendar-en.js"></script> + <script type="text/javascript" src="jscalendar-1.0/calendar-setup.js"></script> + + <link type="text/css" href="stylesheet.css" rel="stylesheet" title="Style Sheet" > + <style type="text/css"><?php echoMessage("admin.css.source");?> </style> + + <link type="text/css" href="custom.css" rel="stylesheet" title="Style Sheet"> + <link type="text/css" href="local.css" rel="stylesheet" title="Style Sheet"> + + <link type="text/css" href="print.css" rel="stylesheet" media="print"> + + <meta name="keywords" content='<?php echoMessage("header.keywords");?>'> + <meta name="description" content='<?php echoMessage("header.description");?>'> + + <title><?php echoMessage("website.title")?></title> + + + </head> + + <body class="body"> + <div class="wc"> + <table class="language"> +<tr> + <td> + <?php generateLanguageForm(true);?> + </td> + <td><a href="cyclelanguage"><img class="languageflag" src="flags/<?php echo getCurrentLanguage();?>" alt="<?php echoMessage("language.selectnext");?>" title="<?php echoMessage("language.selectnext");?>"></a></td> +</tr> + </table> + + <?php include("navigation.php");?> + <div class="ical"> + <?php echoMessage("index.ical");?> + </div> + + <div class="wb"> + + <?php + + if(adminMode()){ + echo '<div class="admincontrolcontainer clearfix">'; + createNavigationLinks("navlinks",1); + echo '<div class="clear"></div>'; + echo '</div>'; + } + + if(isDemo()){ + echo '<div class="demomode">'; + echoMessage("admin.demo"); + echo "</div>"; + } + + ?> + + <?php include("previews.php");?> + + <div class="centercontainer clearfix"> diff --git a/emacs/nxhtml/tests/in/rr-090923-header.php b/emacs/nxhtml/tests/in/rr-090923-header.php new file mode 100644 index 0000000..7f739eb --- /dev/null +++ b/emacs/nxhtml/tests/in/rr-090923-header.php @@ -0,0 +1,101 @@ +<?php + require_once("utils.php"); +?> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + + <?php if(!processLanguageURL()) + { + if ($_SESSION["CurrentLanguage"]==0){ + $_SESSION["CurrentLanguage"]=$Default_Lang; + } + } + ?> + + <head> + + <title><?php echo getMessage("website.title");?></title> + + <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> + + <?php + if (AUTO_REFRESH_DELAY>0 && !adminMode()) + echo '<meta http-equiv="refresh" content="'.AUTO_REFRESH_DELAY.'"/>'; + ?> + + + <link type="text/css" href="jscalendar-1.0/calendar-win2k-1.css" rel="stylesheet" title="Style Sheet"/> <!-- indicate local copy --> + <script type="text/javascript" src="jscalendar-1.0/calendar.js"></script> + <script type="text/javascript" src="jscalendar-1.0/lang/calendar-en.js"></script> + <script type="text/javascript" src="jscalendar-1.0/calendar-setup.js"></script> + + + <link type="text/css" href="stylesheet.css" rel="stylesheet" title="Style Sheet" /> + <link type="text/css" href="print.css" rel="stylesheet" media="print"/> + + <!--[if lt IE 7]> + <link type="text/css" href="ie.css" rel="stylesheet" title="Style Sheet"/> + <link type="text/css" href="site-ie.css" rel="stylesheet" title="Style Sheet"/> + <![endif]--> + + + <link type="text/css" href="/custom/site.css" rel="stylesheet" title="Style Sheet"/> <!-- project custom --> + <style type="text/css"><?php echo htmlentities(getMessage("header.custom.css"));?> </style> + + +<?php undercon(); +echoHeaderContent("keywords",curPageName()); +echoHeaderContent("description",curPageName()); +echoHeaderContent("verify-v1",curPageName()); +?> + + <link rel="SHORTCUT ICON" href="favicon.ico"/> + + <META NAME="AUTHOR" CONTENT="Richard G. Riley"/> + <meta name="copyright" content="Copyright Richard G. Riley 2009" /> + + + + </head> + + <body id="body"> + + <div id="wcbg"> + + <div id="wc" class="clearfix"> + + <?php + checkWebLicense(); + ?> + + <?php + include("navigation.php"); + ?> + + <div id="wb"> + + <?php + if(isDemo()){ + echo '<div class="demomode">'; + echoMessage("admin.demo"); + echo "</div>"; + } + if(adminMode()){ + echo '<div id="admincontrolcontainer">'; + createNavigationLinks("navlinks",1); + echo '<div class="clear"></div>'; + echo '</div>'; + } + ?> + + <div id="centercontainer"> + <?php + if(messageMode()){ + echo '<div class="editwebtitle">'; + echoMessage("website.title"); + echo '</div>'; + } + ?> + diff --git a/emacs/nxhtml/tests/in/rr-address-090304.php b/emacs/nxhtml/tests/in/rr-address-090304.php new file mode 100644 index 0000000..34cbe25 --- /dev/null +++ b/emacs/nxhtml/tests/in/rr-address-090304.php @@ -0,0 +1,4 @@ +<div class="addresscontainer" title="Hot Love Fan Mail"> + +<a target="_self" href="/Site/Content/Exhibitors/exhibitors-welcome.aspx"><img height="100" border="0" width="170" vspace="7" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Image21','','/site/images/intro_button_exhib_over.jpg',1)" id="Image21" name="Image21" alt="Exhibitors button" src="http://www.farnborough.com/site/images/intro_button_exhib_static.jpg"/></a> +</div> \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/rr-address-nxhtml.err b/emacs/nxhtml/tests/in/rr-address-nxhtml.err new file mode 100644 index 0000000000000000000000000000000000000000..f06b0a05ec04b50fedf2fd532713970a488e8570 GIT binary patch literal 6647 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 DiWrO- literal 0 HcmV?d00001 diff --git a/emacs/nxhtml/tests/in/rr-min8.php b/emacs/nxhtml/tests/in/rr-min8.php new file mode 100644 index 0000000..bf464f1 --- /dev/null +++ b/emacs/nxhtml/tests/in/rr-min8.php @@ -0,0 +1,6 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + +<head> + +<script type="text/javascript" src="jscalendar-1.0/calendar.js"></script> +<script type="text/javascript" src="jscalendar-1.0/lang/calendar-en.js"></script> diff --git a/emacs/nxhtml/tests/in/ryan-091104-literal.tpl b/emacs/nxhtml/tests/in/ryan-091104-literal.tpl new file mode 100644 index 0000000..64c9d26 --- /dev/null +++ b/emacs/nxhtml/tests/in/ryan-091104-literal.tpl @@ -0,0 +1,148 @@ +{include file="library/header.tpl"} + +{* comment *} + +{literal} +<script language="JavaScript" type="text/javascript"> +function validate_form(f){ + allElements = f.getInputs('text'); + var get_time = /^times\[(.+)\]$/; + var get_date = /^dates\[(.+)\]$/; + for(var index=0; index < allElements.length; ++index){ + var item = allElements[index]; + if(get_time.test(item.name)){ + if($F(item)){ + var key = get_time.exec(item.name) + var sibling_date = 'dates[' + key[1] + ']'; + if(! $F(sibling_date)){ + alert("Date is required if entering a manual time!"); + $(sibling_date).addClassName('problem'); + return false; + } + } + + } + } + else if(get_date.test(item.name)){ + if($F(item)){ + var key = get_date.exec(item.name) + var sibling_time = 'times[' + key[1] + ']'; + if(! $F(sibling_time)){ + alert("Time is required if entering a manual date!"); + $(sibling_time).addClassName('problem'); + return false; + } + } + } + return true; +} + +function validate_date( el ) +{ + var date = /^\d\d\d\d-\d\d-\d\d$/; + if ( !date.test(el.value) ) { + alert('The date you have entered is not properly formatted (yyyy-mm-dd). Please re-enter it.'); + el.value=''; + el.focus(); + el.className='problem'; + return false; + } + el.className=''; + return true; +} + +function validate_time( el ) +{ + var time = /^\d\d:\d\d$/; + if ( !time.test(el.value) ) { + alert('The time you have entered is not properly formatted (hh:mm). Please re-enter it.'); + el.value=''; + el.focus(); + el.className = 'problem'; + return false; + } + el.className = ''; + return true; +} +</script> + +<style type="text/css"> + foo: { + font-weight: bold; + color: #F00; + } +</style> +{/literal} + +{if $containers|@count } + +<form name="test" method=post onsubmit="return validate_form(this);"> +<input type="hidden" name="date" value="{$smarty.request.date}"> +<input type="hidden" name="page_name" value="{$page_name}" /> + +<table frame="void" bordercolor="#000000" rules="cols" class="data" style="float:center;"> +<thead> +<tr class="sortHeader"> + {if $goahead} + <th onclick="sortTable(this)">{t}Date{/t}<br /><span class="ex">YYYY-MM-DD</span></th> + {/if} + {if $goahead} + <th onclick="sortTable(this)">{t}Time{/t}<br /><span class="ex">HH:MM</span></th> + {/if} + + <th onclick="sortTable(this)">{t}Quantity{/t}</th> +</tr> +</thead> + +{foreach from=$widgets item="widget"} +<tbody class="{cycle values=",highlight}" ondblclick="return insertHeader(this);"> + {if $widget->date != $today} + {assign var=newday value=true} + {assign var=today value=$widget->date} + {else} + {assign var=newday value=false} + {/if} + +<tr class="{if $newday}group{/if}"> + {if $goahead} + {if $widget->activity_allowed} + <td class="ctext"><input type="text" value="" onchange="validate_date(this, this.form );" name="dates[{$widget->widget_id_for_web}]" id="dates[{$widget->widget_id_for_web}]" size=10 maxlength=10></td> + {else} + <td></td> + {/if} + {/if} + + {if $goahead} + {if $widget->activity_allowed} + <td class="ctext"><input type="text" value="" onchange="validate_time(this, this.form);" name="times[{$widget->widget_id_for_web}]" id="times[{$widget->widget_id_for_web}]"size=5 maxlength=5></td> + {else} + <td></td> + {/if} + {/if} + + <td>{$widget->quantity}</td> +</tr> +</tbody> +{/foreach} +</table> + +<hr /> + {if $goahead} + <br /> + <b>{t}Note{/t}:</b> {t}Changes may not occur immediately.{/t} + <br /> + <input type=submit value="Update Widgets"> + {/if} + + </form> +{else} + {t}There are no widgets on this day{/t} +{/if} + +{literal} +<hr/>test + +<p>Paragraph</p> +{/literal} + +{include file="library/footer.tpl"} diff --git a/emacs/nxhtml/tests/in/ryan-091111-wrong-side.tpl b/emacs/nxhtml/tests/in/ryan-091111-wrong-side.tpl new file mode 100644 index 0000000..51164a8 --- /dev/null +++ b/emacs/nxhtml/tests/in/ryan-091111-wrong-side.tpl @@ -0,0 +1,18 @@ +<script language="javascript" type="text/javascript"> +//<!-- +{literal} +$('account').observe("change", function(event) {should_get_account_data( +'first', 'acct' );}); +$('desc').observe("change", function(event) {should_get_account_data( +'first', 'name' );}); +{/literal} +{if $autocomplete} +{literal} +document.observe("dom:loaded", function(event) +{auto_complete_customers('first', 'acct');}); +document.observe("dom:loaded", function(event) +{auto_complete_customers('first', 'name');}); +{/literal} +{/if} +//--> +</script> diff --git a/emacs/nxhtml/tests/in/schemas.xml b/emacs/nxhtml/tests/in/schemas.xml new file mode 100644 index 0000000..09b0bac --- /dev/null +++ b/emacs/nxhtml/tests/in/schemas.xml @@ -0,0 +1,3 @@ +<?xml version="1.0"?> +<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0"> +</locatingRules> diff --git a/emacs/nxhtml/tests/in/sd-080803-test.php b/emacs/nxhtml/tests/in/sd-080803-test.php new file mode 100644 index 0000000..e44ccc6 --- /dev/null +++ b/emacs/nxhtml/tests/in/sd-080803-test.php @@ -0,0 +1,14 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + <head> + <style type="text/css"> + table { + border-collapse: collapse; + } + </style> + </head> + <body> + <h1><?= $title ?></h1> + </body> +</html> + diff --git a/emacs/nxhtml/tests/in/senny-091118.htm b/emacs/nxhtml/tests/in/senny-091118.htm new file mode 100644 index 0000000..dda2fe3 --- /dev/null +++ b/emacs/nxhtml/tests/in/senny-091118.htm @@ -0,0 +1,247 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<title>PostFinance - Home</title> +<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /> +<meta http-equiv="Content-Style-Type" content="text/css" /> +<meta name="description" content="" /> +<meta name="keywords" content="" /> +<meta name="language" content="en" /> +<meta name="copyright" content="Copyright (c) by PostFinance" /> +<meta name="robots" content="all" /> +<link rel="canonical" href="http://www.postfinance.ch/pf/content/en" /> + + + +<meta name="WT.pf_nav_L1" content="HOMEPAGE" /> +<meta name="WT.pf_nav_L2" content="" /> +<meta name="WT.pf_nav_L3" content="" /> + + +<!-- WT meta tag library 0.0.30 --> +<!-- Execution time: 0ms --> +<script type="text/javascript"> +var aWtAdviews = new Array(); +var aWtTags = new Array(); +</script> + + +<link rel="stylesheet" href="./../../../staticcontent/css/styles.css" type="text/css" media="screen,print" /> + +<!--[if IE 6]> +<link rel="stylesheet" href="./../../../staticcontent/css/styles_ie6.css" type="text/css" media="screen,print" /> +<![endif]--> + +<!--[if IE 7]> +<link rel="stylesheet" href="./../../../staticcontent/css/styles_ie7.css" type="text/css" media="screen,print" /> +<![endif]--> + +<link rel="stylesheet" href="./../../../staticcontent/css/bok.css" type="text/css" media="screen,print" /> +<link rel="stylesheet" href="./../../../staticcontent/css/print.css" type="text/css" media="print" /> + + + + +</head><body> + + <!-- WT1 start --> +<script type="text/javascript" src="./../../../staticcontent/js/webtrends.js"></script> +<noscript> +<img alt="" style="border:none;" name="DCSIMG" width="1" height="1" src="/dcsez1c8510000g4ydy8x63gm_3g9z/njs.gif?dcsuri=/nojavascript&WT.js=No&WT.tv=8.6.2"/> +</noscript> +<script type="text/javascript"> +<!-- +var _tag=new WebTrends(); +_tag.domain = window.location.hostname; +_tag.dcsid = "dcsez1c8510000g4ydy8x63gm_3g9z"; +_tag.fpcdom = ".postfinance.ch"; +_tag.dcsGetId(); +//--> +</script> +<!-- WT1 end --> + + + + + + + + + +<script type="text/javascript" src="./../../../staticcontent/js/old/util.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/old/AJAXService.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/old/engine.js"></script> + +<script type="text/javascript">document.documentElement.className+=" js";</script> +<script type="text/javascript" src="./../../../staticcontent/js/jquery-1.2.6.min.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/jquery.bgiframe.pack.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/definitions.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/main.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/tabbed.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/aria.js"></script> +<script type="text/javascript" src="./../../../staticcontent/js/tooltip2.js"></script> + + + +<script type="text/javascript"> +//<![CDATA[ +// SubContentGroup +_tag.WT.cg_s='_home'; +//]]> +</script> + + +<div id="page"> + <div id="header" class="header-en"> + <!-- Skip Navigation Start --> + + + +<h1>Navigation of PostFinance.ch</h1> +<ul id="skipLinks"> + <li> + <a accesskey="1" href="#navTopRoot" title="Directly to the navigation">Navigation</a> + </li> + <li> + <a accesskey="2" href="#mainContent" title="Directly to the content">Content</a> + </li> + <li> + <a accesskey="3" href="/pf/ref/de/seg/bridge/nav/efinoverview.html" title="Directly to E-Finance">E-Finance</a> + </li> + <li> + <a accesskey="4" href="/pf/content/en/service/sitemap.html" title="Directly to the sitemap">Sitemap</a> + </li> +</ul> + + + + + +<!-- Logo/Claim Start --><a accesskey="0" href="/pf/content/en.html" id="pfLogo">PostFinance, Swiss Post</a><p id="pfClaim" class="pfClaim-en"><strong>Surpassing support</strong></p> +<!-- Logo/Claim End --> + + <!-- Skip Navigation End --> + + <h2>Language, tools and important links</h2> + <!-- Language Selector Start --> +<div id="languageSelector"><ul><li class="first-child "><a href="/pf/content/de.html"><abbr xml:lang="de">de</abbr></a></li><li ><a href="/pf/content/fr.html"><abbr xml:lang="fr">fr</abbr></a></li><li ><a href="/pf/content/it.html"><abbr xml:lang="it">it</abbr></a></li><li class="selected"><a href="/pf/content/en.html"><abbr xml:lang="en">en</abbr></a></li></ul></div> +<!-- Language Selector End --> + + + + + <!-- globalNavRoot Start --> + <div id="globalNavRoot"> + + + + +<div class="globalLinks"><p><a href="http://www.post.ch/en/" rel="external">Swiss Post</a></p> + + +<ul class="serviceLinks"><li class="first-child"><a href="/pf/content/en/service/contact.html">Contact</a></li><li><a href="/pf/content/en/service/sitemap.html">Sitemap</a></li></ul></div> + </div> + <!-- globalNavRoot End --> + + <!-- Suche start --><form action="/pf/content/en/single/search.html" method="get" id="searchform"><div id="search"><label for="searchfield">Search</label><input value="" maxlength="2048" type="text" class="search-field" name="query" id="searchfield" /><input value="Search" type="submit" class="search-button" name="searchsubmit" /><input value="/content/pf/content/en" type="hidden" name="nav" /></div></form><!-- Suche end --> + + + +<!-- Topnavigation start --><div id="topNav"><a name="navTopRoot"></a><h2 class="hd">Main navigation</h2><ul class="top-nav-links"><li><a href="/pf/content/en/seg/priv.html">Private customers</a></li><li><a href="/pf/content/en/seg/biz.html">Business customers</a></li><li><a href="/pf/content/en/seg/about.html">About us</a></li></ul> + <div class="user-login"> + + </div> +</div> +<!-- end navTop --> + + </div> + <div id="mainArea"> + <div class="hp-split"> + <div id="content"> + <div class="mood-home" style="background: transparent url(/content/pf/content/en.parsys-0001-Image.0.0.0.mainImage1.jpg) no-repeat scroll 0 0; z-index: 100000;"> +<span class="hidden"> + <a href="https://e-finance.postfinance.ch/ef/secure/html/"> + E-finance login + </a> +</span> +</div> + +<div class="tri-split"> + <div class="col col0"> + <div class="mod"><a name="mainContent"></a> + <h2 class="hd"><a href="/pf/content/en/seg/priv.html" rel="nofollow" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Private');">Private customers</a></h2> + <div class="bd"> + <p>Everything you need <br/>for your private finances.</p> + <ul class="list-links"><li><a href="/pf/content/en/seg/priv/prod.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Products_priv');">Products<span class="hidden">Private customers</span></a></li><li><a href="/pf/content/en/seg/priv/customer.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Customer_priv');">Customer Service<span class="hidden">Private customers</span></a></li><li><a href="/pf/ref/de/seg/bridge/nav/efinoverview.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_E-finance');">E-finance</a></li><li><a href="/pf/content/en/seg/priv/etrade.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_E-trading');">E-trading</a></li></ul> + </div> + </div> + </div> + <div class="col col1"> + <div class="mod"> + <h2 class="hd"><a href="/pf/content/en/seg/biz.html" rel="nofollow" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Business');">Business customers </a></h2> + <div class="bd"> + <p>Everything you need <br/>for your business finances.</p> + <ul class="list-links"><li><a href="/pf/content/en/seg/biz/product.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Products_biz');">Products<span class="hidden">Business customers </span></a></li><li><a href="/pf/content/en/seg/biz/customer.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Customer_biz');">Customer Service<span class="hidden">Business customers </span></a></li><li><a href="/pf/content/en/seg/biz/offer/startup.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_startup');">Company founder and start-up company<span class="hidden">Business customers </span></a></li><li><a href="/pf/content/en/seg/biz/offer/sbiz.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_sbiz');">Small and medium-sized enterprises</a></li><li><a href="/pf/content/en/seg/biz/offer/smbiz.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_smbiz');">Medium-sized/large businesses</a></li><li><a href="/pf/content/en/seg/biz/offer/publicentity.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Public');">Public entities</a></li><li><a href="/pf/content/en/seg/biz/offer/club.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Associations');">Associations</a></li><li><a href="/pf/content/en/seg/biz/offer/bank.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Banks');">Banks</a></li></ul> + </div> + </div> + </div> + <div class="col col2"> + <div class="mod"> + <h2 class="hd"><a href="/pf/content/en/seg/about.html" rel="nofollow" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Aboutus');">About us</a></h2> + <div class="bd"> + <p>Key facts about PostFinance.</p> + <ul class="list-links"><li><a href="/pf/content/en/seg/about/pf.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Company');">Company</a></li><li><a href="/pf/content/en/seg/about/media.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Media');">Media</a></li><li><a href="/pf/content/en/seg/about/job.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Jobs');">Jobs</a></li><li><a href="/pf/content/en/seg/about/event.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_Events');">Events</a></li></ul> + </div> + </div> + </div> +</div> + </div> + + <!-- serviceArea Start --> + <div id="serviceArea"> + <h1>Related content</h1> + <div class="mod nofoot"><h2 class="hd">E-Services</h2><div class="bd"><ul class="list-links"><li><a href="/pf/ref/de/seg/bridge/nav/efinloginhomeen.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_le_home_LoginE-Finance');">Login E-Finance</a></li><li><a href="/pf/ref/de/seg/bridge/etrade/loginen.html" title="" onmousedown="_tag.dcsAdTrack('WT.ac', '_li_home_LoginE-Trading');">Login E-Trading</a></li></ul></div></div> + <!-- Kudicontainer --> + <div id="AJAX_Teaser" lang="en"><div class="mod nofoot teaser one-click"><h2 class="hd"> +<a href="/pf/content/en/seg/priv/prod/eserv/etrade/promotion.html" title="More information about the offer." onmousedown="_tag.dcsAdTrack('WT.ac', 'PK952_APK_TE_A_EN_L0_A_Homepage_1_en', 'WT.mc_id', 'PK952', 'WT.mc_ev', 'click');">E-trading</a></h2> +<p class="bd"> +<a href="/pf/content/en/seg/priv/prod/eserv/etrade/promotion.html" title="More information about the offer." onmousedown="_tag.dcsAdTrack('WT.ac', 'PK952_APK_TE_A_EN_L0_A_Homepage_1_en', 'WT.mc_id', 'PK952', 'WT.mc_ev', 'click');"><img src="/staticcontent/teasers/content/_etc_medialib_pf_de_teaser_camp_2009_pk952_Par_0009_Image.jpg" alt="" /><span class="hidden"> More information about the offer.</span> +<span>No brokerage fees until the end of January 2010.* + <em>More</em></span></a></p></div><div class="mod nofoot teaser one-click"><h2 class="hd"> +<a href="/pf/content/en/seg/bcase/lohnkonto.html" title="More information on the salary account" onmousedown="_tag.dcsAdTrack('WT.ac', 'PK920_APK_TE_A_EN_L0_A_Homepage_2_en', 'WT.mc_id', 'PK920', 'WT.mc_ev', 'click');">Competition</a></h2> +<p class="bd"> +<a href="/pf/content/en/seg/bcase/lohnkonto.html" title="More information on the salary account" onmousedown="_tag.dcsAdTrack('WT.ac', 'PK920_APK_TE_A_EN_L0_A_Homepage_2_en', 'WT.mc_id', 'PK920', 'WT.mc_ev', 'click');"><img src="/staticcontent/teasers/content/_content_teaser_content_en_seg_running_kampagnen_ci_pk920_pfch_parsys_0001_Image.jpg" alt="" /><span class="hidden"> More information on the salary account</span> +<span>Double your income: switch your salary account to PostFinance. + <em>More</em></span></a></p></div> +<script type="text/javascript"> aWtTags[aWtTags.length] = "WT.pf_nav_L1"; aWtTags[aWtTags.length] = "HOMEPAGE"; aWtTags[aWtTags.length] = "WT.ad"; aWtTags[aWtTags.length] = "PK952_APK_TE_A_EN_L0_A_Homepage_1_en;PK920_APK_TE_A_EN_L0_A_Homepage_2_en"; aWtTags[aWtTags.length] = "WT.pf_logstatus"; aWtTags[aWtTags.length] = "anonym"; aWtTags[aWtTags.length] = "WT.pf_segment"; aWtTags[aWtTags.length] = "anonym"; aWtTags[aWtTags.length] = "WT.cg_n"; aWtTags[aWtTags.length] = "PF HOME anonym"; aWtTags[aWtTags.length] = "WT.pf_pagetype"; aWtTags[aWtTags.length] = "L0_A_Homepage"; </script></div> + </div> + + </div> + </div> +</div> + + +<!-- Footer start --><div id="footer"><h1>References</h1><ul id="footerLinks"><li><a href="/pf/content/en/footer/access.html">Accessibility</a></li><li><a href="/pf/content/en/footer/legal.html">Legal disclaimer</a></li><li><a href="/pf/content/en/footer/cond.html">Prices/Conditions/GTC</a></li><li><a href="/pf/content/en/footer/impressum.html">Publishing details</a></li></ul><!-- Footernavigation end --> +<p>Copyright (c) 2009 by PostFinance. All rights reserved.</p> +</div><!-- Footer end --> + + + + + + + + + + +<script type="text/javascript"> + if (typeof(_tag) != "undefined") { + _tag.dcsCollect(); + } +</script> + + + +</body> +</html> + diff --git a/emacs/nxhtml/tests/in/sheit-2007-12-26.php b/emacs/nxhtml/tests/in/sheit-2007-12-26.php new file mode 100644 index 0000000..8aa97cc --- /dev/null +++ b/emacs/nxhtml/tests/in/sheit-2007-12-26.php @@ -0,0 +1,9 @@ +<?php +/** + * + * @param string $name + */ + public function setName($name) { + $this->name = $name; + } +?> diff --git a/emacs/nxhtml/tests/in/short-tags.php b/emacs/nxhtml/tests/in/short-tags.php new file mode 100644 index 0000000..a297e03 --- /dev/null +++ b/emacs/nxhtml/tests/in/short-tags.php @@ -0,0 +1,3 @@ +<? $foo=1 ?>, <?= "bla" ?> + instead of +<?php $foo=1 ?>, <?php echo "bla" ?> diff --git a/emacs/nxhtml/tests/in/single-question-sign.html b/emacs/nxhtml/tests/in/single-question-sign.html new file mode 100644 index 0000000..bb7d6fc --- /dev/null +++ b/emacs/nxhtml/tests/in/single-question-sign.html @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> + <?> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/ssjs.ssjs b/emacs/nxhtml/tests/in/ssjs.ssjs new file mode 100644 index 0000000..501ed68 --- /dev/null +++ b/emacs/nxhtml/tests/in/ssjs.ssjs @@ -0,0 +1,9 @@ +<p id="msg"></p> +<script runat="server"> + var nme = document.createTextNode( + "Hello my name is Jaxer."); + var para = document.getElementById("name"); + para.appendChild(nme); +</script> + +<p>Hello, my name is <% response.name %>.</p> diff --git a/emacs/nxhtml/tests/in/string-bug.php b/emacs/nxhtml/tests/in/string-bug.php new file mode 100644 index 0000000..3b25c9f --- /dev/null +++ b/emacs/nxhtml/tests/in/string-bug.php @@ -0,0 +1 @@ + <?= "bla" ?> diff --git a/emacs/nxhtml/tests/in/style=.html b/emacs/nxhtml/tests/in/style=.html new file mode 100644 index 0000000..e005fad --- /dev/null +++ b/emacs/nxhtml/tests/in/style=.html @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> + <p style=""> + </p> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/style=string-font.html b/emacs/nxhtml/tests/in/style=string-font.html new file mode 100644 index 0000000..e5dd87d --- /dev/null +++ b/emacs/nxhtml/tests/in/style=string-font.html @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>News and Notes about nXhtml</title> + </head> + <body> + <p id="hadron-bugs" style="margin-top:1em;">Thanks for testing!</p> + + <p id="state-of-the-art" style="margin-top:1em; + background-color: #00fa9a; + background-color: #20b2aa; + padding: 0.5em; + ">The State of the Art</p> + <p id="something"></p> + <p id="something" style="background-color: #54ff9f; padding: 0.5em"></p> + <p id="something"></p> diff --git a/emacs/nxhtml/tests/in/svg.svg b/emacs/nxhtml/tests/in/svg.svg new file mode 100644 index 0000000..1b24f33 --- /dev/null +++ b/emacs/nxhtml/tests/in/svg.svg @@ -0,0 +1 @@ +something diff --git a/emacs/nxhtml/tests/in/temp2.php b/emacs/nxhtml/tests/in/temp2.php new file mode 100644 index 0000000..34271ba --- /dev/null +++ b/emacs/nxhtml/tests/in/temp2.php @@ -0,0 +1,48 @@ +<?php +/* We must use this header to be correct and for the css validator to + find our stylesheet without us having to provide a fully qualified + path (address) to it. */ +header("Content-type:application/xhtml+xml; charset=utf-8"); +echo '<'.'?xml version="1.0" encoding="utf-8"?'.'>'; +?> + <body> + <div id="container"> + <div id="header">Top area</div> + <div id="left-menu"> + <ul> + <li><a href="index.php">Home</a></li> + <li><a href="index.php?page=a">First Main Page</a></li> + <li><a href="index.php?page=b">Second Main Page</a></li> + </ul> + </div> + <div id="main"> + <?php + if (isset($_GET["page"])) { + $thepage = $_GET['page']; + + if ($thepage != 'a' && $thepage != 'b') { + print('You hacker you!'); + } + else { + require('main-div-'.$thepage.'.html'); + } + } + else { + require('main-div-a.html'); + } + ?> + </div> + <div id="right-menu">Right area</div> + <div id="footer"> + <p> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="valid-xhtml10.png" alt="Valid XHTML 1.0 Strict"></img> + </a> + <a href="http://jigsaw.w3.org/css-validator/check?uri=referer"> + <img src="vcss.png" alt="Valid CSS!"></img> + </a> + </p> + </div> + </div> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/temp3.html b/emacs/nxhtml/tests/in/temp3.html new file mode 100644 index 0000000..276b754 --- /dev/null +++ b/emacs/nxhtml/tests/in/temp3.html @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>News and Notes about nXhtml</title> + <link href="wd/grapes/nxhtml-grapes.css" rel="StyleSheet" type="text/css" /> +<style type="text/css"> +#nxhtml-home a { + /* Image */ + display: block; + background: transparent url("img/getitbuttons.png") 0 0 no-repeat; + overflow: hidden; + width: 200px; + xheight: 35px; + /* Text placement and size, etc */ + text-align: center; + padding-top: 11px; + font-size: 12px; + padding-bottom: 9px; + text-decoration: none; + white-space: nowrap; + margin: 0; + border: none; +} +#nxhtml-home a:hover { + background-position: 0 -35px; + color: yellow; +} + +</style> + </head> + <body> + <div id="container"> + + <div id="rgtcol"> + <p id="nxhtml-home"><a href='nxhtml.html'>To nXhtml main page</a></p> + + <h1>News and Notes about nXhtml</h1> + + <dl> + + <dt id="hadron-bugs" style="margin-top:1em;">Thanks for testing!</dt> + <dd> diff --git a/emacs/nxhtml/tests/in/test-only-nxml.my-xhtml b/emacs/nxhtml/tests/in/test-only-nxml.my-xhtml new file mode 100644 index 0000000..2f9398c --- /dev/null +++ b/emacs/nxhtml/tests/in/test-only-nxml.my-xhtml @@ -0,0 +1,38 @@ +<?php + +// some basic library functions +include_once 'lib.php'; + +$book = new Mybook($api_key, $secret); + +if (isset($_POST['to'])) { + $prints_id = (int)$_POST['to']; + $prints = do_step($user, $prints_id); +} else { + if (isset($_GET['to'])) { + $prints_id = (int)$_GET['to']; + } else { + $prints_id = $user; + } + $prints = get_prints($prints_id); +} + +?> +<div style="padding: 10px;"> + <h2>Hi <mb:name firstnameonly="true" uid="<?php=$user?>" useyou="false"/>!</h2><br/> + <a href="<?= $book->get_add_url() ?>">Put prints in your profile</a>. + <form method="post" action="http://my-domain.com/footprints/"> +<?php + if ($prints_id != $user) { + echo '<input type="hidden" name="to" value="' . $prints_id . '"/>'; + } else { + echo '<br/>'; + } +?> + <input value="step" type="submit"/> + </form> + <hr/> + These are <mb:name uid="«?= $prints_id ?»" possessive="true"/> Footprints:<br/> + <?php echo render_prints($prints, 10); ?> + <div style="clear: both;"/> +</div> diff --git a/emacs/nxhtml/tests/in/test.tt b/emacs/nxhtml/tests/in/test.tt new file mode 100644 index 0000000..01ff84a --- /dev/null +++ b/emacs/nxhtml/tests/in/test.tt @@ -0,0 +1,11 @@ +[% IF blah %] + +[%# test GET ] + # comment +[% test %] and [% test %] + +[% test % test %] + +[%+ test -%] + +[% BLOCK %] diff --git a/emacs/nxhtml/tests/in/tut1.jsp b/emacs/nxhtml/tests/in/tut1.jsp new file mode 100644 index 0000000..e921950 --- /dev/null +++ b/emacs/nxhtml/tests/in/tut1.jsp @@ -0,0 +1,5 @@ +<HTML> + <BODY> + Hello! The time is now <%= new java.util.Date() %> + </BODY> +</HTML> diff --git a/emacs/nxhtml/tests/in/utf8-problem.el b/emacs/nxhtml/tests/in/utf8-problem.el new file mode 100644 index 0000000..c5e8b32 --- /dev/null +++ b/emacs/nxhtml/tests/in/utf8-problem.el @@ -0,0 +1,7 @@ + +(defvar utf8-problem + "\\(?:^\\|[[:space:]]\\)\\(?:href\\|src\\)[[:space:]]*=[[:space:]]*\"\\([^<«\"]*\\)\"") + +;; Local Variables: +;; coding: utf-8 +;; End: diff --git a/emacs/nxhtml/tests/in/wiki-080606-indent.php b/emacs/nxhtml/tests/in/wiki-080606-indent.php new file mode 100644 index 0000000..0776f03 --- /dev/null +++ b/emacs/nxhtml/tests/in/wiki-080606-indent.php @@ -0,0 +1,18 @@ +<?php + +include_once(APP_AAA_INCLUDE."bb.php"); +include_once(APP_AAA_INCLUDE."cc.php"); +include_once(APP_AAA_INCLUDE."dd.php"); +include_once(APP_AAA_INCLUDE."ee.php"); +include_once(APP_AAA_INCLUDE."ff.php"); +include_once(APP_AAA_INCLUDE."gg.php"); + +class Test +{ + public $var1; + + function __construct() + { + $this->var1 = 5; + } +} \ No newline at end of file diff --git a/emacs/nxhtml/tests/in/wiki-080708-ind-problem.rhtml b/emacs/nxhtml/tests/in/wiki-080708-ind-problem.rhtml new file mode 100644 index 0000000..d51d116 --- /dev/null +++ b/emacs/nxhtml/tests/in/wiki-080708-ind-problem.rhtml @@ -0,0 +1,5 @@ +<%= t("Hola") %> + <%= ink_to name, target %> + <% if quiero do %> + <%= do_something_nifty(with_me) %> + <% end %> diff --git a/emacs/nxhtml/tests/in/wiki-090804-js.html b/emacs/nxhtml/tests/in/wiki-090804-js.html new file mode 100644 index 0000000..2762ed9 --- /dev/null +++ b/emacs/nxhtml/tests/in/wiki-090804-js.html @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> + + <script type="text/javascript"> + // <![CDATA[ + Some code to see if we can find the problem + // ]]> +</script> + +<?php + $htmlstuff = <<<EOTHTML + + <p>some stuff</p> + <p>some other stuff</p> + + <script type="text/javascript"> + // <![CDATA[ + Some code to see if we can find the problem + // ]]> +</script> + +EOTHTML; + +?> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/wiki-2008-01-30.rhtml b/emacs/nxhtml/tests/in/wiki-2008-01-30.rhtml new file mode 100644 index 0000000..5eefdc7 --- /dev/null +++ b/emacs/nxhtml/tests/in/wiki-2008-01-30.rhtml @@ -0,0 +1 @@ +<div class="widget"> diff --git a/emacs/nxhtml/tests/in/wiki-comments.php b/emacs/nxhtml/tests/in/wiki-comments.php new file mode 100644 index 0000000..0581443 --- /dev/null +++ b/emacs/nxhtml/tests/in/wiki-comments.php @@ -0,0 +1,20 @@ +<?php +/* + ' + */ +/* + Problem updating comments during editing. To reproduce place cursor after the single x above and press RET and some other character. + + Or just edit here, fill the paragraph above etc. Seems like problem + with mumamo-after-change which assumes that it is only called once + before post-command-hook is called. + + BTW fill-paragraph does not work either ... - why does it run + c-fill-paragraph in php-mode? (Mailed Alan about this. The only + reason seems to be to support filladapt.el, but is that needed any + more? + + It looks like more code (like filling) needs to be run under the + correct syntax table etc. Implemented. + */ +?> diff --git a/emacs/nxhtml/tests/in/wiki-strange-hili-080629.html b/emacs/nxhtml/tests/in/wiki-strange-hili-080629.html new file mode 100644 index 0000000..9f8c202 --- /dev/null +++ b/emacs/nxhtml/tests/in/wiki-strange-hili-080629.html @@ -0,0 +1,5 @@ +<html> +<body> +<span style="color:red">red</span> +</body> +</html> diff --git a/emacs/nxhtml/tests/in/xml-as-string.php b/emacs/nxhtml/tests/in/xml-as-string.php new file mode 100644 index 0000000..e779a5c --- /dev/null +++ b/emacs/nxhtml/tests/in/xml-as-string.php @@ -0,0 +1,54 @@ +<?php header("Content-type:application/xml; charset=utf-8"); echo '<'; echo '?xml version="1.0" encoding="utf-8"?'; echo '>'; ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Lab 2 - Layout Control - Task 2 - XHTML/CSS version</title> + <link rel="stylesheet" type="text/css" href="stylesheet.css" /> + </head> + <body> + <div id="container"> + <div id="header">Top area</div> + <div id="left-menu"> + <ul> + <li><a href="index.php">Home</a></li> + <li><a href="index.php?page=a">First Main Page</a></li> + <li><a href="index.php?page=b">Second Main Page</a></li> + </ul> + </div> + <!-- + <? + ?> + --> + <div id="main"> + <?php + // comment + $thepage = $_GET['page']; + + if (empty($thepage)) { + require('main-div-a.html'); + } + else { + if ($thepage != 'a' && $thepage != 'b') { + print('You hacker you!'); + } + else { + require('main-div-'.$thepage.'.html'); + } + for (;;) { + } + } + ?> + </div> + <div id="right-menu">Right area</div> + <div id="footer"> + <p> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="valid-xhtml10.png" alt="Valid XHTML 1.0 Strict"></img> + </a> + <a href="http://jigsaw.w3.org/css-validator/validator?uri=http%3A%2F%2Fwww-und.ida.liu.se%2F%7Emikas493%2Ftask-2%2Fxhtml-css%2Fstylesheet.css"> + <img src="vcss.png" alt="Valid CSS!"></img> + </a> + </p> + </div> + </div> diff --git a/emacs/nxhtml/tests/in/ygne-2008-02-07-hotproperty.html.php b/emacs/nxhtml/tests/in/ygne-2008-02-07-hotproperty.html.php new file mode 100644 index 0000000..1802272 --- /dev/null +++ b/emacs/nxhtml/tests/in/ygne-2008-02-07-hotproperty.html.php @@ -0,0 +1,1967 @@ +<?php +// hotproperty.html.php +/** + * Something's Presentation Code + * + * @package Something + * @copyright (C) 2004 Lee Cher Yeong + * @url http://www.somewhere.com/ + * @author Lee Cher Yeong <cy@somewhere.com> + **/ + +defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' ); + +class hotproperty_HTML { + + /*** + * Include CSS file + ***/ + function include_CSS() { + global $hp_css; + ?> + <link rel="stylesheet" href="components/com_hotproperty/css/<?php echo $hp_css; ?>.css" type="text/css"> + <?php + } + + function include_Container_Start() { + ?> +<div id="con_global"> +<div class="componentheading"><!--<?php echo _HP_COM_TITLE; ?>--></div> + <?php + } + function include_Container_End() { + ?> +</div> + + + <?php + } + + + /*** + * Front Page + ***/ + function show_Frontpage(&$campos, &$featured, &$featured_fields_caption, &$featured_total, &$types, &$types_hotproperty, &$types_total) { + global $hp_fp_show_featured, $hp_fp_show_search, $mainframe, $hp_css, $mosConfig_live_site, $my; + + $mainframe->setPageTitle( _HP_COM_TITLE );?> + + <link rel="stylesheet" href="components/com_hotproperty/css/ppal_<?php echo $hp_css; ?>.css" type="text/css"/> + + <div id="total_alojamientos"> + <span class="saludo"><?= _HP_HOLA ?></span> <?= _HP_TENEMOS ?> + <?php hotproperty_HTML::show_ResumenTipos() ?> + </div> + + <div id="buscar_alojamiento"> + </div> + <div id="incluir_alojamiento"> + </div> + + <br clear="all"/> + +<?php + +/* if ($hp_fp_show_featured && count($featured) > 0 ){ + hotproperty_HTML::show_fp_Featured($featured, $featured_fields_caption, $featured_total); + echo '<br class="clearboth" />'; + } + + if ($hp_fp_show_search) { + hotproperty_HTML::show_Search($types); + echo '<br class="clearboth" />'; + } + + hotproperty_HTML::show_Types($types, $types_hotproperty, $types_total);*/ + } + + /*** + * Featured Listing + ***/ + function show_fp_Featured(&$prop, &$caption, $featured_total) { + global $hp_fp_featured_count, $Itemid; + ?> + <div id="con_featured1"> + <div id="heading_Featured"><?php echo _HP_FEATURED_TITLE; ?></div> + <div id="list_featured"> + <?php hotproperty_HTML::list_properties($prop, $caption); ?> + <br class="clearboth" /> + <?php if ($featured_total > $hp_fp_featured_count) { + echo "<a href=\"". sefRelToAbs("index.php?option=com_hotproperty&task=viewfeatured&Itemid=$Itemid") ."\">"._HP_MOREFEATURED."</a>"; + } ?> + </div> + </div> + <?php + } + + /*** + * List Types + ***/ + function show_Types(&$types, &$types_hotproperty, $types_total) { + global $Itemid; + ?> + <div id="con_types1"> + <div id="heading_Types"><?php echo _HP_TYPES_TITLE; ?></div> + <div id="con_types2"> + <?php + foreach($types AS $t) { + if ($types_total[$t->id]->total > 0) { + ?> + <div class="con_types3"> + <a class="types_title" href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewtype&id=$t->id&Itemid=$Itemid"); ?>"><?php echo $t->name ."</a>(".$types_total[$t->id]->total.")"; ?><br /> + <div class="types_desc"> + <?php echo $t->desc; ?> + <ul class="types_hp"> + <?php + foreach($types_hotproperty[$t->id] AS $t_hp) { + if ($t_hp->name <> "" && $t_hp->id <> "") { + ?> + <li><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=view&id=$t_hp->id&Itemid=$Itemid"); ?>"><?php echo $t_hp->name; ?></a></li> + <?php + } + } + ?> + </ul> + <?php + if ($types_total[$t->id]->total > 3) { ?> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewtype&id=$t->id&Itemid=$Itemid"); ?>"><?php echo _HP_MORE; ?></a> + <?php + } + ?> + </div> + </div> + <?php + } + } + ?> + </div> + </div> + <?php + } + + /*** + * Search Facility + ***/ + function show_Search(&$types) { + global $Itemid, $hp_use_advsearch, $mosConfig_live_site; + /* + global $custom404, $mosConfig_sef, $sufix; + + # Using Built in SEF feature in Mambo + if ( !isset($custom404) && $mosConfig_sef ) { + $onclickCmd = "document.location.href= '$mosConfig_live_site/component/option,com_hotproperty/task,search/Itemid,$Itemid/type,0/search,' + encodeURI(document.searchfrm.hp_search.value) + '/'"; + } elseif ( $mosConfig_sef && isset($custom404) && !empty($sufix) ) { + + global $custom_comp, $hp_default_limit_search; + $hotproperty = "hotproperty"; + if (in_array("hotproperty", $custom_comp)) { + $hotproperty = array_search($component_name, $custom_comp); + } + + $onclickCmd = "document.location.href='" . $hotproperty . "/" . _HP_SEF_SEARCH . "/0/".$hp_default_limit_search."/0/" . "' + encodeURI(document.searchfrm.hp_search.value)"; + + } else { + # Using SEF advance or no SEF at all + $onclickCmd = "document.location.href='" . sefRelToAbs("index.php?option=com_hotproperty&task=search&Itemid=$Itemid&type=0&search=' + encodeURI(document.searchfrm.hp_search.value)"); + } + */ + ?> + <div id="con_search1"> + <div id="heading_Search"><?php echo _HP_SEARCH_TITLE; ?></div> + <div id="con_search2"> + <form action="index.php" method="POST" name="searchfrm"> + <strong><?php echo _HP_SEARCH_TEXT; ?></strong> + <input type="text" name="search" class="inputbox" /> + <input type="submit" class="button" value="<?php echo _HP_SEARCH; ?>" /><?php + if ($hp_use_advsearch == '1') { + ?> <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=advsearch&Itemid=$Itemid"); ?>"><?php echo _HP_SEARCH_ADV_TITLE; ?></a><?php + } + ?> + <input type="hidden" name="option" value="com_hotproperty" /> + <input type="hidden" name="task" value="search" /> + <input type="hidden" name="Itemid" value="<?php echo $Itemid;?>" /> + </form> + </div> + </div> + <?php + } + + /*** + * Advanced Search Facility + ***/ + function show_AdvSearch($fields, $tipos_renta) { + global $Itemid, $mainframe; + + $mainframe->setPageTitle( _HP_SEARCH_ADV_TITLE ); + ?> + <script language="javascript"> + /* Selecciona por defecto España como paÃs para la búsqueda */ + function select_idioma(id) { + select=document.getElementById(id); + select.options[62].selected="1"; + } + /* Muestra o oculta la búsqueda por disponibilidad y el precio según el tipo de oferta */ + function swap_tipo_oferta(id) { + select=document.getElementById(id); + disp=document.getElementById('disp_busq_av'); + precio=document.getElementById('precio_busq_av'); + if (select.options[1].selected) { // Alquiler + disp.style.display = "block"; + precio.style.display = "none"; + } + if (select.options[2].selected) { // Venta + disp.style.display = "none"; + precio.style.display = "block"; + } + if (select.options[0].selected) { // Cualquiera + disp.style.display = "block"; + precio.style.display = "block"; + } + + + } + /* Muestra o oculta una capa, y cambia el texto del enlace lanzador */ + function swap(id, llamador) + { + id=document.getElementById(id); + if (id.style.display == "none" || id.style.display == "") { + id.style.display = "block"; + llamador.innerHTML = "<?= _HP_OCULTAR ?>"; + } + else { + id.style.display = "none"; + llamador.innerHTML = "<?= _HP_MOSTRAR ?>"; + } + } + /* Selecciona todos los alojamientos O sólo las viviendas en un combobox con los tipos de alojamiento */ + function selecc_vivienda(select) + { + select = document.getElementById(select); + if (select.selectedIndex == 1) + { + select.options[select.selectedIndex].selected = ""; + for (i=2; i <= select.length-1; i++) + if (i != 11 && i!= 13) select.options[i].selected="1"; + } + } + /* Muestra u oculta los campos de búsqueda por disponibilidad */ + function swap_disp(input,id) { + if (input.checked) + document.getElementById(id).style.display="block"; + else + document.getElementById(id).style.display="none"; + } + </script> + <div id="heading_AdvSearch"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em><?php echo _HP_SEARCH_ADV_TITLE; ?></div> + <div id="con_asearch1"> + <form action="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=asearch&Itemid=$Itemid"); ?>" method="POST" name="searchfrm"> + <div class="cabecera_busq_avzda"> + <div class="titulo_cabecera_busq_avzda"><?= _HP_DATOS_GENERALES ?></div> + </div><br class="clearboth"/> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['type']->caption; ?>:</div> + <?= $fields['type']->input; ?> + </div> + <div class="cont_form"> + <div class="campo_con_ayuda"> + <div class="titulo_campo"><?= $fields['Tipo_Alojamiento']->caption; ?>:</div> + <?= $fields['Tipo_Alojamiento']->input; ?> + </div> + <div class="msj_ayuda"><?= _HP_AYUDA_TIPO_ALOJ ?></div> + </div> + <br class="clearboth"/> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Superficie_habitable']->caption; ?>:</div> + <?php echo $fields['Superficie_habitable']->input; ?> + <?php echo $fields['Superficie_habitable']->append_text; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Num_plazas']->caption; ?>:</div> + <?= $fields['Num_plazas']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Numero_dormitorios']->caption; ?>:</div> + <?= $fields['Numero_dormitorios']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['country']->caption; ?>:</div> + <?= $fields['country']->input; ?> + <script language="javascript"> + select_idioma('idioma'); + </script> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['state']->caption; ?>:</div> + <?= $fields['state']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['suburb']->caption; ?>:</div> + <?= $fields['suburb']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['postcode']->caption; ?>:</div> + <?= $fields['postcode']->input; ?> + </div> + <div id="precio_busq_av"> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['price']->caption; ?>:</div> + <?= $fields['price']->input; ?> + </div> + </div> + <div id="disp_busq_av"> + <div class="cont_form"> + <input type="checkbox" name="busq_disp" onclick="swap_disp(this,'campos_disp');"><?= _HP_BUSQ_POR_DISP ?></input> + <div id="campos_disp"> + <div class="titulo_campo"><?= _HP_BUSQ_DISP ?> </div> + <div class="flota_izq interl_doble"> + <?php hotproperty_HTML::seleccion_fecha("desde"); ?> + <?php hotproperty_HTML::seleccion_fecha("hasta"); ?> + </div> + <div class="campo_avl"> + <?= _HPAVL_RENTA; ?> + <select size="1" class="campo_dcha inputbox" name="renta"> + <option value="0"><?= _HP_SEARCH_ALLTYPES ?></option> + <?php foreach ($tipos_renta AS $tipo_renta) { ?> + <option value="<?php echo $tipo_renta->id; ?>"><?php echo $tipo_renta->nombre; ?></option> + <?php } ?> + </select> + </div> + </div> + </div> + </div> + <!-- Otros datos --> + <div class="cabecera_busq_avzda"> + <div class="titulo_cabecera_busq_avzda"><?= _HP_OTROS_DATOS ?></div> + <div class="botonera_dcha"> + <a href="#" class="enlace_blanco" onclick="swap('otros_datos', this);"><?= _HP_MOSTRAR; ?></a> + </div> + </div><br class="clearboth"/> + <div id="otros_datos"> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['MetrosConstruidos']->caption; ?>:</div> + <?= $fields['MetrosConstruidos']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Superficie_parcela']->caption; ?>:</div> + <?= $fields['Superficie_parcela']->input; ?> + <?= $fields['Superficie_parcela']->append_text; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Numero_dormitorios']->caption; ?>:</div> + <?= $fields['Numero_dormitorios']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Cuartos_banio_con_duchas']->caption; ?>:</div> + <?= $fields['Cuartos_banio_con_duchas']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Aseos']->caption; ?>:</div> + <?= $fields['Aseos']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['AnioConstruccion']->caption; ?>:</div> + <?= $fields['AnioConstruccion']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['UltimaReforma']->caption; ?>:</div> + <?= $fields['UltimaReforma']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Amueblado']->caption; ?>:</div> + <?= $fields['Amueblado']->input; ?> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Dispone']->caption; ?>:</div> + <?= $fields['Dispone']->input; ?> + <br class="clearboth"/> + </div> + <div class="cont_form"> + <div class="titulo_campo"><?= $fields['Zona']->caption; ?>:</div> + <?= $fields['Zona']->input; ?> + <br class="clearboth"/> + </div> + </div> + + <br/> + <div class="centro"> + <input type="submit" value="Buscar" class="button" > + </div> + + </div> + + <?php + } + + /*** + * Empty Advanced Search Results + ***/ + function show_advSearchResults_error($msg) { + global $Itemid, $mainframe; + $mainframe->setPageTitle( _HP_SEARCH_ADV_TITLE ); + ?> + <div id="con_asearch1"> + <div id="heading_AdvSearch"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em><?php echo _HP_SEARCH_ADV_TITLE; ?></div> + <p /> + <?php echo $msg; ?> + <p /> + <a href=""><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=advsearch&Itemid=$Itemid"); ?>"><?php echo _HP_SEARCH_TRYAGAIN; ?></a> + </div> + <?php + } + + /*** + * Advanced Search Results + ***/ + function show_advSearchResults(&$search_id, &$prop, &$caption, &$pageNav, &$searchString) { + global $Itemid, $mainframe; + $mainframe->setPageTitle( _HP_SEARCH_ADV_TITLE ); + ?> + <div id="con_asearch1"> + <div id="heading_AdvSearch"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em><?php echo _HP_SEARCH_ADV_TITLE; ?></div> + <!-- <div id="hp_searchresult_con"> + <div id="hp_search_pagecounter_top"> + <div class="right"><?php echo $pageNav->writePagesCounter(); ?></div> + <br class="clearboth" /> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=asearch&Itemid='.$Itemid.'&search_id='.$search_id); ?> + </div> + </div> --> + <div id="list_searchresults"> + <?php hotproperty_HTML::list_properties($prop, $caption); ?> + </div> + </div> + <br class="clearboth" /> + <div id="hp_search_pagecounter_bottom"> + <div class="dcha"><?php echo $pageNav->writePagesCounter(); ?></div> + <br class="clearboth" /> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=asearch&Itemid='.$Itemid.'&search_id='.$search_id); ?> + </div> + + <?php + } + + /*** + * Search Results + ***/ + function show_SearchResults(&$types, &$prop, &$caption, &$pageNav, &$searchString) { + global $Itemid, $hp_use_advsearch, $mosConfig_live_site, $mainframe; + global $custom404, $mosConfig_sef, $sufix; + $mainframe->setPageTitle( _HP_SEARCH_RESULT_TITLE ); + + # Using Built in SEF feature in Mambo + /* + if ( !isset($custom404) && $mosConfig_sef ) { + + $onclickCmd = "document.location.href= '$mosConfig_live_site/component/option,com_hotproperty/task,search/Itemid,$Itemid/type,' + document.searchfrm.type.options[document.searchfrm.type.selectedIndex].value + '/search,' + encodeURI(document.searchfrm.hp_search.value) + '/'"; + + } elseif ( $mosConfig_sef && isset($custom404) && !empty($sufix) ) { + + global $custom_comp, $hp_default_limit_search; + $hotproperty = "hotproperty"; + if (in_array("hotproperty", $custom_comp)) { + $hotproperty = array_search($component_name, $custom_comp); + } + + $onclickCmd = "document.location.href='" . $hotproperty . "/" . _HP_SEF_SEARCH . "/' + document.searchfrm.type.options[document.searchfrm.type.selectedIndex].value + '/".$hp_default_limit_search."/0/" . "' + encodeURI(document.searchfrm.hp_search.value)"; + + } else { + + # Using SEF advance or no SEF at all + $onclickCmd = "document.location.href='" . sefRelToAbs("index.php?option=com_hotproperty&task=search&Itemid=$Itemid&type=' + document.searchfrm.type.options[document.searchfrm.type.selectedIndex].value + '&search=' + encodeURI(document.searchfrm.hp_search.value)"); + } + */ + ?> + <div id="con_search1"> + <form action="index.php" method="POST" name="searchfrm"> + <div id="heading_Search"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN ." "._HP_ARROW." "; ?></a><?php echo _HP_SEARCH_RESULT_TITLE; ?></div> + <div id="hp_searchresult_con"> + <strong><?php echo _HP_SEARCH_TEXT; ?></strong> + <input type="text" name="search" class="inputbox" value="<?php echo $searchString->search; ?>" /> <?php echo _HP_IN; ?> + <select name="type" class="inputbox" size="1"> + <option value="0"><?php echo _HP_SEARCH_ALLTYPES; ?></option> + <?php + foreach($types AS $t) { ?> + <option value="<?php echo $t->id; ?>"<?php echo (($searchString->type==$t->id) ? " selected" : ""); ?>><?php echo $t->name; ?></option> + <?php } + ?></select> + + <input type="submit" class="button" value="<?php echo _HP_SEARCH; ?>" /><?php + if ($hp_use_advsearch == '1') { + ?> <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=advsearch&Itemid=$Itemid"); ?>"><?php echo _HP_SEARCH_ADV_TITLE; ?></a><?php + } + ?> + <div id="hp_search_pagecounter_top"> + <div class="right"><?php echo $pageNav->writePagesCounter(); ?></div> + <br class="clearboth" /> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=search&Itemid='.$Itemid.'&type='.$searchString->type.'&search='.$searchString->search); ?> + </div> + </div> + <input type="hidden" name="option" value="com_hotproperty" /> + <input type="hidden" name="task" value="search" /> + </form> + </div> + + <div id="list_searchresults"> + <?php hotproperty_HTML::list_properties($prop, $caption); ?> + </div> + <br class="clearboth" /> + <div id="hp_search_pagecounter_bottom"> + <div class="right"><?php echo $pageNav->writePagesCounter(); ?></div> + <br class="clearboth" /> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=search&Itemid='.$Itemid.'&type='.$searchString->type.'&search='.$searchString->search); ?> + </div> + + <?php + } + + /*** + * List Properties for a particular Type + ***/ + function show_Type($prop, $type, $caption, $pageNav, $sortby_sort, $sortby_order) { + global $hp_use_diplaynum, $hp_use_sort_name, $hp_use_sort_agent, $hp_use_sort_price, $hp_use_sort_suburb, $hp_use_sort_state, $hp_use_sort_country, $hp_use_sort_type, $hp_use_sort_modified, $hp_use_sort_hits; + + global $Itemid, $database, $mainframe; + + $mainframe->setPageTitle( $type->name ); + ?> + <div id="con_type1"> + <?php if ($type != '') { ?> + <div id="heading_Type"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em><?php echo $type->name; ?></div> + <?php } ?> + <?php + if ($hp_use_diplaynum == '1' || !empty($hp_use_sort_name) || !empty($hp_use_sort_agent) || !empty($hp_use_sort_price) || !empty($hp_use_sort_suburb) || !empty($hp_use_sort_state) || !empty($hp_use_sort_country) || !empty($hp_use_sort_type) || !empty($hp_use_sort_modified) || !empty($hp_use_sort_hits)) { + ?> + <div id="con_sort"> + <?php if ($hp_use_diplaynum == '1') { ?> + <div id="con_sort1"> + <?php echo _PN_DISPLAY_NR; ?> + <?php echo $pageNav->writeLimitBox('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort='.$sortby_sort.'&order='.$sortby_order.'&Itemid='.$Itemid); ?> + </div> + <?php + } + if (!empty($hp_use_sort_name) || !empty($hp_use_sort_agent) || !empty($hp_use_sort_price) || !empty($hp_use_sort_suburb) || !empty($hp_use_sort_state) || !empty($hp_use_sort_country) || !empty($hp_use_sort_type) || !empty($hp_use_sort_modified) || !empty($hp_use_sort_hits)) { + ?> + <div id="con_sort2"> + <?php echo _HP_SORT_BY; ?> + | + + <?php if (!empty($hp_use_sort_name)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=name&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>" title="<?php echo _HP_SORT_A_Z; ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo _HP_SORT_AZ; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=name&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>" title="<?php echo _HP_SORT_Z_A; ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_agent) && !empty($caption['agent']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=agent&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['agent']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=agent&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_price) && !empty($caption['price']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=price&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>" title="<?php echo _HP_SORT_LOWEST_PRICE; ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['price']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=price&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>" title="<?php echo _HP_SORT_HIGHEST_PRICE; ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_suburb) && !empty($caption['suburb']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=suburb&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['suburb']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=suburb&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_state) && !empty($caption['state']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=state&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['state']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=state&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_country) && !empty($caption['country']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=country&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['country']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=country&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_type) && !empty($caption['type']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=type&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['type']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=type&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_modified) && !empty($caption['modified']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=modified&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['modified']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=modified&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + <?php if (!empty($hp_use_sort_hits) && !empty($caption['hits']->caption)) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=hits&order=asc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_ASC; ?> </a> <?php echo $caption['hits']->caption; ?> <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort=hits&order=desc&limit='.$pageNav->limit.'&limitstart='.$pageNav->limitstart.'&Itemid='.$Itemid); ?>"> <?php echo _HP_SORT_DESC; ?> </a> | + <?php } ?> + + </div> + <?php } ?> + </div> + <?php } ?> + <div id="list_properties"> + <?php hotproperty_HTML::list_properties($prop, $caption); ?> + </div> + + + <?php if ($type != '') { ?> + <div id="hp_pagecounter_bottom"> + <div align="right"><?php $pageNav->writePagesCounter(); ?></div> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=viewtype&id='.$prop[0]->typeid.'&sort='.$sortby_sort.'&order='.$sortby_order.'&Itemid='.$Itemid); ?> + </div> + <?php } ?> + </div> + <?php + } + + /*** + * List Featured Properties + ***/ + function show_Featured($prop, $caption, $pageNav) { + global $Itemid, $mainframe; + $mainframe->setPageTitle( _HP_FEATURED ); + ?> + <div id="con_type1"> + <div id="heading_Featured"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN ." "._HP_ARROW." "; ?></a><?php echo _HP_FEATURED; ?></div> + <div id="list_properties"> + <?php hotproperty_HTML::list_properties($prop, $caption); ?> + </div> + <br class="clearboth" /> + <div id="hp_pagecounter_bottom"> + <div align="right"><?php echo $pageNav->writePagesCounter(); ?></div> + <br class="clearboth" /> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=viewfeatured'); ?> + </div> + </div> + <?php + } + + /*** + * Display Company's contact details and list all agents under it. + ***/ + function show_Company(&$company, &$agent, &$prop, &$caption, $pageNav) { + global $mosConfig_live_site, $hp_imgdir_agent, $mainframe, $Itemid; + $mainframe->setPageTitle( $company[0]->name ); + ?> + + <div id="hp_view_agent_title_nav"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em> <?php echo _HP_CO_TITLE; ?></div> + <div id="hp_view_co_con"> + <?php hotproperty_HTML::show_CoInfo($company, $agent) ?> + </div> + <br class="clearboth" /> + + <div id="heading_Agent"><span class="flecha_big">⺠</span><?= _HP_PROPBYAGENT.$company[0]->name; ?></div> + <div id="list_properties"> + <?php hotproperty_HTML::list_properties($prop, $caption); ?> + </div> + + <br class="clearboth" /> + <div id="hp_pagecounter_bottom"> + <div align="right"><?php echo $pageNav->writePagesCounter(); ?></div> + <br class="clearboth" /> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=viewco&id='.$company[0]->id); ?> + </div> + + <?php + } + + /*** + * Display Agent's information and list all properties under it. + ***/ + function show_Agent($prop_alq, $prop_vta, $caption, $agent, $types, $pageNav) { + global $mosConfig_live_site, $hp_imgdir_agent, $Itemid, $mainframe; + $mainframe->setPageTitle( $agent->name ); + ?> + + <div id="hp_view_agent_title_nav"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em><?php echo $agent->name; ?></div> + + <div id="hp_view_agent_con"> + <?php hotproperty_HTML::show_AgentInfo($agent) ?> + </div> + <br class="clearboth" /> + + <div id="heading_Agent"><span class="flecha_big">⺠</span><?= _HP_PROPBYAGENT.$agent->name; ?></div> + <div class="cabecera_ver_ofertas"><?= _OFER_ALQ; ?></div> + <?php hotproperty_HTML::show_Type($prop_alq, "", $caption, $pageNav, "desc", "modified"); ?> + <br class="clearboth" /> + <div class="cabecera_ver_ofertas"><?= _OFER_VEN; ?></div> + <?php hotproperty_HTML::show_Type($prop_vta, "", $caption, $pageNav, "desc", "modified"); ?> + + +<!-- <div id="hp_pagecounter_bottom"> + <div align="right"><?php echo $pageNav->writePagesCounter(); ?></div> + <br class="clearboth" /> + <?php echo $pageNav->writePagesLinks('index.php?option=com_hotproperty&task=viewagent&id='.$agent->id); ?> + </div>--> + <br class="clearboth" /> + <?php + } + + /*** + * Display Company's information and an enquiry form. + ***/ + function show_CoEmail($company) { + global $Itemid, $mainframe; + $mainframe->setPageTitle( _HP_CO_CONTACT .' - '.$company[0]->name ); + + ?> + <div id="heading_Co"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em><?php echo _HP_CO_TITLE; ?></div> + <div id="hp_view_co_con"> + <?php hotproperty_HTML::show_CoInfo($company) ?> + </div> + <br class="clearboth" /> + <div id="heading_Co_Contact"><?php echo _HP_CO_CONTACT; ?></div> + <div id="hp_emailform_con"> + <?php hotproperty_HTML::show_EmailForm('company',$company[0]->id) ?> + </div> + + <?php + } + + /*** + * Display Agent's information and an enquiry form. + ***/ + function show_AgentEmail($agent) { + global $Itemid, $mainframe; + $mainframe->setPageTitle( _HP_VIEW_AGENT_CONTACT .' - '.$agent[0]->name ); + ?> + <!--<div id="hp_view_agent_title_nav"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?><em><?php echo _HP_ARROW; ?></em></a> <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewco&id=".$agent[0]->companyid."&Itemid=".$Itemid); ?>"><?php echo $agent[0]->company; ?></a><em><?php echo _HP_ARROW; ?></em><?php echo _HP_VIEW_AGENT_TITLE; ?></div> --> +<!-- <div id="hp_view_agent_con"> + <?php hotproperty_HTML::show_AgentInfo($agent) ?> + </div> --> + <div id="hp_view_agent_contact"><span class="flecha_big"><?= _HP_ARROW ?></span><?php echo _HP_VIEW_AGENT_CONTACT; ?></div> + <div id="hp_emailform_con"> + <?php hotproperty_HTML::show_EmailForm('agent',$agent[0]->id) ?> + </div> + + <?php + } + + /*** + * Show Property + ***/ + function show_Prop(&$prop, &$caption, &$images, &$agent, $num_periodos) { + global $Itemid, $my, $mosConfig_live_site, $mosConfig_absolute_path, $pop, $mainframe; + global $hp_imgdir_thumb, $hp_imgdir_standard, $hp_currency, $hp_imgsize_thumb, $hp_img_noimage_thumb, $hp_imgdir_agent, $hp_show_agentdetails, $hp_show_enquiryform, $hp_thousand_sep, $hp_dec_point, $hp_link_open_newwin, $hp_show_moreinfo, $hp_use_companyagent, $hp_dec_string, $hp_thousand_string; + global $hp_show_pdficon, $hp_show_printicon, $hp_show_emailicon; + + $mainframe->appendMetaTag( 'description', $prop[0]->metadesc ); + $mainframe->appendMetaTag( 'keywords', $prop[0]->metakey ); + $mainframe->setPageTitle( $prop[0]->name ); + if ($pop == '') $pop = 0; + ?> + <script language="javascript"> + // Si es una pop-up, es la ventana de impresión: imprime. + if (<?= $pop ?> == 1 ) { window.print(); } + </script> + <script src="components/com_hotproperty/js/resalte.js" type="text/javascript"></script> + + <div id="con_hp1"> + <?php if (!$pop) { ?> + <div id="heading_Prop"> + <div class="obj_con_botonera"> + <div class="nombre_objeto"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&Itemid=$Itemid"); ?>"><?php echo _HP_COM_PATHWAY_MAIN; ?></a><em><?php echo _HP_ARROW; ?></em><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewtype&id=".$prop[0]->typeid."&Itemid=$Itemid"); ?>"><?php echo $prop[0]->type; ?> </a> <em><?php echo _HP_ARROW; ?></em> <?php echo $prop[0]->name; ?> + </div> + <?php } ?> + <div class="botonera_dcha"> + <div class="mini_botones"> + + <?php + + # Show edit icon for authorized agent + if (!$pop && $prop[0]->user == $my->id && $prop[0]->user > 0 && $my->id > 0) { ?> + <div class="mini_boton"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=editprop&id=". $prop[0]->id ."&Itemid=$Itemid"); ?>" title="<?= _E_EDIT; ?>"><img src="administrator/images/editar.png" alt="<?= _E_EDIT ?>" title="<?= _E_EDIT ?>" onmouseover="this.src='administrator/images/editar_on.png';swap_resalte('editar',1);" onmouseout="this.src='administrator/images/editar.png';swap_resalte('editar',0);" class="bot_gestionar" id="img_editar"/></a> + </div> + <div class="texto_mini_boton"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=editprop&id=". $prop[0]->id ."&Itemid=$Itemid"); ?>" onmouseover="swap_resalte('editar',1);" onmouseout="swap_resalte('editar',0);" title="<?= _E_EDIT; ?>" id="a_editar"><?= _E_EDIT ?></a></div> + <?php } ?> + + <?php + if ($hp_show_pdficon && !$pop) { + ?> + <div class="mini_boton"> + <a href="javascript:void window.open('<?php echo $mosConfig_live_site; ?>/components/com_hotproperty/pdf.php?id=<?php echo $prop[0]->id; ?>', 'win2', 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no');" title="<?php echo _CMN_PRINT;?>"> + <img src="<?php echo $mosConfig_live_site;?>/administrator/images/imprimir.png" border="0" alt="<?php echo _CMN_PDF;?>" onmouseover="this.src='administrator/images/imprimir_on.png';swap_resalte('imprimir',1);" onmouseout="this.src='administrator/images/imprimir.png'; swap_resalte('imprimir',0);" class="bot_gestionar" id="img_imprimir"/></a> + </div> + <div class="texto_mini_boton"> + <a href="javascript:void window.open('<?php echo $mosConfig_live_site; ?>/components/com_hotproperty/pdf.php?id=<?php echo $prop[0]->id; ?>', 'win2', 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no');" onmouseover="swap_resalte('imprimir',1);" onmouseout="swap_resalte('imprimir',0);" class="enlace" id="a_imprimir"><?php echo _CMN_PDF;?></a> + </div> + <?php + } // End of if $hp_show_pdficon + + if ($hp_show_printicon && !$pop) { ?> + <div class="mini_boton"> + <a href="javascript:void window.open('<?php echo $mosConfig_live_site; ?>/index2.php?option=com_hotproperty&task=view&id=<?php echo $prop[0]->id; ?>&pop=1', 'win2', 'status=no,toolbar=no,scrollbars=yes,menubar=no,resizable=yes,width=940,height=480,directories=no,location=no');" title="<?php echo _CMN_PRINT;?>" onmouseover="swap_resalte('imprimir',1);"> + <img src="administrator/images/imprimir.png" alt="<?= _CMN_PRINT ?>" title="<?= _CMN_PRINT ?>" onmouseover="this.src='administrator/images/imprimir_on.png';" onmouseout="this.src='administrator/images/imprimir.png'; swap_resalte('imprimir',0);" class="bot_gestionar" id="img_imprimir"/></a> + </div> + <div class="texto_mini_boton"> + <a href="javascript:void window.open('<?php echo $mosConfig_live_site; ?>/index2.php?option=com_hotproperty&task=view&id=<?php echo $prop[0]->id; ?>&pop=1', 'win2', 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=940,height=480,directories=no,location=no');" title="<?php echo _CMN_PRINT;?>" onmouseover="swap_resalte('imprimir',1);" onmouseout="swap_resalte('imprimir',0);" class="enlace" id="a_imprimir"> + <?= _CMN_PRINT ?></a> </div> + + <?php } // End of if $hp_show_printicon + + if ($hp_show_emailicon && !$pop) { ?> + <div class="mini_boton"> + <a href="javascript:void window.open('<?php echo $mosConfig_live_site; ?>/index2.php?option=com_hotproperty&task=emailform&id=<?php echo $prop[0]->id; ?>', 'win2', 'status=no,toolbar=no,scrollbars=no,titlebar=no,menubar=no,resizable=yes,width=400,height=285,directories=no,location=no');" title="<?php echo _CMN_EMAIL;?>"><img src="administrator/images/correo.png" alt="<?= _CMN_EMAIL ?>" title="<?= _CMN_EMAIL ?>" onmouseover="this.src='administrator/images/correo_on.png';swap_resalte('correo',1);" onmouseout="this.src='administrator/images/correo.png'; swap_resalte('correo',0);" class="bot_gestionar" id="img_correo"/></a> + </div> + <div class="texto_mini_boton"> + <a href="javascript:void window.open('<?php echo $mosConfig_live_site; ?>/index2.php?option=com_hotproperty&task=emailform&id=<?php echo $prop[0]->id; ?>', 'win2', 'status=no,toolbar=no,scrollbars=no,titlebar=no,menubar=no,resizable=yes,width=400,height=285,directories=no,location=no');" title="<?php echo _CMN_EMAIL;?>" onmouseover="swap_resalte('correo',1);" onmouseout="swap_resalte('correo',0);" id="a_correo"> + <?= _HP_EMAIL_AMIGO ?></a> </div> + <?php } ?> + </div> + </div> + </div> <!-- fin div.mini_botones --> + </div> + + <br class="clearboth"> + <br class="clearboth"> + +<?php + // Copyright é 2006, Michael Rice + // License: GPL but you must email when you use it to let me know and this copyright MUST remain intact. + // Email: meikeric {at] gmail [dot} com + // You can donate to my Paypal and request hacks for HotProperty. Every little bit helps. + // Paypal: meikeric {at] gmail [dot} com + + ?> + <?php $iCount = count($images); ?> + <script language="JavaScript" type="text/javascript"> + //for image viewer slide show + + myCount = 0; + + function UpdateCounter( currentCount ) + { + myCount = currentCount; + } + + function loadImgArray( strList ){ + myImgList = strList.split(","); + } + function NextSlideShow( maxCount ){ + if(myCount >= maxCount){ + myCount = 0; + }else{ + myCount++; + } + //alert( myImgList[myCount] ); + show('MainPhoto',myImgList[myCount]); + } + function PrevSlideShow( maxCount ){ + if(myCount <= 0){ + myCount = maxCount; + }else{ + myCount--; + } + //alert( myImgList[myCount] ); + show('MainPhoto',myImgList[myCount]); + } + + function fillLabel(inField,inValue){ + if(inValue == ''){ + inValue = myCount + 1; + } + if(document.layers) //NN4+ + { + document.layers[inField].innerHTML = inValue; + } + else if(document.getElementById) //gecko(NN6) + IE 5+ + { + var obj = document.getElementById(inField); + obj.innerHTML = inValue; + } + else if(document.all) // IE 4 + { + document.all[inField].innerHTML = inValue; + } + } + + function show(name,src) { + if (document.images) + document.images[name].src = src; + } + </script> + + + <div id="hp_view_standard_photo_con1"> + <a href='javascript:NextSlideShow( <?php echo $iCount-1; ?>);'><img src='<?php echo $mosConfig_live_site.$hp_imgdir_standard.$images[0]->standard; ?>' name='MainPhoto' alt='Click here to view the next image' border='0' class='search01'/></a> + <br/> + <?php if (!$pop) { ?> + <a href='javascript:PrevSlideShow( <?php echo $iCount-1; ?> );'>< <?php echo _CMN_PREV;?></a> + <a href='javascript:NextSlideShow( <?php echo $iCount-1; ?> );'><?php echo _CMN_NEXT;?> ></a> + <?php } ?> + + <script language='Javascript' type="text/javascript"> + loadImgArray( '<?php + $i = 1; + foreach($images AS $image) { + echo $mosConfig_live_site.$hp_imgdir_standard.$image->standard; + if($iCount > 1 && $i != $iCount) { + echo ','; + } + $i++; + } + ?>' ); + </script> + </div> + + <?php foreach($prop AS $p) { + ?> +<?php + /* Escupe los campos de manera poco flexible pero práctica (igual que en listado) */ + + echo '<div id="datos_inmueble">'; + + + // Name (Titulo) + echo '<div id="titulo_inmueble">'.$p->name.'.</div>'; + + // Referencia propia + echo '<div class="linea_inmueble">'; + echo '<span class="hp_caption"> ⺠'._OFER_REF."</span>: "; + if ($p->id <> "") echo $p->id.".<br />"; else echo _OFER_NO_DEF; + echo '</div>'; + + + // Type (Tipo de oferta) + echo '<div class="linea_inmueble">'; + if (!$caption['type']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['type']->caption."</span>: "; + echo $p->type.".<br/>"; + echo '</div>'; + + // Tipo_Alojamiento + echo '<div class="linea_inmueble">'; + if (!$caption['Tipo_Alojamiento']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Tipo_Alojamiento']->caption."</span>: "; + if ($p->Tipo_Alojamiento<>"") echo $p->Tipo_Alojamiento.".<br/>"; else echo _OFER_NO_DEF; + echo '</div>'; + + // Address y postcode (Dirección y CP) + echo '<div class="linea_inmueble">'; + if (!$caption['address']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['address']->caption."</span>: "; + if ($p->address<>"") echo $p->address." ".$p->postcode."<br/>"; else echo _OFER_NO_DEF; + echo '</div>'; + + + // Barrio + if ( $p->Barrio <> "") + { + echo '<div class="linea_inmueble">'; + if (!$caption['Barrio']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Barrio']->caption."</span>: "; + echo $p->Barrio; + echo '</div>'; + } + + // Suburb y State (Población y Provincia) + echo '<div class="linea_inmueble">'; + if (!$caption['suburb']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['suburb']->caption."</span>: "; + if ($p->suburb<>"") echo $p->suburb." (".$p->state.")"."<br/>"; else echo _OFER_NO_DEF; + echo '</div>'; + + // Precio + if ($p->typeid == 2) // Venta + { + echo '<div class="linea_inmueble">'; + if (!$caption['price']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['price']->caption."</span>: "; + if ($p->price<>"") echo number_format($p->price,2,',','.')." ".$caption['price']->append_text."<br />"; else echo _OFER_NO_DEF; + echo '</div>'; + } + + + // Num_plazas + if ($p->typeid == 1) // Alquiler + { + echo '<div class="linea_inmueble">'; + if (!$caption['Num_plazas']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Num_plazas']->caption."</span>: "; + if ($p->Num_plazas<>"") echo $p->Num_plazas.".<br />"; else echo _OFER_NO_DEF; + echo '</div>'; + } + + // Numero_dormitorios + echo '<div class="linea_inmueble">'; + if ($p->typeid == 1) // Alquiler + { + if (!$caption['Numero_dormitorios']->hideCaption) + { + echo '<span class="hp_caption"> ⺠'.$caption['Numero_dormitorios']->caption."</span>: "; + } + } + else + echo '<span class="hp_caption"> ⺠Nº habitaciones: </span>'; + + if ($p->Numero_dormitorios<>"") echo $p->Numero_dormitorios.".<br />"; else echo _OFER_NO_DEF; + echo '</div>'; + + + // Cuartos_banio_con_duchas + echo '<div class="linea_inmueble">'; + if (!$caption['Cuartos_banio_con_duchas']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Cuartos_banio_con_duchas']->caption."</span>: "; + if ($p->Cuartos_banio_con_duchas<>"") echo $p->Cuartos_banio_con_duchas.". "; else echo _OFER_NO_DEF." "; + + // Aseos + if ($p->Aseos <> "") + { + if (!$caption['Aseos']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Aseos']->caption."</span>: "; + if ($p->Aseos<>"") echo $p->Aseos.".<br />"; else echo _OFER_NO_DEF; + } + echo '</div>'; + + // Dispone + echo '<div class="linea_inmueble">'; + if (!$caption['Dispone']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Dispone']->caption."</span>: "; + if ($p->Dispone<>"") echo str_replace("|",", ",$p->Dispone).".<br />"; else echo _OFER_NO_DEF; + echo '</div>'; ?> + + </div> <!-- fin capa datos_inmueble --> + + <div class="hp_view_details"> + <div id="mas_datos"> + <div class="titulito_inmueble">CaracterÃsticas del inmueble</div> + <?php + // Año Construcción + if ($p->typeid == 2) // Venta + { + echo '<div class="linea_inmueble">'; + if (!$caption['AnioConstruccion']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['AnioConstruccion']->caption."</span>: "; + if ($p->AnioConstruccion <> "") echo $p->AnioConstruccion.". "; else echo _OFER_NO_DEF; + if (!$caption['UltimaReforma']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['UltimaReforma']->caption."</span>: "; + if ($p->UltimaReforma <> "") echo $p->UltimaReforma.". "; else echo _OFER_NO_DEF; + echo '</div>'; + } + + // Metros construidos + echo '<div class="linea_inmueble">'; + if ($p->typeid == 2) // Venta + { + if (!$caption['MetrosConstruidos']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['MetrosConstruidos']->caption."</span>: "; + if ($p->MetrosConstruidos <> "") echo $p->MetrosConstruidos." ".$caption['Superficie_habitable']->append_text.". "; else echo _OFER_NO_DEF; + } + + if (!$caption['Superficie_habitable']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Superficie_habitable']->caption."</span>: "; + echo $p->Superficie_habitable." ".$caption['Superficie_habitable']->append_text.". "; + + // Superficie_parcela + if ($p->Superficie_parcela <> "") + { + if (!$caption['Superficie_parcela']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Superficie_parcela']->caption."</span>: "; + echo $p->Superficie_parcela." ".$caption['Superficie_parcela']->append_text."."; + } + echo "<br />"; + echo '</div>'; + + + if ($p->Camas_dobles <> 0 || $p->Camas_individuales <> 0 || $p->Camas_supletorias <> 0 || $p->Camas_litera <> 0) + echo '<div class="linea_inmueble">'; + + + if ($p->typeid == 1) // Alquiler + { + // Camas_dobles + if ($p->Camas_dobles <> 0) + { + if (!$caption['Camas_dobles']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Camas_dobles']->caption."</span>: "; + echo $p->Camas_dobles.". "; + } + + // Camas_individuales + if ($p->Camas_individuales <> 0) + { + if (!$caption['Camas_individuales']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Camas_individuales']->caption."</span>: "; + echo $p->Camas_individuales.". "; + } + + // Camas_supletorias + if ($p->Camas_supletorias <> 0) + { + if (!$caption['Camas_supletorias']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Camas_supletorias']->caption."</span>: "; + echo $p->Camas_supletorias.". "; + } + + // Camas_litera + if ($p->Camas_litera <> 0) + { + if (!$caption['Camas_litera']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Camas_litera']->caption."</span>: "; + echo $p->Camas_litera.". "; + } + if ($p->Camas_dobles <> 0 || $p->Camas_individuales <> 0 || $p->Camas_supletorias <> 0 || $p->Camas_litera <> 0) + { + echo "<br/>"; + echo "</div>"; + } + + // Sofa_cama_individual + if ($p->Sofa_cama_individual<>"" && $p->Sofa_cama_individual<>"") + { + echo '<div class="linea_inmueble">'; + // Sofa_cama_individual + if ( $p->Sofa_cama_individual <> "") + { + if (!$caption['Sofa_cama_individual']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Sofa_cama_individual']->caption."</span>: "; + echo $p->Sofa_cama_individual.". "; + } + + // Sofa_cama_doble + if ( $p->Sofa_cama_doble <> "") + { + if (!$caption['Sofa_cama_doble']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Sofa_cama_doble']->caption."</span>: "; + echo $p->Sofa_cama_doble.". "; + } + echo "</div>"; + } + + // Superficie_terraza_solarium + if ($p->Superficie_terraza_solarium <> "") + { + echo '<div class="linea_inmueble">'; + if (!$caption['Superficie_terraza_solarium']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Superficie_terraza_solarium']->caption."</span>: "; + echo $p->Superficie_terraza_solarium." ".$caption['Superficie_terraza_solarium']->append_text.".<br />"; + echo "</div>"; + } + } + // Enseres + echo '<div class="linea_inmueble">'; + if (!$caption['Enseres']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Enseres']->caption."</span>: "; + echo str_replace("|",", ",$p->Enseres).".<br />"; + echo '</div>'; + + // Animales + if ($p->typeid == 1) // Alquiler + { + echo '<div class="linea_inmueble">'; + if (!$caption['Animales']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Animales']->caption."</span>: "; + echo $p->Animales.".<br />"; + echo '</div>'; + } + + + // *** CaracterÃsticas de la zona ** + echo '<div class="titulito_inmueble">CaracterÃsticas de la zona</div>'; + + // Zona + echo '<div class="linea_inmueble">'; + if (!$caption['Zona']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Zona']->caption."</span>: "; + echo str_replace("|",", ",$p->Zona).".<br />"; + echo '</div>'; + + // ActividadesDeportivas + if ($p->typeid == 1) // Alquiler + { + if($caption['ActividadesDeportivas'] != '') + { + echo '<div class="linea_inmueble">'; + if (!$caption['ActividadesDeportivas']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['ActividadesDeportivas']->caption."</span>: "; + echo str_replace("|",", ",$p->ActividadesDeportivas).".<br />"; + echo '</div>'; + } + } + + // Distancia_a_la_playa + echo '<div class="linea_inmueble">'; + if ($p->Distancia_a_la_playa <> "") + { + if (!$caption['Distancia_a_la_playa']->hideCaption) + echo '<span class="hp_caption"> ⺠'.$caption['Distancia_a_la_playa']->caption."</span>: "; + echo $p->Distancia_a_la_playa." ".$caption['Distancia_a_la_playa']->append_text.".<br />"; + } + echo '</div>'; + + if ($p->A_minutos_andando <> "") + { + echo '<div class="linea_inmueble">'; + echo '<span class="hp_caption">'; + if (!$caption['A_minutos_andando']->hideCaption) + echo ' ⺠'.$caption['A_minutos_andando']->caption.' '; + echo $p->A_minutos_andando." ".$caption['A_minutos_andando']->append_text." "; + if (!$caption['de_andando']->hideCaption) + echo ' '.$caption['de_andando']->caption.' '; + echo $p->de_andando.".</span><br />"; + echo '</div>'; + } + + if ($p->A_minutos_coche <> "") + { + echo '<div class="linea_inmueble">'; + echo '<span class="hp_caption">'; + if (!$caption['A_minutos_coche']->hideCaption) + echo ' ⺠'.$caption['A_minutos_coche']->caption.' '; + echo $p->A_minutos_coche." ".$caption['A_minutos_coche']->append_text." "; + if (!$caption['de_coche']->hideCaption) + echo ' '.$caption['de_coche']->caption.' '; + echo $p->de_coche.".</span><br />"; + echo '</div>'; + echo '<br/>'; + } + + // *** Descripción detallada *** + echo '<div class="titulito_inmueble">'.$caption['full_text']->caption.'</div>'; + echo '<div class="linea_inmueble">'; + echo '<div class="descripcion">'; + echo $p->full_text; + echo '</div>'; + echo '</div>'; + + // *** Disponibilidad *** + if ($p->typeid == 1 && $num_periodos > 0) // Alquiler + { + echo '<div class="titulito_inmueble">'.$caption['intro_text']->caption.'</div>'; + echo '<div class="linea_inmueble">'; ?> + <iframe src="index2.php?option=com_hp_avl&task=ext_show_year&lang=<?php echo $_GET['lang']?>&property_id=<?php echo $p->id; ?>" name="com_hp_avl" id="com_hp_avl" width="97%" height="<?php echo (($num_periodos * 20)+580); ?>" marginwidth="0" marginheight="0" align="top" scrolling="no" frameborder="0" hspace="0" vspace="0" background="white"></iframe> + <div id="combo_num_anios"> + <script language="javascript"> + function RecargaCalendario(id,alto,num_anios,lang,property_id) + { + iframe=document.getElementById(id); + + iframe.src="index2.php?option=com_hp_avl&task=ext_show_year&num_anios="+num_anios+"&lang=" +lang+"&property_id="+property_id; + if (num_anios > 1) + iframe.height=alto * 0.9 * num_anios; + else + iframe.height=alto; + } + </script> + <form action="" method="GET" name="calendarioForm"> + <p>Mostrar <select name="num_anios" size="1" onChange="RecargaCalendario('com_hp_avl',<?php echo (($num_periodos * 20)+580); ?>,this.value,'<?php echo mosGetParam( $_GET, 'lang',0);?>',<?php echo $p->id; ?>);"> + <option value="1" label="1" <?php if ($num_years==1) echo "selected"; ?>>1</option> + <option value="2" label="2" <?php if ($num_years==2) echo "selected"; ?>>2</option> + </select> + años. + <input type="hidden" name="option" value="<?php echo $option; ?>" /> + <input type="hidden" name="task" value="ext_show_year" /> + <input type="hidden" name="property_id" value="<?php echo $property_id; ?>" /> + </form> + </div> + </div> + </div> + <?php } + } ?> + <br class="clearboth" /> + + <?php if ($hp_show_agentdetails && $hp_use_companyagent) { ?> + <div id="hp_view_agent_title"><span class="flecha_big">⺠</span><?php echo _HP_VIEW_AGENT_TITLE; ?></div> + <div id="hp_view_agent_con"> + <?php hotproperty_HTML::show_AgentInfo($agent) ?> + </div> + <?php } ?> + <?php if ($hp_show_enquiryform && !$pop) { ?> + <br class="clearboth" /> + <div id="hp_view_agent_contact"><span class="flecha_big">⺠</span><?php echo _HP_VIEW_AGENT_CONTACT; ?></div> + <div id="hp_emailform_con"> + <?php hotproperty_HTML::show_EmailForm('property',$prop[0]->id,$prop[0]->name,$prop[0]->typeid); ?> + </div> + <?php } + if ($pop) { + ?> + <center><a href='javascript:window.close();'><span class="small"><?php echo _PROMPT_CLOSE;?></span></a></center> + <?php } ?> + </div> + <?php + } + + /*** + * Common Routine to display Agent's Info + **/ + function show_AgentInfo($agent) { + global $mosConfig_live_site, $hp_imgdir_agent, $task, $Itemid, $my; + + if (empty($agent)) { + echo _HP_AGENT_ERROR_EMPTY; + } else { ?> + <script src="components/com_hotproperty/js/resalte.js" type="text/javascript"></script> + <div class="hp_view_agent"> + <div id="hp_view_agent_details"> + <?php if (!empty($agent->photo)) { ?> + <div id="hp_view_agent_photo"> + <?php if ($task <> "viewagent") { ?> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagent&id=$agent->id&Itemid=$Itemid"); ?>"> + <img border="0" src="<?php echo $mosConfig_live_site.$hp_imgdir_agent.$agent->photo; ?>" alt="<?php echo $agent->name; ?>" /> + </a> + <?php } else { ?> + <img border="0" src="<?php echo $mosConfig_live_site.$hp_imgdir_agent.$agent->photo; ?>" alt="<?php echo $agent->name; ?>" /> + <?php } ?> + </div> + <?php } ?> + <div class="obj_con_botonera"> + <div class="nombre_objeto"> + <span id="hp_caption_agentname"><?php if ($task <> "viewagent") { ?><a id="hp_caption_agentname" href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagent&id=$agent->id&Itemid=$Itemid"); ?>"><?php echo $agent->name; ?></a><?php } else { ?><?php echo $agent->name; ?><?php } ?></span> + </div> + <div class="botonera_dcha"> + <?php + # Muestra el icono para modificar el perfil si somos el usuario adecuado + if ($agent->user == $my->id && $agent->user > 0 && $my->id > 0) { ?> + <div class="mini_boton"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=editagent&Itemid=$Itemid"); ?>" title="<?= _HP_AGENT_MODIFY ?>"><img src="administrator/images/modif_perfil.png" alt="<?= _HP_AGENT_MODIFY ?>" title="<?= _HP_AGENT_MODIFY ?>" onmouseover="swap_resalte('modif_perfil',1);" onmouseout="swap_resalte('modif_perfil',0);" class="bot_gestionar" id="img_modif_perfil"/></a> + </div> + <div class="texto_mini_boton"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=editagent&Itemid=$Itemid"); ?>" title="<?= _HP_AGENT_MODIFY ?>" id="a_modif_perfil" onmouseover="swap_resalte('modif_perfil',1);" onmouseout="swap_resalte('modif_perfil',0);"> <?= _HP_AGENT_MODIFY ?> </a> + </div> + <?php } ?> + + <?php + # Muestra icono enviar email si estamos en viewagent|viewco y somos un usuario distinto + if( ($task == "viewagent" || $task == "viewco") && !empty($agent->email) && $agent->user != $my->id) { ; ?> + <div class="mini_boton"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagentemail&id=$agent->id&Itemid=$Itemid"); ?>"><img src="administrator/images/correo.png" alt="<?= _HP_AGENT_SENDEMAIL ?>" title="<?= _HP_AGENT_SENDEMAIL ?>" onmouseover="this.src='administrator/images/correo_on.png';swap_resalte('correo',1);" onmouseout="this.src='administrator/images/correo.png';swap_resalte('correo',0);" class="bot_gestionar" id="img_correo"/></a> + </div> + <div class="texto_mini_boton"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagentemail&id=$agent->id&Itemid=$Itemid"); ?>" id="a_correo" onmouseover="swap_resalte('correo',1);" onmouseout="swap_resalte('correo',0);"><?= _HP_AGENT_SENDEMAIL ?></a> + </div> + <?php } ?> + <?php + # Muestra enlace ver todas las ofertas si estamos en página detalle + if( $task == "view" ) { ?> + <div class="mini_boton"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagent&id=$agent->id&Itemid="); ?>"><img src="administrator/images/ver.png" alt="<?= _HP_VER_OFERTAS ?>" title="<?= _HP_VER_OFERTAS ?>" onmouseover="swap_resalte('ver',1);" onmouseout="swap_resalte('ver',0);" class="bot_gestionar" id="img_ver"/></a> + </div> + <div class="texto_mini_boton"> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagent&id=$agent->id&Itemid="); ?>" id="a_ver" onmouseover="swap_resalte('ver',1);" onmouseout="swap_resalte('ver',0);"><?= _HP_VER_OFERTAS ?></a> + </div> + <?php } ?> + + </div> + </div> + <br class="clearboth"/> + <br class="clearboth"/> + + <?php if (!empty($agent->desc)) { ?> + <div id="hp_view_agent_desc"><?php echo $agent->desc; ?></div> + <?php } ?> + + <?php + # Display Mobile number if not empty + if (!empty($agent->mobile)) { ?> + <span class="hp_caption"><?= _HP_AGENT_MOBILE; ?>:</span> <?= $agent->mobile; ?>.<br/> + <?php # Muestra disponibiblidad teléfono móvil + if (!empty($agent->disp_mov_from)) { ?> + <span class="hp_caption"><?= _HP_AGENT_DISP; ?></span> de <?= dia_semana($agent->disp_mov_from); ?> a <?= dia_semana($agent->disp_mov_to); ?> de <?= $agent->disp_mov_from_hora; ?> a <?= $agent->disp_mov_to_hora; ?>.<br/> + <?php } + } ?> <!-- fin movil --> + + <?php + # Muestra el teléfono fijo si existe + if (!empty($agent->fijo)) { ?> + <span class="hp_caption"><?php echo _HP_AGENT_PHONE; ?>:</span> <?php echo $agent->fijo; ?>. + <br/> + <?php + # Muestra disponibilidad teléfono fijo + if (!empty($agent->disp_fijo_from)) { ?> + <span class="hp_caption"><?= _HP_AGENT_DISP ?></span> de <?= dia_semana($agent->disp_fijo_from); ?> a <?= dia_semana($agent->disp_fijo_to); ?> de <?= $agent->disp_fijo_from_hora; ?> a <?= $agent->disp_fijo_to_hora; ?>.<br /> + <?php } ?> <!-- fin disponibilidad --> + + <?php } ?> <!-- fin fijo --> + + <?php + # Muestra los idiomas hablados si no está vacÃo + if (!empty($agent->idiomas_hablados)) { ?> + <span class="hp_caption"><?php echo _HP_AGENT_IDIOMAS; ?>:</span> <?= str_replace("|",", ",$agent->idiomas_hablados) ?>. + <br /> + <?php } ?> + </div> + </div> + <?php + } // End If + } + + /*** + * Common Routine to display Company's Info + **/ + function show_CoInfo($companies, $agent) { + global $mosConfig_live_site, $hp_imgdir_company, $task, $Itemid, $my; + + foreach($companies AS $co) { + ?> + <div class="hp_view_co"> + <?php if (!empty($co->photo)) { ?> + <div id="hp_view_co_photo"><img src="<?php echo $mosConfig_live_site.$hp_imgdir_company.$co->photo; ?>" alt="<?php echo $co->name; ?>" /></div> + <?php } ?> + <div class="obj_con_botonera"> + <div class="nombre_objeto_corto"> + <div id="hp_view_co_details"> + <span id="hp_caption_coname"> + <?php if ($task <> "viewco") { ?><a id="hp_caption_coname" href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewco&id=$co->id&Itemid=$Itemid"); ?>"><?php echo $co->name; ?></a><?php } else { + echo $co->name; + } ?></span> + </div> + <br/> + <div id="hp_co_addr"> + <?php + if (trim($co->address)!="") { + echo "$co->address <br />"; + } + if ((trim($co->suburb)!="") && (trim($co->state)!="") && (trim($co->postcode)!="")) { + echo "$co->suburb, $co->state, $co->postcode <br />"; + } elseif ((trim($co->suburb)!="") && (trim($co->state)!="")) { + echo "$co->suburb, $co->state <br />"; + } elseif ((trim($co->suburb)!="") && (trim($co->postcode)!="")) { + echo "$co->suburb, $co->postcode <br />"; + } elseif ((trim($co->state)!="") && (trim($co->postcode)!="")) { + echo "$co->state, $co->postcode <br />"; + } elseif ((trim($co->state)!="")) { + echo "$co->state <br />"; + } elseif ((trim($co->suburb)!="")) { + echo "$co->suburb <br />"; + } elseif ((trim($co->postcode)!="")) { + echo "$co->postcode <br />"; + } + if (trim($co->country)!="") { + echo "$co->country <br />"; + } + ?></div> + </div> + <div class="botonera_dcha"> + <?php + # Show an edit icon to allow user to edit their own profile + if ($agent->user == $my->id && $agent->user > 0 && $my->id > 0) { ?> + + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=editagent&Itemid=$Itemid"); ?>" title="<?= _HP_AGENT_MODIFY ?>"><img src="administrator/images/editar.png" alt="<?= _HP_AGENT_MODIFY ?>" title="<?= _HP_AGENT_MODIFY ?>" onmouseover="this.src='administrator/images/editar_on.png';" onmouseout="this.src='administrator/images/editar.png'" class="bot_gestionar"/></a> + <?php } ?> + + <?php + # Display "Send email link" if user at viewagent or viewco + if( ($task == "viewagent" || $task == "viewco") && !empty($agent->email) ) { ; ?> + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagentemail&id=$agent->id&Itemid=$Itemid"); ?>"><img src="administrator/images/correo.png" alt="<?= _HP_AGENT_SENDEMAIL ?>" title="<?= _HP_AGENT_SENDEMAIL ?>" onmouseover="this.src='administrator/images/correo_on.png';" onmouseout="this.src='administrator/images/correo.png'" class="bot_gestionar"/></a><br /> + <?php } ?> + </div> <!-- FIN div.botonera_dcha --> + </div> <!-- FIN div.obj_con_botonera --> + + <br class="clearboth"/> + <div id="hp_view_co_other_data"> + <br/> + + <!-- Teléfono fijo --> + <?php if (!empty($co->telephone)) { ?> + <span class="hp_caption"><?php echo _HP_CONTACTNUMBER; ?>: </span><?php echo $co->telephone; ?>. + <br/> + <?php + # Muestra disponibilidad teléfono fijo + if (!empty($co->disp_fijo_from)) { ?> + <span class="hp_caption"><?= _HP_AGENT_DISP ?></span> <?= dia_semana($co->disp_fijo_from); ?> a <?= dia_semana($co->disp_fijo_to); ?> de <?= $co->disp_fijo_from_hora; ?> a <?= $co->disp_fijo_to_hora; ?>.<br /> + <?php } ?> <!-- fin disponibilidad --> + <?php }?> <!-- fin teléfono fijo --> + + <!-- Teléfono móvil --> + <?php if (!empty($co->mobile)) { ?> + <span class="hp_caption"><?php echo _HP_AGENT_MOBILE; ?>: </span><?php echo $co->mobile; ?><br /> + <?php + # Muestra disponibilidad teléfono móvil + if (!empty($co->disp_mov_from)) { ?> + <span class="hp_caption"><?= _HP_AGENT_DISP ?></span> <?= dia_semana($co->disp_mov_from); ?> a <?= dia_semana($co->disp_mov_to); ?> de <?= $co->disp_mov_from_hora; ?> a <?= $co->disp_mov_to_hora; ?>.<br /> + <?php } ?> <!-- fin disponibilidad --> + <?php }?> <!-- fin teléfono móvil --> + + <?php if (!empty($co->website)) { ?> + <span class="hp_caption"><?php echo _HP_CO_WEBSITE; ?> </span><a href="<?php echo $co->website; ?>" target="_blank"><?php echo $co->website; ?></a><br /> + <?php }?> + <?php if (!empty($co->desc)) { ?> + <p /> + <?php echo $co->desc; ?> + <?php } ?> + </div> + <?php + # Muestra los idiomas hablados si no está vacÃo + if (!empty($co->idiomas_hablados)) { ?> + <span class="hp_caption"><?php echo _HP_AGENT_IDIOMAS; ?>:</span> <?= str_replace("|",", ",$co->idiomas_hablados) ?>. + <br/> + <?php } ?> + + </div> + <br class="clearboth" /> + <?php + } + } + + /*** + * Display Email form + ***/ + function show_EmailForm($subject, $id, $titulo=null, $tipo_oferta=null) { + global $Itemid; + + if ($subject <> "agent" && $subject <> "property" && $subject <> "company") return false; + ?> + <form method="POST" action="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=sendenquiry&id=".$id."&Itemid=".$Itemid); ?>"> + <input type="hidden" name="titulo" value="<?= $titulo ?>"> + <input type="hidden" name="tipo_oferta" value="<?= $tipo_oferta ?>"> + + <div class="cont_form"><div class="agent_text"><?php echo _CMN_NAME; ?>*:</div> + <input type="text" class="inputbox" name="hp_name" size="24" /></div> + + <div class="cont_form"><div class="agent_text"><?php echo _CMN_EMAIL; ?>*:</div> + <input type="text" class="inputbox" name="hp_email" size="30" /></div> + + <div class="cont_form"><div class="agent_text"><?php echo _HP_CONTACTNUMBER; ?>*:</div> + <input type="text" class="inputbox" name="hp_contactnumber" size="30" /></div> + + <div class="cont_form "> + <span class="agent_text"><?= _HP_AGENT_DISP ?><?= _HP_AGENT_DISP_DE ?></span> + <select name="disp_mov_from" class="inputbox"> + <?php $valor=$row->disp_mov_from; ?> + <option value='0'><?= _HP_DIA; ?></option> + <option value ='1'><?= _HP_L; ?></option> + <option value ='2'><?= _HP_M; ?></option> + <option value ='3'><?= _HP_X; ?></option> + <option value ='4'><?= _HP_J; ?></option> + <option value ='5'><?= _HP_V; ?></option> + <option value ='6'><?= _HP_S; ?></option> + <option value ='7'><?= _HP_D; ?></option> + </select> + <?= _HP_AGENT_DISP_A ?> + <select name="disp_mov_to" class="inputbox"> + <?php $valor=$row->disp_mov_to; ?> + <option value='0'><?php echo _HP_DIA; ?></option> + <option value ='1'><?php echo _HP_L; ?></option> + <option value ='2'><?php echo _HP_M; ?></option> + <option value ='3'><?php echo _HP_X; ?></option> + <option value ='4'><?php echo _HP_J; ?></option> + <option value ='5'><?php echo _HP_V; ?></option> + <option value ='6'><?php echo _HP_S; ?></option> + <option value ='7'><?php echo _HP_D; ?></option> + </select> + <?= _HP_AGENT_DISP_DE ?> + <select name="disp_mov_from_hora" class="inputbox"> + <?php $valor=$row->disp_mov_from_hora; ?> + <option value='0' ><?= _HP_HORA ?></option> + <option value ='06:00'>06:00</option> + <option value ='07:00'>07:00</option> + <option value ='08:00'>08:00</option> + <option value ='09:00'>09:00</option> + <option value ='10:00'>10:00</option> + <option value ='11:00'>11:00</option> + <option value ='12:00'>12:00</option> + <option value ='13:00'>13:00</option> + <option value ='14:00'>14:00</option> + <option value ='15:00'>15:00</option> + <option value ='16:00'>16:00</option> + <option value ='17:00'>17:00</option> + <option value ='18:00'>18:00</option> + <option value ='19:00'>19:00</option> + <option value ='20:00'>20:00</option> + <option value ='21:00'>21:00</option> + <option value ='22:00'>22:00</option> + <option value ='23:00'>23:00</option> + <option value ='00:00'>00:00</option> + </select> + <?= _HP_AGENT_DISP_A ?> + <select name="disp_mov_to_hora" class="inputbox"> + <?php $valor=$row->disp_mov_to_hora; ?> + <option value='0' ><?= _HP_HORA ?></option> + <option value ='06:00'>06:00</option> + <option value ='07:00'>07:00</option> + <option value ='08:00'>08:00</option> + <option value ='09:00'>09:00</option> + <option value ='10:00'>10:00</option> + <option value ='11:00'>11:00</option> + <option value ='12:00'>12:00</option> + <option value ='13:00'>13:00</option> + <option value ='14:00'>14:00</option> + <option value ='15:00'>15:00</option> + <option value ='16:00'>16:00</option> + <option value ='17:00'>17:00</option> + <option value ='18:00'>18:00</option> + <option value ='19:00'>19:00</option> + <option value ='20:00'>20:00</option> + <option value ='21:00'>21:00</option> + <option value ='22:00'>22:00</option> + <option value ='23:00'>23:00</option> + <option value ='00:00'>00:00</option> + </select> + </div> + + + <div class="cont_form"><div class="agent_text"><?php echo _HP_SPOKEN_LANG; ?>:</div> + <?php + + $idiomas = explode("|",_HP_IDIOMAS); + $hablados = explode("|",$row->idiomas_hablados); + + foreach($hablados as $hablado) + $idiomas_hablados[$hablado]=true; + + + foreach($idiomas as $idioma) { ?> + <input type='checkbox' value='<?= $idioma ?>' name='habla[]'/><?= $idioma ?> + <?php } ?> + </div> + + + <?php if ( $tipo_oferta==1 ) /* Alquiler */ { ?> + <div class="cont_form"><div class="agent_text"><?php echo _HP_DIA_LLEGADA ?>:</div> + <input class="inputbox" type="text" name="dia_llegada" size="10" maxlength="10"> + </div> + <div class="cont_form"><div class="agent_text"><?php echo _HP_DIA_SALIDA ?>:</div> + <input class="inputbox" type="text" name="dia_salida" size="10" maxlength="10"> + </div> + <?php } ?> + + <div class="cont_form"><div class="agent_text"><?php echo _ENQUIRY; ?>*:</div> + <textarea rows="4" cols="40" class="inputbox" name="hp_enquiry"></textarea> + <br/> + <input type="hidden" name="sbj" value="<?php echo $subject; ?>" /> + <input class="button" type="submit" value="<?php echo _HP_SENDENQUIRY; ?>" /></div> + + </form> + <?php + } + + function sendEmailForm($id, $title) { + global $mosConfig_sitename; +?> +<script language="javascript" type="text/javascript"> + function submitbutton() { + var form = document.frontendForm; + + // do field validation + if (form.email.value == "" || form.youremail.value == "") { + alert( '<?php echo addslashes( _EMAIL_ERR_NOINFO ); ?>' ); + return false; + } + return true; + } + function textCounter(field, maxlimit) { + if (field.value.length > maxlimit) // if too long...trim it! + field.value = field.value.substring(0, maxlimit); + } + </script> +<title><?php echo $mosConfig_sitename; ?> :: <?php echo $title; ?></title> +<body class="contentpane"> +<form action="index2.php?option=com_hotproperty&task=emailsend" name="frontendForm" method="POST" onSubmit="return submitbutton();"> + <br/> + <div class="titulo"><span class="flecha_big">⺠</span><?php echo _EMAIL_FRIEND; ?></div> + <br/> + <div class="cont_form"> + <div class="agent_text"><?php echo _EMAIL_FRIEND_ADDR; ?></div> + <input type="text" name="email" class="inputbox" size="25"> + </div> + <div class="cont_form"> + <div class="agent_text"><?php echo _EMAIL_YOUR_NAME; ?></div> + <input type="text" name="yourname" class="inputbox" size="25"> + </div> + <div class="cont_form"> + <div class="agent_text"><?php echo _EMAIL_YOUR_MAIL; ?></div> + <input type="text" name="youremail" class="inputbox" size="25"> + </div> + <div class="cont_form"> + <div class="agent_text"><?php echo _EMAIL_YOUR_MESS; ?></div> + <textarea name="yourmess" class="inputbox" cols="23" rows="4" onkeydown="textCounter(this.form.yourmess, 250);" onkeyup="textCounter(this.form.yourmess, 250);"></textarea> + </div> + <br/> + <div class="centro"> + <input type="submit" name="submit" class="button" value="<?php echo _BUTTON_SUBMIT_MAIL; ?>"> + <input type="button" name="cancel" value="<?php echo _BUTTON_CANCEL; ?>" class="button" onClick="window.close();"></td> + </div> + <input type="hidden" name="id" value="<?php echo $id; ?>"> +</form> +<?php + } + + function emailSent( $to ) { + global $mosConfig_sitename; +?> +<br /> +<?php echo _EMAIL_SENT; ?> +<br /> +<br /> +<?php if (!$hide_js) { php?> + <a href='javascript:window.close();'> + <span class="small"><?php echo _PROMPT_CLOSE;?></span> + </a> +<?php + } + } + /*** + * Common Routine to display properties + ***/ + function list_properties(&$prop, &$caption) { + global $Itemid, $task, $my, $mosConfig_live_site, $mosConfig_absolute_path; + global $hp_imgdir_thumb, $hp_currency, $hp_imgsize_thumb, $hp_img_noimage_thumb, $hp_thousand_sep, $hp_dec_point, $hp_link_open_newwin, $hp_show_thumb, $hp_dec_string, $hp_thousand_string; + + if(empty($prop)) { + ?> + <div id="hp_error_empty"> + <?php echo _HP_PROP_ERROR_EMPTY; ?> + </div> + <?php + } else { + foreach($prop AS $p) { + if ($p->thumb <> '') { + $thumb_imgsize = GetImageSize ($mosConfig_absolute_path.$hp_imgdir_thumb.$p->thumb); + } else { + $thumb_imgsize = GetImageSize ($mosConfig_absolute_path.$hp_imgdir_thumb.$hp_img_noimage_thumb); + } + ?> + <div class="hp_prop"> + <div class="hp_details"> + <?php if ($hp_show_thumb) { ?> + <div class="img_thumb"><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=view&id=$p->id&Itemid=$Itemid"); ?>"><img <?php echo $thumb_imgsize[3]; ?> border="0" src="<?php + if ($p->thumb <> '') echo $mosConfig_live_site.$hp_imgdir_thumb.$p->thumb; + else echo $mosConfig_live_site.$hp_imgdir_thumb.$hp_img_noimage_thumb; + ?>" alt="<?php echo $p->thumb_title ?>" /></a></div> + <?php } ?> + <div class="datos_oferta"> + <div class="nombre_objeto"> + <a class="hp_title" href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=view&id=$p->id&Itemid=$Itemid"); ?>"><?php echo $p->name; ?></a> + </div> + <div class="botonera_dcha"> + <?php + # Show an edit icon to allow user to edit the property + if ($p->user == $my->id && $p->user > 0 && $my->id > 0) { ?> + + <a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=editprop&id=$p->id&Itemid=$Itemid"); ?>" title="<?php echo _E_EDIT; ?>"><img src="administrator/images/editar.png" alt="<?= _E_EDIT ?>" title="<?= _E_EDIT ?>" onmouseover="this.src='administrator/images/editar_on.png';" onmouseout="this.src='administrator/images/editar.png'" class="bot_gestionar"/></a> + <?php } + ?> + </div> + <br class="clearboth"/> + <?php + /* Escupe los campos de manera poco flexible pero práctica */ + echo '<div class="columna_listado_izq">'; + // Población + if (!$caption['suburb']->hideCaption) + echo '<span class="hp_caption">'.$caption['suburb']->caption."</span>: "; + echo $p->suburb.".<br />"; + // Provincia + if (!$caption['state']->hideCaption) + echo '<span class="hp_caption">'.$caption['state']->caption."</span>: "; + echo $p->state.".<br />"; + + // Barrio + if (!$p->Barrio=="") + { + if (!$caption['Barrio']->hideCaption) + + echo '<span class="hp_caption">'.$caption['Barrio']->caption."</span>: "; + echo $p->Barrio.".<br />"; + } + + + // Nº plazas + if ($p->typeid == 1 && $p->Num_plazas != "") + { + if (!$caption['Num_plazas']->hideCaption) + echo '<span class="hp_caption">'.$caption['Num_plazas']->caption."</span>: "; + echo $p->Num_plazas.".<br />"; + } + + // Metros construidos + if ($p->MetrosConstruidos != "") // Venta + { + if (!$caption['MetrosConstruidos']->hideCaption) + echo '<span class="hp_caption">'.$caption['MetrosConstruidos']->caption."</span>: "; + echo $p->MetrosConstruidos." ".$caption['MetrosConstruidos']->append_text.".<br />"; + } + + // Año construccion + if ($p->AnioConstruccion != "") // Venta + { + if (!$caption['AnioConstruccion']->hideCaption) + echo '<span class="hp_caption">'.$caption['AnioConstruccion']->caption."</span>: "; + echo $p->AnioConstruccion."<br />"; + } + + // Número de dormitorios + if ($p->Numero_dormitorios != "") // Alquiler + { + if (!$caption['Numero_dormitorios']->hideCaption) + echo '<span class="hp_caption">'.$caption['Numero_dormitorios']->caption."</span>: "; + echo $p->Numero_dormitorios.".<br/>"; + } + + // Precio + if ($p->price != "0") // Venta + { + if (!$caption['price']->hideCaption) + echo '<span class="hp_caption">'.$caption['price']->caption."</span>: "; + echo number_format($p->price,2,',','.')." ".$caption['price']->append_text."<br/>"; + } + + echo '</div>'; + + echo '<div class="columna_listado_dcha">'; + // Cuartos de baño + if (!$caption['Cuartos_banio_con_duchas']->hideCaption) + echo '<span class="hp_caption">'.$caption['Cuartos_banio_con_duchas']->caption."</span>: "; + if ($p->Cuartos_banio_con_duchas <> "") + echo $p->Cuartos_banio_con_duchas.". "; + else + echo _OFER_NINGUNO." "; + // Aseos + if (!$caption['Aseos']->hideCaption) + echo '<span class="hp_caption">'.$caption['Aseos']->caption."</span>: "; + + if ($p->Aseos <> "") + echo $p->Aseos.".<br />"; + else + echo _OFER_NINGUNO."<br />"; + // Dispone + if (!$caption['Dispone']->hideCaption) + echo '<span class="hp_caption">'.$caption['Dispone']->caption."</span>: "; + + echo str_replace("|",", ",$p->Dispone).".<br />"; + echo '</div>'; + ?> + <?php + echo '<br class="clearboth">'; + // Resumen + # echo $p->Resumen."<br/><br/>"; + + + /* Antiguo código que escupÃÂa los campos */ + /*foreach($p as $key => $value) { + if ( array_key_exists($key,$caption) && ($caption[$key]->name <> 'name' && $caption[$key]->name <> 'thumb' && $caption[$key]->name <> 'thumb_title' && $caption[$key]->name <> '' && $value <> "") ) + # Replace '|' with a comma for checkbox and select multiple fields + if ($caption[$key]->field_type == "checkbox" || $caption[$key]->field_type == "selectmultiple") { + if (!$caption[$key]->hideCaption) echo '<span class="hp_caption">'.$caption[$key]->caption."</span>: "; + echo str_replace("|",", ",$value).".<br />"; + # Web Link + } elseif ($caption[$key]->field_type == "link") { + + // Evaluate mambot style data + $value = str_replace( '{property_id}', $p->id, $value ); + $value = str_replace( '{type_id}', $p->typeid, $value ); + $value = str_replace( '{agent_id}', $p->agentid, $value ); + $value = str_replace( '{company_id}', $p->companyid, $value ); + $value = str_replace( '{Itemid}', $Itemid, $value ); + + if (!$caption[$key]->hideCaption) { + ?><span class="hp_caption"><?php echo $caption[$key]->caption; ?></span>: <?php } + echo $caption[$key]->prefix_text; + $link = explode("|",$value); + if (count($link) == 1 && ( substr(trim($link[0]),0,4) == "http" || substr(trim($link[0]),0,5) == "index" ) ) { + ?><a <?php echo ($hp_link_open_newwin) ? 'target="_blank" ': ''; ?>href="<?php echo $link[0]; ?>"><?php echo $link[0]; ?></a><?php + } elseif (count($link) > 1 && ( substr(trim($link[1]),0,4) == "http" || substr(trim($link[1]),0,5) == "index" ) ) { + ?><a <?php echo ($hp_link_open_newwin) ? 'target="_blank" ': ''; ?>href="<?php echo $link[1]; ?>"><?php echo $link[0]; ?></a><?php + } else { + echo $value; + } + echo $caption[$key]->prefix_text."<br />"; + + } else { + # Do not display agent field when viewing agent's properties + # Do not display type field when viewing type's properties + if ( !($key == "agent" && $task == "viewagent") && !($key =="type" && $task == "viewtype") ) { + # Show agent link + if ($key == "agent") { + if (!$caption[$key]->hideCaption) { + ?><span class="hp_caption"><?php echo $caption[$key]->caption; ?></span>: <?php + } + ?><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewagent&id=$p->agentid&Itemid=$Itemid"); ?>"><?php echo $caption[$key]->prefix_text.$value.$caption[$key]->append_text; ?></a><br /><?php + # Show company link + } elseif ($key == "company") { + if (!$caption[$key]->hideCaption) { + ?><span class="hp_caption"><?php echo $caption[$key]->caption; ?></span>: <?php } + ?><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewco&id=".$p->companyid."&Itemid=$Itemid"); ?>"> <?php echo $caption[$key]->prefix_text.$value.$caption[$key]->append_text; ?></a><br /> <?php + # Show type link + } elseif ($key == "type") { + if (!$caption[$key]->hideCaption) { + ?><span class="hp_caption"><?php echo $caption[$key]->caption; ?></span>: <?php } + ?><a href="<?php echo sefRelToAbs("index.php?option=com_hotproperty&task=viewtype&id=".$p->typeid."&Itemid=$Itemid"); ?>"> <?php echo $caption[$key]->prefix_text.$value.$caption[$key]->append_text; ?></a><br /> <?php + # Show Price with proper formating + } elseif ($key == "price") { + if (!$caption[$key]->hideCaption) { + ?><span class="hp_caption"><?php echo $caption[$key]->caption; ?></span>:<?php } + ?><span class="hp_price"><?php echo $caption[$key]->prefix_text.$hp_currency." ".number_format($value, $hp_dec_point, $hp_dec_string, ($hp_thousand_sep) ? $hp_thousand_string:'').$caption[$key]->append_text; ?></span><br /> <?php + # Show Featured as Yes/No instead of 1/0 + } elseif ($key == "featured") { + if (!$caption[$key]->hideCaption) { + echo '<span class="hp_caption">'.$caption[$key]->caption."</span>: "; + } + echo $caption[$key]->prefix_text + . ( ($value == '1') ? _CMN_YES : _CMN_NO ) + . $caption[$key]->append_text + . "<br />"; + # Else, show normal 'caption: value' + } else { + if (!$caption[$key]->hideCaption) { + echo '<span class="hp_caption">'.$caption[$key]->caption."</span>: "; + } + echo $caption[$key]->prefix_text + . ( ($key=="price") ? $hp_currency." " : "" ) + . $value + . $caption[$key]->append_text + . "<br />"; + } + } + } + }*/ + + ?> + </div> + </div> + + </div> + <?php + } // End Foreach + } // End If + } + + function seleccion_fecha ( $name ) { + ?> + <?php + if ($name == "desde") + { + echo "<div class=\"titulo_fecha\">"._HPAVL_DESDE." </div>"; + } + else + { + echo "<div class=\"titulo_fecha\">"._HPAVL_HASTA." </div>"; + } + ?> + <!-- DÃa --> + <select size="1" name="<?php echo $name."_dia"; ?>" class="campo_fecha inputbox"> + <?php + for ($i=1; $i<=31; $i++) + echo "<option value='".$i."'>".$i."</option>"; + ?> + </select> + + <!-- Mes --> + <select size="1" name="<?php echo $name."_mes"; ?>" class="campo_fecha inputbox"> + <?php + for ($i=1; $i<=12; $i++) + echo "<option value='".$i."'>".$i."</option>"; + ?> + </select> + <!-- Año --> + <select size="1" name="<?php echo $name."_año"; ?>" class="campo_fecha inputbox"> + <?php + $hoy=getdate(); + for ($i=$hoy['year']; $i<=2080; $i++) + echo "<option value='".$i."'>".$i."</option>"; + ?> + </select> + <br class="clearboth"/> + <?php + } + + + function show_ResumenTipos() { + global $database; + + # Select published types + $database->setQuery( "SELECT * FROM #__hp_prop_types AS t" + . "\nWHERE t.published='1'" + . "\nORDER BY t.ordering ASC"); + $types = $database->loadObjectList(); + + foreach($types AS $t) { ?> + <a href="<?php echo sefRelToAbs('index.php?option=com_hotproperty&task=viewtype&id='.$t->id.'&Itemid='.$Itemid); ?>"><?= $t->name ?> ( <?= getNumOfertas($t->id) ?>)</a> + <?php } + } + + function getNumOfertas($type_id) { + $database->setQuery( "SELECT id FROM #__hp_properties AS p" + . "\nWHERE p.type=".$type_id); + return $database->getNumRows(); + } +} + + +?> diff --git a/emacs/nxhtml/tests/in/zero-pi.html b/emacs/nxhtml/tests/in/zero-pi.html new file mode 100644 index 0000000..6bb247c --- /dev/null +++ b/emacs/nxhtml/tests/in/zero-pi.html @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title></title> + </head> + <body> +© <??> + </body> +</html> diff --git a/emacs/nxhtml/tests/in/zn-090529-doxysample.php b/emacs/nxhtml/tests/in/zn-090529-doxysample.php new file mode 100644 index 0000000..3eddd90 --- /dev/null +++ b/emacs/nxhtml/tests/in/zn-090529-doxysample.php @@ -0,0 +1,37 @@ +<?php +/** + * @file doxysample.php + * @author Zoltán Nagy <abesto0@gmail.com> + * @date Fri May 29 15:28:06 2009 + * + * @brief Example file commented with Doxygen (via doxymacs) + * + * Longer description of what this file is + * Possibly multiline + */ + + +/** + * Echos the parameter + * + * @param text Text to echo + * + * @return EOL message + */ +function say($text) +{ + echo $text; + return "I spoketh."; +} +?> + +<div> +This is HTML, so the following has no special meaning: +/** + * Fake comment + * + * @param whatever Foo + * + * @return bar + */ +</div> diff --git a/emacs/nxhtml/tests/inemacs/bug1013.el b/emacs/nxhtml/tests/inemacs/bug1013.el new file mode 100644 index 0000000..6b0aab2 --- /dev/null +++ b/emacs/nxhtml/tests/inemacs/bug1013.el @@ -0,0 +1,35 @@ +;; Setup +(defvar word-wrap2 nil) +(make-variable-buffer-local 'word-wrap2) +(set-default 'word-wrap2 nil) + +(defcustom word-wrap3 nil + "doc 3" + :type 'boolean) +(make-variable-buffer-local 'word-wrap3) +(set-default 'word-wrap3 nil) + +(set-default 'word-wrap nil) +(set-default 'truncate-lines nil) + +(put 'truncate-lines 'permanent-local t) +(put 'word-wrap 'permanent-local t) +(put 'word-wrap2 'permanent-local t) +(put 'word-wrap3 'permanent-local t) + +(setq truncate-lines t) +(setq word-wrap t) +(setq word-wrap2 t) +(setq word-wrap3 t) + +(kill-all-local-variables) + +;; Test +(ert-should (eq (default-value 'word-wrap3) nil)) +(ert-should (eq word-wrap3 t)) +(ert-should (eq (default-value 'word-wrap2) nil)) +(ert-should (eq word-wrap2 t)) +(ert-should (eq (default-value 'truncate-lines) nil)) +(ert-should (eq truncate-lines t)) +(ert-should (eq (default-value 'word-wrap) nil)) +(ert-should (eq word-wrap t)) diff --git a/emacs/nxhtml/tests/mumamo-test.el b/emacs/nxhtml/tests/mumamo-test.el new file mode 100644 index 0000000..ecbac10 --- /dev/null +++ b/emacs/nxhtml/tests/mumamo-test.el @@ -0,0 +1,299 @@ +;;; mumamo-test.el --- Test routines for mumamo +;; +;; Author: Lennart Borgman +;; Created: Sat Mar 31 03:59:26 2007 +;; Version: 0.1 +;; Last-Updated: +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file defines some test for mumamo.el and a the minor mode +;; `mumamu-test-mode' to bind the test functions to some keys for +;; convenient use. This will define F3 to run +;; `mumamo-test-create-chunk-at' and Shift-F3 to +;; `mumamo-test-create-chunks-at-all-points'. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;(eval-when-compile (require 'mumamo)) +(eval-when-compile (require 'mumamo)) +(require 'whelp) + +;;;;;;; TESTS, run in fundamental-mode buffer + +(defvar mumamo-test-mode-keymap + (let ((map (make-sparse-keymap))) + (define-key map [f11] 'goto-char) + (define-key map [(meta f3)] 'mumamo-test-fontify-region) + (define-key map [(shift f3)] 'mumamo-test-create-chunks-at-all-points) + (define-key map [f3] 'mumamo-test-create-chunk-at-point) + map)) + +(defvar mumamo-test-current-chunk-family nil) +(make-variable-buffer-local 'mumamo-test-current-chunk-family) + +(define-minor-mode mumamo-test-mode + "For testing creating mumamo-mode chunks. +When this mode is on the following keys are defined: + + \\{mumamo-test-mode-keymap} + +" + nil + " MuMaMo-TEST" + :keymap mumamo-test-mode-keymap + (if mumamo-test-mode + (progn + (setq mumamo-test-current-chunk-family mumamo-current-chunk-family) + (setq mumamo-use-condition-case nil) + (setq mumamo-debugger nil) + (run-with-idle-timer 0 nil 'mumamo-test-tell-bindings)) + (setq mumamo-use-condition-case t) + (setq mumamo-debugger (default-value 'mumamo-debugger))) + ) + +(defun mumamo-test-tell-bindings () + (save-match-data ;; runs in timer + (let ((s "mumamo-test-mode is on, use F3/shift-F3 for simple testing")) + (put-text-property 0 (length s) + 'face 'font-lock-warning-face + s) + (message "%s" s)))) + +;;(mumamo-test-mode 1) + + +;; (defun mumamo-test-fontify-buffer () +;; (interactive) +;; (unless mumamo-current-chunk-family +;; (mumamo-select-chunk-family)) +;; ;;(when mumamo-mode (mumamo-mode 0)) +;; (when mumamo-multi-major-mode (mumamo-turn-off-actions)) +;; (save-excursion +;; (mumamo-remove-all-chunk-overlays) +;; (mumamo-save-buffer-state nil +;; (put-text-property (point-min) (point-max) 'face nil)) +;; (mumamo-fontify-buffer))) + +(defun mumamo-test-create-chunk-at-point () + (interactive) + (remove-hook 'post-command-hook 'mumamo-post-command t) + (font-lock-mode -1) + (setq fontification-functions nil) + (save-excursion + (mumamo-remove-all-chunk-overlays) + (mumamo-save-buffer-state nil + (remove-text-properties (point-min) (point-max) '(face nil syntax-table nil))) + (let* ((mumamo-current-chunk-family mumamo-test-current-chunk-family) + (here (point)) + chunk + chunk2) + (mumamo-save-buffer-state nil + ;;(setq chunk (mumamo-create-chunk-at here))) + (setq chunk (mumamo-find-chunks here "test1"))) + ;;(setq chunk2 (mumamo-get-chunk-at here)) + (setq chunk2 (mumamo-find-chunks here "set chunk2")) + ;;(message "mumamo-test-create-chunk-at-point.chunk 1=%s" chunk) + ;;(lwarn 'test-create-chunk-at :warning "chunk=%s, chunk2=%s" chunk chunk2) + ;;(when (overlay-buffer chunk) + (assert (eq chunk chunk2)) + ;;) + ;;(message "mumamo-test-create-chunk-at-point.chunk 2=%s" chunk) + ;;(syntax-ppss-flush-cache (1- (overlay-start chunk))) + (syntax-ppss-flush-cache (overlay-start chunk)) + (let ((start (overlay-start chunk)) + (end (overlay-end chunk))) + ;;(setq syntax-ppss-last (cons 319 (parse-partial-sexp 1 1))) + ;;(message "mumamo-test-create-chunk-at-point.chunk 2a=%s" chunk) + (mumamo-save-buffer-state nil + (mumamo-fontify-region-1 start end nil))) + ;;(message "mumamo-test-create-chunk-at-point.chunk 3=%s" chunk) + (unless mumamo-test-mode (mumamo-test-mode 1)) + ;;(message "mumamo-test-create-chunk-at-point.chunk 4=%s" chunk) + chunk + ;;(message "test 2.debugger=%s" debugger) + ;;(mumamo-get-chunk-at here) + (mumamo-find-chunks here "return value") + ))) + +(defun mumamo-test-create-chunks-at-all-points () + (interactive) + ;;(goto-char (point-min)) + (let (last-ovl + this-ovl) + (while (< (point) (point-max)) + ;;(setq this-ovl (mumamo-test-create-chunk-at-point)) + (setq this-ovl (mumamo-find-chunks (point) "test loop")) + ;;(message "this-ovl=%s" this-ovl) + (sit-for 0.005) + ;;(sit-for 0) + (when last-ovl + (if (= (point) (overlay-end last-ovl)) + (assert (= (overlay-end last-ovl) (overlay-start this-ovl))) + (assert (= (overlay-start last-ovl) (overlay-start this-ovl))) + (assert (= (overlay-end last-ovl) (overlay-end this-ovl))) + )) + (if last-ovl + (move-overlay last-ovl (overlay-start this-ovl) (overlay-end this-ovl)) + (setq last-ovl (make-overlay (overlay-start this-ovl) (overlay-end this-ovl)))) + (forward-char 1) + ) + (message "No problems found"))) + +(defun mumamo-test-fontify-region () + (interactive) + (let ((font-lock-mode t)) + ;;(mumamo-fontify-region-with (point-min) (point-max) nil 'php-mode nil) + (mumamo-fontify-region (point-min) (point-max) t))) + +;; Fix-me: can't byte compile: +;; (defun mumamo-test-easy-make () +;; (interactive) +;; (let ((start-str "--Start Submode:") +;; (end-str "--End Submode--") +;; (start-reg nil)) +;; (setq start-reg +;; ;; (rx +;; ;; (eval start-str) +;; ;; (0+ space) +;; ;; (submatch +;; ;; (0+ (any "a-z-"))) +;; ;; (0+ space) +;; ;; "--" +;; ;; ) +;; (rx-to-string +;; `(and +;; ,start-str +;; (0+ space) +;; (submatch +;; (0+ (any "a-z-"))) +;; (0+ space) +;; "--" +;; )) +;; ) +;; (mumamo-easy-make-chunk-fun testchunk +;; start-str +;; start-reg +;; end-str)) +;; (setq mumamo-current-chunk-family +;; (list "testing" +;; 'text-mode +;; (list +;; 'testchunk +;; )))) + +;; (defun mumamo-test-emb-perl () +;; (interactive) +;; (let ((start-str "[-") +;; (end-str "-]") +;; (start-reg nil)) +;; (mumamo-easy-make-chunk-fun testchunk-ep +;; start-str +;; start-reg +;; end-str)) +;; (setq mumamo-current-chunk-family +;; (list "emb perl test" +;; 'perl-mode +;; (list +;; 'testchunk-ep +;; )))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; These are for testing bad initialization in mumamo. They can be +;; used for example with php-mode. (They are mainly for development +;; purposes.) +;; +;; (mumamo-bad-c-init) +(defun mumamo-bad-c-init() (/ 1 0)) +(defun mumamo-setup-bad-c-init () + (interactive) + (add-hook 'c-mode-common-hook 'mumamo-bad-c-init)) +(defun mumamo-teardown-bad-c-init () + (interactive) + (remove-hook 'c-mode-common-hook 'mumamo-bad-c-init)) + + +;; (defmacro mumamo-get-backtrace (bodyform) +;; "Evaluate BODYFORM, return backtrace as a string. +;; If there is an error in BODYFORM then return the backtrace as a +;; string, otherwise return nil." +;; `(let* ((debugger-ret nil) +;; (debugger (lambda (&rest debugger-args) +;; (message "DEBUGGER CALLED BEFORE") +;; (setq debugger-ret (with-output-to-string (backtrace))) +;; (message "DEBUGGER CALLED AFTER, debugger-ret=%s" debugger-ret) +;; )) +;; (debug-on-error t) +;; (debug-on-signal t) +;; ) +;; (condition-case err +;; (progn +;; ,bodyform +;; nil) +;; (error +;; (message "err=%S" err) +;; (message "debugger-ret=%S\n\n\n" debugger-ret) +;; (let* ((errmsg (error-message-string err)) +;; (debugger-lines (split-string debugger-ret "\n")) +;; (dbg-ret (mapconcat 'identity (nthcdr 6 debugger-lines) "\n"))) +;; (concat errmsg "\n" dbg-ret)))))) + +;; (defun mumamo-test3-debug() +;; (interactive) +;; (message "%s" +;; (mumamo-get-backtrace +;; (mumamo-test-major-mode-init 'php-mode)))) + +;; (defun mumamo-test2-debug() +;; (interactive) +;; (mumamo-condition-case var +;; (mumamo-test-major-mode-init 'php-mode) +;; handlers)) + +(defun mumamo-test-debug() + (interactive) + (condition-case err + (let ((debugger 'mumamo-debug) + (debug-on-error t) + (debug-on-signal t)) + ;;(message "here d")(sit-for 1) + (mumamo-test-major-mode-init 'php-mode)) + (error (message "here 2 err=%S" err)))) + +(defun mumamo-debug (&rest debugger-args) + (let ((s (with-output-to-string (backtrace)))) + (message "mumamo-debug: %s" s))) + +;; (defun mumamo-bt-to-msg (msg) +;; (mumamo-msgfntfy "%s: %s" msg +;; (with-output-to-string +;; (backtrace)))) + +(defun mumamo-test-major-mode-init (major) + "Turn on major mode MAJOR in a temp buffer. +This function should be used after getting errors during +fontification where the message in the *Message* buffer tells +that you should call it to get a traceback. + +Send the traceback you get, if any, together with the message in +the message buffer when reporting the error." + (interactive "CMajor mode: ") + (with-temp-buffer + ;;(setq mumamo-explicitly-turned-on-off t) + (setq debug-on-error t) + (funcall major))) + +(provide 'mumamo-test) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo-test.el ends here diff --git a/emacs/nxhtml/tests/nxhtmltest-Q.el b/emacs/nxhtml/tests/nxhtmltest-Q.el new file mode 100644 index 0000000..b89857d --- /dev/null +++ b/emacs/nxhtml/tests/nxhtmltest-Q.el @@ -0,0 +1,114 @@ +;;; test-Q.el --- Run test from a fresh Emacs +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-07-08T23:05:40+0200 Tue +;; Version: 0.1 +;; Last-Updated: 2008-07-09T00:17:26+0200 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; Required feature `test-Q' was not provided. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Defines `nxhtmltest-Q'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'ourcomments-util)) + +(eval-and-compile + (defvar nxhtmltest-bin-Q + (file-name-directory (or load-file-name + (when 'bytecomp-filename bytecomp-filename) + buffer-file-name))) + + (add-to-list 'load-path nxhtmltest-bin-Q) + (require 'nxhtmltest-helpers)) + +;;;###autoload +(defun nxhtmltest-run-Q () + "Run all tests defined for nXhtml in fresh Emacs. +See `nxhtmltest-run' for more information about the tests." + (interactive) + (let* ((test-el (expand-file-name "nxhtmltest-suites.el" nxhtmltest-bin-Q)) + (nxhtml-auto-start (expand-file-name "../autostart.el" nxhtmltest-bin-Q)) + (temp-eval-file (expand-file-name "temp-test.el" nxhtmltest-bin-Q)) + (temp-eval-buf (find-file-noselect temp-eval-file)) + (load-path load-path)) + ;;(load (expand-file-name "nxhtmltest-helpers" nxhtmltest-bin-Q)) + (add-to-list 'load-path nxhtmltest-bin-Q) + (require 'nxhtmltest-helpers) + (nxhtmltest-get-fontification-method) + (with-current-buffer temp-eval-buf + (erase-buffer) + (insert "(setq debug-on-error t)\n" + "(eval-when-compile (require 'cl))\n" + "(delete-other-windows)\n" + "(eval-after-load 'nxhtml '(setq nxhtml-skip-welcome t))\n" + (format "(setq nxhtmltest-default-fontification-method '%s)\n" + nxhtmltest-default-fontification-method) + )) + (when (featurep 'ruby-mode) + (with-current-buffer temp-eval-buf + (insert "(pushnew \"" + (file-name-directory (locate-library "ruby-mode")) + "\" load-path)"))) + (with-current-buffer temp-eval-buf + (save-buffer)) + (kill-buffer temp-eval-buf) + (unless (file-exists-p nxhtmltest-bin-Q) + (error "Can't find directory %s" nxhtmltest-bin-Q)) + (setq nxhtmltest-bin-Q (file-name-sans-extension nxhtmltest-bin-Q)) + (unless (file-exists-p test-el) + (error "Can't find file %s" test-el)) + (setq test-el (file-name-sans-extension test-el)) + (unless (file-exists-p nxhtml-auto-start) + (error "Can't find file %s" nxhtml-auto-start)) + (setq nxhtml-auto-start (file-name-sans-extension nxhtml-auto-start)) + (message "nxhtmltest-bin-Q=%s" nxhtmltest-bin-Q) + (message "nxhtml-auto-start=%s" nxhtml-auto-start) + (setenv "nxhtmltest-run-Q" "run") + (message "After setenv nxhtmltest-run-Q=%s" (getenv "nxhtmltest-run-Q")) + (message "(ourcomments-find-emacs) => %s" (ourcomments-find-emacs)) + (call-process (ourcomments-find-emacs) nil 0 nil "-Q" + "-l" temp-eval-file + "-l" nxhtml-auto-start + "-l" test-el) + (message "After call-process") + (setenv "nxhtmltest-run-Q") + (message "Starting new Emacs instance for test - it will be ready soon ..."))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtmltest-Q.el ends here diff --git a/emacs/nxhtml/tests/nxhtmltest-helpers.el b/emacs/nxhtml/tests/nxhtmltest-helpers.el new file mode 100644 index 0000000..b05a6ca --- /dev/null +++ b/emacs/nxhtml/tests/nxhtmltest-helpers.el @@ -0,0 +1,156 @@ +;;; nxhtmltest-helpers.el --- Helper functions for testing +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-07-08T19:10:54+0200 Tue +;; Version: 0.2 +;; Last-Updated: 2008-09-01T01:13:15+0200 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `button', `help-fns', `help-mode', `view'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(require 'ert2) + +(defun nxhtmltest-goto-line (line) + (save-restriction + (widen) + (goto-char (point-min)) + (forward-line (1- line)))) + +(defun nxhtmltest-mumamo-error-messages () + (ert-get-messages "^MU:MuMaMo error")) + +(defun nxhtmltest-should-no-mumamo-errors () + (ert-should (not (nxhtmltest-mumamo-error-messages)))) + +(defun nxhtmltest-should-no-nxml-errors () + (ert-should (not (ert-get-messages "Internal nXML mode error")))) + +(defun nxhtmltest-be-really-idle (seconds &optional prompt-mark) + (unless prompt-mark (setq prompt-mark "")) + (with-timeout (4 (message "<<<< %s - not really idle any more at %s" + prompt-mark + (format-time-string "%H:%M:%S"))) + (let ((prompt (format + ">>>> %s Starting beeing really idle %s seconds at %s" + prompt-mark + seconds + (format-time-string "%H:%M:%S ...")))) + (message "%s" prompt) + (read-minibuffer prompt) + (redisplay)))) + +;;(nxhtmltest-be-really-idle 4 "HERE I AM!!") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Fontification methods + +(defvar nxhtmltest-default-fontification-method nil) + +(defun nxhtmltest-get-fontification-method () + "Ask user for default fontification method." + (let* ((collection + '( + ("Fontify as usual (wait)" fontify-as-usual) + ("Fontify by calling timer handlers" fontify-w-timer-handlers) + ("Fontify ps print " fontify-as-ps-print) + ("Call fontify-buffer" fontify-buffer) + )) + (hist (mapcar (lambda (rec) + (car rec)) + collection)) + (method-name (or t + (completing-read "Default fontification method: " + collection nil t + (car (nth 1 collection)) + 'hist)))) + (setq nxhtmltest-default-fontification-method + ;;(nth 1 (assoc method-name collection)) + ;;'fontify-w-timer-handlers + 'fontify-as-ps-print + ))) + +(defun nxhtmltest-fontify-as-usual (seconds prompt-mark) + (font-lock-mode 1) + ;; This does not work now since I deleted the function below: + (error "font-lock-wait not defined") + ;;(font-lock-wait (nxhtmltest-be-really-idle seconds prompt-mark)) + ) + +(defun nxhtmltest-fontify-w-timers-handlers () + ;;(dolist (timer (copy-list timer-idle-list)) + (dolist (timer (copy-sequence timer-idle-list)) + (timer-event-handler timer)) + (redisplay t)) + +(declare-function jit-lock-fontify-now "jit-lock" (&optional start end)) +(declare-function lazy-lock-fontify-region "lazy-lock" (beg end)) + +;; to avoid compilation gripes +;;(defun ps-print-ensure-fontified (start end) +(defun nxhtmltest-fontify-as-ps-print() + (save-restriction + (widen) + (let ((start (point-min)) + (end (point-max))) + (cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode)) + (jit-lock-fontify-now start end)) + ((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode)) + (lazy-lock-fontify-region start end)))))) + +(defun nxhtmltest-fontify-buffer () + (font-lock-fontify-buffer) + (redisplay t)) + +(defun nxhtmltest-fontify-default-way (seconds &optional pmark) + ;;(assert (not font-lock-mode)) + (case nxhtmltest-default-fontification-method + (fontify-as-usual (nxhtmltest-fontify-as-usual seconds pmark)) + (fontify-w-timer-handlers (nxhtmltest-fontify-w-timers-handlers)) + (fontify-as-ps-print (nxhtmltest-fontify-as-ps-print)) + (fontify-buffer (nxhtmltest-fontify-buffer)) + (t (error "Unrecognized default fontification method: %s" + nxhtmltest-default-fontification-method)))) + + + +(provide 'nxhtmltest-helpers) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtmltest-helpers.el ends here diff --git a/emacs/nxhtml/tests/nxhtmltest-suites.el b/emacs/nxhtml/tests/nxhtmltest-suites.el new file mode 100644 index 0000000..5af8ab8 --- /dev/null +++ b/emacs/nxhtml/tests/nxhtmltest-suites.el @@ -0,0 +1,632 @@ +;;; nxhtmltest-suites.el --- Test suites for mumamo / nXhtml +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-07-08T20:17:36+0200 Tue +;; Version: 0.12 +;; Last-Updated: 2008-09-01T01:13:28+0200 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Defines `nxhtmltest-run'. When (getenv "nxhtmltest-run-Q") +;; returns non-nil also runs this function. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; Added code from Christian Ohler for writing ert tests. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +;;(eval-when-compile (require 'cl)) +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'rng-valid)) +(eval-when-compile (require 'rngalt)) +(require 'mumamo) +(require 'mumamo-fun) +(require 'nxhtml) +(require 'nxhtml-mumamo) +(when (fboundp 'nxml-mode) + (require 'rng-valid) + (require 'rngalt)) + +(setq debug-on-error t) + +(defvar nxhtmltest-ert-default-selector "nxhtml-ert-" + "Set this to run a single test with `nxhtmltest-run-Q'.") + +(defvar nxhtmltest-bin + (file-name-directory (if load-file-name load-file-name buffer-file-name))) + +(pushnew nxhtmltest-bin load-path) +(require 'nxhtmltest-helpers) +;;(require 'ert) + +(defvar nxhtmltest-files-root + (let* ((this-dir nxhtmltest-bin) + (root (expand-file-name "in/" this-dir))) + (unless (file-accessible-directory-p root) + (error (if (file-exists-p root) + "Can't read files in test directory %s" + "Can't find test directory %s") + root)) + root)) + +(let ((distr-in "c:/EmacsW32/nxhtml/tests/in/")) + (when (file-directory-p distr-in) + (setq nxhtmltest-files-root distr-in))) + +;; (setq nxhtmltest-update-method +;; ;;'font-lock-wait +;; 'font-lock-run-timers +;; ;;'font-lock-fontify-buffer +;; ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Define tests using ert.el + +(ert-deftest nxhtml-ert-bug531328 () + "Test of eRuby chunks with nothing between." + (ert-with-temp-buffer-include-file "bug531328.rhtml" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(eruby-html-mumamo-mode) t) + (nxhtmltest-get-fontification-method) + (nxhtmltest-fontify-default-way 2 "trans") + (ert-simulate-command '(goto-char 12) t) + (ert-should (eq major-mode 'ruby-mode)) + )) + +(ert-deftest nxhtml-ert-indent-bug-johan-2010-02-17() + "Test of eRuby indentation. +Got a bug report by mail on the emacs-on-rails list." + (ert-with-temp-buffer-include-file "bug-johan-2010-02-17.erb" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(eruby-html-mumamo-mode) t) + (nxhtmltest-fontify-default-way 2 "trans") + (ert-simulate-command '(mark-whole-buffer) t) + (ert-simulate-command '(indent-for-tab-command) t) + (nxhtmltest-goto-line 1) (ert-should (= 0 (current-indentation))) + (nxhtmltest-goto-line 2) (ert-should (= 2 (current-indentation))) + (nxhtmltest-goto-line 3) (ert-should (= 0 (current-indentation))) + )) + +(ert-deftest nxhtml-ert-indent-bug-johan-2010-02-12() + "Test of eRuby indentation. +Got a bug report by mail on the emacs-on-rails list." + (ert-with-temp-buffer-include-file "bug-johan-2010-02-12.rhtml" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(eruby-html-mumamo-mode) t) + (nxhtmltest-fontify-default-way 2 "trans") + (ert-simulate-command '(mark-whole-buffer) t) + (ert-simulate-command '(indent-for-tab-command) t) + (nxhtmltest-goto-line 12) (ert-should (= 2 (current-indentation))) + )) + +;;(setq nxhtmltest-ert-default-selector "nxhtml-ert-indent-rr-min8") +(ert-deftest nxhtml-ert-indent-rr-min8 () + "Test of indentation bug. +As per Richard Riley's bug report 2009-10-08. Last line gave an +error." + (ert-with-temp-buffer-include-file "rr-min8.php" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(nxhtml-mumamo-mode) t) + (nxhtmltest-fontify-default-way 2 "trans") + (ert-simulate-command '(mark-whole-buffer) t) + (ert-simulate-command '(indent-for-tab-command) t))) + +;;(setq nxhtmltest-ert-default-selector "nxhtml-ert-bug-400415") +(ert-deftest nxhtml-ert-bug-400415-foo2 () + "Test for changes before in-here-doc using 400415. +See URL `https://bugs.launchpad.net/nxhtml/+bug/400415'. This is +not the bug reported there however." + (ert-with-temp-buffer-include-file "bug400415-foo2.php" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(nxhtml-mumamo-mode) t) + (nxhtmltest-fontify-default-way 2 "trans") + (ert-simulate-command '(goto-char 74) t) + (ert-should (eq major-mode 'sql-mode)) + (ert-simulate-command '(goto-char 23) t) + (ert-simulate-command '(backward-delete-char-untabify 1) t) + (ert-simulate-command '(goto-char 74) t) + (ert-should (eq major-mode 'sql-mode)) + )) + +(ert-deftest nxhtml-ert-bug-300946-index () + "Test for bug 300946 in Launchpad. +See URL `https://bugs.launchpad.net/nxhtml/+bug/300946'. This is +a test for the file attached by Chris on 2008-12-02." + (ert-with-temp-buffer-include-file "bug-300946-index.html" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(nxhtml-mumamo-mode) t) + (font-lock-mode 1) + )) + +(ert-deftest nxhtml-ert-indent-bug290364 () + "Test for bug 290364 in Launchpad. +See URL `https://bugs.launchpad.net/nxhtml/+bug/290364'. + +Note: If this test fails Emacs loops. Therefore the whole test +is included in a when clause so you can avoid it easily." + ;;(when t + (ert-with-temp-buffer-include-file "bug-290364.php" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(nxhtml-mumamo-mode) t) + (font-lock-mode 1) + )) +;) + +(ert-deftest nxhtml-ert-indent-bug271497 () + "Test for bug 271497 in Launchpad. +This is a bug in Emacs 22. It should work in Emacs 23 though. +See URL `https://bugs.launchpad.net/nxhtml/+bug/271497'." + (ert-with-temp-buffer-include-file "bug271497.txt" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (load-file (ert-get-test-file-name "bug271497.el")) + (ert-simulate-command '(bug271497-mumamo) t) + ;;(font-lock-mode 1) + (nxhtmltest-fontify-default-way 2 "trans") + (ert-simulate-command '(goto-char 42) t) + (message "after goto-char 42") + (let ((ac42 after-change-functions) + ac88) + (ert-simulate-command '(goto-char 88) t) + (message "after goto-char 88") + (setq ac88 after-change-functions) + (ert-should (not (equal ac88 ac42)))))) + +(ert-deftest nxhtml-ert-indent-question43320 () + "Test for question 43320 in Launchpad. +See URL `https://answers.launchpad.net/nxhtml/+question/43320'. + +Note: This fails in Emacs 22, but should work in Emacs 23." +;; I did see some problem here: + +;; - nXhtml 081222 + unpatched Emacs 081219 => ok +;; - nXhtml 081222 + unpatched Emacs 081124 => ok +;; - nXhtml 081222 + patched Emacs 081219 => ok + +;; - nXhtml 081222 + patched Emacs 081124 => ok, but it fails if I +;; use `nxhtmltest-run-Q'! I e, it fails if the autostart.el from +;; the nxhtml dir in 081222 is used - but not if the copy in +;; c:/EmacsW32 is used??? Which turned out to be if the old +;; php-mode was used ... + + (ert-with-temp-buffer-include-file "question43320.html" + (add-hook 'ert-simulate-command-post-hook + 'nxhtmltest-should-no-mumamo-errors + nil t) + (ert-simulate-command '(nxhtml-mumamo-mode) t) + (font-lock-mode 1) + (nxhtmltest-goto-line 25) (ert-should (/= 14 (current-indentation))) + (put 'mumamo-submode-indent-offset-0 'permanent-local t) + (put 'mumamo-submode-indent-offset 'permanent-local t) + ;; + ;;(set (make-local-variable 'mumamo-submode-indent-offset-0) nil) + (set (make-local-variable 'mumamo-submode-indent-offset-0) 0) + (set (make-local-variable 'mumamo-submode-indent-offset) nil) + ;;(set (make-local-variable 'mumamo-submode-indent-offset) 2) + (ert-simulate-command '(mark-whole-buffer) t) + (ert-simulate-command '(indent-for-tab-command) t) + (nxhtmltest-goto-line 8) (ert-should (= 8 (current-indentation))) + (nxhtmltest-goto-line 9) (ert-should (= 0 (current-indentation))) + (nxhtmltest-goto-line 15) (ert-should (= 8 (current-indentation))) + (nxhtmltest-goto-line 16) (ert-should (= 8 (current-indentation))) + (nxhtmltest-goto-line 22) (ert-should (= 6 (current-indentation))) + (nxhtmltest-goto-line 25) (ert-should (= 4 (current-indentation))) + (nxhtmltest-goto-line 8) (indent-line-to 0) + ;;(message "before indent-for-tab-command") + (ert-simulate-command '(indent-for-tab-command) t) + ;;(message "after indent-for-tab-command") + (ert-should (= 8 (current-indentation))) + ;; + (set (make-local-variable 'mumamo-submode-indent-offset-0) 0) + (set (make-local-variable 'mumamo-submode-indent-offset) 2) + (ert-simulate-command '(mark-whole-buffer) t) + (ert-simulate-command '(indent-for-tab-command) t) + (nxhtmltest-goto-line 8) (ert-should (= 8 (current-indentation))) + (nxhtmltest-goto-line 9) (ert-should (= 10 (current-indentation))) + (nxhtmltest-goto-line 15) (ert-should (= 8 (current-indentation))) + (nxhtmltest-goto-line 16) (ert-should (= 8 (current-indentation))) + (nxhtmltest-goto-line 22) (ert-should (= 16 (current-indentation))) + (nxhtmltest-goto-line 25) (ert-should (= 14 (current-indentation))) + )) + +(ert-deftest nxhtml-ert-only-php-no-end () + "Check for nXml error." + (ert-with-temp-buffer-include-file "no-php-end-4.php" + (nxhtml-mumamo-mode) + (run-hooks 'after-change-major-mode-hook) + (run-hooks 'post-command-hook) + (nxhtmltest-fontify-default-way 2 "trans") + (rng-validate-mode 1) + ;;(rngalt-validate) + (ert-should (eq rng-validate-mode t)) + (nxhtmltest-should-no-mumamo-errors) + (nxhtmltest-should-no-nxml-errors) + (goto-char 324) + (message "before insert, after-change-functions local=%s" after-change-functions) + (insert "\n") + (nxhtmltest-should-no-mumamo-errors) + (nxhtmltest-should-no-nxml-errors))) + +(ert-deftest nxhtml-ert-xhtml-1.0-transitional () + "Test XHTML 1.0 Transitional with `nxhtml-mumamo-mode'. +NOTICE: This test SHOULD FAIL because there is currently no rng +schema for transitional. The schema for strict is used instead +and the file is invalid then." + (ert-with-temp-buffer-include-file "lg-080813-label.html" + (nxhtml-mumamo-mode) + (nxhtmltest-fontify-default-way 2 "trans") + (rng-validate-mode 1) + (rngalt-validate) + (ert-should (eq rng-validate-mode t)) + (nxhtmltest-should-no-mumamo-errors) +;;; (ert-should +;;; (not (eq (get-char-property 398 'category) +;;; 'rng-error))) + (ert-should + (eq (get-text-property 398 'face) + 'font-lock-function-name-face)) + (ert-should-not + (= 0 rng-error-count)) + )) + +(ert-deftest nxhtml-ert-genshi-valid-in-genshi () + (ert-with-temp-buffer-include-file "genshi-auto-mode.html" + (message "\n") + (genshi-nxhtml-mumamo-mode) + (font-lock-mode 1) + (mumamo-post-command) + (ert-should (eq font-lock-mode t)) + (ert-should (eq major-mode 'nxhtml-genshi-mode)) + (ert-should + (memq mumamo-multi-major-mode '(genshi-nxhtml-mumamo-mode + genshi-html-mumamo-mode))) + (nxhtmltest-fontify-default-way 2 "sheit") + (rng-validate-mode 1) + (rngalt-validate) + (ert-should (eq rng-validate-mode t)) + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (= 0 rng-error-count)))) + +(ert-deftest nxhtml-ert-genshi-invalid-in-nxhtml () + (ert-with-temp-buffer-include-file "genshi-auto-mode.html" + (message "\n") + (nxhtml-mumamo-mode) + (nxhtmltest-fontify-default-way 2 "sheit") + (font-lock-mode 1) + (mumamo-post-command) + (rng-validate-mode 1) + (rngalt-validate) + (ert-should (eq rng-validate-mode t)) + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (= 2 rng-error-count)))) + +(ert-deftest nxhtml-ert-genshi-magic-mode () + "Test if genshi file is recognized." + (let ((file1 (ert-get-test-file-name "genshi-auto-mode.html")) + buf1) + ;; Ensure we open the files + (setq buf1 (find-buffer-visiting file1)) + (when buf1 (kill-buffer buf1)) + ;; Open file 1 + (setq buf1 (find-file file1)) + (nxhtmltest-fontify-default-way 2 "mod") + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (with-current-buffer buf1 + (memq mumamo-multi-major-mode '(genshi-nxhtml-mumamo-mode + genshi-html-mumamo-mode)))) + (kill-buffer buf1))) + +(ert-deftest nxhtml-ert-genshi-auto-mode () + "Test if file extension .ghtml is recognized." + (let ((file1 (ert-get-test-file-name "genshi-HelloWorldPage.ghtml")) + buf1) + ;; Ensure we open the files + (setq buf1 (find-buffer-visiting file1)) + (when buf1 (kill-buffer buf1)) + ;; Open file 1 + (setq buf1 (find-file file1)) + (nxhtmltest-fontify-default-way 2 "mod") + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (with-current-buffer buf1 + (memq mumamo-multi-major-mode '(genshi-nxhtml-mumamo-mode + genshi-html-mumamo-mode)))) + (kill-buffer buf1))) + +(ert-deftest nxhtml-ert-opened-modified () + "Test if buffer get modified when opening a file." + (let ((file1 (ert-get-test-file-name "cvd-080805-ac.php")) + (file2 (ert-get-test-file-name "cvd-080805-cc.php")) + buf1 + buf2) + ;; Ensure we open the files + (setq buf1 (find-buffer-visiting file1)) + (when buf1 (kill-buffer buf1)) + (setq buf2 (find-buffer-visiting file2)) + (when buf2 (kill-buffer buf2)) + ;; Open file 1 + (setq buf1 (find-file file1)) + (nxhtmltest-fontify-default-way 2 "mod") + (nxhtmltest-should-no-mumamo-errors) + ;; Open file 2 + (setq buf2 (find-file file2)) + (nxhtmltest-fontify-default-way 2 "mod") + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (not (or (buffer-modified-p buf1) + (buffer-modified-p buf2)))) + (kill-buffer buf1) + (kill-buffer buf2))) + +(ert-deftest nxhtml-ert-wiki-strange-hili-080629 () + "From a report on EmacsWiki." + (ert-with-temp-buffer-include-file "wiki-strange-hili-080629.html" + ;;(ert-should (not font-lock-mode)) + (nxhtml-mumamo-mode) + ;;(ert-should (not font-lock-mode)) + (nxhtmltest-fontify-default-way 2 "hili") + (goto-char 44) + (nxhtmltest-should-no-mumamo-errors) + (message "face at 44=%s" (get-text-property 44 'face)) + (ert-should + (eq (get-text-property 44 'face) + 'font-lock-function-name-face)))) + +(ert-deftest nxhtml-ert-indent-wiki-080708-ind-problem () + (ert-with-temp-buffer-include-file "wiki-080708-ind-problem.rhtml" + (require 'ruby-mode nil t) + (if (not (featurep 'ruby-mode)) + ;; Fix-me: ert should maybe have some way to just display + ;; informational messages? + (error "ruby-mode not available, skipping test") + ;;(ert-should (not font-lock-mode)) + (eruby-nxhtml-mumamo-mode) + ;;(ert-should (not font-lock-mode)) + (nxhtmltest-fontify-default-way 2 "ind") + (mark-whole-buffer) + (indent-for-tab-command) + (nxhtmltest-goto-line 3) + (nxhtmltest-should-no-mumamo-errors) + (ert-should (= (current-indentation) 0))))) + +(ert-deftest nxhtml-ert-indent-wiki-080708-ind-problem-a () + "From a report on EmacsWiki. +NOTICE: This SHOULD FAIL. There is currently no support for the +kind of indentation needed here. + +Notice 2: For some reason I sometimes get the error overlayp, nil +here." + (ert-with-temp-buffer-include-file "wiki-080708-ind-problem.rhtml" + (require 'ruby-mode nil t) + (if (not (featurep 'ruby-mode)) + (error "ruby-mode not available, skipping test") + ;;(ert-should (not font-lock-mode)) + (eruby-nxhtml-mumamo-mode) + ;;(ert-should (not font-lock-mode)) + (nxhtmltest-fontify-default-way 2 "ind") + (insert " ") + (mark-whole-buffer) + (indent-for-tab-command) + (nxhtmltest-goto-line 3) + ;; Test + (nxhtmltest-should-no-mumamo-errors) + (ert-should-not (= (current-indentation) 2))))) + +(ert-deftest nxhtml-ert-sheit-2007-12-26 () + (ert-with-temp-buffer-include-file "sheit-2007-12-26.php" + ;;(ert-should (not font-lock-mode)) + (nxhtml-mumamo-mode) + ;;(ert-should (not font-lock-mode)) + (nxhtmltest-fontify-default-way 2 "sheit") + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (and + (eq (get-text-property 21 'face) + 'font-lock-comment-face) + (eq (get-text-property 22 'face) + 'font-lock-comment-face) + (eq (get-text-property 35 'face) + 'font-lock-comment-face))))) + + +;; Now some tests with a big file. Jumping backwards can fail. + +(defun nxhtml-ert-nxhtml-changes-jump-back-2 (pos) + ;;(ert-should (not font-lock-mode)) + (nxhtml-mumamo-mode) + (run-hooks 'post-command-hook) + ;;(ert-should (not font-lock-mode)) + (goto-char (- (point-max) (- 64036 63869))) + (nxhtmltest-fontify-default-way 2) + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (eq (get-text-property (point) 'face) + 'font-lock-variable-name-face)) + (message "here 1") + (goto-char pos) + (nxhtmltest-fontify-default-way 2) + (nxhtmltest-should-no-mumamo-errors) + (message "here 2") + (ert-should + (eq (get-text-property (point) 'face) + 'font-lock-function-name-face))) + +;; Fix-me: forgot to copy nxhtml-changes.html. I can't find any +;; similar error now. +;; +;; (ert-deftest nxhtml-ert-nxhtml-changes-jump-back-7014-2 () +;; "this is a docstring. +;; wonder how that works now ..." +;; (ert-with-temp-buffer-include-file "../../nxhtml/doc/nxhtml-changes.html" +;; (nxhtml-ert-nxhtml-changes-jump-back-2 7014))) + +;; (ert-deftest nxhtml-ert-nxhtml-changes-jump-back-10488-2 () +;; (ert-with-temp-buffer-include-file "../../nxhtml/doc/nxhtml-changes.html" +;; (nxhtml-ert-nxhtml-changes-jump-back-2 10488))) + +;; (ert-deftest nxhtml-ert-nxhtml-changes-jump-2 () +;; (ert-with-temp-buffer-include-file "../../nxhtml/doc/nxhtml-changes.html" +;; ;;(ert-should (not font-lock-mode)) +;; (nxhtml-mumamo-mode) +;; ;;(ert-should (not font-lock-mode)) +;; (goto-char 10420) +;; (nxhtmltest-fontify-default-way 2 "jump-2") +;; (nxhtmltest-should-no-mumamo-errors) +;; (ert-should +;; (eq (get-text-property (point) 'face) +;; 'font-lock-variable-name-face)))) + +;;; Indentation tests + +(ert-deftest nxhtml-ert-php-indent-bug-1 () + "Test indentation in php only file. +The indentation on line 7 should be 0." + (ert-with-temp-buffer-include-file "only-php.php" + (nxhtml-mumamo-mode) + ;; No fontification needed for indentation. + (nxhtmltest-goto-line 7) + (indent-for-tab-command) + (nxhtmltest-should-no-mumamo-errors) + (ert-should + (= 0 + (current-indentation))))) + +;;; Scroll tests + +;; (ert-deftest nxhtml-ert-scroll-jump-test () +;; "Test if `scroll-conservatively' eq 1 works." +;; (ert-with-temp-buffer-include-file "../../nxhtml/doc/nxhtml-changes.html" +;; (ert-should (not font-lock-mode)) +;; (nxhtml-mumamo-mode) +;; (ert-should (not font-lock-mode)) +;; (nxhtmltest-fontify-default-way 2 "jump-2") +;; (let ((scroll-conservatively 1) +;; (ws (list (window-start))) +;; (xi (loop for ii from 1 to 100 by 1 +;; do +;; (next-line) +;; (sit-for 0.01) +;; collect (list (window-start) +;; (let ((here (point))) +;; (goto-char (window-start)) +;; (prog1 (line-end-position) +;; (goto-char here))) +;; (point)) +;; )) +;; (jumps 0) +;; prev-win-start +;; prev-win-start-le +;; ) +;; (loop for xx in xi +;; do +;; (message "xx=%s" xx) +;; (let ((win-start (nth 0 xx)) +;; (win-start-le (nth 1 xx)) +;; (cur-point (nth 2 xx))) +;; (unless (or (not prev-win-start) +;; (= prev-win-start win-start) +;; (= (1+ prev-win-start-le) win-start)) +;; (setq jumps (1+ jumps))) +;; (setq prev-win-start win-start) +;; (setq prev-win-start-le win-start-le) +;; ) +;; ) +;; (ert-should (= 0 jumps)) +;; ))) + +;;(defvar ert-error-on-test-redefinition nil) + +;;; End of test definitions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun nxhtmltest-run-ert (selector) + "Run test with ert library." + (unless selector (setq selector nxhtmltest-ert-default-selector)) + (setq ert-test-files-root nxhtmltest-files-root) + (if noninteractive + (ert-run-tests-batch selector) + (ert-kill-temp-test-buffers) + (ert-run-tests-interactively selector) + (other-window 1) + (ert-list-temp-test-buffers))) + +;;;###autoload +(defun nxhtmltest-run-indent () + "Run indentation tests." + (interactive) + (setq ert-test-files-root nxhtmltest-files-root) + (let ((selector "nxhtml-ert-indent-")) + (ert-kill-temp-test-buffers) + (nxhtmltest-get-fontification-method) + (ert-run-tests-interactively selector)) + (other-window 1) + (ert-list-temp-test-buffers)) + +;;;###autoload +(defun nxhtmltest-run () + "Run all tests defined for nXhtml. +Currently there are only tests using ert.el defined. + +Note that it is currently expected that the following tests will +fail (they corresponds to known errors in nXhtml/Emacs): + + `nxhtml-ert-nxhtml-changes-jump-back-10549' + `nxhtml-ert-nxhtml-changes-jump-back-7014' +" + (interactive) + (setq message-log-max t) + (when (called-interactively-p) + (nxhtmltest-get-fontification-method)) + (nxhtmltest-run-ert nil)) + +(when (getenv "nxhtmltest-run-Q") + (nxhtmltest-run)) + +(provide 'nxhtmltest-suites) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; nxhtmltest-suites.el ends here diff --git a/emacs/nxhtml/util/anchored-transpose.el b/emacs/nxhtml/util/anchored-transpose.el new file mode 100644 index 0000000..3a5464c --- /dev/null +++ b/emacs/nxhtml/util/anchored-transpose.el @@ -0,0 +1,305 @@ +;;; anchored-transpose.el --- Transposes a phrase around an anchor phrase + +;; Copyright (C) 2004 Free Software Foundation, Inc. + +;; Author: Rick Bielawski <rbielaws@i1.net> +;; Keywords: tools convenience + +;; 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. + +;;; Commentary: + +;; `anchored-transpose' is an interactive autoload function to transpose +;; portions of a region around an anchor phrase. In other words it swaps +;; two regions. +;; +;; See C-h f anchored-transpose <ret> for a complete description. + +;;; Installing: + +;; 1) Put anchored-transpose.el on your load path. +;; 2) Put the following 2 lines in your .emacs +;; (global-set-key [?\C-x ?t] 'anchored-transpose) ;; Just a suggestion... +;; (autoload 'anchored-transpose "anchored-transpose" nil t) + +;;; History: + +;; 2004-09-24 RGB Seems useable enough to release. +;; 2004-10-15 RGB Only comments and doc strings were updated. +;; 2004-10-22 RGB Added support for 2 phrase selection. +;; 2004-12-01 RGB Added secondary selection support. +;; 2005-07-21 RGB Updated help text and comments. +;; Added support for A C B D and C A D B selection. +;; Fixed bug affecting multi line selections. +;; 2005-09-28 RGB Allow swapping regions with no anchor text between. + +;; Changes by Lennart Borgman +;; 2009-11-25 LB Set and clear secondary selection from keyboard. +;; Always use secondary selection. +;; Keep selections right after swapping. +;; Clear them if not used again. +;; Swap between buffers. +;; Check for read-only. +;; Probably broke something... ;-) + +;;; Code: + +(defvar anchored-transpose-anchor () + "begin/end when `anchored-transpose' is in progress else nil") + +;;;###autoload +(defun anchored-transpose (beg1 end1 flg1 &optional beg2 end2 flg2 win2) + "Transpose portions of the region around an anchor phrase. + +`this phrase but not that word' can be transposed into +`that word but not this phrase' + +I want this phrase but not that word. + |----------------------------|. .This is the entire phrase. + |-------|. . . . . . .This is the anchor phrase. + +First select the entire phrase and type \\[anchored-transpose]. +This set the secondary selection. + +Then select the anchor phrase and type \\[anchored-transpose] +again. Alternatively you can do the selections like this: + +I want this phrase but not that word. + |----------| |---------| Separate phrase selection. + +By default the anchor phrase will automatically include +any surrounding whitespace even if you don't explicitly select +it. Also, it won't include certain trailing punctuation. See +`anchored-transpose-do-fuzzy' for details. A prefix arg prior to +either selection means `no fuzzy logic, use selections +literally'. + +You can select the regions to be swapped separately in any +order. + +After swapping both primary and secondary selection are still +active. They will be canceled after second next command if you +do not swap regions again. \(Second because this allow you to +adjust the regions and try again.) + +You can also swap text between different buffers this way. + +Typing \\[anchored-transpose] with nothing selected clears any +prior selection, ie secondary selection." + (interactive `(,(region-beginning) ,(region-end) + ,current-prefix-arg + ,@anchored-transpose-anchor)) + (setq anchored-transpose-anchor nil) + (when (and mouse-secondary-overlay + mark-active + (overlay-buffer mouse-secondary-overlay) + (/= (overlay-start mouse-secondary-overlay) + (overlay-end mouse-secondary-overlay))) + (if (eq (overlay-buffer mouse-secondary-overlay) (current-buffer)) + (progn + (setq beg2 (overlay-start mouse-secondary-overlay)) + (setq end2 (overlay-end mouse-secondary-overlay)) + (setq flg2 flg1) + (delete-overlay mouse-secondary-overlay)) + (let* ((sec-buf (overlay-buffer mouse-secondary-overlay)) + (sec-win (get-buffer-window sec-buf)) + (sec-new nil)) + (unless sec-win + (setq sec-new t) + (setq sec-win (split-window))) + (with-selected-window sec-win + (set-window-buffer (selected-window) sec-buf) + (goto-char (overlay-start mouse-secondary-overlay))) + (if (not (y-or-n-p "Swap between buffers ")) + (when sec-new (delete-window sec-win)) + (setq beg2 (overlay-start mouse-secondary-overlay)) + (setq end2 (overlay-end mouse-secondary-overlay)) + (setq flg2 flg1) + (setq win2 sec-win))))) + (setq win2 (or win2 (selected-window))) + (if mark-active + (if end2 ; then both regions are marked. swap them. + (if (not (eq win2 (selected-window))) + (anchored-transpose-swap beg1 end1 beg2 end2 win2) + (if (and (< beg1 beg2) ;A C B D + (< end1 end2) + (> end1 beg2)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg1 beg2 end1 end2 flg1 flg2 flg1 flg2)) + (if (and (> beg1 beg2) ;C A D B + (> end1 end2) + (> end2 beg1)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg2 beg1 end2 end1 flg2 flg1 flg2 flg1)) + (if (and (< beg1 beg2) ;A C D B + (> end1 end2)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg1 beg2 end2 end1 flg1 flg2 flg2 flg1)) + (if (and (> beg1 beg2) ;C A B D + (< end1 end2)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg2 beg1 end1 end2 flg2 flg1 flg1 flg2)) + (if (<= end1 beg2) ;A B C D + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg1 end1 beg2 end2 flg1 flg1 flg2 flg2)) + (if (<= end2 beg1) ;C D A B + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg2 end2 beg1 end1 flg2 flg2 flg1 flg1)) + (error "Regions have invalid overlap")))))))) + ;; 1st of 2 regions. Save it and wait for the other. + ;;(setq anchored-transpose-anchor (list beg1 end1 flg1)) + (if (or buffer-read-only + (get-char-property beg1 'read-only) + (get-char-property end1 'read-only)) + ;; Fix-me: move test, clean up a bit. + (message "Buffer text is readonly") + (set-secondary-selection beg1 end1) + (setq deactivate-mark t) + (message "%s" (this-command-keys)) + (message (propertize "Transpose: Select second region and call again - (without selection to cancel)" + 'face 'secondary-selection)))) + (if (and mouse-secondary-overlay + (overlay-buffer mouse-secondary-overlay)) + (progn + (cancel-secondary-selection) + (message (propertize "Canceled secondary selection" 'face + 'highlight))) + (message (propertize "Command requires a marked region" 'face + 'highlight))))) + +;;;###autoload +(defun set-secondary-selection (beg end) + "Set the secondary selection to the current region. +This must be bound to a mouse drag event." + (interactive "r") + (move-overlay mouse-secondary-overlay beg end (current-buffer)) + (when (called-interactively-p 'interactive) + ;;(deactivate-mark) + ) + (x-set-selection + 'SECONDARY + (buffer-substring (overlay-start mouse-secondary-overlay) + (overlay-end mouse-secondary-overlay)))) + +;;;###autoload +(defun cancel-secondary-selection () + (interactive) + (delete-overlay mouse-secondary-overlay) + (x-set-selection 'SECONDARY nil)) + +(defun anchored-transpose-do-fuzzy (r1beg r1end r2beg r2end + lit1 lit2 lit3 lit4) + "Returns the first 4 arguments after adjusting their value if necessary. + +I want this phrase but not that word. + |----------------------------|. .This is the entire phrase. + |-------|. . . . . . .This is the anchor phrase. + R1BEG R1END R2BEG R2END + +R1BEG and R1END define the first region and R2BEG and R2END the second. + +The flags, LIT1 thru LIT4 indicate if fuzzy logic should be applied to the +beginning of R1BEG, the end of R1END, the beginning of R2BEG, the end of R2END +respectively. If any flag is nil then fuzzy logic will be applied. Otherwise +the value passed should be returned LITerally (that is, unchanged). + +See `anchored-transpose-fuzzy-begin' and `anchored-transpose-fuzzy-end' for +specifics on what adjustments these routines will make when LITx is nil." + (list + (if lit1 r1beg + (anchored-transpose-fuzzy-begin r1beg r1end "[\t ]+")) + (if lit2 r1end + (anchored-transpose-fuzzy-end r1beg r1end "\\s +")) + (if lit3 r2beg + (anchored-transpose-fuzzy-begin r2beg r2end "[\t ]+")) + (if lit4 r2end + (anchored-transpose-fuzzy-end r2beg r2end "\\s *[.!?]")) + nil)) + +(defun anchored-transpose-fuzzy-end (beg end what) + "Returns END or new value for END based on the regexp WHAT. +BEG and END are buffer positions defining a region. If that region ends +with WHAT then the value for END is adjusted to exclude that matching text. + +NOTE: The regexp is applied differently than `looking-back' applies a regexp. + +Example: if (buffer-string beg end) contains `1234' the regexp `432' matches +it, not `234' as `looking-back' would. Also, your regexp never sees the char +at BEG so the match will always leave at least 1 character to transpose. +The reason for not using looking-back is that it's not greedy enough. +\(looking-back \" +\") will only match one space no matter how many exist." + (let ((str (concat + (reverse (append (buffer-substring (1+ beg) end) nil))))) + (if (string-match (concat "`" what) str) + (- end (length (match-string 0 str))) + end))) + +(defun anchored-transpose-fuzzy-begin (beg end what) + "Returns BEG or a new value for BEG based on the regexp WHAT. +BEG and END are buffer positions defining a region. If the region begins +with WHAT then BEG is adjusted to exclude the matching text. + +NOTE: Your regexp never sees the last char defined by beg/end. This insures +at least 1 char is always left to transpose." + (let ((str (buffer-substring beg (1- end)))) + (if (string-match (concat "`" what) str) + (+ beg (length (match-string 0 str))) + beg))) + +(defun anchored-transpose-swap (r1beg r1end r2beg r2end win2) + "Swaps region r1beg/r1end with r2beg/r2end. Flags are currently ignored. +Point is left at r1end." + (let ((reg1 (buffer-substring r1beg r1end)) + (reg2 nil) + (old-buffer (current-buffer))) + (when win2 + (unless (eq (selected-window) win2) + (select-window win2) + (set-buffer (window-buffer (selected-window))))) + (setq reg2 (delete-and-extract-region r2beg r2end)) + (goto-char r2beg) + (let ((new-mark (point))) + (insert reg1) + (push-mark new-mark)) + ;; I want to leave point at the end of phrase 2 in current buffer. + (save-excursion + (with-current-buffer old-buffer + (goto-char r1beg) + (delete-region r1beg r1end) + (let ((here (point))) + (insert reg2) + (set-secondary-selection here (point))))) + (setq deactivate-mark nil) + (when (eq old-buffer (current-buffer)) + (add-hook 'post-command-hook 'anchored-swap-post-command t t)))) + +(defun anchored-swap-post-command () + (condition-case err + (unless mark-active + (cancel-secondary-selection) + (remove-hook 'post-command-hook 'anchored-swap-post-command t)) + (error (message "anchored-swap-post-command: %s" err)))) + +(provide 'anchored-transpose) + +;; Because I like it this way. So there! +;;; fill-column:78 *** +;;; emacs-lisp-docstring-fill-column:78 *** +;;; +;;; Local Variables: *** +;;; End: *** +;;; anchored-transpose.el ends here. diff --git a/emacs/nxhtml/util/appmenu-fold.el b/emacs/nxhtml/util/appmenu-fold.el new file mode 100644 index 0000000..938ab92 --- /dev/null +++ b/emacs/nxhtml/util/appmenu-fold.el @@ -0,0 +1,79 @@ +;;; appmenu-fold.el --- Support form fold-dwim in AppMenu +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed Jan 11 21:48:02 2006 +(defconst appmenu-fold:version "0.51") ;; Version: +;; Last-Updated: Mon Jan 15 03:10:59 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(require 'fold-dwim nil t) +(eval-when-compile (require 'appmenu)) + +(when (featurep 'fold-dwim) + + (defun appmenu-fold-no-hs-minor-mode () + t) + (defun appmenu-fold-no-outline-minor-mode () + t) + (defun appmenu-fold-setup () + "Adds some tweaks for using fold-dwim in AppMenu." + (let ((fd-map (make-sparse-keymap))) + (define-key fd-map [fold-dwim-toggle] + (list 'menu-item "Fold Dwin Toggle" 'fold-dwim-toggle)) + (define-key fd-map [fold-dwim-hide-all] + (list 'menu-item "Fold Dwin Hide All" 'fold-dwim-hide-all)) + (define-key fd-map [fold-dwim-show-all] + (list 'menu-item "Fold Dwin Show All" 'fold-dwim-show-all)) + ;;(add-to-list 'appmenu-alist (cons t (cons "Folding" fd-map))) + (appmenu-add 'appmenu-fold nil t "Folding" fd-map) + ) +;;; (add-to-list 'appmenu-minor-modes-exclude +;;; '(hs-minor-mode appmenu-fold-no-hs-minor-mode)) +;;; (add-to-list 'appmenu-minor-modes-exclude +;;; '(outline-minor-mode appmenu-fold-no-outline-minor-mode))) + ) + ) + +(provide 'appmenu-fold) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; appmenu-fold.el ends here diff --git a/emacs/nxhtml/util/appmenu.el b/emacs/nxhtml/util/appmenu.el new file mode 100644 index 0000000..1f060ef --- /dev/null +++ b/emacs/nxhtml/util/appmenu.el @@ -0,0 +1,523 @@ +;;; appmenu.el --- A framework for [apps] popup menus. + +;; Copyright (C) 2008 by Lennart Borgman + +;; Author: Lennart Borgman <lennart DOT borgman AT gmail DOT com> +;; Created: Thu Jan 05 14:00:26 2006 +(defconst appmenu:version "0.63") ;; Version: +;; Last-Updated: 2010-01-04 Mon +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; appmenu.el is a framework for creating cooperative context +;; sensitive popup menus with commands from different major and minor +;; modes. For more information see `appmenu-mode'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; Version 0.61: +;; - Remove support for minor and major menus. +;; - Add support for text and overlay keymaps. +;; - Add customization options. +;; +;; Version 0.62: +;; - Fix problem with keymap at point. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'flyspell)) +(eval-when-compile (require 'help-mode)) +(eval-when-compile (require 'ourcomments-util nil t)) +(eval-when-compile (require 'mumamo nil t)) +;;(eval-when-compile (require 'mlinks nil t)) + +;;;###autoload +(defgroup appmenu nil + "Customization group for `appmenu-mode'." + :group 'convenience) + +(defcustom appmenu-show-help nil + "Non-nil means show AppMenu help on AppMenu popup." + :type 'boolean + :group 'appmenu) + +(defcustom appmenu-show-point-menu t + "If non-nil show entries fetched from keymaps at point." + :type 'boolean + :group 'appmenu) + +(defvar appmenu-alist nil + "List of additional menu keymaps. +To change this list use `appmenu-add' and `appmenu-remove'. + +The entries in this list are lists: + + \(ID PRIORITY TEST TITLE DEFINITION) + +ID is a unique identity. + +PRIORITY is a number or a variable whose value is a number +telling where to put this entry when showing the menu. + +TEST should be a form to evaluate. The entry is used if \(eval +TEST) returns non-nil. + +DEFINITION should be either a keymap or a function that returns a +keymap. + +The function must take no argument and return a keymap. If the +function returns nil then the entry is not shown in the popup +menu. Using this you can make context sensitive popup menus. + +For an example of use see mlinks.el.") + +(defun appmenu-sort-by-priority () + "Sort `appmenu-alist' entries by priority." + (setq appmenu-alist + (sort appmenu-alist + (lambda (recA recB) + (let ((priA (nth 1 recA)) + (priB (nth 1 recB))) + (when (symbolp priA) (setq priA (symbol-value priA))) + (when (symbolp priB) (setq priB (symbol-value priB))) + (< priA priB)))))) + +;;;###autoload +(defun appmenu-add (id priority test title definition) + "Add entry to `appmenu-alist'. +Add an entry to this list with ID, PRIORITY, TEST, TITLE and +DEFINITION as explained there." + (assert (symbolp id)) + (unless priority (setq priority 100)) + (assert (numberp priority)) + (assert (stringp title)) + (let ((rec (list id priority test title definition))) + (appmenu-remove id) + (add-to-list 'appmenu-alist rec))) + +(defun appmenu-remove (id) + "Remove entry with id ID from `appmenu-alist'." + (setq appmenu-alist (assq-delete-all id appmenu-alist))) + +(defun appmenu-help () + "Show help for minor mode function `appmenu-mode'." + (interactive) + (describe-function 'appmenu-mode)) + +(defun appmenu-keymap-len (map) + "Return length of keymap MAP." + (let ((ml 0)) + (map-keymap (lambda (e f) (setq ml (1+ ml))) map) + ml)) + +(defvar appmenu-mouse-only + '((flyspell-correct-word appmenu-flyspell-correct-word-before-point))) + +(defun appmenu-flyspell-correct-word-before-point () + "Pop up a menu of possible corrections for misspelled word before point. +Special version for AppMenu." + (interactive) + (flyspell-correct-word-before-point)) + +(defcustom appmenu-at-any-point '(ispell-word) + "Commands that may work at any point in a buffer. +Some important but not too often used commands that may be useful +for most points in a buffer." + :group 'appmenu) + +(defvar appmenu-map-fun) ;; dyn var, silence compiler + +(defun appmenu-make-menu-for-point (this-point) + "Construct a menu based on point THIS-POINT. +This includes some known commands for point and keymap at +point." + (let ((point-map (get-char-property this-point 'keymap)) + (funs appmenu-at-any-point) + (map (make-sparse-keymap "At point")) + (num 0) + last-prefix + this-prefix) + ;; Known for any point + (when point-map + (let ((appmenu-map-fun + (lambda (key fun) + (if (keymapp fun) + (map-keymap appmenu-map-fun fun) + (when (and (symbolp fun) + (fboundp fun)) + (let ((mouse-only (assq fun appmenu-mouse-only))) + (when mouse-only + (setq fun (cadr mouse-only))) + (add-to-list 'funs fun))))))) + (map-keymap appmenu-map-fun point-map))) + (dolist (fun funs) + (let ((desc (when fun (documentation fun)))) + (when desc + (setq desc (car (split-string desc "[\n]"))) + ;;(lwarn t :warning "pk: %s, %s" fun desc) + (setq this-prefix + (car (split-string (symbol-name fun) "[-]"))) + (when (and last-prefix + (not (string= last-prefix this-prefix))) + (define-key map + (vector (intern (format "appmenu-point-div-%s" num))) + (list 'menu-item "--"))) + (setq last-prefix this-prefix) + (setq num (1+ num)) + (define-key map + (vector (intern (format "appmenu-point-%s" num))) + (list 'menu-item desc fun))))) + (when (> num 0) map))) + +(defvar appmenu-level) ;; dyn var +(defvar appmenu-funs) ;; dyn var +(defvar appmenu-events) ;; dyn var +(defvar appmenu-this-point) ;; dyn var + +(defun appmenu-keymap-map-fun (ev def) + (if (keymapp def) + (progn + (add-to-list 'appmenu-funs (list appmenu-level ev)) + (setq appmenu-events (cons ev appmenu-events)) + (setq appmenu-level (1+ appmenu-level)) + + (map-keymap 'appmenu-keymap-map-fun def) + + (setq appmenu-events (cdr appmenu-events)) + (setq appmenu-level (1- appmenu-level))) + (when (and (symbolp def) + (fboundp def)) + (let* ((mouse-only (assq def appmenu-mouse-only)) + (fun (if mouse-only (cadr mouse-only) def)) + (doc (when fun + (if (not (eq fun 'push-button)) + (documentation fun) + (concat + "Button: " + (with-current-buffer (marker-buffer appmenu-this-point) + (or (get-char-property appmenu-this-point 'help-echo) + (let ((action-fun (get-char-property appmenu-this-point 'action))) + (if action-fun + (documentation action-fun) + "No action, ignored")) + "No documentation available"))))))) + (add-to-list 'appmenu-funs (list appmenu-level (cons ev appmenu-events) def doc)))))) + +;;(appmenu-as-help (point)) +(defun appmenu-as-help (this-point) + "Show keybindings specific done current point in buffer. +This shows the binding in the help buffer. + +Tip: This may be helpful if you are using `css-color-mode'." + (interactive (list (copy-marker (point)))) + ;; Split this for debugging + (let ((menu-here + (with-current-buffer (or (and (markerp this-point) + (marker-buffer this-point)) + (current-buffer)) + (unless (markerp this-point) (setq this-point (copy-marker this-point))) + (get-char-property this-point 'keymap)))) + ;;(describe-variable 'menu-here) + (appmenu-as-help-1 menu-here this-point))) + +(defun appmenu-as-help-1 (menu-here this-point) + (let ((appmenu-level 0) + (appmenu-funs nil) + (appmenu-events nil) + (appmenu-this-point this-point)) + (when menu-here + (map-keymap 'appmenu-keymap-map-fun menu-here)) + ;;(describe-variable 'appmenu-funs) + ;; Fix-me: collect info first in case we are in help-buffer! + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'appmenu-as-help this-point) (interactive-p)) + (with-current-buffer (help-buffer) + (let ((fmt " %s%15s %-30s\n")) + (insert (propertize + ;;"AppMenu: Keys found at point in buffer\n\n" + (format "Appmenu: Key bindings specific to point %s in buffer %S\n\n" + (+ 0 this-point) + (when (markerp this-point) + (buffer-name (marker-buffer this-point)))) + 'face 'font-lock-comment-face)) + (if (not menu-here) + (insert "\n\nThere are no point specific key bindings there now.") + (insert (propertize (format fmt "" "Key" "Function") 'face 'font-lock-function-name-face)) + (insert (propertize (format fmt "" "---" "--------") 'face 'font-lock-function-name-face)) + (dolist (rec appmenu-funs) + (let* ((lev (nth 0 rec)) + (ev (nth 1 rec)) + (fun (nth 2 rec)) + (doc (nth 3 rec)) + (d1 (when doc (car (split-string doc "[\n]"))))) + (if fun + (insert (format fmt + "" ;;(concat "*" (make-string (* 4 lev) ?\ )) + (key-description (reverse ev)) + d1) + (if nil (format "(%s)" fun) "")) + ;;(insert (format "something else=%S\n" rec)) + ))))))))) + + +(defun appmenu-map () + "Return menu keymap to use for popup menu." + (let* ((map (make-sparse-keymap + "AppMenu" + )) + (map-len (appmenu-keymap-len map)) + (map-init-len map-len) + (num-minor 0) + (id 0) + (point-menu (when appmenu-show-point-menu + (appmenu-make-menu-for-point (point))))) + ;; AppMenu itself + (when appmenu-show-help + (define-key map [appmenu-customize] + (list 'menu-item "Customize AppMenu" + (lambda () (interactive) (customize-group 'appmenu)) + :help "Customize AppMenu" + :visible 'appmenu-show-help)) + (define-key map [appmenu-help] + (list 'menu-item "Help for AppMenu" 'appmenu-help + :help "Help for how to use AppMenu" + :visible 'appmenu-show-help)) + (define-key map [appmenu-separator-1] + (list 'menu-item "--"))) + (setq map-len (appmenu-keymap-len map)) + (appmenu-sort-by-priority) + (dolist (rec appmenu-alist) + (let* ((test (nth 2 rec)) + (title (nth 3 rec)) + (mapdef (nth 4 rec)) + (usedef (if (symbolp mapdef) + (funcall mapdef) + mapdef))) + (when (and usedef + (eval test)) + (setq id (1+ id)) + (define-key map + (vector (intern (format "appmenu-%s" id))) + (list 'menu-item title usedef))) + )) + (when point-menu + (setq map-len (appmenu-keymap-len map)) + (when (> map-len map-init-len) + (define-key map [appmenu-at-point-div] + (list 'menu-item "--"))) + (define-key map [appmenu-at-point] + (list 'menu-item "Bound To Point" + point-menu))) + (setq map-len (appmenu-keymap-len map)) + (when (> map-len map-init-len) + map))) + +;; (defun appmenu-get-submenu (menu-command) +;; (let (subtitle submenumap) +;; (if (eq 'menu-item (car menu-command)) +;; (progn (setq subtitle (cadr menu-command)) +;; (setq submenumap (caddr menu-command))) +;; (setq subtitle (car menu-command)) +;; (setq submenumap (cdr menu-command))) +;; (unless (keymapp submenumap) (error "Submenu not a keymap=%s" submenumap)) +;; (cons subtitle submenumap))) + +(defun appmenu-popup () + "Pops up the AppMenu menu." + (interactive) + (let* ((mod (event-modifiers last-input-event)) + (is-mouse (or (memq 'click mod) + (memq 'down mod) + (memq 'drag mod)))) + (when is-mouse + (goto-char (posn-point (event-start last-input-event))) + (sit-for 0.01)) + (let ((menu (appmenu-map))) + (if menu + (popup-menu-at-point menu) + (message "Appmenu is empty"))))) + +(defvar appmenu-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [apps] 'appmenu-popup) + (define-key map [mouse-3] 'appmenu-popup) + (define-key map [(control apps)] 'appmenu-as-help) + map)) + + +;;(setq appmenu-auto-help 4) +(defcustom appmenu-auto-help 2 + "Automatically show help on keymap at current point. +This shows up after the number of seconds in this variable. +If it it nil this feature is off. + +This feature is only on in `appmenu-mode'." + :type '(choice (number :tag "Number of seconds to wait") + (const :tag "Turned off" nil)) + :set (lambda (sym val) + (set-default sym val) + (if val + (add-hook 'post-command-hook 'appmenu-auto-help-post-command nil t) + (remove-hook 'post-command-hook 'appmenu-auto-help-post-command t))) + :group 'appmenu) + +(defcustom appmenu-auto-match-keymaps + '(css-color) + "Keymaps listed here can be avoided." + :type '(set (const unknown) + (const mlink) + (const css-color)) + :group 'appmenu) + +(defvar appmenu-auto-help-timer nil) + +(defun appmenu-dump-keymap (km) + (let ((fun (lambda (ev def) + (message "ev=%S def=%S" ev def) + (when (keymapp def) + (map-keymap fun def))))) + (map-keymap fun km))) + +(defun appmenu-on-keymap (where) + (setq where (or where (point))) + (let* ((rec (get-char-property-and-overlay where 'keymap)) + (kmp (car rec)) + (ovl (cdr rec))) + (when kmp + (or (memq 'unknown appmenu-auto-match-keymaps) + (and (memq 'css-color appmenu-auto-match-keymaps) + (get-text-property where 'css-color-type)) + (and (memq 'mlinks appmenu-auto-match-keymaps) + (boundp 'mlinks-point-hilighter-overlay) + (eq ovl mlinks-point-hilighter-overlay)) + )))) + +(defsubst appmenu-auto-help-add-wcfg (at-point wcfg) + (mumamo-with-buffer-prepared-for-jit-lock + (add-text-properties at-point (1+ at-point) + (list 'point-left 'appmenu-auto-help-maybe-remove + 'appmenu-auto-help-wcfg wcfg)))) + +(defsubst appmenu-auto-help-remove-wcfg (at-point) + (mumamo-with-buffer-prepared-for-jit-lock + (remove-list-of-text-properties at-point (1+ at-point) + '(appmenu-auto-help-wcfg point-left)))) + +(defun appmenu-auto-help-maybe-remove (at-point new-point) + "Run in 'point-left property. +Restores window configuration." + (let ((old-wcfg (get-text-property at-point 'appmenu-auto-help-wcfg))) + (appmenu-auto-help-remove-wcfg at-point) + (if (appmenu-on-keymap new-point) + (appmenu-auto-help-add-wcfg new-point old-wcfg) + (if old-wcfg + (set-window-configuration old-wcfg) + (help-xref-go-back (help-buffer)))))) + +(defun appmenu-as-help-in-timer (win buf) + (condition-case err + (when (and (eq (selected-window) win) + (eq (current-buffer) buf) + appmenu-auto-help + (appmenu-on-keymap (point))) + (let* ((old-help-win (get-buffer-window (help-buffer))) + (wcfg (unless old-help-win + (current-window-configuration)))) + (unless old-help-win + (display-buffer (help-buffer))) + (appmenu-auto-help-add-wcfg (point) wcfg) + (appmenu-as-help (copy-marker (point))))) + (error (message "appmenu-as-help-in-timer: %s" (error-message-string err))))) + +(defun appmenu-auto-help-cancel-timer () + (when (timerp appmenu-auto-help-timer) + (cancel-timer appmenu-auto-help-timer)) + (setq appmenu-auto-help-timer nil)) + +(defun appmenu-auto-help-post-command () + (when (fboundp 'appmenu-as-help) + (condition-case err + (appmenu-auto-help-post-command-1) + (error (message "css-color-post-command: %s" (error-message-string err)))))) + +;; #fff #c9ff33 +(defun appmenu-auto-help-post-command-1 () + (appmenu-auto-help-cancel-timer) + (and appmenu-auto-help + (appmenu-on-keymap (point)) + (not (get-text-property (point) 'appmenu-auto-help-wcfg)) + (setq appmenu-auto-help-timer + (run-with-idle-timer appmenu-auto-help nil 'appmenu-as-help-in-timer + (selected-window) + (current-buffer))))) + + +;;;###autoload +(define-minor-mode appmenu-mode + "Use a context sensitive popup menu. +AppMenu (appmenu.el) is a framework for creating cooperative +context sensitive popup menus with commands from different major +and minor modes. Using this different modes may cooperate about +the use of popup menus. + +There is also the command `appmenu-as-help' that shows the key +bindings at current point in the help buffer. + +The popup menu and the help buffer version are on these keys: + +\\{appmenu-mode-map} + +The variable `appmenu-alist' is where the popup menu entries +comes from. + +If there is a `keymap' property at point then relevant bindings +from this is also shown in the popup menu. + +You can write functions that use whatever information you want in +Emacs to construct these entries. Since this information is only +collected when the popup menu is shown you do not have to care as +much about computation time as for entries in the menu bar." + :global t + :keymap appmenu-mode-map + :group 'appmenu + (if appmenu-mode + (add-hook 'post-command-hook 'appmenu-auto-help-post-command) + (remove-hook 'post-command-hook 'appmenu-auto-help-post-command))) + +(when (and appmenu-mode + (not (boundp 'define-globa-minor-mode-bug))) + (appmenu-mode 1)) + +(provide 'appmenu) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; appmenu.el ends here diff --git a/emacs/nxhtml/util/as-external.el b/emacs/nxhtml/util/as-external.el new file mode 100644 index 0000000..b1330c1 --- /dev/null +++ b/emacs/nxhtml/util/as-external.el @@ -0,0 +1,310 @@ +;;; as-external.el --- Emacs as an external editor to other apps +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Mon Jun 25 19:02:49 2007 +(defconst as-external:version "0.6") ;;Version: +;; Last-Updated: 2009-08-04 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This little library should make it easier to use Emacs as an +;; external editor in certain cases. One such case is when want to +;; use Emacs as the external editor with the Firefox add-on "It's All +;; Text". +;; +;; See variable `as-external-mode' for more information. +;; +;; +;;; A note on the implementation: +;; +;; You may wonder why this does not use `auto-mode-alist' since it +;; checks the file name in nearly the same way? It is perhaps possible +;; to use that, but there are two things to be aware of: +;; +;; 1. The choice made must override other possible choices. +;; +;; 2. Beside the file name the implementation here also checks if the +;; buffer has clients waiting. That makes the check more reliable. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'html-write nil t)) +(eval-when-compile (require 'mlinks nil t)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'nxhtml-mode nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) +(eval-when-compile (require 'pause nil t)) +(eval-when-compile (require 'server)) +(eval-when-compile (require 'wikipedia-mode nil t)) +(eval-and-compile (require 'wrap-to-fill nil t)) + +;;;###autoload +(defgroup as-external nil + "Settings related to Emacs as external editor." + :group 'nxhtml + :group 'external) + +(defcustom as-external-its-all-text-regexp "/itsalltext/" + "Regular expression matching It's All Text buffer's file." + :type 'regexp + :group 'as-external) + +(defcustom as-external-alist + '( + ("/itsalltext/.*wiki" as-external-for-wiki) + ("/itsalltext/.*mail" as-external-for-mail-mode) + ("/itsalltext/" as-external-for-xhtml) + ) + "List to determine setup if Emacs is used as an external Editor. +Element in this list should have the form + + \(FILE-REGEXP BUFFER-SETUP) + +where FILE-REGEXP should be a regular expression to match +`buffer-file-name'. If it matches then BUFFER-SETUP should be +called in the buffer. + +* Tip when using Firefox's add-on It's All Text: It looks like + the file name used will be constructed from the host url. For + example if your are editing something on + http://www.emacswiki.org/ the file name may be something like + 'www.emacswiki.org.283b1y212e.html'. + + +The list is processed by `as-external-setup'. Note that the first +match is used! + +The default entries in this list supports for Firefox addon It's +All Text: + +- `as-external-for-xhtml'. For text areas on web pages where you + can enter some XHTML code, for example blog comment fields. + +- `as-external-for-mail-mode', for editing web mail messages. + +- `as-external-for-wiki', for mediawiki. + +See also `as-external-mode'." + :type '(repeat + (list (choice (variable :tag "Regexp variable") + regexp) + command)) + :group 'as-external) + +(defcustom as-external-its-all-text-coding 'utf-8 + "Coding system to use for It's All Text buffers. +See also `as-external-for-xhtml'." + :type '(choice (const :tag "No special coding system" nil) + coding-system) + :group 'as-external) + +(defun as-external-fall-back (msg) + "Fallback to text-mode if necessary." + (text-mode) + (lwarn t :warning "%s. Using text-mode" msg)) + +;;;###autoload +(defun as-external-for-xhtml () + "Setup for Firefox addon It's All Text to edit XHTML. +It's All Text is a Firefox add-on for editing textareas with an +external editor. +See URL `https://addons.mozilla.org/en-US/firefox/addon/4125'. + +In this case Emacs is used to edit textarea fields on a web page. +The text will most often be part of a web page later, like on a +blog. Therefore turn on these: + +- `nxhtml-mode' since some XHTML tags may be allowed. +- `nxhtml-validation-header-mode' since it is not a full page. +- `wrap-to-fill-column-mode' to see what you are writing. +- `html-write-mode' to see it even better. + +Also bypass the question for line end conversion when using +emacsw32-eol." + (interactive) + (if (not (fboundp 'nxhtml-mode)) + (as-external-fall-back "Can't find nXhtml") + (nxhtml-mode) + (nxhtml-validation-header-mode 1) + (set (make-local-variable 'wrap-to-fill-left-marg-modes) + '(nxhtml-mode fundamental-mode)) + (wrap-to-fill-column-mode 1) + ;;(visible-point-mode 1) + (when (fboundp 'html-write-mode) (html-write-mode 1)) + (when (boundp 'emacsw32-eol-ask-before-save) + (make-local-variable 'emacsw32-eol-ask-before-save) + (setq emacsw32-eol-ask-before-save nil)))) + + +(defvar as-external-mail-mode-comment-pattern "^>.*$" + "Regular expression for a comment line.") + +(defvar as-external-mail-mode-email-pattern + (concat "[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*" + "\@" + "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}") + "Regular expression for a mail address.") + +(defvar as-external-mail-mode-font-lock-keywords + (list + (list as-external-mail-mode-comment-pattern + '(0 font-lock-comment-face)) + ;; (list as-external-mail-mode-email-pattern + ;; '(0 font-lock-keyword-face)) + )) + +;;;###autoload +(define-derived-mode as-external-for-mail-mode text-mode "ExtMail " + "Setup for Firefox addon It's All Text to edit mail. +Set normal mail comment markers in column 1 (ie >). + +Set `fill-column' to 90 and enable `wrap-to-fill-column-mode' so +that it will look similar to how it will look in the sent plain +text mail. + +See also `as-external-mode'." + ;; To-do: Look at http://globs.org/articles.php?lng=en&pg=2 + (set (make-local-variable 'comment-column) 0) + (set (make-local-variable 'comment-start) ">") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'font-lock-defaults) + '((as-external-mail-mode-font-lock-keywords) nil)) + (setq fill-column 90) + (mlinks-mode 1) + (wrap-to-fill-column-mode 1)) + +;;;###autoload +(defun as-external-for-wiki () + "Setup for Firefox addon It's All Text to edit MediaWikis." + (interactive) + (require 'wikipedia-mode nil t) + (if (not (featurep 'wikipedia-mode)) + (as-external-fall-back "Can't find file wikipedia-mode.el") + (wikipedia-mode))) + + +;;;###autoload +(define-minor-mode as-external-mode + "If non-nil check if Emacs is called as external editor. +When Emacs is called as an external editor for example to edit +text areas on a web page viewed with Firefox this library tries +to help to setup the buffer in a useful way. It may for example +set major and minor modes for the buffer. + +This can for example be useful when blogging or writing comments +on blogs. + +See `as-external-alist' for more information." + :global t + :group 'as-external + ;;(modify-coding-system-alist 'file "/itsalltext/" as-external-its-all-text-coding) + (let ((coding-entry + (cons + as-external-its-all-text-regexp + (cons as-external-its-all-text-coding + as-external-its-all-text-coding)))) + ;;(message "as-external-mode=%s" as-external-mode) + (if as-external-mode + (progn + (add-to-list 'file-coding-system-alist coding-entry) + (add-hook 'server-visit-hook 'as-external-setup t)) + (setq file-coding-system-alist + (delq coding-entry file-coding-system-alist)) + (remove-hook 'server-visit-hook 'as-external-setup)))) + +(defun as-external-setup () + "Check if Emacs is used as an external editor. +If so then turn on useful major and minor modes. +This is done by checking `as-external-alist'." + (condition-case err + (as-external-setup-1) + (error (message "as-external-setup error: %s" err)))) + +(defvar as-external-my-frame nil) +(make-variable-buffer-local 'as-external-my-frame) + +(defvar as-external-last-buffer nil) + +(defun as-external-server-window-fix-frames () + (condition-case err + (with-current-buffer as-external-last-buffer + (unless (buffer-live-p pause-buffer) + (remove-hook 'pause-break-exit-hook 'as-external-server-window-fix-frames) + (setq as-external-my-frame (or as-external-my-frame + (make-frame))) + (dolist (f (frame-list)) + (unless (eq f as-external-my-frame) + (lower-frame f))) + (raise-frame as-external-my-frame))) + (error (message "%s" (error-message-string err))))) + +(defun as-external-server-window (buffer) + (setq server-window nil) + (with-current-buffer buffer + (setq as-external-last-buffer (current-buffer)) + (run-with-idle-timer 2 nil 'as-external-server-window-fix-frames) + (add-hook 'pause-break-exit-hook 'as-external-server-window-fix-frames) + (add-hook 'kill-buffer-hook 'as-external-delete-my-frame nil t))) + +(defun as-external-delete-my-frame () + (let ((win (and (frame-live-p as-external-my-frame) + (get-buffer-window nil as-external-my-frame)))) + (when (and win + (= 1 (length (window-list as-external-my-frame 'no-mini)))) + (delete-frame as-external-my-frame) + (lower-frame)))) + +(defun as-external-setup-1 () + ;; Fix-me: How does one know if the file names are case sensitive? + (unless (when (boundp 'nowait) nowait) ;; dynamically bound in `server-visit-files' + (unless server-window + ;; `server-goto-toplevel' has been done here. + ;; Setup to use a new frame + (setq server-window 'as-external-server-window)) + (catch 'done + (dolist (rec as-external-alist) + (let ((file-regexp (car rec)) + (setup-fun (cadr rec))) + (when (symbolp file-regexp) + (setq file-regexp (symbol-value file-regexp))) + (when (string-match file-regexp (buffer-file-name)) + (funcall setup-fun) + (throw 'done t))))))) + +(provide 'as-external) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; as-external.el ends here diff --git a/emacs/nxhtml/util/buffer-bg.el b/emacs/nxhtml/util/buffer-bg.el new file mode 100644 index 0000000..d6459d6 --- /dev/null +++ b/emacs/nxhtml/util/buffer-bg.el @@ -0,0 +1,89 @@ +;;; buffer-bg.el --- Changing background color of windows +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-05-22T19:06:23+0200 Thu +;; Version: 0.5 +;; Last-Updated: 2008-05-22T23:19:55+0200 Thu +;; URL: http://www.emacswiki.org/cgi-bin/wiki/buffer-bg.el +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; There is currently no way to change background colors of Emacs +;; windows. This library implements a workaround using overlays. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(defvar buffer-bg-overlay nil) +(put 'buffer-bg-overlay 'permanent-local t) + +;;;###autoload +(defun buffer-bg-set-color (color buffer) + "Add an overlay with background color COLOR to buffer BUFFER. +If COLOR is nil remove previously added overlay." + (interactive + (let* ((prompt (if buffer-bg-overlay + "Background color (empty string to remove): " + "Background color: ")) + (color (read-color prompt nil t))) + (when (= 0 (length color)) + (setq color nil)) + (list color (current-buffer)) + )) + (if (not color) + (when buffer-bg-overlay + (delete-overlay buffer-bg-overlay) + (setq buffer-bg-overlay nil)) + (save-restriction + (widen) + (setq buffer-bg-overlay + (make-overlay (point-min) (point-max) nil nil t)) + ;; Fix-me: Let the overlay have priority 0 which is the + ;; lowest. Change this to below char properties if this is ever + ;; allowed in Emacs. + (overlay-put buffer-bg-overlay 'priority 0) + (let* ((bg-face (list :background color)) + (bg-after (propertize (make-string 10 ?\n) + 'face bg-face + 'intangible t))) + (overlay-put buffer-bg-overlay 'face bg-face) + ;; This is just confusing, don't use it: + ;;(overlay-put buffer-bg-overlay 'after-string bg-after) + ) + ))) + + +(provide 'buffer-bg) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; buffer-bg.el ends here diff --git a/emacs/nxhtml/util/chartg.el b/emacs/nxhtml/util/chartg.el new file mode 100644 index 0000000..7470710 --- /dev/null +++ b/emacs/nxhtml/util/chartg.el @@ -0,0 +1,844 @@ +;;; chartg.el --- Google charts (and maybe other) +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-04-06 Sun +(defconst chart:version "0.2") ;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) + +(defconst chartg-types + '((line-chartg-x lc) + (line-chartg-xy lxy) + (line-chart ls) + + (bar-chartg-horizontal bhs) + (bar-chartg-vertical bvs) + (bar-chartg-horizontal-grouped bhg) + (bar-chartg-vertical-grouped bvg) + + (pie-2-dimensional p) + (pie-3-dimensional p3) + + (venn-diagram v) + (scatter-plot s) + + (radar-chart r) + (radar-chartg-w-splines rs) + + (geographical-map t) + (meter gom))) + +(defconst chartg-types-keywords + (mapcar (lambda (rec) + (symbol-name (car rec))) + chartg-types)) + +(defvar chartg-mode-keywords-and-states + '(("Output-file:" (accept file-name)) + ("Size:" (accept number)) + ("Data:" (accept number)) + ("Type:" (accept chartg-type)) + )) + +(defvar chartg-mode-keywords + (mapcar (lambda (rec) + (car rec)) + chartg-mode-keywords-and-states)) + +;; Fix-me: I started to implement a parser, but I think I will drop it +;; and wait for Semantic to be easily available instead. Or just use +;; Calc/Org Tables. + +(defvar chartg-intermediate-states + '((end-or-label (or end-of-file label)) + )) + +(defvar chartg-extra-keywords-and-states + '( + ;;("Provider:") + ("Colors:") + ("Solid-fill:") + ("Linear-gradient:") + ("Linear-stripes:") + ("Chartg-title:" (and string end-or-label)) + ("Legends:" (accept string)) + ("Axis-types:") + ("Axis-labels:") + ("Axis-ranges:") + ("Axis-styles:") + ("Bar-thickness:") + ("Bar-chartg-zero-line:") + ("Bar-chartg-zero-line-2:") + ("Line-styles-1:") + ("Line-styles-2:") + ("Grid-lines:") + ("Shape-markers:") + ("Range-markers:") + )) + +(defvar chartg-extra-keywords + (mapcar (lambda (rec) + (car rec)) + chartg-extra-keywords-and-states)) + +(defvar chartg-raw-keywords-and-states + '( + ("Google-chartg-raw:" (accept string)) + )) + +(defvar chartg-raw-keywords + (mapcar (lambda (rec) + (car rec)) + chartg-raw-keywords-and-states)) + +(defvar chartg-mode-keywords-re (regexp-opt chartg-mode-keywords)) +(defvar chartg-extra-keywords-re (regexp-opt chartg-extra-keywords)) +(defvar chartg-types-keywords-re (regexp-opt chartg-types-keywords)) +(defvar chartg-raw-keywords-re (regexp-opt chartg-raw-keywords)) + +(defvar chartg-font-lock-keywords + `((,chartg-mode-keywords-re . font-lock-keyword-face) + (,chartg-extra-keywords-re . font-lock-variable-name-face) + (,chartg-types-keywords-re . font-lock-function-name-face) + (,chartg-raw-keywords-re . font-lock-preprocessor-face) + )) + +(defvar chartg-font-lock-defaults + '(chartg-font-lock-keywords nil t)) + +(defvar chartg-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?\n "> " table) + (modify-syntax-entry ?\; "< " table) + table)) + +(defun chartg-create (provider out-file size data type + title legends &optional extras) + "Create a chart image. +PROVIDER is what to use for creating the chart. Currently only +`google' for Google's chart API is supported. + +OUT-FILE is where the image goes. + +SIZE is a cons cell with pixel width and height. + +DATA is the data to draw the chart from. It is a list of data +sets where each data set has the form: + + (list (list NUMBERS ...) (MIN . MAX))) + +TYPE can be the following: + +* Line charts + + - lc: Line chart with only y values. Each dataset is a new + line. + + - lxy: Line chart with both x and y values. For each line there + should be a pair of datasets, the first for x and the second + for y. If the x dataset just contains a single -1 then values + are evenly spaced along the x-axis. + + - ls: Like above, but axis are not drawn. + +* Bar charts: + + - bhs: horizontal bars. + - bvs: vertical bars. + - bhg, bvg: dito grouped. + +* Pie charts: + + - cht=p: one dimensional + - cht=p3: three dimensional + +* Venn diagrams + + - cht=v: data should be specified as + * the first three values specify the relative sizes of three + circles, A, B, and C + * the fourth value specifies the area of A intersecting B + * the fifth value specifies the area of A intersecting C + * the sixth value specifies the area of B intersecting C + * the seventh value specifies the area of A intersecting B + intersecting C + +* Scatter plots + + - cht=s: Supply a pair of datasets, first for x and second for + y coordinates. + +* Radar charts + + - cht=r: straight lines. + - cht=rs: splines. + + You will have to find out the format of the datasets + yourself, I don't understand it ;-) + + Or perhaps mail google? + +* Maps + + - cht=t + + together with + + - chtm=AREA: AREA for provider `google' is currently one of + * africa + * asia + * europe + * middle_east + * south_america + * usa + * world + +* Meter + + - cht=gom: A speed meter type meter. Takes a single value. + +TITLE is a string to use as title. + +LEGENDS is a list of labels to put on the data. + +EXTRAS is a list of extra arguments with the form + + (EXTRA-TYPE EXTRA-VALUE) + +Where EXTRA-TYPE is the extra argument type and EXTRA-VALUE the +value. The following EXTRA-TYPEs are supported: + +* COLORS: value is a list of colors corresponding to the list of + DATA. Each color have the format RRGGBB or RRGGBBTT where the + first form is the normal way to specify colors in rgb-format + and the second has an additional TT for transparence. TT=00 + means completely transparent and TT=FF means completely opaque. + +FILL-AREA are fill colors for data sets in line charts. It should +be a list + + (list COLOR START-INDEX END-INDEX) + +" + (message "(chartg-create %s %s %s %s %s %s %s" provider out-file size data type + title legends) + (unless (symbolp type) + (error "Argument TYPE should be a symbol")) + (unless (assoc type chartg-types) + (error "Unknown chart type: %s" type)) + (cond + ((eq provider 'google) + (let* ((g-type (nth 1 (assoc type chartg-types))) + (width (car size)) + (height (cdr size)) + ;;(size-par (format "&chs=%sx%s" width height)) + ;; + numbers + scales + colors-par + ;; + url + content + ) + (setq url + (format + "http://chart.apis.google.com/chart?cht=%s&chs=%dx%d" g-type width height)) + ;;(setq url (concat url size-par)) + ;; Data and scales + (unless data + (error "No data")) + (dolist (rec data) + (let* ((rec-numbers (car rec)) + (number-str + (let (str) + (dolist (num rec-numbers) + (setq str + (if (not str) + (number-to-string num) + (concat str "," (number-to-string num))))) + str)) + (rec-scale (cadr rec)) + (rec-min (car rec-scale)) + (rec-max (cdr rec-scale)) + (scale-str (when rec-scale (format "%s,%s" rec-min rec-max))) + ) + (if (not numbers) + (progn + (setq numbers (concat "&chd=t:" number-str)) + (when (or scale-str + (memq g-type '(p p3 gom))) + (setq scales (concat "&chds=" scale-str)))) + (setq numbers (concat numbers "|" number-str)) + (when scale-str + (setq scales (concat scales "," scale-str)))))) + (setq url (concat url numbers)) + (when scales (setq url (concat url scales))) + ;; fix-me: encode the url + (when title (setq url (concat url "&chtt=" (url-hexify-string title)))) + (when legends + (let ((url-legends (mapconcat 'url-hexify-string legends "|")) + (arg (if (memq g-type '(p p3 gom)) + "&chl=" + "&chdl="))) + (setq url (concat url arg url-legends)))) + (dolist (extra extras) + (let ((extra-type (car extra)) + (extra-value (cdr extra))) + (cond + ((eq extra-type 'GOOGLE-RAW) + (setq url (concat url extra-value))) + ((eq extra-type 'colors) + ;; Colors + (dolist (color extra-value) + (if (not colors-par) + (setq colors-par (concat "&chco=" color)) + (setq colors-par (concat colors-par "," color)))) + (when colors-par (setq url (concat url colors-par)))) + (t (error "Unsupported extra type: %s" extra-type))))) + + ;;(lwarn t :warning "url=%s" url)(top-level) + ;;(setq url (concat url "&chxt=y")) + (message "Sending %s" url) + (setq content + (with-current-buffer (url-retrieve-synchronously url) + (goto-char (point-min)) + (if (search-forward "\n\n" nil t) + (buffer-substring-no-properties (point) (point-max)) + (view-buffer-other-window (current-buffer)) + (error "Bad content")))) + (let* ((is-html (string-match-p "</body></html>" content)) + (fname (progn + (when is-html + (setq out-file (concat (file-name-sans-extension out-file) ".html"))) + (expand-file-name out-file) + )) + (do-it (or (not (file-exists-p fname)) + (y-or-n-p + (concat "File " fname " exists. Replace it? ")))) + (buf (find-buffer-visiting fname)) + (this-window (selected-window))) + (when do-it + (when buf (kill-buffer buf)) + (with-temp-file fname + (insert content)) + (if (not is-html) + (view-file-other-window fname) + (chartg-show-last-error-file fname)) + (select-window this-window))))) + (t (error "Unknown provider: %s" provider))) + ) + +(defun chartg-show-last-error-file (fname) + (interactive) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'chartg-show-last-error-file fname) (interactive-p)) + (with-current-buffer (help-buffer) + (insert "Error, see ") + (insert-text-button "result error page" + 'action + `(lambda (btn) + (browse-url ,fname)))))) + +(defvar chartg-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(meta tab)] 'chartg-complete) + (define-key map [(control ?c) (control ?c)] 'chartg-make-chart) + map)) + +(defun chartg-missing-keywords () + (let ((collection (copy-sequence chartg-mode-keywords))) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward chartg-mode-keywords-re nil t) + (setq collection + (delete (match-string-no-properties 0) + collection))))) + collection)) + +;;;###autoload +(defun chartg-complete () + (interactive) + (let* ((here (point)) + (partial (when (looking-back (rx word-start + (optional ?\") + (0+ (any "[a-z]")))) + (match-string-no-properties 0))) + (part-pos (if partial + (match-beginning 0) + (setq partial "") + (point))) + (state (catch 'pos-state (chartg-get-state (point)))) + (msg "No completions") + collection + all + prompt + res) + (when state + (cond + ((or (= (current-column) 0) + (equal state 'need-label)) + (setq collection (append (chartg-missing-keywords) + chartg-extra-keywords + chartg-raw-keywords + nil)) + (setq prompt "Label: ")) + ((equal state '(accept number)) + (setq res nil) + (setq msg (propertize "Needs a number here!" + 'face 'secondary-selection))) + ((equal state '(accept chartg-type)) + (setq collection chartg-types-keywords) + (setq prompt "Chart type: ")) + ((equal state '(accept file-name)) + (setq res + (concat "\"" (read-file-name "Output-file: " + nil + ;; fix-me: handle partial + partial) + "\"")))) + (when collection + (let ((all (if partial + (all-completions partial collection) + collection))) + (setq res (when all + (if (= (length all) 1) + (car all) + (completing-read prompt collection nil t partial))))))) + (if (not res) + (message "%s" msg) + (insert (substring res (length partial)))))) + + +(defun chartg-get-state (want-pos-state) + (let* (par-output-file + par-provider + par-size + par-data par-data-temp + par-data-min par-data-max + par-type + par-title + par-legends + par-google-raw + (here (point)) + token-before-pos + pos-state + (state 'need-label) + (problems + (catch 'problems + (save-restriction + ;;(widen) + (if want-pos-state + (unless (re-search-backward chartg-mode-keywords-re nil t) + (goto-char (point-min))) + (goto-char (point-min))) + (let (this-keyword + this-start + this-end + params + token + token-pos + next-token + found-labels + current-label) + (while (or token + (progn + (setq pos-state state) + (setq token-before-pos (point)) + (condition-case err + (setq token (read (current-buffer))) + (error + (if (eq (car err) 'end-of-file) + (unless (or (eq state 'need-label) + (member '(quote |) state)) + (throw 'problems (format "Unexpected end, state=%s" state))) + (throw 'problems + (error-message-string err))))))) + (message "token=%s, label=%s, state=%s" token current-label state) + (when (and want-pos-state + (>= (point) want-pos-state)) + (when (= (point) want-pos-state) + ;; right after item + (setq pos-state nil)) + (goto-char here) + (throw 'pos-state pos-state)) + (when (and (listp state) (memq 'number state)) + (unless (numberp token) + (save-match-data + (let ((token-str (format "%s" token))) + (setq token-str (replace-regexp-in-string "\\([0-9]\\),\\([0-9]\\)" "\\1\\2" token-str)) + (when (string-match-p "^[0-9]+$" token-str) + (setq token (string-to-number token-str))))))) + (cond ;; state + ;; Label + ((eq state 'need-label) + (unless (symbolp token) + (throw 'problems (format "Expected label, got %s" token))) + (unless (member (symbol-name token) + (append chartg-mode-keywords + chartg-extra-keywords + chartg-raw-keywords + nil)) + (throw 'problems (format "Unknown label %s" token))) + (when (member (symbol-name token) found-labels) + (throw 'problems (format "Label %s defined twice" token))) + (setq current-label token) + (setq found-labels (cons current-label found-labels)) + (setq token nil) + ;;(setq state 'need-value) + (case current-label + ('Output-file: + (setq state '(accept file-name))) + ('Size: + (setq state '(accept number))) + ('Data: + (setq state '(accept number))) + ('Type: + (setq state '(accept chartg-type))) + ('Chartg-title: + (setq state '(accept string))) + ('Legends: + (setq state '(accept string))) + ('Google-chartg-raw: + (setq state '(accept string))) + )) + ;;;; Values + ;; Alt + ((equal state '(accept '| symbol)) + (if (eq '| token) + (case current-label + ('Legends: + (setq token nil) + (setq state '(accept string))) + (t (error "internal error, current-label=%s, state=%s" current-label state))) + (if (symbolp token) + (progn + ;;(setq token nil) + (setq state 'need-label)) + (throw 'problems (format "Expected | or label, got %s" token))))) + ;; Strings + ((equal state '(accept string)) + (unless (stringp token) + (throw 'problems "Expected string")) + (case current-label + ('Chartg-title: + (setq par-title token) + (setq token nil) + (setq state 'need-label)) + ('Legends: + (setq par-legends (cons token par-legends)) + (setq token nil) + (setq state '(accept '| symbol))) + ('Google-chartg-raw: + (setq par-google-raw token) + (setq token nil) + (setq state 'need-label)) + (t (error "internal error, current-label=%s, state=%s" current-label state)))) + ;; Output file + ((equal state '(accept file-name)) + (unless (stringp token) + (throw 'problems "Expected file name string")) + (assert (eq current-label 'Output-file:)) + (setq par-output-file token) + (setq token nil) + (setq state 'need-label)) + ;; Numbers + ((equal state '(accept number)) + (unless (numberp token) + (throw 'problems "Expected number")) + (case current-label + ('Size: + (if (not par-size) + (progn + (setq par-size token) + (setq token nil) + (setq state '(accept number 'x 'X))) + (setq par-size (cons par-size token)) + (setq token nil) + (setq state 'need-label))) + ('Data: + ;;(assert (not par-data-temp)) + (setq par-data-temp (cons token par-data-temp)) + (setq par-data-min token) + (setq par-data-max token) + (setq token nil) + (setq state '(accept number ', '| symbol)) + ) + (t (error "internal error, state=%s, current-label=%s" state current-label))) + ) + ;; Numbers or | + ((equal state '(accept number ', '| symbol)) + (if (numberp token) + (progn + (setq par-data-min (if par-data-min (min par-data-min token) token)) + (setq par-data-max (if par-data-max (max par-data-max token) token)) + (setq par-data-temp (cons token par-data-temp)) + (message "par-data-min/max=%s/%s, token=%s -- %s" par-data-min par-data-max token par-data-temp) + (setq token nil)) + (if (eq ', token) + (setq token nil) + (if (or (eq '| token) + (symbolp token)) + (progn + (unless par-data-temp + (throw 'problems "Empty data set")) + (setq par-data (cons (list (reverse par-data-temp) (cons par-data-min par-data-max)) par-data)) + (setq par-data-temp nil) + (setq par-data-min nil) + (setq par-data-max nil) + (if (not (eq '| token)) + (setq state 'need-label) + (setq state '(accept number)) + (setq token nil))) + (throw 'problems "Expected | or EOF") + )))) + ;; Numbers or x/X + ((equal state '(accept number 'x 'X)) + (assert (eq current-label 'Size:)) + (let ((is-n (numberp token)) + (is-x (memq token '(x X)))) + (unless (or is-n is-x) + (throw 'problems "Expected X or number")) + (if is-x + (progn + (setq token nil) + (setq state '(accept number))) + (setq par-size (cons par-size token)) + (setq token nil) + (setq state 'need-label)))) + ;; Chart type + ((equal state '(accept chartg-type)) + (setq par-type token) + (unless (assoc par-type chartg-types) + (throw 'problems (format "Unknown chart type: %s" par-type))) + (setq token nil) + (setq state 'need-label)) + (t (error "internal error, state=%s" state)))))) + ;; fix-me here + + nil))) + (when want-pos-state + (goto-char here) + (throw 'pos-state state)) + (unless problems + (let ((missing-lab (chartg-missing-keywords))) + (when missing-lab + (setq problems (format "Missing required labels: %s" missing-lab))))) + (if problems + (let ((msg (if (listp problems) + (nth 1 problems) + problems)) + (where (if (listp problems) + (nth 0 problems) + token-before-pos))) + (goto-char where) + (skip-chars-forward " \t") + (error msg)) + (goto-char here) + ;;(defun chartg-create (out-file provider size data type &rest extras) + (setq par-provider 'google) + (setq par-legends (nreverse par-legends)) + (let ((extras nil)) + (when par-google-raw + (setq extras (cons (cons 'GOOGLE-RAW par-google-raw) extras))) + (chartg-create par-provider par-output-file par-size + par-data par-type par-title par-legends extras)) + nil))) + +;;;###autoload +(defun chartg-make-chart () + "Try to make a new chart. +If region is active then make a new chart from data in the +selected region. + +Else if current buffer is in `chartg-mode' then do it from the +chart specifications in this buffer. Otherwise create a new +buffer and initialize it with `chartg-mode'. + +If the chart specifications are complete enough to make a chart +then do it and show the resulting chart image. If not then tell +user what is missing. + +NOTE: This is beta, no alpha code. It is not ready. + +Below are some examples. To test them mark an example and do + + M-x chartg-make-chart + +* Example, simple x-y chart: + + Output-file: \"~/temp-chart.png\" + Size: 200 200 + Data: 3 8 5 | 10 20 30 + Type: line-chartg-xy + +* Example, pie: + + Output-file: \"~/temp-depression.png\" + Size: 400 200 + Data: + 2,160,000 + 3,110,000 + 1,510,000 + 73,600 + 775,000 + 726,000 + 8,180,000 + 419,000 + Type: pie-3-dimensional + Chartg-title: \"Depression hits on Google\" + Legends: + \"SSRI\" + | \"Psychotherapy\" + | \"CBT\" + | \"IPT\" + | \"Psychoanalysis\" + | \"Mindfulness\" + | \"Meditation\" + | \"Exercise\" + + +* Example, pie: + + Output-file: \"~/temp-panic.png\" + Size: 400 200 + Data: + 979,000 + 969,000 + 500,000 + 71,900 + 193,000 + 154,000 + 2,500,000 + 9,310,000 + Type: pie-3-dimensional + Chartg-title: \"Depression hits on Google\" + Legends: + \"SSRI\" + | \"Psychotherapy\" + | \"CBT\" + | \"IPT\" + | \"Psychoanalysis\" + | \"Mindfulness\" + | \"Meditation\" + | \"Exercise\" + + +* Example using raw: + + Output-file: \"~/temp-chartg-slipsen-kostar.png\" + Size: 400 130 + Data: 300 1000 30000 + Type: bar-chartg-horizontal + Chartg-title: \"Vad killen i slips tjänar jämfört med dig och mig\" + Google-chartg-raw: \"&chds=0,30000&chco=00cd00|ff4500|483d8b&chxt=y,x&chxl=0:|Killen+i+slips|Partiledarna|Du+och+jag&chf=bg,s,ffd700\" + + +" + (interactive) + (if mark-active + (let* ((rb (region-beginning)) + (re (region-end)) + (data (buffer-substring-no-properties rb re)) + (buf (generate-new-buffer "*Chart from region*"))) + (switch-to-buffer buf) + (insert data) + (chartg-mode)) + (unless (eq major-mode 'chartg-mode) + (switch-to-buffer (generate-new-buffer "*Chart*")) + (chartg-mode))) + (chartg-get-state nil)) + +;; (defun chartg-from-region (min max) +;; "Try to make a new chart from data in selected region. +;; See `chartg-mode' for examples you can test with this function." +;; (interactive "r") +;; (unless mark-active (error "No region selected")) +;; (let* ((rb (region-beginning)) +;; (re (region-end)) +;; (data (buffer-substring-no-properties rb re)) +;; (buf (generate-new-buffer "*Chart from region*"))) +;; (switch-to-buffer buf) +;; (insert data) +;; (chartg-mode) +;; (chartg-get-state nil))) + +(define-derived-mode chartg-mode fundamental-mode "Chart" + "Mode for specifying charts. +\\{chartg-mode-map} + +To make a chart see `chartg-make-chart'. + +" + (set (make-local-variable 'font-lock-defaults) chartg-font-lock-defaults) + (set (make-local-variable 'comment-start) ";") + ;; Look within the line for a ; following an even number of backslashes + ;; after either a non-backslash or the line beginning. + (set (make-local-variable 'comment-start-skip) + "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *") + ;; Font lock mode uses this only when it KNOWS a comment is starting. + (set (make-local-variable 'font-lock-comment-start-skip) ";+ *") + (set (make-local-variable 'comment-add) 1) ;default to `;;' in comment-region + (set (make-local-variable 'comment-column) 40) + ;; Don't get confused by `;' in doc strings when paragraph-filling. + (set (make-local-variable 'comment-use-global-state) t) + (set-syntax-table chartg-mode-syntax-table) + (when (looking-at (rx buffer-start (0+ whitespace) buffer-end)) + (insert ";; Type C-c C-c to make a chart, M-Tab to complete\n")) + (let ((missing (chartg-missing-keywords))) + (when missing + (save-excursion + (goto-char (point-max)) + (dolist (miss missing) + (insert "\n" miss " ")))))) + +;; Tests +;;(chartg-create 'google "temp.png" '(200 . 150) '(((90 70) . nil)) 'pie-3-dimensional "test title" nil '((colors "FFFFFF" "00FF00"))) + +;; Fix-me +(add-to-list 'auto-mode-alist '("\\.mx-chart\\'" . chartg-mode)) + +(provide 'chartg) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; chartg.el ends here diff --git a/emacs/nxhtml/util/css-color.el b/emacs/nxhtml/util/css-color.el new file mode 100644 index 0000000..38d400c --- /dev/null +++ b/emacs/nxhtml/util/css-color.el @@ -0,0 +1,983 @@ +;;; css-color.el --- Highlight and edit CSS colors + +(defconst css-color:version "0.03") +;; Copyright (C) 2008 Niels Giesen + +;; Author: Niels Giesen +;; Keywords: processes, css, extensions, tools +;; Some smaller changes made by Lennart Borgman + +;; Last-Updated: 2009-10-19 Mon + +;; 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 3 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, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Edit css-colors in hex, rgb or hsl notation in-place, with +;; immediate feedback by font-locking. Cycle between color-spaces. + +;; Usage: + +;; (autoload 'css-color-mode "css-color" "" t) +;; (add-hook 'css-mode-hook 'css-color-mode-turn-on) + +;; Css-Css-color.el propertizes colours in a CSS stylesheet found by +;; font-locking code with a keymap. From that keymap, you can easily +;; adjust values such as red green and blue, hue, saturation and +;; value, or switch between different color (space) notations. + +;; It supports all 'css-colors', so hex, rgb(), hsl() and even HTML +;; color names (although I wouldn't use them myself, it is nice to be +;; able to quickly convert those), can be used and switched between. + +;; The rgb() notation can be expressed either in percentages or in +;; values between 0-255. + +;; You can cycle between the different formats (with SPACE), so that +;; it is possible to edit the color in hsl mode (which is more +;; intuitive than hsv, although hsv has its merits too), and switch +;; back to rgb or hex if so desired. + +;; With point on a color, the keys - and = to are bound to the down +;; and up functions for channels (or 'fields'). Toggling percentage +;; in rgb() is done with the % key (not sure if that is wise +;; though). The TAB key is bound to go to the next channel, cycling +;; when at the end. color.el propertizes the longhand hexcolours +;; found by the + +;; Caveats: + +;; Notation cycling can often introduce small errors inherent to +;; switching color spaces. Currently there is no check nor a warning +;; for that. + +;; ToDo: + +;; Try and fix those conversion inaccuracies. This cannot be done +;; completely I guess. But maybe we can check whether this has +;; occured, and then warn. + +;;; Change log: + +;; 2009-01-11 Lennart Borgman +;; - Minor code clean up. +;; 2009-05-23 Lennart Borgman +;; - Let bound m1 and m2. + +;;; Code: +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'mumamo nil t)) + +;;;###autoload +(defgroup css-color () + "Customization group for library `css-color'." + :group 'css + :group 'nxhtml) + +(defconst css-color-hex-chars "0123456789abcdefABCDEF" + "Composing chars in hexadecimal notation, save for the hash (#) sign.") + +(defconst css-color-hex-re + "#\\([a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)") + +(defconst css-color-hsl-re + "hsla?(\\([[:digit:]]\\{1,3\\}\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*\\)\\)%,[[:space:]]*\\([[:digit:]]\\{1,3\\}\\)\\(?:\.?[[:digit:]]*\\)%)") + +(defconst css-color-rgb-re + "rgba?(\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\)\\(:?,[[:space:]]*\\(0\.[0-9]+\\|1\\)\\)?)") + +(defconst css-color-html-colors + '(("AliceBlue" "#F0F8FF") + ("AntiqueWhite" "#FAEBD7") + ("Aqua" "#00FFFF") + ("Aquamarine" "#7FFFD4") + ("Azure" "#F0FFFF") + ("Beige" "#F5F5DC") + ("Bisque" "#FFE4C4") + ("Black" "#000000") + ("BlanchedAlmond" "#FFEBCD") + ("Blue" "#0000FF") + ("BlueViolet" "#8A2BE2") + ("Brown" "#A52A2A") + ("BurlyWood" "#DEB887") + ("CadetBlue" "#5F9EA0") + ("Chartreuse" "#7FFF00") + ("Chocolate" "#D2691E") + ("Coral" "#FF7F50") + ("CornflowerBlue" "#6495ED") + ("Cornsilk" "#FFF8DC") + ("Crimson" "#DC143C") + ("Cyan" "#00FFFF") + ("DarkBlue" "#00008B") + ("DarkCyan" "#008B8B") + ("DarkGoldenRod" "#B8860B") + ("DarkGray" "#A9A9A9") + ("DarkGrey" "#A9A9A9") + ("DarkGreen" "#006400") + ("DarkKhaki" "#BDB76B") + ("DarkMagenta" "#8B008B") + ("DarkOliveGreen" "#556B2F") + ("Darkorange" "#FF8C00") + ("DarkOrchid" "#9932CC") + ("DarkRed" "#8B0000") + ("DarkSalmon" "#E9967A") + ("DarkSeaGreen" "#8FBC8F") + ("DarkSlateBlue" "#483D8B") + ("DarkSlateGray" "#2F4F4F") + ("DarkSlateGrey" "#2F4F4F") + ("DarkTurquoise" "#00CED1") + ("DarkViolet" "#9400D3") + ("DeepPink" "#FF1493") + ("DeepSkyBlue" "#00BFFF") + ("DimGray" "#696969") + ("DimGrey" "#696969") + ("DodgerBlue" "#1E90FF") + ("FireBrick" "#B22222") + ("FloralWhite" "#FFFAF0") + ("ForestGreen" "#228B22") + ("Fuchsia" "#FF00FF") + ("Gainsboro" "#DCDCDC") + ("GhostWhite" "#F8F8FF") + ("Gold" "#FFD700") + ("GoldenRod" "#DAA520") + ("Gray" "#808080") + ("Grey" "#808080") + ("Green" "#008000") + ("GreenYellow" "#ADFF2F") + ("HoneyDew" "#F0FFF0") + ("HotPink" "#FF69B4") + ("IndianRed" "#CD5C5C") + ("Indigo" "#4B0082") + ("Ivory" "#FFFFF0") + ("Khaki" "#F0E68C") + ("Lavender" "#E6E6FA") + ("LavenderBlush" "#FFF0F5") + ("LawnGreen" "#7CFC00") + ("LemonChiffon" "#FFFACD") + ("LightBlue" "#ADD8E6") + ("LightCoral" "#F08080") + ("LightCyan" "#E0FFFF") + ("LightGoldenRodYellow" "#FAFAD2") + ("LightGray" "#D3D3D3") + ("LightGrey" "#D3D3D3") + ("LightGreen" "#90EE90") + ("LightPink" "#FFB6C1") + ("LightSalmon" "#FFA07A") + ("LightSeaGreen" "#20B2AA") + ("LightSkyBlue" "#87CEFA") + ("LightSlateGray" "#778899") + ("LightSlateGrey" "#778899") + ("LightSteelBlue" "#B0C4DE") + ("LightYellow" "#FFFFE0") + ("Lime" "#00FF00") + ("LimeGreen" "#32CD32") + ("Linen" "#FAF0E6") + ("Magenta" "#FF00FF") + ("Maroon" "#800000") + ("MediumAquaMarine" "#66CDAA") + ("MediumBlue" "#0000CD") + ("MediumOrchid" "#BA55D3") + ("MediumPurple" "#9370D8") + ("MediumSeaGreen" "#3CB371") + ("MediumSlateBlue" "#7B68EE") + ("MediumSpringGreen" "#00FA9A") + ("MediumTurquoise" "#48D1CC") + ("MediumVioletRed" "#C71585") + ("MidnightBlue" "#191970") + ("MintCream" "#F5FFFA") + ("MistyRose" "#FFE4E1") + ("Moccasin" "#FFE4B5") + ("NavajoWhite" "#FFDEAD") + ("Navy" "#000080") + ("OldLace" "#FDF5E6") + ("Olive" "#808000") + ("OliveDrab" "#6B8E23") + ("Orange" "#FFA500") + ("OrangeRed" "#FF4500") + ("Orchid" "#DA70D6") + ("PaleGoldenRod" "#EEE8AA") + ("PaleGreen" "#98FB98") + ("PaleTurquoise" "#AFEEEE") + ("PaleVioletRed" "#D87093") + ("PapayaWhip" "#FFEFD5") + ("PeachPuff" "#FFDAB9") + ("Peru" "#CD853F") + ("Pink" "#FFC0CB") + ("Plum" "#DDA0DD") + ("PowderBlue" "#B0E0E6") + ("Purple" "#800080") + ("Red" "#FF0000") + ("RosyBrown" "#BC8F8F") + ("RoyalBlue" "#4169E1") + ("SaddleBrown" "#8B4513") + ("Salmon" "#FA8072") + ("SandyBrown" "#F4A460") + ("SeaGreen" "#2E8B57") + ("SeaShell" "#FFF5EE") + ("Sienna" "#A0522D") + ("Silver" "#C0C0C0") + ("SkyBlue" "#87CEEB") + ("SlateBlue" "#6A5ACD") + ("SlateGray" "#708090") + ("SlateGrey" "#708090") + ("Snow" "#FFFAFA") + ("SpringGreen" "#00FF7F") + ("SteelBlue" "#4682B4") + ("Tan" "#D2B48C") + ("Teal" "#008080") + ("Thistle" "#D8BFD8") + ("Tomato" "#FF6347") + ("Turquoise" "#40E0D0") + ("Violet" "#EE82EE") + ("Wheat" "#F5DEB3") + ("White" "#FFFFFF") + ("WhiteSmoke" "#F5F5F5") + ("Yellow" "#FFFF00") + ("YellowGreen" "#9ACD32"))) + +(defvar css-color-html-re + (concat "\\<\\(" + (funcall 'regexp-opt + (mapcar 'car css-color-html-colors)) + "\\)\\>")) + +(defconst + css-color-color-re + "\\(?:#\\(?:[a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)\\|hsl(\\(?:[[:digit:]]\\{1,3\\}\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}\\)%,[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}\\)%)\\|rgba?(\\(?:[[:digit:]]\\{1,3\\}%?\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}%?\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}%?\\)\\(?:,[[:space:]]*\\(?:0.[0-9]+\\|1\\)\\)?)\\)" + "Regular expression containing only shy groups matching any type of CSS color") + +;; (defconst css-color-color-re +;; (concat "\\(?1:" +;; (mapconcat +;; 'identity +;; (list css-color-hex-re +;; css-color-hsl-re +;; css-color-rgb-re) "\\|") +;; "\\)")) + +(defvar css-color-keywords + `((,css-color-hex-re + (0 + (progn + (when (= 7 (- (match-end 0) + (match-beginning 0))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-map)) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'hex) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + (match-string-no-properties 0) + :foreground + (css-color-foreground-color + (match-string-no-properties 0))))))) + (,css-color-html-re + (0 + (let ((color + (css-color-string-name-to-hex (match-string-no-properties 0)))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'name) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))) + (,css-color-hsl-re + (0 + (let ((color (concat "#" (apply 'css-color-hsl-to-hex + (mapcar 'string-to-number + (list + (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3))))))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'hsl) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))) + (,css-color-rgb-re + (0 + (let ((color (css-color-string-rgb-to-hex (match-string-no-properties 0)))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'rgb) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))))) + + +;;;###autoload +(define-minor-mode css-color-mode + "Show hex color literals with the given color as background. +In this mode hexadecimal colour specifications like #6600ff are +displayed with the specified colour as background. + +Certain keys are bound to special colour editing commands when +point is at a hexadecimal colour: + +\\{css-color-map}" + :initial-value nil + :group 'css-color + (unless font-lock-defaults + (error "Can't use css-color-mode for this major mode")) + (if css-color-mode + (progn + (unless font-lock-mode (font-lock-mode 1)) + (css-color-font-lock-hook-fun) + (add-hook 'font-lock-mode-hook 'css-color-font-lock-hook-fun nil t)) + (remove-hook 'font-lock-mode-hook 'css-color-font-lock-hook-fun t) + (font-lock-remove-keywords nil css-color-keywords)) + ;;(font-lock-fontify-buffer) + (save-restriction + (widen) + (mumamo-mark-for-refontification (point-min) (point-max)))) + +(put 'css-color-mode 'permanent-local t) + +(defun css-color-turn-on-in-buffer () + "Turn on `css-color-mode' in `css-mode'." + (when (derived-mode-p 'css-mode) + (css-color-mode 1))) + +;;;###autoload +(define-globalized-minor-mode css-color-global-mode css-color-mode + css-color-turn-on-in-buffer + :group 'css-color) + +(defun css-color-font-lock-hook-fun () + "Add css-color pattern to font-lock's." + (if font-lock-mode + (font-lock-add-keywords nil css-color-keywords t) + (css-color-mode -1))) + +(defvar css-color-map + (let ((m (make-sparse-keymap "css-color"))) + (define-key m "=" 'css-color-up) + (define-key m "-" 'css-color-down) + (define-key m "h" 'css-color-hue-up) + (define-key m "H" 'css-color-hue-down) + (define-key m "s" 'css-color-saturation-up) + (define-key m "S" 'css-color-saturation-down) + (define-key m "v" 'css-color-value-up) + (define-key m "V" 'css-color-value-down) + (define-key m "\t" 'css-color-next-channel) + (define-key m " " 'css-color-cycle-type) + m) + "Mode map for `css-color-minor-mode'") + +(defvar css-color-generic-map + (let ((m (make-sparse-keymap "css-color"))) + (define-key m "=" 'css-color-num-up) + (define-key m "-" 'css-color-num-down) + (define-key m " " 'css-color-cycle-type) + (define-key m "%" 'css-color-toggle-percentage) + (define-key m "\t" 'css-color-next-channel) + m) + "Mode map for simple numbers in `css-color-minor-mode'") + +(defun css-color-pal-lumsig (r g b) + "Return PAL luminance signal, but in range 0-255." + (+ + (* 0.3 r) + (* 0.59 g) + (* 0.11 b))) + +(defun css-color-foreground-color (hex-color) + (multiple-value-bind (r g b) (css-color-hex-to-rgb hex-color) + (if (< (css-color-pal-lumsig r g b) 128) + "#fff" + "#000"))) + +;; Normalizing funs +(defun css-color-normalize-hue (h) + (mod (+ (mod h 360) 360) 360)) + +(defun css-color-within-bounds (num min max) + (min (max min num) max)) + +;; Source: hex +(defun css-color-hex-to-rgb (str) + (cond + ((not (string-match "^#?[a-fA-F[:digit:]]*$" str)) + (error "No valid hexadecimal: %s" str)) + ((= 0 (length str)) + nil) + ((= (aref str 0) 35) + (css-color-hex-to-rgb (substring str 1))) + (;;(oddp (length str)) + (= (mod (length str) 2) 1) + (css-color-hex-to-rgb (mapconcat (lambda (c) + (make-string 2 c)) + (string-to-list str) ""))) + (t (cons (string-to-number (substring str 0 2) 16) + (css-color-hex-to-rgb (substring str 2)))))) + +(defun css-color-hex-to-hsv (hex) + (multiple-value-bind (r g b) (css-color-hex-to-rgb hex) + (css-color-rgb-to-hsv r g b))) + +;; Source: rgb +(defun css-color-rgb-to-hex (r g b) + "Return r g b as #rrggbb in hexadecimal, propertized to have +the keymap `css-color-map'" + (format "%02x%02x%02x" r g b)) ;val + +(defun css-color-rgb-to-hsv (r g b) + "Return list of (hue saturation value). +Arguments are: R = red; G = green; B = blue. +Measure saturation and value on a scale from 0 - 100. +GIMP-style, that is." + (let* ((r (float r)) + (g (float g)) + (b (float b)) + (max (max r g b)) + (min (min r g b))) + (values + (round + (cond ((and (= r g) (= g b)) 0) + ((and (= r max) + (>= g b)) + (* 60 (/ (- g b) (- max min)))) + ((and (= r max) + (< g b)) + (+ 360 (* 60 (/ (- g b) (- max min))))) + ((= max g) + (+ 120 (* 60 (/ (- b r) (- max min))))) + ((= max b) + (+ 240 (* 60 (/ (- r g) (- max min))))))) ;hue + (round (* 100 (if (= max 0) 0 (- 1 (/ min max))))) ;sat + (round (/ max 2.55))))) + +(defun css-color-rgb-to-hsl (r g b) + "Return R G B (in range 0-255) converted to HSL (0-360 for hue, rest in %)" + (let* ((r (/ r 255.0)) + (g (/ g 255.0)) + (b (/ b 255.0)) + (h 0) + (s 0) + (l 0) + (v (max r g b)) + (m (min r g b)) + (l (/ (+ m v) 2.0)) + (vm 0) + (r2 0) + (g2 0) + (b2 0)) + (multiple-value-bind (h s v) + (if (<= l 0) + (values h s l) + (setq vm (- v m) + s vm) + (if (>= 0 s) + (values h s l) + (setq s (/ s (if (<= l 0.5) + (+ v m) + (- 2.0 v m)))) + (if (not (= 0 vm)) + (setq r2 (/ (- v r) vm) + g2 (/ (- v g) vm) + b2 (/ (- v b) vm))) + (cond ((= r v) + (setq h (if (= g m) + (+ 5.0 b2) + (- 1.0 g2)))) + ((= g v) + (setq h (if (= b m) + (+ 1.0 r2) + (- 3.0 b2)))) + (t + (setq h (if (= r m) + (+ 3.0 g2) + (- 5.0 r2))))) + (values (/ h 6.0) s l))) + (list (round(* 360 h)) + (* 100 s) + (* 100 l))))) + +;; Source: hsv +(defun css-color-hsv-to-hsl (h s v) + (multiple-value-bind (r g b) (css-color-hsv-to-rgb h s v) + (css-color-rgb-to-hsl r g b))) + +(defun css-color-hsv-to-hex (h s v) + (apply 'css-color-rgb-to-hex (css-color-hsv-to-rgb h s v))) + +(defun css-color-hsv-to-rgb (h s v) + "Convert a point in the Hue, Saturation, Value (aka Brightness) +color space to list of normalized Red, Green, Blue values. + +HUE is an angle in the range of 0 degrees inclusive to 360 +exclusive. The remainder of division by 360 is used for +out-of-range values. +SATURATION is in the range of 0 to 100. +VALUE is in the range of 0 to 100. +Returns a list of values in the range of 0 to 255. +" + ;; Coerce to float and get hue into range. + (setq h (mod h 360.0) + s (/ (float s) 100) + v (/ (float v) 100)) + (let* ((hi (floor h 60.0)) + (f (- (/ h 60.0) hi)) + (p (* v (- 1.0 s))) + (q (* v (- 1.0 (* f s)))) + ;; cannot use variable t, obviously. + (u (* v (- 1.0 (* (- 1.0 f) s)))) + r g b) + (case hi + (0 (setq r v g u b p)) + (1 (setq r q g v b p)) + (2 (setq r p g v b u)) + (3 (setq r p g q b v)) + (4 (setq r u g p b v)) + (5 (setq r v g p b q))) + (mapcar (lambda (color) (round (* 255 color))) (list r g b)))) + +(defun css-color-hsv-to-prop-hexstring (color-data) + (propertize + (apply 'css-color-hsv-to-hex color-data) + 'keymap css-color-map + 'css-color color-data)) + +;; Source: hsl +(defun css-color-hsl-to-rgb-fractions (h s l) + (let (m1 m2) + (if (<= l 0.5) + (setq m2 (* l (+ s 1))) + (setq m2 (- (+ l s) (* l s)))) + (setq m1 (- (* l 2) m2)) + (values (css-color-hue-to-rgb m1 m2 (+ h (/ 1 3.0))) + (css-color-hue-to-rgb m1 m2 h) + (css-color-hue-to-rgb m1 m2 (- h (/ 1 3.0)))))) + +(defun css-color-hsl-to-rgb (h s l) + (multiple-value-bind (r g b) + (css-color-hsl-to-rgb-fractions + (/ h;; (css-color-normalize-hue h) + 360.0) + (/ s 100.0) + (/ l 100.0)) + (values (css-color-within-bounds (* 256 r) 0 255) + (css-color-within-bounds (* 256 g) 0 255) + (css-color-within-bounds (* 256 b) 0 255)))) + +(defun css-color-hsl-to-hex (h s l) + (apply 'css-color-rgb-to-hex + (css-color-hsl-to-rgb h s l))) + +(defun css-color-hue-to-rgb (x y h) + (when (< h 0) (incf h)) + (when (> h 1) (decf h)) + (cond ((< h (/ 1 6.0)) + (+ x (* (- y x) h 6))) + ((< h 0.5) y) + ((< h (/ 2.0 3.0)) + (+ x (* (- y x) (- (/ 2.0 3.0) h) 6))) + (t x))) + +(defun css-color-parse-hsl (str) + (string-match + css-color-hsl-re + str) + (mapcar 'string-to-number + (list + (match-string 1 str) + (match-string 2 str) + (match-string 3 str)))) + +(defun css-color-inchue (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list (+ incr h) s v)))) + +(defun css-color-incsat (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list h (css-color-within-bounds (+ incr s) 0 100) v)))) + +(defun css-color-incval (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list h s (css-color-within-bounds (+ incr v) 0 100))))) + +(defun css-color-hexval-beginning () + (skip-chars-backward css-color-hex-chars) + (if (= (char-after) 35) + (forward-char 1))) + +(defun css-color-replcolor-at-p (fun increment) + (let ((pos (point))) + (css-color-hexval-beginning) + (insert + (funcall fun + (css-color-get-color-at-point) + increment)) + (delete-region (point) (+ (point) 6)) + (goto-char pos))) + +(defun css-color-get-color-at-point () + (save-excursion + (css-color-hexval-beginning) + (let ((saved-color (get-text-property (point) 'css-color))) + (or saved-color + (css-color-hex-to-hsv + (buffer-substring-no-properties (point) (+ (point) 6))))))) + +(defun css-color-adj-hue-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-inchue increment)) + +(defun css-color-adj-saturation-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-incsat increment)) + +(defun css-color-adj-value-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-incval increment)) + +(defun css-color-what-channel () + (let ((pos (point))) + (prog1 + (/ (skip-chars-backward css-color-hex-chars) -2) + (goto-char pos)))) + +(defun css-color-adjust-hex-at-p (incr) + (interactive "p") + (let ((pos (point)) + (channel (css-color-what-channel))) + (css-color-hexval-beginning) + (let ((rgb + (css-color-hex-to-rgb + (buffer-substring-no-properties (point) + (+ 6 (point)))))) + (setf (nth channel rgb) + (css-color-within-bounds + (+ incr (nth channel rgb)) + 0 255)) + (delete-region (point) (+ 6 (point))) + (insert + (propertize + (apply 'format "%02x%02x%02x" rgb) + 'keymap css-color-map + 'css-color nil + 'rear-nonsticky t))) + (goto-char pos))) + +;; channels (r, g, b) +(defun css-color-up (val) + "Adjust R/G/B up." + (interactive "p") + (css-color-adjust-hex-at-p val)) + +(defun css-color-down (val) + "Adjust R/G/B down." + (interactive "p") + (css-color-adjust-hex-at-p (- val))) +;; hue +(defun css-color-hue-up (val) + "Adjust Hue up." + (interactive "p") + (css-color-adj-hue-at-p val)) + +(defun css-color-hue-down (val) + "Adjust Hue down." + (interactive "p") + (css-color-adj-hue-at-p (- val))) +;; saturation +(defun css-color-saturation-up (val) + "Adjust Saturation up." + (interactive "p") + (css-color-adj-saturation-at-p val)) + +(defun css-color-saturation-down (val) + "Adjust Saturation down." + (interactive "p") + (css-color-adj-saturation-at-p (- val))) +;; value +(defun css-color-value-up (val) + "Adjust Value up." + (interactive "p") + (css-color-adj-value-at-p val)) + +(defun css-color-value-down (val) + "Adjust Value down." + (interactive "p") + (css-color-adj-value-at-p (- val))) + +(defun css-color-num-up (arg) + "Adjust HEX number up." + (interactive "p") + (save-excursion + (let ((digits "1234567890")) + (skip-chars-backward digits) + (when + (looking-at "[[:digit:]]+") + (replace-match + (propertize + (let ((num (+ (string-to-number (match-string 0)) arg))) + ;max = 100 when at percentage + (save-match-data + (cond ((looking-at "[[:digit:]]+%") + (setq num (min num 100))) + ((looking-back "hsla?(") + (setq num (css-color-normalize-hue num))) + ((memq 'css-color-type (text-properties-at (point))) + (setq num (min num 255))))) + (number-to-string num)) + 'keymap + css-color-generic-map)))))) + +(defun css-color-num-down (arg) + "Adjust HEX number down." + (interactive "p") + (save-excursion + (let ((digits "1234567890")) + (skip-chars-backward digits) + (when + (looking-at "[[:digit:]]+") + (replace-match + (propertize + (let ((num (- (string-to-number (match-string 0)) arg))) + ;max = 100 when at percentage + (save-match-data + (cond ((looking-back "hsla?(") + (setq num (css-color-normalize-hue num))) + (t (setq num (max 0 num))))) + (number-to-string num)) + 'keymap css-color-generic-map)))))) + + +(defun css-color-beginning-of-color () + "Skip to beginning of color. + +Return list of point and color-type." + (while (memq 'css-color-type (text-properties-at (point))) + (backward-char 1)) + (forward-char 1) + (cons (point) (plist-get (text-properties-at (point)) 'css-color-type))) + +(defun css-color-end-of-color () + "Skip to beginning of color. + +Return list of point and color-type." + (while (plist-get (text-properties-at (point)) 'css-color-type) + (forward-char 1)) + (cons (point) (plist-get (text-properties-at (1- (point))) 'css-color-type))) + +(defun css-color-color-info () + (destructuring-bind ((beg . type) + (end . type)) + (list + (css-color-beginning-of-color) + (css-color-end-of-color)) + (list beg end type (buffer-substring-no-properties beg end)))) + +(defconst css-color-type-circle '#1=(hex hsl rgb name . #1#)) + +(defun css-color-next-type (sym) + (cadr (member sym css-color-type-circle))) + +(defun css-color-cycle-type () + "Cycle color type." + (interactive) + (destructuring-bind (beg end type color) (css-color-color-info) + (if (or (= 0 (length color)) (null type)) + (error "Not at color")) + (delete-region beg end) + (insert + (propertize (funcall + (intern-soft (format "css-color-string-%s-to-%s" + type + (css-color-next-type type))) + color) + 'keymap (if (eq (css-color-next-type type) 'hex) + css-color-map + css-color-generic-map) 'rear-nonsticky t)) + (goto-char beg))) + +(defun css-color-string-hex-to-hsl (str) + (multiple-value-bind (h s l) + (apply 'css-color-rgb-to-hsl + (css-color-hex-to-rgb str)) + (format "hsl(%d,%d%%,%d%%)" + h s l))) + +(defun css-color-string-hsl-to-rgb (str) + (multiple-value-bind (h s l) + (css-color-parse-hsl str) + (apply 'format + "rgb(%d,%d,%d)" + (mapcar 'round (css-color-hsl-to-rgb h s l))))) + +(defun css-color-string-rgb-to-name (str) + (let ((color (css-color-string-rgb-to-hex str))) + (or (car (rassoc (list (upcase color)) css-color-html-colors)) ;if name ok + color))) ;else return hex + +(defun css-color-string-name-to-hex (str) + (let ((str (downcase str))) + (cadr (assoc-if + (lambda (a) + (string= + (downcase a) + str)) + css-color-html-colors)))) + +(defun css-color-string-rgb-to-hex (str) + (save-match-data + (string-match css-color-rgb-re str) + (concat "#" + (apply 'css-color-rgb-to-hex + (mapcar + ;;'string-to-number + (lambda (s) + (if (= (aref s (1- (length s))) ?\%) + (round (* (string-to-number s) 2.55)) + (string-to-number s))) + (list + (match-string-no-properties 1 str) + (match-string-no-properties 2 str) + (match-string-no-properties 3 str))))))) + +(defun css-color-string-hsl-to-hex (str) + (concat "#" (apply 'css-color-hsl-to-hex (css-color-parse-hsl str)))) + +(defun css-color-next-channel () + "Cycle color channel." + (interactive) + (multiple-value-bind (beg end type color) + (save-excursion (css-color-color-info)) + (case type + ((hsl rgb) + (if (not (re-search-forward ",\\|(" end t)) + (goto-char (+ beg 4)))) + (hex + (cond ((> (point) (- end 3)) + (goto-char (+ 1 beg))) + ((= (char-after) 35) + (forward-char 1)) + ((evenp (- (point) beg)) + (forward-char 1)) + (t (forward-char 2))))))) + +(defun css-color-hexify-anystring (str) + (cond ((string-match "^hsl" str) + (css-color-string-hsl-to-hex str)) + ((string-match "^rgb" str) + (css-color-string-rgb-to-hex str)) + (t str))) + +(defun css-color-toggle-percentage () + "Toggle percent ??" + (interactive) + (let ((pos (point))) + (if (eq (nth 2 (save-excursion (css-color-color-info))) 'rgb) + (let ((chars "%1234567890.")) + (skip-chars-backward chars) + (when + (looking-at "[[:digit:]]+\\(?:\.?[[:digit:]]*%\\)?%?") + (let ((s (match-string 0))) + (replace-match + (propertize + (if (= (aref s (1- (length s))) ?\%) + (number-to-string (round (* (string-to-number s) 2.55))) + (format "%d%%" (/ (string-to-number s) 2.55))) + 'keymap css-color-generic-map + 'rear-nonsticky t))) + ;;(goto-char pos) + )) + (message "No toggling at point.")))) + +;; provide some backwards-compatibility to hexcolor.el: +(defvar css-color-fg-history nil) +(defvar css-color-bg-history nil) + +;;;###autoload +(defun css-color-test (fg-color bg-color) + "Test colors interactively. +The colors are displayed in the echo area. You can specify the +colors as any viable css color. Example: + + red + #f00 + #0C0 + #b0ff00 + hsla(100, 50%, 25%) + rgb(255,100,120)" + (interactive (list (completing-read "Foreground color: " + css-color-html-colors + nil nil nil nil css-color-fg-history) + (completing-read "Background color: " + css-color-html-colors + nil nil nil nil css-color-bg-history))) + (let* ((s (concat " Foreground: " fg-color ", Background: " bg-color " "))) + (put-text-property 0 (length s) + 'face (list + :foreground (css-color-hexify-anystring fg-color) + :background (css-color-hexify-anystring bg-color)) + s) + (message "Here are the colors: %s" s))) + +(defun css-color-run-tests () + (interactive) + (unless + (progn + (assert + (string= (css-color-string-hex-to-hsl "#ffff00") "hsl(60,100%,50%)")) + (assert + (string= (css-color-string-rgb-to-hex "rgb(255, 50%, 0)")"#ff7f00")) + (assert + (string= (css-color-string-hsl-to-rgb "hsl(60, 100%, 50%)") "rgb(255,255,0)")) + (assert + (string= (css-color-string-hsl-to-hex "hsl(60, 100%, 50%)") "#ffff00"))) + (message "All tests passed"))) + +(provide 'css-color) +;;; css-color.el ends here diff --git a/emacs/nxhtml/util/css-palette.el b/emacs/nxhtml/util/css-palette.el new file mode 100644 index 0000000..44287be --- /dev/null +++ b/emacs/nxhtml/util/css-palette.el @@ -0,0 +1,471 @@ +;;; css-palette.el + +(defconst css-palette:version "0.02") +;; Copyright (C) 2008 Niels Giesen + +;; Author: Niels Giesen <nielsforkgiesen@gmailspooncom, but please +;; replace the kitchen utensils with a dot before hitting "Send"> +;; Keywords: processes, css, multimedia, extensions, tools +;; Homepage: http://niels.kicks-ass.org/ + +;; 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 3 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, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; css-palette defines commands to have "palettes" inside a block +;; comment to circumvent the absence of (color or other) variable +;; definitions in the CSS specification. It can import and export GIMP +;; color palettes. See the documentation of `css-palette-mode' +;; for details of usage. + +;;; Installation: + +;; Something like: + +;; put it in your load-path. + +;; (autoload 'css-palette-mode "css-palette" "" t) +;; (add-hook 'css-mode-hook +;; (lambda () +;; (css-palette-mode t))) + +;; Notes: + +;; css-palette depends on css-color.el to do font-locking. + +;; ccs-palette is orthogonal to css-mode, so it could probably be used +;; inside other language modes, provided they support multiline block +;; comments. + +;;; Change log: + +;; 2009-01-11 Lennart Borgman +;; - Minor code clean up. + +;;; Code: +(require 'css-color) +(eval-when-compile (require 'cl)) ;i'm a bad bad boy... + +(defconst css-palette-hex-chars "0123456789abcdefABCDEF" + "Composing chars in hexadecimal notation, save for the hash (#) sign.") + +(defvar css-palette-mode-map + (let ((m (make-sparse-keymap))) + (define-key m "\C-c\C-c" 'css-palette-update-all) + (define-key m "\C-c\C-i" 'css-palette-insert-reference) + (define-key m "\C-c\C-p" 'css-palette-import-from-GIMP) + (define-key m "\C-c\C-f" 'css-palette-insert-files) + m) + "Mode map for `css-palette-mode'") + +;;;###autoload +(define-minor-mode css-palette-mode + "Minor mode for palettes in CSS. + +The mode `css-palette-mode' acts on the first COLORS declaration in your + file of the form: + +COLORS: +\( +c0 \"#6f5d25\" ;tainted sand +c1 \"#000000\" ;Black +c2 \"#cca42b\" ;goldenslumber +c3 \"#6889cb\" ;far off sky +c4 \"#fff\" ;strange aeons +) + +Such declarations should appear inside a block comment, in order + to be parsed properly by the LISP reader. + +Type \\[css-palette-update-all], and any occurence of + + color: #f55; /*[c3]*/ + +will be updated with + + color: #6899cb; /*[c3]*/ + +The following commands are available to insert key-value pairs + and palette declarations: + \\{css-palette-mode-map} + +You can extend or redefine the types of palettes by defining a + new palette specification of the form (PATTERN REGEXP + REF-FOLLOWS-VALUE), named according to the naming scheme + css-palette:my-type, where + +PATTERN is a pattern containing two (%s) format directives which + will be filled in with the variable and its value, + +REGEXP is a regular expression to match a value - variable + pattern, + +and REF-FOLLOWS-VALUE defined whether or not the reference comes + after the value. This allows for more flexibility. + +Note that, although the w3c spec at URL + `http://www.w3.org/TR/CSS2/syndata.html#comments' says that + comments \" may occur anywhere between tokens, and their + contents have no influence on the rendering\", Internet + Explorer does not think so. Better keep all your comments after + a \"statement\", as per the default. This means `css-palette' + is ill-suited for use within shorthands. + +See variable `css-palette:colors' for an example of a palette + type. + +The extension mechanism means that palette types can be used to + contain arbitrary key-value mappings. + +Besides the colors palette, css-palette defines the palette + definition variables `css-palette:colors-outside' and + `css-palette:files', for colors with the reference outside and + for file url()'s respectively. + +You can fine-control which palette types css-palette should look + at via the variable `css-palette-types'. + +" + nil + "-palette" + css-palette-mode-map + (css-color-mode +1)) + +;;;###autoload +(defgroup css-palette nil + "Customization group for css-palette library. + +See function `css-palette-mode' for documentation" + :group 'css-color) + +(defcustom css-palette:colors + `("%s; /*[%s]*/ " + ,(concat "\\(" + css-color-color-re +;; (mapconcat +;; 'identity +;; (list css-color-hex-re +;; css-color-hsl-re +;; css-color-rgb-re) "\\|") + "\\)" + "[[:space:]]*;[[:space:]]*\/\\*\\[\\([^[:space:]]+\\)\\]\\*\/") + t) + "Color palette specification. + +See function `css-palette-mode' for documentation" + :group 'css-palette + :type '(list + (string :tag "Pattern") + (regexp :tag "Regexp") + (boolean :tag "Reversed"))) + +(defcustom css-palette:files + '("url(%s); /*[%s]*/ " + "url(\\([^)]+\\))[[:space:]]*;[[:space:]]*\/\\*\\[\\([^[:space:]]+\\)\\]\\*\/" + t) + "File palette specification. + +See function `css-palette-mode' for documentation" + :group 'css-palette + :type '(list + (string :tag "Pattern") + (regexp :tag "Regexp") + (boolean :tag "Reversed"))) + +(defcustom css-palette-types + '(colors) + "List of palette types to check for in buffer. + +See function `css-palette-mode' for documentation" + :group 'css-palette + :type '(repeat (symbol :tag "Palette type"))) +(make-variable-buffer-local 'css-palette-types) + +;; (defun css-palette-mode-turn-on () +;; "Turn on `css-palette-mode'." +;; (css-palette-mode 1)) + +;; ;;;###autoload +;; (defcustom css-palette-mode-activate-p nil +;; "Start `css-palette-mode' when `css-mode' is activated." +;; :group 'css-palette +;; :set (lambda (sym val) +;; (set-default sym val) +;; (if val +;; (add-hook 'css-mode-hook 'css-palette-mode-turn-on) +;; (remove-hook 'css-mode-hook 'css-palette-mode-turn-on))) +;; :type 'boolean) + +(defun css-palette-turn-on-in-buffer () + "Turn on `css-palette-mode' in `css-mode'." + (when (derived-mode-p 'css-mode) + (message "turn-on-in-b:before (css-palette-mode 1) cb=%s" (current-buffer)) + (css-palette-mode 1) + (message "turn-on-in-b:after (css-palette-mode 1)") + )) + +;;;###autoload +(define-globalized-minor-mode css-palette-global-mode css-palette-mode + css-palette-turn-on-in-buffer + :group 'css-color) + +(defun css-palette-get (key spec) + (plist-get + (css-palette-spec-to-plist + (symbol-value + (intern-soft + (format "css-palette:%s" spec)))) key)) + +(defun css-palette-spec-to-plist (palette) + (destructuring-bind (pattern regexp ref-follows-value) palette + (list :regexp regexp + :pattern pattern + :ref-follows-value ref-follows-value))) + +(defun css-palette-choose-type () + (intern-soft + (if (null (cdr css-palette-types)) + (car css-palette-types) + (completing-read "Type: " + (mapcar 'symbol-name css-palette-types))))) + +(defun css-palette-get-declaration (type) + "Return `css-palette' declaration of TYPE in current buffer. + +If none is found, throw an error." + (let ((type (symbol-name type))) + (save-excursion + (goto-char (point-min)) + (or (re-search-forward (format "%s:" + (upcase type)) nil t) + (error "No %s declaration found in buffer; check value of variable + `css-palette-types'" type)) + (let ((palette (read (current-buffer)))) + ;; Check (could be better..) + (if (not (and + (listp palette) + (= 0 (% (length palette) 2)))) + (error "Invalid %s " type)) + palette)))) + +(defun css-palette-update (type) +"Update buffer references for palette of TYPE." + (interactive (list + (css-palette-choose-type))) + (let ((palette (css-palette-get-declaration type)) + (regexp (css-palette-get :regexp type)) + (ref-follows-value (css-palette-get :ref-follows-value type))) + (flet ((getval (key palette) + (let ((value (plist-get palette (intern-soft key)))) + (if (null value) + (error + "%S not specified in %S palette " + key + type + ;; (signal 'css-palette-not-found-error nil) + ) + value)))) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward + regexp + (point-max) t) + (replace-match + (getval (match-string-no-properties (if ref-follows-value 2 1)) palette) + nil nil nil (if ref-follows-value 1 2)))))) + (css-color-mode 1)) + +(defun css-palette-update-all () + "Update all references for palettes in `css-palette-types'" + (interactive) + (catch 'err + (mapc (lambda (type) + (condition-case err + (css-palette-update type) + (if (y-or-n-p (format "%s, skip? " err)) + nil))) + css-palette-types))) + +;; Reference Insertion +(defun css-palette-insert-reference (type) + "Insert `css-palette' reference of TYPE at point." + (interactive + (list (css-palette-choose-type))) + (let* ((palette (css-palette-get-declaration type)) + (ref-follows-value (css-palette-get :ref-follows-value type)) + (pattern (css-palette-get :pattern type)) + (var + (completing-read (format "%s variable: " + (capitalize + (substring (symbol-name type) + 0 -1))) + (loop for i on + palette + by 'cddr + collect + (css-palette-colorify + (symbol-name (car i)) + (cadr i))))) + (val (plist-get palette (read var)))) + (insert (apply 'format + pattern + (if ref-follows-value + (list val var) + (list var val)))) + (css-color-mode +1))) + +(defun css-palette-hex-color-p (str) + (string-match "#\\([a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)" str)) + +(defun css-palette-colorify (string color) + (let ((color (if (css-palette-hex-color-p color) + color + "#000"))) + (propertize string + 'font-lock-face + (list :background color + :foreground (css-color-foreground-color color) + string) + 'fontified t))) + +;; Imports +(defun css-palette-from-existing-colors () + (interactive) + (let ((palette) + (count -1)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "#[[:digit:]a-fA-F]\\{6\\}\\>" nil t) + (if (not (member (match-string-no-properties 0) palette)) + (setq palette (append (list + (match-string-no-properties 0) + (intern(format "c%d" (incf count)))) + palette))) + (save-match-data (re-search-forward ";" nil t)) + (insert (format "/*[%S]*/" (cadr (member (match-string-no-properties 0) palette)))))) + (insert (format "COLORS:\n%S" (nreverse palette))) + (forward-sexp -1) + (forward-char 1) + (while + (not (looking-at ")")) + (forward-sexp 2) + (newline) + (indent-for-tab-command)))) + +(defun css-palette-newest-GIMP-dir () + "Return newest (version-wise) ~/.gimp-n.n/palettes directory on disk. + +Return `nil' if none such directory is found." + (catch 'none + (concat + (or + (car + (last + (directory-files "~/" t "^.gimp-[[:digit:].]\\{3,\\}"))) + (throw 'none ())) + "/palettes/"))) + +(defun css-palette-import-from-GIMP () + "Import GIMP palette file as a `css-palette' palette. + +GIMP palettes can be made with the GIMP or on-line tools such as +found at URL `http://colourlovers.com'." + (interactive) + (let ((file (read-file-name "File: " (css-palette-newest-GIMP-dir))) + (this-buffer (current-buffer)) + (count -1)) + (insert "\nCOLORS:\n(\n") + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (while (re-search-forward + (concat + "^" + "[[:space:]]*\\([[:digit:]]+\\)" ;red + "[[:space:]]+\\([[:digit:]]+\\)" ;green + "[[:space:]]+\\([[:digit:]]+\\)" ;blue + "[[:space:]]+\\(.*\\)$") ;name (=> used as comment) + nil t) + (destructuring-bind (rb re gb ge bb be nb ne &rest ignore) + (cddr (match-data t)) + (let ((color + (apply 'format "c%d \"#%02x%02x%02x\" ;%s\n" + (incf count) + (append + (mapcar 'string-to-number + (list + (buffer-substring-no-properties rb re) + (buffer-substring-no-properties gb ge) + (buffer-substring-no-properties bb be))) + (list (buffer-substring-no-properties nb ne)))))) + (with-current-buffer this-buffer + (insert color)))))) + (insert ")") + (message "C-c C-c to update colors"))) + +(defun css-palette-insert-files (dir) + "Insert a `css-palette' declaration for all files in DIR. + +Filenames are relative. +Main use-case: an image directory." + (interactive "DDirectory: ") + (save-excursion + (let ((image-count -1)) + (insert "\nFILES:\n(\n") + (mapc + (lambda (f) + (insert + (format "file-%d %S\n" + (incf image-count) + (file-relative-name + f + (file-name-directory (buffer-file-name)))))) + (directory-files dir t "...+")) + (insert ")\n\n")))) + +;; Exports +(defun css-palette-export-to-GIMP (type name columns) + "Export the COLORS declaration to a GIMP (.gpl) palette. + +See also `gpl-mode' at URL +`http://niels.kicks-ass.org/public/elisp/gpl.el'." + (interactive + (list + (css-palette-choose-type) + (read-string "Name: ") + (read-number "Number of columns: " 2))) + (let ((palette (css-palette-get-declaration type))) + (find-file + (concat (css-palette-newest-GIMP-dir) + name + ".gpl")) + (insert + (format "GIMP Palette +Name: %s +Columns: %d +# +" name columns)) + (loop for i on palette + by 'cddr + do + (multiple-value-bind (r g b)(css-color-hex-to-rgb + (css-color-hexify-anystring (cadr i))) + (insert (format "%3d %3d %3d\t%s\n" + r g b + (car i)))))) + (if (featurep 'gpl) + (gpl-mode))) + +(provide 'css-palette) +;; css-palette.el ends here diff --git a/emacs/nxhtml/util/css-simple-completion.el b/emacs/nxhtml/util/css-simple-completion.el new file mode 100644 index 0000000..95bf27b --- /dev/null +++ b/emacs/nxhtml/util/css-simple-completion.el @@ -0,0 +1,238 @@ +;;; css-simple-completion.el --- Partly context aware css completion +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-11-22 Sun +;; Version: +;; Last-Updated: 2009-11-22 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Simple partly context aware completion. Context is based on +;; guessing mainly. +;; +;; This can be combined with with flymake-css.el that can check the +;; syntax. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +;; Fix-me: bad structure, does not fit completion frameworks +(defun css-simple-completing-w-pred (regexp matnum prompt collection) + (let (pre start len) + (when (looking-back regexp (line-beginning-position) t) + (setq pre (downcase (match-string matnum))) + (setq len (length pre)) + (setq start (match-beginning matnum)) + (unless (try-completion pre collection) + (throw 'result nil)) + (throw 'result (list start + (completing-read prompt + collection + (lambda (alt) + (and (>= (length alt) len) + (string= pre + (substring alt 0 len)))) + t + pre)))))) + +(defun css-simple-complete () + "Try to complete at current point. +This tries to complete keywords, but no CSS values. + +This is of course a pity since the value syntax is a bit +complicated. However you can at least check the syntax with +flymake-css if you want to." + (interactive) + (let ((context (css-simple-guess-context)) + result + cur + pre + start) + (setq result + (catch 'result + + (case context + + ( 'css-media-ids + (css-simple-completing-w-pred "\\<[a-z0-9-]*" 0 "Media type: " css-media-ids)) + + ( 'css-at-ids + (css-simple-completing-w-pred "@\\([a-z0-9-]*\\)" 1 "At rule: @" css-at-ids)) + + ( 'css-property-ids + (css-simple-completing-w-pred "\\<[a-z-]*" 0 "CSS property name: " css-property-ids)) + + ( 'css-simple-selectors + + ;; Fix-me: Break out the first two + (when (looking-back "\\W#\\([a-z0-9-]*\\)") + (setq cur (match-string 1)) + (setq start (match-beginning 1)) + (throw 'result (list (point) + (read-string (concat "Html tag Id: " cur))))) + (when (looking-back "\\W\\.\\([a-z0-9-]*\\)") + (setq cur (match-string 1)) + (setq start (match-beginning 1)) + (throw 'result (list (point) + (read-string (concat "CSS class name: " cur))))) + + (css-simple-completing-w-pred "[a-z0-9]:\\([a-z0-9-]*\\)" 1 "Pseudo id: " css-pseudo-ids) + + (css-simple-completing-w-pred "[a-z0-9-]+" 0 "HTML tag: " (cddr css-simple-selectors)) + + (when (looking-back "\\<\\(?:#\\|\\.\\)") + (setq pre nil) + (while t + (setq pre (completing-read "HTML tag, id or CSS class: " css-simple-selectors nil nil pre)) + (if (string= (substring pre 0 1) "#") + (if (or (= 1 (length pre)) + (and (> (length pre) 2) + (string= (substring pre 0 3) "# ("))) + (throw 'result (list (point) (concat "#" (read-string "Html tag id: #")))) + (throw 'result (list (point) pre))) + (if (string= (substring pre 0 1) ".") + (if (or (= 1 (length pre)) + (and (> (length pre) 2) + (string= (substring pre 0 3) ". ("))) + (throw 'result (list (point) (concat "." (read-string "CSS class name: .")))) + (throw 'result (list (point) pre))) + (when (member pre css-simple-selectors) + (throw 'result (list (point) pre))))) + )))))) + (message "result=%S" result) + (if result + (let ((str (cadr result)) + (len (- (point) (car result)))) + (insert (substring str len))) + (message "No matching alternatives")))) + +(defun css-simple-guess-context () + "Try to find a context matching none constant. +Return the symbol corresponding to the context or nil if none +could be found. + +The symbols are the names of the defconst holding the possibly +matching ids. + +* Note: This function assumes that comments are fontified before + point." + ;; Kind of hand-written backward parser ... ;-) + (let ((ignore-case t) ;; fix-me + (here (point)) + (after-colon (and (not (bobp)) (eq (char-before) ?:))) + ret) + (prog1 + (catch 'return + ;; No completion in comments. + (when (eq (get-text-property (point) 'face) + 'font-lock-comment-face) + (throw 'return nil)) + + ;; If we are not on whitespace then don't complete + (css-simple-skip-backwards-to-code) + (unless (or (eobp) + (= (char-syntax (char-after)) ?\ ) + (< (point) here)) + (throw 'return nil)) + + ;; Skip backwards to see if after first selector + (let ((here2 (1+ (point)))) + (while (/= here2 (point)) + (setq here2 (point)) + (css-simple-skip-backwards-to-code) + (when (and (not (bobp)) + (eq (char-before) ?,)) + (backward-char)) + (skip-chars-backward "#.:a-z0-9-"))) + ;; Selector + (when (or (bobp) + (eq (char-before) ?})) + (throw 'return 'css-simple-selectors)) + + ;; Property names + (when (memq (char-before) '( ?{ ?\; )) + (throw 'return 'css-property-ids)) + + ;; If we are in the value we can't complete there yet. + (when (eq (char-before) ?:) + (throw 'return nil)) + + + ;; @ + (goto-char here) + (skip-chars-backward "a-z0-9-") + (when (eq (char-before) ?@) + (throw 'return 'css-at-ids)) + + ;; @media ids + (when (looking-back "@media\\W+") + (throw 'return 'css-media-ids)) + + ) + (goto-char here)))) +;;; Fix-me: complete these ... +;;css-descriptor-ids ;; Removed or? + +(defun css-simple-skip-backwards-to-code () + "Skip backwards until we reach code. +Requires that comments are fontified." + (let ((here (1+ (point)))) + (while (/= here (point)) + (setq here (point)) + (skip-syntax-backward " ") + (unless (bobp) + (when (memq (get-text-property (1- (point)) 'face) + '(font-lock-comment-face font-lock-comment-delimiter-face)) + (goto-char (or (previous-single-property-change (1- (point)) 'face) + (point-min)))))))) + +(defconst css-simple-selectors + '(". (for class)" + "# (for id)" + ;; HTML 4.01 tags + "a" "abbr" "acronym" "address" "applet" "area" "b" "base" "basefont" "bdo" "big" + "blockquote" "body" "br" "button" "caption" "center" "cite" "code" "col" + "colgroup" "dd" "del" "dfn" "dir" "div" "dl" "dt" "em" "fieldset" "font" "form" + "frame" "frameset" "head" "h1" "h2" "h3" "h4" "h5" "h6" "hr" "html" "i" "iframe" "img" + "input" "ins" "kbd" "label" "legend" "li" "link" "map" "menu" "meta" "noframes" + "noscript" "object" "ol" "optgroup" "option" "p" "param" "pre" "q" "s" "samp" + "script" "select" "small" "span" "strike" "strong" "style" "sub" "sup" "table" + "tbody" "td" "textarea" "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var" + )) + +(provide 'css-simple-completion) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; css-simple-completion.el ends here diff --git a/emacs/nxhtml/util/cus-new-user.el b/emacs/nxhtml/util/cus-new-user.el new file mode 100644 index 0000000..c727425 --- /dev/null +++ b/emacs/nxhtml/util/cus-new-user.el @@ -0,0 +1,803 @@ +;;; cus-new-user.el --- Customize some important options +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-07-10 Fri +;; Version: 0.2 +;; Last-Updated: 2009-07-10 Fri +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Customize significant options for which different user +;; environment expectations might dictate different defaults. +;; +;; After an idea of Scot Becker on Emacs Devel. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(defvar cusnu-my-skin-widget nil) + +(defvar cusnu-insert-os-spec-fun nil) + +;;(customize-for-new-user) +;;;###autoload +(defun customize-for-new-user (&optional name) + "Show special customization page for new user. +" + (interactive) + ;;(setq debug-on-error t) + ;;(setq buffer-read-only t) + (require 'cus-edit) + (let ((inhibit-read-only t) + fill-pos) + (pop-to-buffer (custom-get-fresh-buffer (or name "*Customizations for New Users*"))) + (buffer-disable-undo) + (Custom-mode) + (erase-buffer) + (widget-insert (propertize "Easy Customization for New Users\n" 'face '(:weight bold :height 1.5))) + (setq fill-pos (point)) + (widget-insert + "Below are some custom options that new users often may want to +tweak since they may make Emacs a bit more like what they expect from +using other software in their environment. + +After this, at the bottom of this page, is a tool for exporting your own specific options. +You choose which to export, make a description and give the group of options a new and click a button. +Then you just mail it or put it on the web for others to use. + +Since Emacs runs in many environment and an Emacs user may use +several of them it is hard to decide by default what a user +wants/expects. Therefor you are given the possibility to easily +do those changes here. + +Note that this is just a collection of normal custom options. +There are no new options here. + + +") + (fill-region fill-pos (point)) + + ;; Normal custom buffer header + (let ((init-file (or custom-file user-init-file))) + ;; Insert verbose help at the top of the custom buffer. + (when custom-buffer-verbose-help + (widget-insert "Editing a setting changes only the text in this buffer." + (if init-file + " +To apply your changes, use the Save or Set buttons. +Saving a change normally works by editing your init file." + " +Currently, these settings cannot be saved for future Emacs sessions, +possibly because you started Emacs with `-q'.") + "\nFor details, see ") + (widget-create 'custom-manual + :tag "Saving Customizations" + "(emacs)Saving Customizations") + (widget-insert " in the ") + (widget-create 'custom-manual + :tag "Emacs manual" + :help-echo "Read the Emacs manual." + "(emacs)Top") + (widget-insert ".")) + (widget-insert "\n") + ;; The custom command buttons are also in the toolbar, so for a + ;; time they were not inserted in the buffer if the toolbar was in use. + ;; But it can be a little confusing for the buffer layout to + ;; change according to whether or nor the toolbar is on, not to + ;; mention that a custom buffer can in theory be created in a + ;; frame with a toolbar, then later viewed in one without. + ;; So now the buttons are always inserted in the buffer. (Bug#1326) +;;; (when (not (and (bound-and-true-p tool-bar-mode) (display-graphic-p))) + (if custom-buffer-verbose-help + (widget-insert "\n + Operate on all settings in this buffer that are not marked HIDDEN:\n")) + (let ((button (lambda (tag action active help icon) + (widget-insert " ") + (if (eval active) + (widget-create 'push-button :tag tag + :help-echo help :action action)))) + (commands custom-commands)) + (apply button (pop commands)) ; Set for current session + (apply button (pop commands)) ; Save for future sessions + (if custom-reset-button-menu + (progn + (widget-insert " ") + (widget-create 'push-button + :tag "Reset buffer" + :help-echo "Show a menu with reset operations." + :mouse-down-action 'ignore + :action 'custom-reset)) + (widget-insert "\n") + (apply button (pop commands)) ; Undo edits + (apply button (pop commands)) ; Reset to saved + (apply button (pop commands)) ; Erase customization + (widget-insert " ") + (pop commands) ; Help (omitted) + (apply button (pop commands)))) ; Exit + (widget-insert "\n\n") + + (widget-insert (propertize "\nThis part is for your own use\n" 'face '(:weight bold :height 1.5))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Editor emulator level + + (widget-insert "\n") + (setq fill-pos (point)) + (widget-insert +"Emacs can emulate some common editing behaviours (and some uncommon too). +For the most common ones you can decide if you want to use them here: +") + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + ;; CUA Mode + (cusnu-insert-options '((cua-mode custom-variable))) + + ;; Viper Mode + (widget-insert "\n") + (widget-insert (propertize "Viper" 'face 'custom-variable-tag)) + (widget-insert ":") + (setq fill-pos (point)) + (widget-insert " + Viper is currently set up in a special way, please see the + command `viper-mode'. You can use custom to set up most of + it. However if you want to load Viper at startup you must + explicitly include \(require 'viper) in your .emacs. +") + (fill-region fill-pos (point)) + + ;; Viper Mode + (backward-delete-char 1) + (cusnu-insert-options '((viper-mode custom-variable))) + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; OS specific + + (widget-insert "\n") + (setq fill-pos (point)) + (widget-insert (format "OS specific options (%s): \n" system-type)) + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + (if cusnu-insert-os-spec-fun + (funcall cusnu-insert-os-spec-fun) + (widget-insert "No OS specific customizations.\n")) + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Disputed settings + + (widget-insert "\n") + (setq fill-pos (point)) + (widget-insert +"Some old time Emacs users want to change the options below: +") + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + (cusnu-insert-options '((global-visual-line-mode custom-variable))) + (cusnu-insert-options '((word-wrap custom-variable))) + (cusnu-insert-options '((blink-cursor-mode custom-variable))) + (cusnu-insert-options '((tool-bar-mode custom-variable))) + (cusnu-insert-options '((tooltip-mode custom-variable))) + ;;(cusnu-insert-options '((initial-scratch-message custom-variable))) + + (widget-insert "\n") + (widget-insert (propertize "\n\nThis part is for exporting to others\n\n" 'face '(:weight bold :height 1.5))) + (setq fill-pos (point)) + (widget-insert +"My skin options - This is for exporting custom options to other users +\(or maybe yourself on another computer). +This works the following way: + +- You add a description of your options and the options you want to export below. +Then you click on `Export my skin options'. +This creates a file that you can send to other Emacs users. +They simply open that file in Emacs and follow the instructions there to test your options +and maybe save them for later use if they like them. +\(You can follow the instructions yourself to see how it works.) + +Please change the group symbol name to something specific for you. +") + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + (widget-insert "\n") + (set (make-local-variable 'cusnu-my-skin-widget) + (car + (cusnu-insert-options '((cusnu-my-skin-options custom-variable))))) + (widget-insert "\n") + (widget-create 'push-button + :tag "Export my skin options " + :action (lambda (&rest ignore) + (let ((use-dialog-box nil)) + (call-interactively 'cusnu-export-my-skin-options)))) + (widget-insert "\n") + (widget-create 'push-button + :tag "Customize my skin options " + :action (lambda (&rest ignore) + (let ((use-dialog-box nil)) + (call-interactively 'cusnu-customize-my-skin-options)))) + (widget-insert "\n") + (widget-create 'push-button + :tag "Reset those options to saved values" + :action (lambda (&rest ignore) + (let ((use-dialog-box nil)) + (call-interactively 'cusnu-reset-my-skin-options)))) + + ;; Finish setup buffer + (mapc 'custom-magic-reset custom-options) + (cusnu-make-xrefs) + (widget-setup) + (buffer-enable-undo) + (goto-char (point-min))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Example on Emacs+Emacw32 +(eval-when-compile (require 'emacsw32 nil t)) +(when (fboundp 'emacsw32-version) + (defun cusnu-emacsw32-show-custstart (&rest args) + (emacsw32-show-custstart)) + (setq cusnu-insert-os-spec-fun 'cusnu-insert-emacsw32-specific-part) + (defun cusnu-insert-emacsw32-specific-part () + (cusnu-insert-options '((w32-meta-style custom-variable))) + (widget-insert "\n") + (widget-insert (propertize "EmacsW32" 'face 'custom-variable-tag)) + (widget-insert " + Easy setup for Emacs+EmacsW32.") + (widget-insert "\n ") + (widget-create 'push-button :tag "Customize EmacsW32" + ;;:help-echo help + :action 'cusnu-emacsw32-show-custstart) + (widget-insert "\n"))) +;; End example +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cusnu-mark-part-desc (beg end) + (let ((ovl (make-overlay beg end))) + (overlay-put ovl 'face 'highlight))) + +(defun cusnu-make-xrefs (&optional beg end) + (save-restriction + (when (or beg end) + (unless beg (setq beg (point-min))) + (unless end (setq end (point-max))) + (narrow-to-region beg end)) + (let ((here (point))) + (goto-char (point-min)) + (cusnu-help-insert-xrefs 'cusnu-help-xref-button) + (goto-char here)))) + +(defun widget-info-link-action (widget &optional event) + "Open the info node specified by WIDGET." + (info-other-window (widget-value widget))) + +(defun widget-documentation-string-value-create (widget) + ;; Insert documentation string. + (let ((doc (widget-value widget)) + (indent (widget-get widget :indent)) + (shown (widget-get (widget-get widget :parent) :documentation-shown)) + (start (point))) + (if (string-match "\n" doc) + (let ((before (substring doc 0 (match-beginning 0))) + (after (substring doc (match-beginning 0))) + button) + (when (and indent (not (zerop indent))) + (insert-char ?\s indent)) + (insert before ?\s) + (widget-documentation-link-add widget start (point)) + (setq button + (widget-create-child-and-convert + widget (widget-get widget :visibility-widget) + :help-echo "Show or hide rest of the documentation." + :on "Hide Rest" + :off "More" + :always-active t + :action 'widget-parent-action + shown)) + (when shown + (setq start (point)) + (when (and indent (not (zerop indent))) + (insert-char ?\s indent)) + (insert after) + (widget-documentation-link-add widget start (point)) + (cusnu-make-xrefs start (point)) + ) + (widget-put widget :buttons (list button))) + (when (and indent (not (zerop indent))) + (insert-char ?\s indent)) + (insert doc) + (widget-documentation-link-add widget start (point)))) + (insert ?\n)) +(defun cusnu-help-xref-button (match-number type what &rest args) + (let ((beg (match-beginning match-number)) + (end (match-end match-number))) + (if nil + (let ((ovl (make-overlay beg end))) + (overlay-put ovl 'face 'highlight)) + (let* ((tag (match-string match-number)) + (value what) + (wid-type (cond + ((eq type 'help-variable) + 'variable-link) + ((eq type 'help-function) + 'function-link) + ((eq type 'help-info) + 'custom-manual) + (t nil))) + ) + (when wid-type + (delete-region beg end) + (backward-char) + ;;(tag action active help icon) + (widget-create wid-type + ;;tag + :value value + :tag tag + :keymap custom-mode-link-map + :follow-link 'mouse-face + :button-face 'custom-link + :mouse-face 'highlight + :pressed-face 'highlight + ;;:help-echo help + ))))) + ) + +;; Override default ... ;-) +(define-widget 'documentation-link 'link + "Link type used in documentation strings." + ;;:tab-order -1 + :help-echo "Describe this symbol" + :button-face 'custom-link + :action 'widget-documentation-link-action) + +(defun cusnu-xref-niy (&rest ignore) + (message "Not implemented yet")) + +(defun cusnu-describe-function (wid &rest ignore) + (let ((fun (widget-get wid :what)) + ) + (describe-function fun))) + +(defun cusnu-help-insert-xrefs (help-xref-button) + ;; The following should probably be abstracted out. + (unwind-protect + (progn + ;; Info references + (save-excursion + (while (re-search-forward help-xref-info-regexp nil t) + (let ((data (match-string 2))) + (save-match-data + (unless (string-match "^([^)]+)" data) + (setq data (concat "(emacs)" data)))) + (funcall help-xref-button 2 'help-info data)))) + ;; URLs + (save-excursion + (while (re-search-forward help-xref-url-regexp nil t) + (let ((data (match-string 1))) + (funcall help-xref-button 1 'help-url data)))) + ;; Mule related keywords. Do this before trying + ;; `help-xref-symbol-regexp' because some of Mule + ;; keywords have variable or function definitions. + (if help-xref-mule-regexp + (save-excursion + (while (re-search-forward help-xref-mule-regexp nil t) + (let* ((data (match-string 7)) + (sym (intern-soft data))) + (cond + ((match-string 3) ; coding system + (and sym (coding-system-p sym) + (funcall help-xref-button 6 'help-coding-system sym))) + ((match-string 4) ; input method + (and (assoc data input-method-alist) + (funcall help-xref-button 7 'help-input-method data))) + ((or (match-string 5) (match-string 6)) ; charset + (and sym (charsetp sym) + (funcall help-xref-button 7 'help-character-set sym))) + ((assoc data input-method-alist) + (funcall help-xref-button 7 'help-character-set data)) + ((and sym (coding-system-p sym)) + (funcall help-xref-button 7 'help-coding-system sym)) + ((and sym (charsetp sym)) + (funcall help-xref-button 7 'help-character-set sym))))))) + ;; Quoted symbols + (save-excursion + (while (re-search-forward help-xref-symbol-regexp nil t) + (let* ((data (match-string 8)) + (sym (intern-soft data))) + (if sym + (cond + ((match-string 3) ; `variable' &c + (and (or (boundp sym) ; `variable' doesn't ensure + ; it's actually bound + (get sym 'variable-documentation)) + (funcall help-xref-button 8 'help-variable sym))) + ((match-string 4) ; `function' &c + (and (fboundp sym) ; similarly + (funcall help-xref-button 8 'help-function sym))) + ((match-string 5) ; `face' + (and (facep sym) + (funcall help-xref-button 8 'help-face sym))) + ((match-string 6)) ; nothing for `symbol' + ((match-string 7) +;;; this used: +;;; #'(lambda (arg) +;;; (let ((location +;;; (find-function-noselect arg))) +;;; (pop-to-buffer (car location)) +;;; (goto-char (cdr location)))) + (funcall help-xref-button 8 'help-function-def sym)) + ((and + (facep sym) + (save-match-data (looking-at "[ \t\n]+face\\W"))) + (funcall help-xref-button 8 'help-face sym)) + ((and (or (boundp sym) + (get sym 'variable-documentation)) + (fboundp sym)) + ;; We can't intuit whether to use the + ;; variable or function doc -- supply both. + (funcall help-xref-button 8 'help-symbol sym)) + ((and + (or (boundp sym) + (get sym 'variable-documentation)) + (or + (documentation-property + sym 'variable-documentation) + (condition-case nil + (documentation-property + (indirect-variable sym) + 'variable-documentation) + (cyclic-variable-indirection nil)))) + (funcall help-xref-button 8 'help-variable sym)) + ((fboundp sym) + (funcall help-xref-button 8 'help-function sym))))))) + ;; An obvious case of a key substitution: + (save-excursion + (while (re-search-forward + ;; Assume command name is only word and symbol + ;; characters to get things like `use M-x foo->bar'. + ;; Command required to end with word constituent + ;; to avoid `.' at end of a sentence. + "\\<M-x\\s-+\\(\\sw\\(\\sw\\|\\s_\\)*\\sw\\)" nil t) + (let ((sym (intern-soft (match-string 1)))) + (if (fboundp sym) + (funcall help-xref-button 1 'help-function sym))))) + ;; Look for commands in whole keymap substitutions: + (save-excursion + ;; Make sure to find the first keymap. + (goto-char (point-min)) + ;; Find a header and the column at which the command + ;; name will be found. + + ;; If the keymap substitution isn't the last thing in + ;; the doc string, and if there is anything on the + ;; same line after it, this code won't recognize the end of it. + (while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n" + nil t) + (let ((col (- (match-end 1) (match-beginning 1)))) + (while + (and (not (eobp)) + ;; Stop at a pair of blank lines. + (not (looking-at "\n\\s-*\n"))) + ;; Skip a single blank line. + (and (eolp) (forward-line)) + (end-of-line) + (skip-chars-backward "^ \t\n") + (if (and (>= (current-column) col) + (looking-at "\\(\\sw\\|\\s_\\)+$")) + (let ((sym (intern-soft (match-string 0)))) + (if (fboundp sym) + (funcall help-xref-button 0 'help-function sym)))) + (forward-line)))))) + ;;(set-syntax-table stab) + )) + +(defun cusnu-insert-options (options) + (widget-insert "\n") + (setq custom-options + (append + (if (= (length options) 1) + (mapcar (lambda (entry) + (widget-create (nth 1 entry) + ;;:documentation-shown t + :custom-state 'unknown + :tag (custom-unlispify-tag-name + (nth 0 entry)) + :value (nth 0 entry))) + options) + (let ((count 0) + (length (length options))) + (mapcar (lambda (entry) + (prog2 + (message "Creating customization items ...%2d%%" + (/ (* 100.0 count) length)) + (widget-create (nth 1 entry) + :tag (custom-unlispify-tag-name + (nth 0 entry)) + :value (nth 0 entry)) + (setq count (1+ count)) + (unless (eq (preceding-char) ?\n) + (widget-insert "\n")) + (widget-insert "\n"))) + options))) + custom-options)) + (unless (eq (preceding-char) ?\n) + (widget-insert "\n")) + custom-options + ) + +(defun cusnu-is-custom-obj (sym) + "Return non-nil if symbol SYM is customizable." + (or (get sym 'custom-type) + (get sym 'face) + (get sym 'custom-group) + )) + +(define-widget 'custom-symbol 'symbol + "A customizable symbol." + :prompt-match 'cusnu-is-custom-obj + :prompt-history 'widget-variable-prompt-value-history + :complete-function (lambda () + (interactive) + (lisp-complete-symbol 'cusnu-is-custom-obj)) + :tag "Custom option") + +(defun cusnu-set-my-skin-options (sym val) + (set-default sym val) + (let ((group (nth 0 val)) + (doc (nth 1 val)) + (members (nth 2 val))) + (custom-declare-group group nil doc) + (put group 'custom-group nil) + (dolist (opt members) + (let ((type (cusnu-get-opt-main-type opt))) + (when type + (custom-add-to-group group opt type)))))) + +(defun cusnu-get-opt-main-type (opt) + (when opt + (cond ((get opt 'face) 'custom-face) + ((get opt 'custom-type) 'custom-variable) + ((get opt 'custom-group) 'custom-group)))) + +(defgroup all-my-loaded-skin-groups nil + "All your loaded skin groups." + :group 'environment + :group 'convenience) + +(defun cusnu-custom-group-p (symbol) + (and (intern-soft symbol) + (or (and (get symbol 'custom-loads) + (not (get symbol 'custom-autoload))) + (get symbol 'custom-group)))) + +(defcustom cusnu-my-skin-options '(my-skin-group "My skin group.\n\n\n\n\n" nil) + "Your custom skin-like options. +The purpose of this variable is to provide for easy export a +selection of variables you choose to set to other users. + +To send these values to other users you export them to a file +with `cusnu-export-my-skin-options'." + :type '(list (symbol :tag "My custom group symbol name (should be specific to you)") + (string :tag "My custom group description") + (repeat :tag "Add your custom options below" + (custom-symbol :tag "My custom option"))) + :set 'cusnu-set-my-skin-options + :group 'all-my-loaded-skin-groups) + +;;(cusnu-ring-bell "bell") +(defun cusnu-ring-bell (format-string &rest args) + (message "%s" (propertize (apply + 'format format-string args) 'face 'secondary-selection)) + (ding) + (throw 'bell nil)) + +;;;###autoload +(defun cusnu-export-my-skin-options (file) + "Export to file FILE custom options in `cusnu-my-skin-options'. +The options is exported to elisp code that other users can run to +set the options that you have added to `cusnu-my-skin-options'. + +For more information about this see `cusnu-export-cust-group'." + (interactive '(nil)) + (catch 'bell + (let ((grp (nth 0 cusnu-my-skin-options)) + buf) + (let ((state (plist-get (cdr cusnu-my-skin-widget) :custom-state))) + (case state + ((set saved) nil) ;;(error "test, state=%s" state)) + (standard (cusnu-ring-bell "Please enter your options first")) + (t (cusnu-ring-bell "My Skin Options must be saved or set, use the State button, %s" state)))) + (unless (nth 2 cusnu-my-skin-options) + (cusnu-ring-bell "You have not added any of your options")) + (unless file + (setq file (read-file-name "Save to file: "))) + (when (file-exists-p file) + (cusnu-ring-bell "File %s already exists, choose another file name" file)) + (setq buf (find-file-other-window file)) + (with-current-buffer buf + (unless (eq major-mode 'emacs-lisp-mode) (emacs-lisp-mode)) + (unless (file-exists-p (buffer-file-name)) + (erase-buffer))) + (cusnu-export-cust-group grp buf)))) + +(defun cusnu-customize-my-skin-options () + (interactive) + (customize-group-other-window (nth 0 cusnu-my-skin-options))) + +(defun cusnu-reset-my-skin-options () + "Reset to my defaults for those options. +" + (interactive) + (cusnu-reset-group-options-to-my-defaults (nth 0 cusnu-my-skin-options))) + +(defun cusnu-reset-group-options-to-my-defaults (group) + (dolist (sym-typ (get group 'custom-group)) + (let ((symbol (nth 0 sym-typ)) + ;;(type (cusnu-get-opt-main-type symbol)) + (type (nth 1 sym-typ)) + defval) + (cond + ((eq type 'custom-variable) + ;; First try reset to saved. + (let* ((set (or (get symbol 'custom-set) 'set-default)) + (value (get symbol 'saved-value)) + (comment (get symbol 'saved-variable-comment))) + (cond ((or comment value) + (put symbol 'variable-comment comment) + (custom-push-theme 'theme-value symbol 'user 'set (car-safe value)) + (condition-case err + (funcall set symbol (eval (car value))) + (error (message "%s" err)))) + ;; If symbol was not saved then reset to standard. + (t + (unless (get symbol 'standard-value) + (error "No standard setting known for %S" symbol)) + (put symbol 'variable-comment nil) + (put symbol 'customized-value nil) + (put symbol 'customized-variable-comment nil) + (custom-push-theme 'theme-value symbol 'user 'reset) + (custom-theme-recalc-variable symbol) + (put symbol 'saved-value nil) + (put symbol 'saved-variable-comment nil) + )))) + ((eq type 'custom-face) + ;; First try reset to saved + (let* ((value (get symbol 'saved-face)) + (comment (get symbol 'saved-face-comment))) + (cond ((or value comment) + (put symbol 'customized-face nil) + (put symbol 'customized-face-comment nil) + (custom-push-theme 'theme-face symbol 'user 'set value) + (face-spec-set symbol value t) + (put symbol 'face-comment comment)) + ;; If symbol was not saved then reset to standard. + (t + (setq value (get symbol 'face-defface-spec)) + (unless value + (error "No standard setting for this face")) + (put symbol 'customized-face nil) + (put symbol 'customized-face-comment nil) + (custom-push-theme 'theme-face symbol 'user 'reset) + (face-spec-set symbol value t) + (custom-theme-recalc-face symbol) + ;; Do this later. + (put symbol 'saved-face nil) + (put symbol 'saved-face-comment nil) + )))) + (t (error "not iy")))))) + +(defun cusnu-export-cust-group (group buf) + "Export custom group GROUP to end of buffer BUF. +Only the options that has been customized will be exported. + +The group is exported as elisp code. Running the code will +create a group with just those members. After this it opens a +customization buffer with the new group. + +The code will also set the options to the customized values, but +it will not save them in the users init file. + +See also the comment in the exported file." + (let (start + (doc (get group 'group-documentation)) + groups options faces + (members (mapcar (lambda (rec) + (car rec)) + (get group 'custom-group)))) + (with-current-buffer buf + (insert (format-time-string ";; Here is my skin custom group %Y-%m-%d.\n")) + (font-lock-mode 1) + (insert (format ";;;;;; Customization group name: %s\n" group)) + (insert ";;\n") + (let ((here (point))) + (insert doc "\n") + (comment-region here (point)) + (fill-region here (point))) + (cusnu-get-options-and-faces members 'groups 'options 'faces) + (unless (or options faces) + (cusnu-ring-bell "There are no options or faces in %s customized by you" group)) + (insert " +;; This file defines the group and sets the options in it, but does +;; not save the values to your init file. +;; +;; To set the values evaluate this file. To do that open this file in Emacs and to +;; +;; M-x eval-buffer +;; +;; To go back to your default evaluate next line (place point at the end and to C-x C-e): +") + (insert (format ";; (cusnu-reset-group-options-to-my-defaults '%s)\n\n" group)) + (insert (format "(let ((grp '%s))\n" group)) + (insert (format " (custom-declare-group grp nil %S)\n" doc)) + (insert " (put grp 'custom-group nil)\n") + (insert (format " (custom-add-to-group 'all-my-loaded-skin-groups '%s 'custom-group)\n" group)) + (dolist (opt members) + (let ((type (cusnu-get-opt-main-type opt))) + (when type + (insert (format " (custom-add-to-group grp '%s '%s)\n" + opt type))))) + (insert " (custom-set-variables\n") + (dolist (opt options) + (let ((my-val (or (get opt 'saved-value) + (get opt 'customized-value)))) + (when my-val + (insert (format " '(%s %S)\n" opt (custom-quote (symbol-value opt))))))) + (insert " )\n") + (insert " (custom-set-faces\n") + (dolist (opt faces) + (let ((my-val (get opt 'customized-face))) + (when my-val + (insert (format " '(%s %S)\n" opt my-val))))) + (insert " ))\n") + (insert (format "\n(customize-group '%s)\n" group)) + ))) + +(defun cusnu-get-options-and-faces (members groups-par options-par faces-par) + (dolist (sym members) + (insert (format ";; sym=%s\n" sym)) + (cond ((and (get sym 'custom-type) + (or (get sym 'saved-value) + (get sym 'customize-value))) + (add-to-list options-par sym)) + ((and (get sym 'face) + (get sym 'customized-face)) + (add-to-list faces-par sym)) + ((get sym 'custom-group) + (unless (memq sym groups-par) ;; Don't loop + (cusnu-get-options-and-faces groups-par options-par faces-par))) + (t (insert ";; Not a custom variable or face: %s\n" sym))))) + +(provide 'cus-new-user) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; cus-new-user.el ends here diff --git a/emacs/nxhtml/util/custsets.el b/emacs/nxhtml/util/custsets.el new file mode 100644 index 0000000..0495dd8 --- /dev/null +++ b/emacs/nxhtml/util/custsets.el @@ -0,0 +1,83 @@ +;;; custsets.el --- Sets of named customizations +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-03-25T00:17:06+0100 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; After an idea expressed by among other Stephen Turnbull on the +;; emacs devel list. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(defcustom custsets-sets + '( + ("Windows" + (cua-mode t) + ) + ) + "Sets of customizations." + :group 'custsets) + +(defun custsets-turn-on (set-name) + (interactive "sCustomization set: ") + (let ((set (assoc-string set-name custsets-sets t))) + (unless set + (error "Can't find customization set %s" set-name)) + (dolist (opt-rec (cdr set)) + (let* ((opt (car opt-rec)) + (val (cdr opt-rec)) + (saved-opt (get opt 'saved-value)) + (saved-val saved-opt) ;; fix-me + (ask (if saved-opt + (format "You have currently customized %s to %s. Change this to %s? " + opt saved-opt val) + (format "Customize %s to %s? " opt val))) + ) + (when (y-or-n-p ask) + (customize-set-variable opt val) + (customize-set-value opt val) + (customize-mark-to-save opt)) + ) + ) + (custom-save-all))) + + +(provide 'custsets) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; custsets.el ends here diff --git a/emacs/nxhtml/util/ecb-batch-compile.el b/emacs/nxhtml/util/ecb-batch-compile.el new file mode 100644 index 0000000..bdd86c6 --- /dev/null +++ b/emacs/nxhtml/util/ecb-batch-compile.el @@ -0,0 +1,65 @@ +;;; ecb-batch-compile.el --- Compile ecb in batch mode +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-25T04:46:35+0200 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Batch byte compile ecb: +;; +;; emacs -Q -l ecb-batch-compile +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-and-compile (require 'udev-ecb nil t)) + +(let* ((this-file load-file-name) + (this-dir (file-name-directory this-file)) + ) + (add-to-list 'load-path this-dir)) + +;;(require 'udev-cedet) +;;(udev-cedet-load-cedet t) + +(eval-when (eval) + (udev-ecb-load-ecb) + (ecb-byte-compile)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ecb-batch-compile.el ends here diff --git a/emacs/nxhtml/util/ediff-url.el b/emacs/nxhtml/util/ediff-url.el new file mode 100644 index 0000000..12329bd --- /dev/null +++ b/emacs/nxhtml/util/ediff-url.el @@ -0,0 +1,188 @@ +;;; ediff-url.el --- Diffing buffer against downloaded url +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Nov 24 2007 +;; Version: 0.56 +;; Last-Updated: 2010-03-18 Thu +;; URL: http://bazaar.launchpad.net/~nxhtml/nxhtml/main/annotate/head%3A/util/ediff-url.el +;; +;; Features that might be required by this library: +;; + ;; `mail-prsvr', `mm-util', `timer', `url-parse', `url-util', + ;; `url-vars'. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file contains a simple function, `ediff-url', to help you +;; update a single file from the web. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(require 'url-util) +(eval-when-compile (require 'cl)) + +(defvar ediff-url-read-url-history nil) + +(defun ediff-url-redir-launchpad (url) + "Check if bazaar list page on Launchpad. +If URL is a description page for a file uploaded to EmacsWiki +suggest to use the download URL instead." + (let* ((bazaar-url "http://bazaar.launchpad.net/") + (bazaar-len (length bazaar-url))) + (if (and (< bazaar-len (length url)) + (string= bazaar-url (substring url 0 bazaar-len))) + (let* ((url-show-status nil) ;; just annoying showing status here + (buffer (url-retrieve-synchronously url)) + (handle nil) + (http-status nil) + ;; Fix-me: better more flexible pattern? + (dl-patt "<a href=\"\\(.*?\\)\">download file</a>") + dl-url) + (unless buffer + (message "Got empty buffer for %s" url) + (throw 'command-level nil)) + (with-current-buffer buffer + (if (= 0 (buffer-size)) + (progn + (message "Got empty page for %s" url) + (throw 'command-level nil)) + (require 'url-http) + (setq http-status (url-http-parse-response)) + (if (memq http-status '(200 201)) + (progn + (goto-char (point-min)) + (unless (search-forward "\n\n" nil t) + (error "Could not find header end in buffer for %s" url)) + (unless (re-search-forward dl-patt nil t) + (error "Could not find download link")) + (setq dl-url (match-string 1)) + (set-buffer-modified-p nil) + (kill-buffer buffer) + dl-url) + (kill-buffer buffer) + (setq buffer nil) + (setq http-status + (concat (number-to-string http-status) + (case http-status + (401 " (unauthorized)") + (403 " (forbidden)") + (404 " (not found)") + (408 " (request timeout)") + (410 " (gone)") + (500 " (internal server error)") + (503 " (service unavailable)") + (504 " (gateway timeout)") + (530 " (user access denied)") + ))) + (message "Got status %s for %s" http-status url) + (throw 'command-level nil))))) + url))) + +(defun ediff-url-redir-emacswiki-description-page (url) + "Check if description page on EmacsWiki. +If URL is a description page for a file uploaded to EmacsWiki +suggest to use the download URL instead." + ;;(let* ((desc-url "http://www.emacswiki.org/emacs/") + (let* ((emacswiki-url "http://www.emacswiki.org/") + (emacswiki-len (length emacswiki-url))) + (if (and (< emacswiki-len (length url)) + (string= emacswiki-url (substring url 0 emacswiki-len)) + (not (string-match-p "/download/" url))) + (let ((prompt + (concat "This seem to be the description page on EmacsWiki," + "\n\tdo you want the download url instead? "))) + (when (y-or-n-p prompt) + ;;(let ((start (+ 6 (string-match "/wiki/" url)))) + (let ((start (+ 7 (string-match "/emacs/" url)))) + (concat (substring url 0 start) + "download/" + (substring url start))))) + ;; Not on the wiki, just return the url: + url))) + +(defcustom ediff-url-redirects '(ediff-url-redir-emacswiki-description-page + ediff-url-redir-launchpad + ) + "List of functions checking url given to `ediff-url'. +Each function should take an URL as argument and return this URL +or a new URL." + :type '(repeat function) + :group 'ediff) + +;;;###autoload +(defun ediff-url (url) + "Compare current buffer to a web URL using `ediff-buffers'. +Check URL using `ediff-url-redirects' before fetching the file. + +This is for checking downloaded file. A the file may have a comment +telling the download URL of thise form in the header: + + ;; URL: http://the-server.net/the-path/the-file.el + +If not the user is asked for the URL." + (interactive (let ((url-init (url-get-url-at-point))) + (unless url-init + (when (eq major-mode 'emacs-lisp-mode) + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "URL:[ \t]*" nil t) + (setq url-init (url-get-url-at-point)))))) + (list (read-from-minibuffer "Url for download file: " + (cons (or url-init "") 1) ;nil + nil nil + 'ediff-url-read-url-history + ;;url-init + )))) + (catch 'command-level ;; Fix-me: remove and let go to top later + (unless (> (length url) 0) + (message "No URL given, aborted by user") + (throw 'command-level nil)) + ;; Check if URL seems reasonable + (dolist (fun ediff-url-redirects) + (setq url (funcall fun url))) + ;; Fetch URL and run ediff + (let* ((url-buf-name (concat "URL=" url)) + (url-buf (get-buffer url-buf-name))) + (when url-buf + (unless (y-or-n-p "Use previously downloaded url? ") + (kill-buffer url-buf) + (setq url-buf nil))) + (unless url-buf + (setq url-buf (get-buffer-create url-buf-name)) + (let ((current-major major-mode)) + (with-current-buffer url-buf + (url-insert-file-contents url) + ;; Assume same modes: + (funcall current-major)))) + (ediff-buffers url-buf (current-buffer))))) + +(provide 'ediff-url) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ediff-url.el ends here diff --git a/emacs/nxhtml/util/ffip.el b/emacs/nxhtml/util/ffip.el new file mode 100644 index 0000000..42d1893 --- /dev/null +++ b/emacs/nxhtml/util/ffip.el @@ -0,0 +1,304 @@ +;;; ffip.el --- Find files in project +;; +;; Authors: extracted from rinari by Phil Hagelberg and Doug Alcorn +;; Changed by Lennart Borgman +;; Created: 2008-08-14T23:46:22+0200 Thu +;; Version: 0.3 +;; Last-Updated: 2008-12-28 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Project data + +;; Fix-me: Change the inner structure of ffip projects +(defvar ffip-project-name nil "Project name.") +(defvar ffip-project-roots nil "Project directory roots.") +(defvar ffip-project-type nil "Project type, `ffip-project-file-types'.") +(defcustom ffip-project-file-types + (list + '(ruby "\\(\\.el$\\|\\.rb$\\|\\.js$\\|\\.emacs\\)") + (list 'nxhtml (concat + (regexp-opt '(".html" ".htm" ".xhtml" + ".css" + ".js" + ".png" ".gif" + )) + "\\'")) + ) + "Project types and file types. +The values in this list are used to determine if a file belongs +to the current ffip project. Entries have the form + + \(TYPE FILE-REGEXP) + +TYPE is the parameter set by `ffip-set-current-project'. Files +matching FILE-REGEXP within the project roots are members of the +project." + :type '(repeat (list + (symbol :tag "Type") + (regexp :tag "File regexp"))) + :group 'ffip) + +(defvar ffip-project-file-matcher nil "Project file matcher.") +(defvar ffip-project-files-table nil "Project file cache.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Project handling + +(defun ffip-reset-project () + "Clear project data." + (remove-hook 'after-save-hook 'ffip-after-save) + (setq ffip-project-name nil) + (setq ffip-project-roots nil) + (setq ffip-project-files-table nil) + (setq ffip-project-type nil) + (setq ffip-project-file-matcher nil)) +;;(ffip-reset-project) + +(defun ffip-is-current (name root type) + "Return non-nil if NAME, ROOT and TYPE match current ffip project. +See `ffip-set-current-project'." + (and name + (string= ffip-project-name name) + (eq ffip-project-type type) + (equal ffip-project-roots root))) + +;;;###autoload +(defun ffip-set-current-project (name root type) + "Setup ffip project NAME with top directory ROOT of type TYPE. +ROOT can either be just a directory or a list of directory where +the first used just for prompting purposes and the files in the +rest are read into the ffip project. + +Type is a type in `ffip-project-file-types'." + (unless (ffip-is-current name root type) + (ffip-reset-project) + (setq ffip-project-name name) + (setq ffip-project-type type) + (setq ffip-project-roots root) + (message "Project %s with %s files setup for find-files-in-project" + name (length ffip-project-files-table)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; File cache handling + +(defun ffip-cache-project-files (file-regexp) + "Read files and cache their names within the ffip project." + (let ((root ffip-project-roots)) + (message "... reading files in %s ..." root) + (add-hook 'after-save-hook 'ffip-after-save) + (if (not (listp root)) + (ffip-populate-files-table root file-regexp) + (setq root (cdr root)) + (dolist (r root) + (ffip-populate-files-table r file-regexp))))) + +(defun ffip-file-matcher () + (when ffip-project-type + (cadr (assoc ffip-project-type ffip-project-file-types)))) + +(defun ffip-project-files () + "Get a list of all files in ffip project. +The members in the list has the format + + \(SHORT-NAME . FULL-NAME) + +where SHORT-NAME is a unique name (normally file name without +directory) and FULL-NAME is the full file name." + (unless ffip-project-files-table + (let ((file-regexp (ffip-file-matcher))) + (ffip-cache-project-files file-regexp))) + ffip-project-files-table) + +;; Fix-me: Seems better to rewrite this to use +;; project-find-settings-file. +(defun ffip-project-root (&optional dir) + (setq dir (or dir + ffip-project-roots + default-directory)) + ;;(locate-dominating-file "." "\\`\\find-file-in-project.el\\'") + (let ((root (locate-dominating-file dir + ;;"\\`\\.emacs-project\\'" + "\\`\\.dir-settings\\.el\\'" + ))) + (if root + (file-name-directory root) + dir))) + +(defun ffip-populate-files-table (file file-regexp) + ;;(message "ffip-populate-files-table.file=%s" file) + (if (file-directory-p file) + (mapc (lambda (file) + (ffip-populate-files-table file file-regexp)) + (directory-files (expand-file-name file) t "^[^\.]")) + (let* ((file-name (file-name-nondirectory file)) + (existing-record (assoc file-name ffip-project-files-table)) + (unique-parts (ffip-get-unique-directory-names file + (cdr existing-record)))) + (when (or (not file-regexp) + (string-match file-regexp file-name)) + (if existing-record + (let ((new-key (concat file-name " - " (car unique-parts))) + (old-key (concat (car existing-record) " - " + (cadr unique-parts)))) + (setf (car existing-record) old-key) + (setq ffip-project-files-table + (acons new-key file ffip-project-files-table))) + (setq ffip-project-files-table + (acons file-name file ffip-project-files-table))))))) + +(defun ffip-get-unique-directory-names (path1 path2) + (let* ((parts1 (and path1 (split-string path1 "/" t))) + (parts2 (and path2 (split-string path2 "/" t))) + (part1 (pop parts1)) + (part2 (pop parts2)) + (looping t)) + (while (and part1 part2 looping) + (if (equal part1 part2) + (setq part1 (pop parts1) part2 (pop parts2)) + (setq looping nil))) + (list part1 part2))) + +(defun ffip-file-is-in-project (file-name) + "Return non-nil if file is in current ffip project." + (save-match-data + (let ((file-regexp (ffip-file-matcher)) + (roots ffip-project-roots) + regexp) + (if (not (listp roots)) + (setq roots (list roots)) + (setq roots (cdr roots))) + (catch 'found + (dolist (root roots) + (setq file-regexp (concat root ".*" file-regexp)) + (when (string-match file-regexp file-name) + (throw 'found t))))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Updating on file changes + +(defun ffip-add-file-if-in-project (file-name) + "Add file to cache if it in ffip project." + (when (ffip-file-is-in-project file-name) + ;; We have already checked so just use nil for the matcher. + (ffip-populate-files-table file-name nil))) + +;; For after-save-hook +(defun ffip-after-save () + "Check if a file should be added to cache." + (condition-case err + (ffip-add-file-if-in-project buffer-file-name) + (error (message "%s" (error-message-string err))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Interactive functions + +;;;###autoload +(defun ffip-find-file-in-dirtree (root) + "Find files in directory tree ROOT." + (interactive "DFind file in directory tree: ") + ;; Setup a temporary + (let ((ffip-project-name nil) + (ffip-project-roots nil) + (ffip-project-files-table nil) + (ffip-project-type nil) + (ffip-project-file-matcher nil)) + (ffip-set-current-project "(temporary)" root nil) + (call-interactively 'ffip-find-file-in-project))) + +(defun ffip-find-file-in-project (file) + "Find files in current ffip project." + (interactive + (list + (let* ((prompt (format "Find file in project %s: " + ffip-project-name))) + (if (memq ido-mode '(file 'both)) + (ido-completing-read prompt + (mapcar 'car (ffip-project-files))) + (let ((files (mapcar 'car (ffip-project-files)))) + (completing-read prompt + files + (lambda (elem) (member elem files)) + t)))))) + (find-file (cdr (assoc file ffip-project-files-table)))) + +;;(global-set-key (kbd "C-x C-M-f") 'find-file-in-project) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Fix-me: This part should go somewhere else +(eval-after-load 'ruby-mode + '(progn + (defun ffip-rails-project-files (&optional file) + (let ((default-directory (or file (rails-root)))) + (unless (and ffip-project-roots + (string= default-directory ffip-project-roots)) + (ffip-set-current-project + "Rails proj" + root + (list default-directory + (expand-file-name "app") + (expand-file-name "lib") + (expand-file-name "test")) + 'ruby + ))) + (ffip-project-files)) + + (defun ffip-find-file-in-rails (file) + (interactive + (list (if (memq ido-mode '(file 'both)) + (ido-completing-read + "Find file in project: " + (mapcar 'car (ffip-rails-project-files))) + (completing-read "Find file in project: " + (mapcar 'car (rails-project-files)))))) + (find-file (cdr (assoc file ffip-project-files-table)))) + + (define-key ruby-mode-map (kbd "C-x C-M-f") 'find-file-in-rails) + (eval-after-load 'nxhtml-mode + '(define-key nxhtml-mode-map (kbd "C-x C-M-f") 'find-file-in-rails)))) + +(provide 'ffip) +;;; ffip.el ends here diff --git a/emacs/nxhtml/util/fold-dwim.el b/emacs/nxhtml/util/fold-dwim.el new file mode 100644 index 0000000..11b3a3d --- /dev/null +++ b/emacs/nxhtml/util/fold-dwim.el @@ -0,0 +1,466 @@ +;;; fold-dwim.el -- Unified user interface for Emacs folding modes +;; +;; Copyright (C) 2004 P J Heslin +;; +;; Author: Peter Heslin <p.j.heslin@dur.ac.uk> +;; URL: http://www.dur.ac.uk/p.j.heslin/Software/Emacs/Download/fold-dwim.el +(defconst fold-dwim:version "1.4") +;; +;; 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. +;; +;; If you do not have a copy of the GNU General Public License, you +;; can obtain one by writing to the Free Software Foundation, Inc., 59 +;; Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Overview: +;; +;; DWIM stands for "do what I mean", as in the idea that one keystroke +;; can do different things depending on the context. In this package, +;; it means that, if the cursor is in a currently hidden folded +;; construction, we want to show it; if it's not, we want to hide +;; whatever fold the cursor is in. +;; +;; Some editors other than Emacs provide a single mechanism for +;; folding text which various file types can exploit. The advantage +;; of this arrangement is that the user only has to know one set of +;; folding commands; the disadvantage is that the various file types +;; are limited to using whatever functionality is provided centrally. +;; Emacs by contrast provides a very general and powerful framework +;; for hiding text, which major modes can use as they see fit. The +;; advantage of this is that each major mode can deal with folding in +;; the way that is suitable for that type of file; the disadvantage is +;; that different major modes have different styles of folding, and +;; provide different key bindings. +;; +;; In practice, matters are simpler than that, since most major modes +;; delegate the task of folding to packages like outline.el and +;; hideshow.el. The key bindings for these two packages alone, +;; however, are numerous and for some people hard to type. Another +;; usability complication arises when a package like AucTeX uses +;; outline-minor-mode for some folds, and provides its own +;; key-bindings for other kinds of folds. Likewise, nXML-mode +;; provides its own style of folding for certain types of files, but +;; for files that don't fit that paradigm (such as XHTML), you may +;; want to use outline-minor-mode instead. +;; +;; The goal of this package is to reduce this complexity to three +;; globally-defined keystrokes: one to toggle the state of the fold at +;; point, whatever its type may be, one to hide all folds of all types +;; in the buffer, and one to show all folds. +;; +;; This package currently knows about folding-mode (from folding.el), +;; hs-minor-mode (from hideshow.el), outline-minor-mode (from +;; outline.el), TeX-fold-mode (from AUCTeX), and nXML-mode outlining. +;; More could be added. It is not necessary to have folding.el, +;; AUCTeX or nXML-mode installed, if you just want to use it with the +;; built-in modes. + +;;; Usage: +;; +;; You will need to have one or more of following minor modes switched +;; on: hs-minor-mode, outline-minor-mode, TeX-fold-mode, folding-mode. +;; Otherwise no folds may be found. There are three functions to try: +;; +;; fold-dwim-toggle: try to show any hidden text at the cursor; if no +;; hidden text is found, try to hide the text at the cursor. +;; +;; fold-dwim-hide-all: hide all folds in the buffer. +;; +;; fold-dwim-show-all: show all folds in the buffer. + +;;; Configuration +;; +;; This package binds no keys by default, so you need to find three +;; free and convenient key-bindings. This is what I use: +;; +;; (global-set-key (kbd "<f7>") 'fold-dwim-toggle) +;; (global-set-key (kbd "<M-f7>") 'fold-dwim-hide-all) +;; (global-set-key (kbd "<S-M-f7>") 'fold-dwim-show-all) +;; + +;;; Advanced Configuration +;; +;; With respect to outline-minor-mode (or outline-mode), dwim-fold +;; provides two different styles of usage. The first is a "nested" +;; style which only shows top-level headings when you fold the whole +;; buffer, and then allows you to drill down progressively through the +;; other levels. The other is a "flat" style, whereby folding the +;; entire buffer shows all headings at every level. +;; +;; The default is "flat", but if you want to change the default, you +;; can set the value of fold-dwim-outline-style-default to be 'flat or +;; 'nested. If you wish to override the default for a particular +;; major mode, put a value of either 'flat or 'nested for the +;; fold-dwim-outline-style property of the major-mode symbol, like so: +;; +;; (put 'org-mode 'fold-dwim-outline-style 'nested) +;; +;; At present, there is no way to customize nXML-mode outlining to use +;; the nested style, since it is not really supported by that mode +;; (there is no function to hide all text and subheadings in the +;; buffer). + +;;; Compatibility +;; +;; Tested with GNU Emacs CVS (from Sept. 10, 2004), AUCTeX version +;; 11.53, nxml-mode version 20041004, folding.el version 2.97. +;; +;; If there are any other important major or minor modes that do +;; folding and that could usefully be handled in this package, please +;; let me know. + +;;; Bugs +;; +;; It is possible that some of the various folding modes may interact +;; badly if used together; I have not tested all permutations. +;; +;; The function fold-dwim-hide tries various folding modes in +;; succession, and stops when it finds one that successfully makes a +;; fold at point. This means that the order in which those modes are +;; tried is significant. I have not spent a lot of time thinking +;; about what the optimal order would be; all I care about is that +;; hideshow and TeX-fold have priority over outline-minor-mode (since +;; for me they usually fold smaller chunks of the file). +;; +;; I don't use folding.el myself, so that functionality is not well +;; tested. + +;;; Changes +;; +;; 1.0 Initial release +;; 1.1 Bugfix: test if folding-mode is bound +;; 1.2 fold-dwim-hide-all and -show-all operate only on active region +;; in transient-mark-mode. +;; 1.3 Added outline-mode (Lennart Borgman) +;; 1.4 Removed nxml-mode style folding (Lennart Borgman) +;; + some functions used by nXhtml. + +(require 'outline) +(require 'hideshow) + +;;;###autoload +(defgroup fold-dwim nil + "Unified interface to folding commands" + :prefix "fold-dwim-" + :group 'editing) + +(defcustom fold-dwim-outline-style-default 'flat + "Default style in which to fold in outline-minor-mode: 'nested or + 'flat." + :type '(choice (const :tag "Flat (show all headings)" flat) + (const :tag "Nested (nest headings hierarchically)" nested)) + :group 'fold-dwim) + +(defvar fold-dwim-toggle-selective-display 'nil + "Set this non-nil to make fold-dwim functions use selective + display (folding of all lines indented as much or more than the + current line). Probably only useful for minor modes like + makefile-mode that don't provide a more intelligent way of + folding.") + +(make-variable-buffer-local + 'fold-dwim-toggle-selective-display) + +(defun fold-dwim-maybe-recenter () + "It's annoyingly frequent that hiding a fold will leave you +with point on the top or bottom line of the screen, looking at +nothing but an ellipsis. TODO: only recenter if we end up near +the top or bottom of the screen" + (recenter)) + +(defun fold-dwim-toggle-selective-display () + "Set selective display to indentation of current line" + (interactive) + (if (numberp selective-display) + (set-selective-display nil) + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (let ((col (current-column))) + (if (zerop col) + (set-selective-display nil) + (set-selective-display col)))))) + +(defun fold-dwim-hide-all () + "Hide all folds of various kinds in the buffer or region" + (interactive) + (save-excursion + (save-restriction + (when (and transient-mark-mode mark-active) + (narrow-to-region (region-beginning) (region-end))) + (when (and (boundp 'TeX-fold-mode) TeX-fold-mode) + (TeX-fold-buffer)) + (when hs-minor-mode + (hs-hide-all)) + (when (or outline-minor-mode (eq major-mode 'outline-mode)) + (if (fold-dwim-outline-nested-p) + (hide-sublevels 1) + (hide-body))) + ;; (when (derived-mode-p 'nxml-mode) + ;; (nxml-hide-all-text-content)) + (when (and (boundp 'folding-mode) folding-mode) + (folding-whole-buffer)))) + (fold-dwim-maybe-recenter)) + +(defun fold-dwim-show-all () + "Show all folds of various kinds in the buffer or region" + (interactive) + (save-excursion + (save-restriction + (when (and transient-mark-mode mark-active) + (narrow-to-region (region-beginning) (region-end))) + (when (and (boundp 'TeX-fold-mode) TeX-fold-mode) + (TeX-fold-clearout-buffer)) + (when hs-minor-mode + (hs-show-all)) + ;; (when (derived-mode-p 'nxml-mode) + ;; (nxml-show-all)) + (when (or outline-minor-mode (eq major-mode 'outline-mode)) + (show-all)) + (when (and (boundp 'folding-mode) folding-mode) + (folding-open-buffer)) + (when fold-dwim-toggle-selective-display + (set-selective-display 'nil))))) + +(defun fold-dwim-hide () + "Hide one item" + (or (and (boundp 'TeX-fold-mode) + TeX-fold-mode + (let ((type (fold-dwim-auctex-env-or-macro))) + (when type + (TeX-fold-item type)))) + ;; Look for html headers. + (when (and (derived-mode-p 'nxml-mode 'html-mode) + outline-minor-mode) + (when (save-excursion + (save-match-data + (looking-back (rx "<" (optional "/") + "h" (any "1-6") + (0+ (not (any "<"))))))) + (hide-entry) + t)) + (and hs-minor-mode + (when (save-excursion + (or (hs-find-block-beginning) (hs-inside-comment-p))) + (hs-hide-block) + (hs-already-hidden-p))) + ;; (and (derived-mode-p 'nxml-mode) + ;; (condition-case nil + ;; (save-excursion + ;; (nxml-back-to-section-start)) + ;; (error nil)) + ;; (nxml-hide-text-content)) + (and (boundp 'folding-mode) + folding-mode + (condition-case nil + (save-excursion + (folding-hide-current-entry) + t) + (error nil))) + (when (or outline-minor-mode (eq major-mode 'outline-mode)) + (if (fold-dwim-outline-nested-p) + (hide-subtree) + (hide-entry)))) + (fold-dwim-maybe-recenter)) + + +(defun fold-dwim-show () + "If point is in a closed or temporarily open fold, + open it. Returns nil if nothing was done" + (save-excursion + (let ((stop)) + (when (and (or outline-minor-mode (eq major-mode 'outline-mode)) + (or (fold-dwim-outline-invisible-p (line-end-position)) + (and (bolp) + (not (bobp)) + (fold-dwim-outline-invisible-p (1- (point)))))) + (if (not (fold-dwim-outline-nested-p)) + (show-entry) + (show-children) + (show-entry)) + (setq stop "outline-minor-mode")) + (when (and (not stop) + hs-minor-mode + (hs-already-hidden-p)) + (hs-show-block) + (setq stop "hs-minor-mode")) + (when (and (not stop) + (boundp 'TeX-fold-mode) + TeX-fold-mode) + (let ((overlays (overlays-at (point)))) + (while overlays + (when (eq (overlay-get (car overlays) 'category) 'TeX-fold) + (delete-overlay (car overlays)) + (setq stop "Tex-fold-mode")) + (setq overlays (cdr overlays))))) + ;; (when (and (not stop) + ;; (derived-mode-p 'nxml-mode)) + ;; (let ((overlays (overlays-at (point)))) + ;; (while (and overlays (not stop)) + ;; (when (overlay-get (car overlays) 'nxml-outline-display) + ;; (setq stop "nxml folding")) + ;; (setq overlays (cdr overlays)))) + ;; (when stop + ;; (nxml-show))) + (when (and (not stop) + (boundp 'folding-mode) + folding-mode + (save-excursion + (beginning-of-line) + (let ((current-line-mark (folding-mark-look-at))) + (when (and (numberp current-line-mark) + (= current-line-mark 0)) + (folding-show-current-entry) + (setq stop "folding-mode")))))) + stop))) + +;;;###autoload +(defun fold-dwim-toggle () + "Toggle visibility or some other visual things. +Try toggling different visual things in this order: + +- Images shown at point with `inlimg-mode' +- Text at point prettified by `html-write-mode'. + +For the rest it unhides if possible, otherwise hides in this +order: + +- `org-mode' header or something else using that outlines. +- Maybe `fold-dwim-toggle-selective-display'. +- `Tex-fold-mode' things. +- In html if `outline-minor-mode' and after heading hide content. +- `hs-minor-mode' things. +- `outline-minor-mode' things. (Turns maybe on this.) + +It uses `fold-dwim-show' to show any hidden text at point; if no +hidden fold is found, try `fold-dwim-hide' to hide the +construction at the cursor. + +Note: Also first turn on `fold-dwim-mode' to get the keybinding +for this function from it." + (interactive) + (fold-dwim-mode 1) + (cond + ((get-char-property (point) 'html-write) + (html-write-toggle-current-tag)) + ((get-char-property (point) 'inlimg-img) + (inlimg-toggle-display (point))) + ((eq major-mode 'org-mode) + (org-cycle)) + ((and (fboundp 'outline-cycle) + outline-minor-mode) + (outline-cycle)) + (t + (unless (or outline-minor-mode hs-minor-mode) + (outline-minor-mode 1)) + (if fold-dwim-toggle-selective-display + (fold-dwim-toggle-selective-display) + (let ((unfolded (fold-dwim-show))) + (if unfolded + (message "Fold DWIM showed: %s" unfolded) + (fold-dwim-hide))))))) + +;;;###autoload +(define-minor-mode fold-dwim-mode + "Key binding for `fold-dwim-toggle'." + :global t + :group 'nxhtml + :group 'foldit + nil) + +;; Fix-me: Maybe move to fold-dwim and rethink? +(defvar fold-dwim-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?+] 'fold-dwim-toggle) + map)) + +;;;###autoload +(defun fold-dwim-unhide-hs-and-outline () + "Unhide everything hidden by Hide/Show and Outline. +Ie everything hidden by `hs-minor-mode' and +`outline-minor-mode'." + (interactive) + (hs-show-all) + (show-all)) + +;;;###autoload +(defun fold-dwim-turn-on-hs-and-hide () + "Turn on minor mode `hs-minor-mode' and hide. +If major mode is derived from `nxml-mode' call `hs-hide-block' +else call `hs-hide-all'." + (interactive) + (hs-minor-mode 1) + (foldit-mode 1) + (if (derived-mode-p 'nxml-mode) + (hs-hide-block) + (hs-hide-all))) + +;;;###autoload +(defun fold-dwim-turn-on-outline-and-hide-all () + "Turn on `outline-minor-mode' and call `hide-body'." + (interactive) + (outline-minor-mode 1) + (foldit-mode 1) + (hide-body)) + +(defun fold-dwim-auctex-env-or-macro () + (let ((type (cond + ;; Fold macro before env, unless it's begin or end + ((save-excursion + (let ((macro-start (TeX-find-macro-start))) + (and macro-start + (not (= macro-start (point))) + (goto-char macro-start) + (not (looking-at + (concat (regexp-quote TeX-esc) + "\\(begin\\|end\\)[ \t]*{")))))) + 'macro) + ((and (eq major-mode 'context-mode) + (save-excursion + (ConTeXt-find-matching-start) (point))) + 'env) + ((and (eq major-mode 'texinfo-mode) + (save-excursion + (Texinfo-find-env-start) (point))) + 'env) + ((and (eq major-mode 'latex-mode) + (condition-case nil + (save-excursion + (LaTeX-find-matching-begin) (point) + (not (looking-at "\\\\begin[ \t]*{document}"))) + (error nil))) + 'env) + (t + nil)))) + type)) + +(defun fold-dwim-outline-invisible-p (pos) + "The version of this function in outline.el doesn't work so + well for our purposes, because it doesn't distinguish between + invisibility caused by outline, and that of other modes." + (save-excursion + (goto-char pos) + (let ((overlays (overlays-at (point))) + (found-one)) + (while overlays + (when (eq (overlay-get (car overlays) 'invisible) 'outline) + (setq found-one t)) + (setq overlays (cdr overlays))) + found-one))) + +(defun fold-dwim-outline-nested-p () + "Are we using the flat or nested style for outline-minor-mode?" + (let ((style (get major-mode 'fold-dwim-outline-style))) + (if style + (eq style 'nested) + (eq fold-dwim-outline-style-default 'nested)))) + +(provide 'fold-dwim) diff --git a/emacs/nxhtml/util/foldit.el b/emacs/nxhtml/util/foldit.el new file mode 100644 index 0000000..0ffacc3 --- /dev/null +++ b/emacs/nxhtml/util/foldit.el @@ -0,0 +1,357 @@ +;;; foldit.el --- Helpers for folding +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-08-10 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Defines `foldit-mode' which puts visual clues on hidden regions. +;; Does not do any folding itself but works with `outline-minor-mode' +;; and `hs-minor-mode'. +;; +;; Fix-me: reveal-mode does not work with this and I have no idea why +;; ... +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +;; Fix-me: start-tag-beg/start-tag-end are workarounds for smaller +;; bugs in hs-minor-mode and outline-minor-mode. Maybe try to fix +;; them... - but there are a whole bunch of other invisibilty related +;; bugs that ought to be fixed first since otherwise it is impossible +;; to know where point goes after hiding/unhiding. + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'hideshow)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'outline)) + +(defsubst foldit-overlay-priority () + (1+ (or (and (boundp 'mlinks-link-overlay-priority) + mlinks-link-overlay-priority) + 100))) + +;;;###autoload +(defgroup foldit nil + "Customization group for foldit folding helpers." + :group 'nxhtml) + +(defvar foldit-temp-at-point-ovl nil) +(make-variable-buffer-local 'foldit-temp-at-point-ovl) + +;;;###autoload +(define-minor-mode foldit-mode + "Minor mode providing visual aids for folding. +Shows some hints about what you have hidden and how to reveal it. + +Supports `hs-minor-mode', `outline-minor-mode' and major modes +derived from `outline-mode'." + :lighter nil + (if foldit-mode + (progn + ;; Outline + (add-hook 'outline-view-change-hook 'foldit-outline-change nil t) + ;; Add our overlays + (when (or (and (boundp 'outline-minor-mode) outline-minor-mode) + ;; Fix-me: mumamo + (derived-mode-p 'outline-mode)) (foldit-outline-change)) + ;; hs + (unless (local-variable-p 'hs-set-up-overlay) + (set (make-local-variable 'hs-set-up-overlay) 'foldit-hs-set-up-overlay)) + ;; Add our overlays + (when (or (and (boundp 'hs-minor-mode) hs-minor-mode)) + (save-restriction + (widen) + (let (ovl) + (dolist (ovl (overlays-in (point-min) (point-max))) + (when (eq (overlay-get ovl 'invisible) 'hs) + (funcall hs-set-up-overlay ovl))))))) + ;; Outline + (remove-hook 'outline-view-change-hook 'foldit-outline-change t) + ;; hs + (when (and (local-variable-p 'hs-set-up-overlay) + (eq hs-set-up-overlay 'foldit-hs-set-up-overlay)) + (kill-local-variable 'hs-set-up-overlay)) + ;; Remove our overlays + (save-restriction + (widen) + (let (ovl prop) + (dolist (ovl (overlays-in (point-min) (point-max))) + (when (setq prop (overlay-get ovl 'foldit)) + (case prop + ;;('display (overlay-put ovl 'display nil)) + ('foldit (delete-overlay ovl)) + (t (delete-overlay ovl)) + ))))))) + +(defcustom foldit-avoid '(org-mode) + "List of major modes to avoid." + :group 'foldit) + +;;;###autoload +(define-globalized-minor-mode foldit-global-mode foldit-mode + (lambda () (foldit-mode 1)) + :group 'foldit) + +(defun foldit-hidden-line-str (hidden-lines type) + "String to display for hidden lines. +HIDDEN-LINES are the number of lines and TYPE is a string +indicating how they were hidden." + (propertize (format " ...(%d %slines)" hidden-lines type) + 'face 'shadow)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Outline + +(defvar foldit-outline-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-outline-show-entry) + (define-key map [down-mouse-1] 'foldit-outline-show-entry) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defun foldit-outline-change () + "Check outline overlays. +Run this in `outline-view-change-hook'." + ;; We get the variables FROM and TO here from `outline-flag-region' + ;; so let us use them. But O is hidden... + (let* (from + to + num-lines + ovl + (tag "")) + (cond + ((and (boundp 'start) + start + (boundp 'end) + end) + (setq from start) + (setq to end)) + (t + (setq from (point-min)) + (setq to (point-max)))) + (dolist (ovl (overlays-in from to)) + (when (eq (overlay-get ovl 'invisible) 'outline) + (setq num-lines (count-lines (overlay-start ovl) (overlay-end ovl))) + (overlay-put ovl 'display (concat + (propertize "+" 'face 'mode-line) + "" + tag (foldit-hidden-line-str num-lines ""))) + (overlay-put ovl 'foldit 'display) ;; Should be a list... + (overlay-put ovl 'keymap foldit-outline-keymap) + (overlay-put ovl 'face 'lazy-highlight) + (overlay-put ovl 'mouse-face 'highlight) + (overlay-put ovl 'help-echo "Press RET to show hidden part") + (overlay-put ovl 'mlinks-link t) + (overlay-put ovl 'priority (foldit-overlay-priority)) + (mumamo-with-buffer-prepared-for-jit-lock + (let* ((start-tag-beg (overlay-start ovl)) + (start-tag-end start-tag-beg)) + (put-text-property start-tag-beg (+ start-tag-beg 1) + 'foldit-tag-end (copy-marker start-tag-end)))) + )))) + +(defvar foldit-outline-hide-again-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-outline-hide-again) + (define-key map [down-mouse-1] 'foldit-outline-hide-again) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defun foldit-outline-show-entry () + "Show hidden entry." + (interactive) + (let ((tag-end (get-text-property (point) 'foldit-tag-end))) + (show-entry) + (mumamo-with-buffer-prepared-for-jit-lock + (set-text-properties (point) (+ (point) 2) 'foldit-tag-end)) + (when tag-end (goto-char tag-end)) + (foldit-add-temp-at-point-overlay "-" + foldit-outline-hide-again-keymap + "Press RET to hide again"))) + +(defun foldit-outline-hide-again () + "Hide entry again." + (interactive) + (when (overlayp foldit-temp-at-point-ovl) + (delete-overlay foldit-temp-at-point-ovl)) + (hide-entry)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Hide/Show + +(defvar foldit-hs-start-tag-end-func 'foldit-hs-default-start-tag-end) +(make-variable-buffer-local 'foldit-hs-start-tag-end-func) +(put 'foldit-hs-start-tag-end-func 'permanent-local t) + +(defun foldit-hs-default-start-tag-end (beg) + "Find end of hide/show tag beginning at BEG." + (min (+ beg 65) + (save-excursion + (goto-char beg) + (line-end-position)))) + +(defvar foldit-hs-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-hs-show-block) + (define-key map [down-mouse-1] 'foldit-hs-show-block) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defvar foldit-hs-hide-again-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-hs-hide-again) + (define-key map [down-mouse-1] 'foldit-hs-hide-again) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defun foldit-hs-set-up-overlay (ovl) + "Set up overlay OVL for hide/show." + (let* ((num-lines (count-lines (overlay-start ovl) (overlay-end ovl))) + (here (point)) + (start-tag-beg (overlay-start ovl)) + (start-tag-end (funcall foldit-hs-start-tag-end-func start-tag-beg)) + (tag (buffer-substring start-tag-beg start-tag-end))) + (goto-char here) + ;;(overlay-put ovl 'isearch-open-invisible t) + (overlay-put ovl 'display (concat + (propertize "+" 'face 'mode-line) + " " + tag (foldit-hidden-line-str num-lines "h"))) + (overlay-put ovl 'foldit 'display) + (overlay-put ovl 'keymap foldit-hs-keymap) + (overlay-put ovl 'face 'next-error) + (overlay-put ovl 'face 'lazy-highlight) + (overlay-put ovl 'mouse-face 'highlight) + (overlay-put ovl 'help-echo "Press RET to show hidden part") + (overlay-put ovl 'mlinks-link t) + (overlay-put ovl 'priority (foldit-overlay-priority)) + (mumamo-with-buffer-prepared-for-jit-lock + (put-text-property start-tag-beg (+ start-tag-beg 1) + 'foldit-tag-end (copy-marker start-tag-end))))) + +(defun foldit-hs-show-block () + "Show hidden block." + (interactive) + (let ((tag-end (get-text-property (point) 'foldit-tag-end))) + (hs-show-block) + (mumamo-with-buffer-prepared-for-jit-lock + (set-text-properties (point) (+ (point) 2) 'foldit-tag-end)) + (when tag-end (goto-char tag-end)) + (foldit-add-temp-at-point-overlay "-" + foldit-hs-hide-again-keymap + "Press RET to hide again"))) + +(defun foldit-hs-hide-again () + "Hide hide/show block again." + (interactive) + (when (overlayp foldit-temp-at-point-ovl) + (delete-overlay foldit-temp-at-point-ovl)) + (hs-hide-block)) + + +;;; Fix-me: break out this +;; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +(defun foldit-add-temp-at-point-overlay (marker keymap msg) + "Add a temporary overlay with a marker MARKER and a keymap KEYMAP. +The overlay is also given the help echo MSG. + +This overlay is removed as soon as point moves from current point." + (let ((ovl (make-overlay (point) (1+ (point)))) + (real (buffer-substring (point) (1+ (point))))) + (overlay-put ovl 'isearch-open-invisible t) + (overlay-put ovl 'display (concat + (propertize marker 'face 'mode-line) + " " + msg + real)) + (overlay-put ovl 'foldit 'foldit) + (overlay-put ovl 'keymap keymap) + (overlay-put ovl 'face 'lazy-highlight) + (overlay-put ovl 'mouse-face 'highlight) + (overlay-put ovl 'help-echo msg) + (overlay-put ovl 'mlinks-link t) + (overlay-put ovl 'priority (foldit-overlay-priority)) + (setq foldit-temp-at-point-ovl ovl) + (add-hook 'post-command-hook + 'foldit-remove-temp-at-point-overlay + nil t))) + +(defun foldit-remove-temp-at-point-overlay () + "Remove overlay made by `foldit-add-temp-at-point-overlay'." + (condition-case err + (unless (and foldit-temp-at-point-ovl + (overlay-buffer foldit-temp-at-point-ovl) + (= (overlay-start foldit-temp-at-point-ovl) + (point))) + (delete-overlay foldit-temp-at-point-ovl) + (setq foldit-temp-at-point-ovl nil) + (remove-hook 'post-command-hook 'foldit-remove-temp-at-point-overlay t) + ) + (error (message "foldit-remove-temp-at-point-overlay: %s" + (propertize (error-message-string err)))))) +;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + +;; (defun put-before-on-invis () +;; (let* (o +;; (io (catch 'io +;; (dolist (o (overlays-at (1+ (point)))) +;; (when (overlay-get o 'invisible) +;; (throw 'io o))))) +;; (str (propertize "IOSTRING" +;; 'face 'secondary-selection +;; ))) +;; (overlay-put io 'before-string str) +;; ;;(overlay-put io 'display "display") +;; (overlay-put io 'display nil) +;; ;;(overlay-put io 'after-string "AFTER") +;; )) + +(provide 'foldit) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; foldit.el ends here diff --git a/emacs/nxhtml/util/fupd.el b/emacs/nxhtml/util/fupd.el new file mode 100644 index 0000000..bb8b3af --- /dev/null +++ b/emacs/nxhtml/util/fupd.el @@ -0,0 +1,127 @@ +;;; fupd.el --- Helper functions for updating files +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Tue Feb 28 17:21:20 2006 +;; Version: 0.1 +;; Last-Updated: Tue Feb 20 21:09:20 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Helper functions for updating files. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(defun fupd-has-contents (file content) + "Check if file FILE contains CONTENT. +Return a vector with these elements: +- elt 0: t if file contains CONTENT and buffer is not modified. +- elt 1: t if file contains CONTENT. +- elt 2: file buffer if file exists. +- elt 3: nil unless file already was in a buffer." + (let (ok same buffer old-buffer) + (when (file-exists-p file) + (setq buffer (get-file-buffer file)) + (setq old-buffer (when buffer t)) + (unless buffer + (setq buffer (find-file-noselect file))) + (with-current-buffer buffer + (setq same (string= + content + (buffer-substring-no-properties + (point-min) (point-max))))) + (setq ok (and same + (not (buffer-modified-p buffer))))) + (vector ok same buffer old-buffer))) + +(defun fupd-ok (ret-val) + "Return t if RET-VAL indicate file is uptodate. +RET-VAL should be the return value from `fupd-has-contents'." + (elt ret-val 0)) + +(defun fupd-kill-new-buffer (ret-val) + "Kill new buffer indicated by RET-VAL. +RET-VAL should be the return value from `fupd-has-contents'." + (unless (elt ret-val 3) + (let ((buffer (elt ret-val 2))) + (when (bufferp buffer) + ;;(message "fupd-kill-new-buffer: %s" (buffer-file-name buffer))(sit-for 4) + (kill-buffer buffer))))) + +;;(fupd-has-contents buffer-file-name (buffer-string)) +;;(fupd-update-file buffer-file-name (buffer-string)) +(defun fupd-update-file (file content) + "Update file FILE with content CONTENT. +Do nothing if the file already has that content. If the file was +not in a buffer before kill the file's buffer afterwards. + +Return t if the file was updated, otherwise nil." + (let* ((osbo (fupd-has-contents file content)) + (ok (elt osbo 0)) + (same (elt osbo 1)) + (buff (elt osbo 2)) + (oldb (elt osbo 3)) + wrote + ) + (unless ok + (if buff + (with-current-buffer buff + (unless same + (erase-buffer) + (insert content)) + (save-buffer) + (setq wrote t) + (unless oldb + (kill-buffer (current-buffer)))) + (with-temp-buffer + (insert content) + (write-file file)))) + wrote)) + +;; (defun fupd-copy-file (from-file to-file) +;; (let ( +;; (from-buff (find-buffer-visiting from-file)) +;; (to-buff (find-buffer-visiting to-file)) +;; (from-attr (file-attributes from-file)) +;; (to-attr (file-attributes to-file)) +;; (from-size (nth 7 from-attr)) +;; (to-size (nth 7 to-attr)) +;; (from-mod (nth 5 from-attr)) +;; (to-mode (nth 5 to-attr)) +;; ) +;; )) + +(provide 'fupd) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; fupd.el ends here diff --git a/emacs/nxhtml/util/gimpedit.el b/emacs/nxhtml/util/gimpedit.el new file mode 100644 index 0000000..e624e9f --- /dev/null +++ b/emacs/nxhtml/util/gimpedit.el @@ -0,0 +1,172 @@ +;;; gimpedit.el --- Edit files with GIMP +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed May 23 14:59:50 2007 +(defconst gimpedit:version "0.31") ;;Version: +;; Last-Updated: 2009-11-03 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `setup-helper', `w32-reg-iface', `w32-regdat'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Simple interface to start editing with GIMP. +;; +;; If you want to edit files from within Emacs see the doc string of +;; `gimpedit-edit-buffer'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-and-compile (require 'w32-regdat nil t)) + +;; (message "%S" (gimpedit-get-remote-command)) +(defun gimpedit-get-remote-command () + (if (featurep 'w32-regdat) + (save-match-data + (let ((cmd (w32-regdat-gimp-win-remote-cmd)) + cmd-list) + (while (< 0 (length cmd)) + (cond + ((or (string-match (rx string-start + ?\" + (submatch + (0+ (not (any ?\")))) + ?\" + (0+ space)) + cmd) + (string-match (rx string-start + (submatch + (0+ (not (any space)))) + (0+ space)) + cmd)) + (setq cmd-list (cons (match-string-no-properties 1 cmd) cmd-list)) + (setq cmd (substring cmd (match-end 0)))))) + (cadr cmd-list))) + (if (memq system-type '(windows-nt)) + (let (prog) + (catch 'found-prog + (dolist (num '(2 3 4 5 6 7 8 9)) + (setq prog (concat (getenv "ProgramFiles") + "\\GIMP-2.0\\bin\\gimp-2." + (number-to-string num) + ".exe")) + (when (file-exists-p prog) + (throw 'found-prog prog))))) + "gimp"))) + +;;;###autoload +(defgroup gimpedit nil + "Customization group for GIMP." + :group 'external + :group 'nxhtml) + +(defcustom gimpedit-remote-command (gimpedit-get-remote-command) + "Program name to use when calling GIMP remotely. +This could be be the full path to the program used when opening +files with GIMP or a just the program file name if it is in the +executables path. + +Example: + + The value is fetched from the registry on MS Windows if + possible or is else given the default value: + + \"C:\\Program Files\\GIMP-2.0\\bin\\gimp-2.6.exe\" + + On other system it has the default value + + \"gimp\"." + :type '(choice (file :tag "Full file name" :must-match t) + (string :tag "File name (must be in path)")) + :group 'gimpedit) + +;;;###autoload +(defun gimpedit-edit-file (image-file &optional extra-args) + "Edit IMAGE-FILE with GIMP. +See also `gimpedit-edit-file'." + (interactive (list (or (get-char-property (point) 'image-file) + (read-file-name "Image to edit in GIMP: ")))) + (setq image-file (expand-file-name image-file)) + (apply 'call-process gimpedit-remote-command + nil + 0 + nil + (reverse (cons image-file (reverse extra-args)))) + (let ((msg " Asked GIMP to open %s - you may have to switch to GIMP")) + (put-text-property 0 (length msg) 'face 'highlight msg) + (message msg (file-name-nondirectory image-file)))) + +;;;###autoload +(defun gimpedit-edit-buffer () + "Edit image file in current buffer with GIMP. +See also `gimpedit-edit-file'. + +You may also be interested in gimpedit-mode with which you can edit +gimp files from within Emacs using GIMP's scripting +possibilities. See + + URL `http://www.emacswiki.org/emacs/GimpMode'" + (interactive) + (unless (buffer-file-name) + (error + "Can't edit in GIMP because this buffer does not have a file name.")) + (gimpedit-edit-file (buffer-file-name))) + +;;;###autoload +(defun gimpedit-can-edit (file-name) + (and file-name + (member (downcase (file-name-extension file-name)) + '("png" "gif" "jpg" "jpeg")))) + +;; (defcustom gimpedit-point-key-bindings '(([(control ?c) ?&] gimpedit-edit-file)) +;; "Key bindings suggested for image links etc." +;; :type '(repeat (list key-sequence function)) +;; :group 'gimpedit) + +;; (defun gimpedit-add-point-bindings (map) +;; "Add `gimpedit-point-key-bindings' to point keymap MAP. +;; Set it up like this: + +;; (eval-after-load 'gimpedit +;; '(gimpedit-add-point-bindings MY-MAP)) + +;; There must also be a character property `image-file' at point for this +;; to work." +;; (dolist (binding gimpedit-point-key-bindings) +;; (let ((key (nth 0 binding)) +;; (fun (nth 1 binding))) +;; (define-key map key fun)))) + +(provide 'gimpedit) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; gimpedit.el ends here diff --git a/emacs/nxhtml/util/gpl.el b/emacs/nxhtml/util/gpl.el new file mode 100644 index 0000000..a109555 --- /dev/null +++ b/emacs/nxhtml/util/gpl.el @@ -0,0 +1,213 @@ +;;; gpl.el --- Highlight and edit gpl color palettes + +(defconst gpl:version "0.01") +;; Copyright (C) 2008 Niels Giesen + +;; Author: Niels Giesen +;; Keywords: extensions, tools + +;; 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 3 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, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; GPL provides font-locking and has functions to edit the values +;; of colors (hue, saturation value, red, green and blue vals) +;; in-place in a simple, intuitive, and lightweight fashion. See the +;; documentation of `gpl-mode'. + +;; The methods and keybindings used are roughly the same as in the new +;; css-color mode. I should maybe have abstracted both color notation +;; models better, but did not feel like it. With under 200 lines of +;; code, it did not seem worth the effort. + +;; The css-color.el used is the one by Niels Giesen, at +;; `http://niels.kicks-ass.org/public/elisp/css-color.el'. + +;; Installation: + +;; Put this file in your load-path. Put a declaration such as + +;; (autoload 'gpl-mode "gpl") +;; (add-to-list 'auto-mode-alist +;; '("\\.gpl\\'" . gpl-mode)) + +;; In your initialization file (e.g. ~/.emacs) to make sure `gpl-mode' +;; is started anytime you open a *.gpl file, and gpl-mode is only +;; loaded when needed. + +;;; Code: +(require 'css-color) + +(defvar gpl-keywords + '(("^[[:space:]]*\\([a-fA-F[:digit:]]\\{1,3\\}\\)[[:space:]]+\\([a-fA-F[:digit:]]\\{1,3\\}\\)[[:space:]]+\\([a-fA-F[:digit:]]\\{1,3\\}\\)" + (0 + (let ((color (concat "#" (apply 'css-color-rgb-to-hex + (mapcar 'string-to-number + (list + (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3))))))) + + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap gpl-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))))) + +;;;###autoload +(define-derived-mode gpl-mode fundamental-mode "GPL" + "Mode for font-locking and editing color palettes of the GPL format. + +Such palettes are used and produced by free software applications +such as the GIMP, Inkscape, Scribus, Agave and on-line tools such +as http://colourlovers.com. + +You can also use +URL `http://niels.kicks-ass.org/public/elisp/css-palette.el' to import +such palette into a css-file as hexadecimal color palette." + (setq font-lock-defaults + '((gpl-keywords) + t))) + +(defvar gpl-map + (let ((m (make-sparse-keymap))) + (define-key m "=" 'gpl-up) + (define-key m "-" 'gpl-down) + (define-key m "h" 'gpl-hue-up) + (define-key m "H" 'gpl-hue-down) + (define-key m "v" 'gpl-value-up) + (define-key m "V" 'gpl-value-down) + (define-key m "s" 'gpl-saturation-up) + (define-key m "S" 'gpl-saturation-down) + m) + "Mode map for `gpl-mode'") + +(defun gpl-get-color-at-point () + (or (get-text-property (point) 'color) + (apply 'css-color-rgb-to-hsv + (gpl-get-rgb-list-at-point)))) + +(defun gpl-get-rgb-list-at-point () + (mapcar 'string-to-number + (split-string + (buffer-substring-no-properties + (point-at-bol) + (+ 11 (point-at-bol))) "[[:space:]]+" t))) + +(defun gpl-replcolor-at-p (fun increment) + (let ((pos (point))) + (beginning-of-line) + (insert + (funcall fun + (gpl-get-color-at-point) + increment)) + (delete-region (point) (+ (point) 11)) + (goto-char pos))) + +(defun gpl-hsv-to-gimp-color (h s v) + (propertize + (apply 'format "%3d %3d %3d" + (css-color-hsv-to-rgb h s v)) + 'keymap gpl-map + 'color (list h s v))) + +(defun gpl-what-channel () + (/ (- (point) (point-at-bol)) 4)) + +(defun gpl-adjust-channel-at-p (incr) + (interactive "p") + (let ((pos (point)) + (channel (gpl-what-channel))) + (beginning-of-line) + (let ((rgb + (gpl-get-rgb-list-at-point))) + (setf (nth channel rgb) + (css-color-within-bounds + (+ incr (nth channel rgb)) + 0 255)) + (delete-region (point) (+ 11 (point))) + (insert + (propertize + (apply 'format "%3d %3d %3d" rgb) + 'keymap gpl-map + 'color nil))) + (goto-char pos))) + +(defun gpl-inchue (color incr) + (destructuring-bind (h s v) color + (gpl-hsv-to-gimp-color + (+ incr h) s v))) + +(defun gpl-incsat (color incr) + (destructuring-bind (h s v) color + (gpl-hsv-to-gimp-color + h (css-color-within-bounds (+ incr s) 0 100) v))) + +(defun gpl-incval (color incr) + (destructuring-bind (h s v) color + (gpl-hsv-to-gimp-color + h s (css-color-within-bounds (+ incr v) 0 100)))) + +(defun gpl-adj-hue-at-p (increment) + (interactive "p") + (gpl-replcolor-at-p 'gpl-inchue increment)) + +(defun gpl-adj-saturation-at-p (increment) + (interactive "p") + (gpl-replcolor-at-p 'gpl-incsat increment)) + +(defun gpl-adj-value-at-p (increment) + (interactive "p") + (gpl-replcolor-at-p 'gpl-incval increment)) + +;; channels (r, g, b) +(defun gpl-up (val) + (interactive "p") + (gpl-adjust-channel-at-p val)) + +(defun gpl-down (val) + (interactive "p") + (gpl-adjust-channel-at-p (- val))) +;; hue +(defun gpl-hue-up (val) + (interactive "p") + (gpl-adj-hue-at-p val)) + +(defun gpl-hue-down (val) + (interactive "p") + (gpl-adj-hue-at-p (- val))) +;; saturation +(defun gpl-saturation-up (val) + (interactive "p") + (gpl-adj-saturation-at-p val)) + +(defun gpl-saturation-down (val) + (interactive "p") + (gpl-adj-saturation-at-p (- val))) +;; value +(defun gpl-value-up (val) + (interactive "p") + (gpl-adj-value-at-p val)) + +(defun gpl-value-down (val) + (interactive "p") + (gpl-adj-value-at-p (- val))) + +(provide 'gpl) +;;; gpl.el ends here diff --git a/emacs/nxhtml/util/hfyview.el b/emacs/nxhtml/util/hfyview.el new file mode 100644 index 0000000..0e0450d --- /dev/null +++ b/emacs/nxhtml/util/hfyview.el @@ -0,0 +1,651 @@ +;;; hfyview.el --- View current buffer as html in web browser + +;; Copyright (C) 2005, 2006, 2007 by Lennart Borgman + +;; Author: Lennart Borgman +;; Created: Fri Oct 21 2005 +(defconst hfyview:version "0.63") ;; Version: +;; Last-Updated: 2010-04-16 Fri +;; Keywords: printing +;; URL: http://OurComments.org/Emacs/DL/elisp/hfyview.el +;; Compatibility: +;; +;; +;; Features that might be required by this library: +;; + ;; `easymenu'. +;; +;; +;; htmlfontify.el is part of Emacs. +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file shows the current buffer in your web browser with all +;; the colors it has. The purpose is mainly to make it possible to +;; easily print what you see in Emacs in colors on different +;; platforms. +;; +;; Put this file in your load-path and in your .emacs this: +;; +;; (require 'hfyview) +;; +;; This defines the commands `hfyview-buffer', `hfyview-region' and +;; `hfyview-window' which will show the whole or a part of the buffer +;; in your web browser. +;; +;; You can add those commands to the menus by customizing +;; `hfyview-quick-print-in-files-menu' to t. This will add an entry +;; "Quick Print (Using Web Browser)" to the files menu. +;; +;; +;; There is also a command `hfyview-frame' to take a "screen shot" of +;; your current frame and produce an html look-alike page. If you +;; turn on `hfyview-frame-mode' you get this function on the <apps> +;; key in most situations. +;; +;; +;; You can see an example of the output here: +;; +;; http://ourcomments.org/Emacs/nXhtml/doc/htmlfontify-example.html +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 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. +;; +;; To find out more about the GNU General Public License you can visit +;; Free Software Foundation's website http://www.fsf.org/. Or, write +;; to the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'htmlfontify)) +(require 'easymenu) + +(defvar hfyview-selected-window) + +(defvar hfyview-frame-mode-emulation-map + (let ((m (make-sparse-keymap))) + ;;(define-key m [apps] 'hfyview-frame) + m)) + +(defvar hfyview-frame-mode-emulation-maps + (list (cons 'hfyview-frame-mode hfyview-frame-mode-emulation-map))) + +;; Fix-me: which are needed? Probably only viper, but have to test. +(defconst hfyview-frame-mode-other-maps + '( + hfyview-frame-mode-emulation-map + minibuffer-local-completion-map + minibuffer-local-filename-completion-map + minibuffer-local-isearch-map + minibuffer-local-map + ;; minibuffer-local-must-match-filename-map + minibuffer-local-must-match-map + minibuffer-local-ns-map + viper-minibuffer-map + isearch-mode-map)) + +(define-minor-mode hfyview-frame-mode + "Define some useful things for `hfyview-frame'. +The <apps> key is bound to `hfyview-frame' in this mode. When +this mode is on you can push <apps> to get all of what you see on +the screen. Without it the minibuffer/echo area will not be +shown." + :global t + :group 'htmlfontify + (if hfyview-frame-mode + (progn + (add-hook 'pre-command-hook 'hfy-grab-minibuffer-content) + (add-hook 'post-command-hook 'hfy-grab-echo-content) + (add-to-list 'emulation-mode-map-alists 'hfyview-frame-mode-emulation-maps) + (dolist (map hfyview-frame-mode-other-maps) + (define-key (symbol-value map) [(apps)] 'hfyview-frame) + ) + ) + (remove-hook 'pre-command-hook 'hfy-grab-minibuffer-content) + (remove-hook 'post-command-hook 'hfy-grab-echo-content) + (setq emulation-mode-map-alists (delq 'hfyview-frame-mode-emulation-maps emulation-mode-map-alists)) + (dolist (map hfyview-frame-mode-other-maps) + (define-key (symbol-value map) [(apps)] nil)))) + +(defun hfyview-fontify-region (start end) + "Fontify region between START and END the htmlfontify way." + ;; If the last command in mumamo resulted in a change of major-mode + ;; the big bug watcher in mumamo will get us if we do not tell that + ;; we know what we are doing: + (let ((mumamo-just-changed-major nil)) + (if start + (save-restriction + (widen) + (narrow-to-region start end) + (assert (= end (point-max))) + (assert (= start (point-min))) + (htmlfontify-buffer)) + (htmlfontify-buffer)))) + +(defun hfyview-buffer-1(start end show-source) + "Convert current buffer between START and END to html. +If SHOW-SOURCE is non-nil then also show produced html in other +window." + (let ((hbuf (hfyview-fontify-region start end))) + (with-current-buffer hbuf + (setq buffer-file-name nil) + (browse-url-of-buffer)) + (when show-source (switch-to-buffer-other-window hbuf)) + hbuf)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Menus + +(defvar hfyview-print-menu (make-sparse-keymap "QP")) +(defvar hfyview-print-region-menu (make-sparse-keymap "QPR")) +(defvar hfyview-print-window-menu (make-sparse-keymap "QPW")) +(defun hfyview-add-to-files-menu () + "Add \"Quick Print\" entry to file menu." + ;; Why did I redo this??? + (setq hfyview-print-menu (make-sparse-keymap "QP")) + (setq hfyview-print-region-menu (make-sparse-keymap "QPR")) + (setq hfyview-print-window-menu (make-sparse-keymap "QPW")) + ;; Main + (define-key-after menu-bar-file-menu [hfyview-print] + (list 'menu-item + "Quick Print (Using Web Browser)" + hfyview-print-menu + :visible 'hfyview-print-visible) + 'separator-print) + ;; Main submenu + (define-key hfyview-print-menu [hfyview-browser-frame-pre] + '(menu-item "Print Preview Frame" hfyview-frame + :help "Print preview frame with web browser")) + (define-key hfyview-print-menu [hfyview-browser-window-pre] + '(menu-item "Print Preview Window" hfyview-window + :help "Print preview window with web browser")) + (define-key hfyview-print-menu [hfyview-browser-region-pre] + (list 'menu-item "Print Preview Region" 'hfyview-region + :help "Print preview region with web browser" + :enable 'mark-active)) + (define-key hfyview-print-menu [hfyview-separator-pre] + '(menu-item "--")) + (define-key hfyview-print-menu [hfyview-browser-pre] + '(menu-item "Print Preview Buffer" hfyview-buffer + :help "Print preview buffer with web browser" + :visible t)) + ) + +;;;###autoload +(defcustom hfyview-quick-print-in-files-menu nil + "Add Quick print entries to File menu if non-nil. +If you set this to nil you have to restart Emacs to get rid of +the Quick Print entry." + :type 'boolean + :set (lambda (sym val) + (set-default sym val) + (if val + (hfyview-add-to-files-menu))) + :group 'hfy-view) + +(defvar hfyview-print-visible t + "Non-nil means show Quick Print entry on the file menu.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Interactive commands + +;;;###autoload +(defun hfyview-buffer (arg) + "Convert buffer to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window." + (interactive "P") + (hfyview-buffer-1 nil nil arg)) + +;;;###autoload +(defun hfyview-region (arg) + "Convert region to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window." + (interactive "P") + (hfyview-buffer-1 (region-beginning) (region-end) arg)) + +;;;###autoload +(defun hfyview-window (arg) + "Convert window to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window." + (interactive "P") + (hfyview-buffer-1 (window-start) (window-end) arg)) + +;;;###autoload +(defun hfyview-frame (whole-buffers) + "Convert frame to html preserving faces and show in web browser. +Make an XHTML view of the current Emacs frame. Put it in a buffer +named *hfyview-frame* and show that buffer in a web browser. + +If WHOLE-BUFFERS is non-nil then the whole content of the buffers +is shown in the XHTML page, otherwise just the part that is +visible currently on the frame. + +If you turn on the minor mode `hfyview-frame-mode' you can also +get the minibuffer/echo area in the output. See this mode for +details. + +With command prefix also show html source in other window." + (interactive (list (y-or-n-p "Enter y for whole buffers, n for only visible part? "))) + (let ((title "Emacs - Frame Dump") + buf) + (setq title (frame-parameter (selected-frame) 'name)) + (setq buf (hfyview-frame-1 whole-buffers title)) + (when current-prefix-arg + (switch-to-buffer-other-window buf)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Internal commands + +(defconst hfyview-modline-format + ;; There seems to be a bug in Firefox that prevents this from + ;; displaying correctly. Anyway this is just a quick and reasonable + ;; approximation. + (concat "<div style=\"width:%sem; color:%s; background:%s; white-space:pre; overflow:hidden; font-family:monospace;\">" + ;; Using <pre> gives empty line above and below + ;;"<pre>" + "-- (Unix)%s <b>%s</b> (%s%s) " + (make-string 6 ?-) + "%s" ;; Viper + (make-string 200 ?-) + ;;"</pre>" + "</div>")) + +(defun hfyview-get-minors () + "Return string with active minor mode highlighters." + (let ((minors "")) + (dolist (mr minor-mode-alist) + (let ((mm (car mr)) + (ml (cadr mr))) + (when (symbol-value mm) + (when (stringp ml) + (setq minors (concat minors ml)))))) + minors)) + +;; (hfyview-dekludge-string "<i> ") +(defun hfyview-dekludge-string (str) + "Return html quoted string STR." + (mapconcat (lambda (c) + (hfy-html-quote + (char-to-string c))) + (append str) + "")) + +(defvar viper-mode-string) ;; Silence compiler + +(defun hfyview-fontify-win-to (win tag whole-buffer) + "Return html code for window WIN. +Sorround the code with the html tag <TAG>. +WHOLE-BUFFER corresponds to the similar argument for +`hfyview-frame-1'." + (let* ((bstart (unless whole-buffer (window-start win))) + (bend (unless whole-buffer (window-end win))) + (hbuf (hfyview-fontify-region bstart bend)) + (edges (window-edges win)) + (width (- (nth 2 edges) (nth 0 edges))) + (height (- (nth 3 edges) (nth 1 edges))) + (border-color (or (hfy-triplet "SystemActiveBorder") + "gray")) + start + end + css-start + css-end + mod-fgcolor + mod-bgcolor + mod-width + mod + bu-name + ma-name + minors + (window-start-line (point-min)) + (window-end-line (point-max)) + (is-selected-window (eq win hfyview-selected-window)) + (mark-viper "") + ) + ;; Fix-me: fetch style too + (with-current-buffer (window-buffer win) + (unless whole-buffer + (save-restriction + (widen) + (setq window-start-line (line-number-at-pos bstart)) + (setq window-end-line (line-number-at-pos bend)) + (unless (or (< (line-number-at-pos (point-min)) window-start-line) + (> (line-number-at-pos (point-max)) window-end-line)) + (setq whole-buffer t)) + ) + ) + (setq mod-fgcolor (face-attribute (if is-selected-window 'mode-line 'mode-line-inactive) :foreground)) + (setq mod-bgcolor (face-attribute (if is-selected-window 'mode-line 'mode-line-inactive) :background)) + (setq mod-fgcolor (hfy-triplet mod-fgcolor)) + (setq mod-bgcolor (hfy-triplet mod-bgcolor)) + (setq mod (if (buffer-modified-p) "**" "--")) + (when buffer-read-only + (setq mod "%%")) + (setq bu-name (buffer-name)) + (setq ma-name mode-name) + (setq minors (hfyview-get-minors)) + (when (and (local-variable-p 'viper-mode-string) viper-mode-string) + (setq mark-viper viper-mode-string)) + ) + ;; Compensate for scroll-bars + (setq mod-width (+ width 1)) + (with-current-buffer hbuf + (setq width (- width 2.5)) + (setq width (* 0.57 width)) + (setq height (+ height 2)) ;; For pre + ;;(setq height (+ height 1.2)) ;; For horisontal scrollbar + (setq height (* 1.16 height)) + (goto-char (point-min)) + (re-search-forward "<body.*?>") + (setq start (point)) + (insert + (format "<%s style=\"width:%sem; height:%sem; border: 1px solid %s; overflow:%s; padding:4px;\">\n" + tag width height border-color + (if whole-buffer "auto" "hidden") ;; overflow + )) + (goto-char (point-max)) + (setq end (search-backward "</body>")) + (unless whole-buffer + (insert + (format "\n<div style=\"margin-top:2em; color: red; text-align: center; \"> Truncated to line %s - %s! </div>\n" + window-start-line window-end-line))) + (insert "</" tag ">\n") + ;;(lwarn t :warning "%s" mark-viper) + (insert (format hfyview-modline-format + width + mod-fgcolor mod-bgcolor mod + (hfyview-dekludge-string bu-name) + (hfyview-dekludge-string ma-name) + (hfyview-dekludge-string minors) + (hfyview-dekludge-string mark-viper))) + (setq end (point)) + (goto-char (point-min)) + (search-forward "<style type=\"text/css\"><!--") + (beginning-of-line) + (setq css-start (point)) + (search-forward "--></style>") + (setq css-end (point)) + (set-buffer-modified-p nil) + (setq buffer-file-name nil)) + (list hbuf start end css-start css-end))) + +;; (defun hfyview-window-framed () +;; "Just a test" +;; (interactive) +;; (let* ((res (hfyview-fontify-win-to (selected-window) "div" nil)) +;; (hbuf (nth 0 res))) +;; (with-current-buffer hbuf +;; (browse-url-of-buffer)))) + +(defun hfyview-fontify-tree-win (win whole-buffer) + "Return html code for window WIN. +WHOLE-BUFFER corresponds to the similar argument for +`hfyview-frame-1'." + (with-selected-window win + (let* ((start (window-start)) + (end (window-end)) + (res (hfyview-fontify-win-to win "div" whole-buffer)) + (hbuf (nth 0 res))) + (with-current-buffer hbuf + (rename-buffer (generate-new-buffer-name (format "%s %s-%s" win start end)))) + ;;(lwarn t :warning "win=%s, hbuf=%s" win hbuf) + res))) + +(defun hfyview-fontify-tree (wt whole-buffers) + "Return list of html code for all windows in tree WT. +WT should be the result of function `window-tree' or a subtree of +this. For WHOLE-BUFFERS see `hfyview-frame-1'." + (if (not (listp wt)) + (hfyview-fontify-tree-win wt whole-buffers) + (let ((ret)) + (dolist (w (cddr wt)) + (setq ret (cons (hfyview-fontify-tree w whole-buffers) ret))) + (list (car wt) ret)))) + +(defun hfyview-frame-to-html (res) + "Return list with css and html code for frame. +RES is the collected result from `hfyview-fontify-tree'." + (let ((html "") + (css "") + (first (car res)) + (td "<td style=\"vertical-align:top;\">") + h) + (cond + ((memq first '(nil t)) + (dolist (sub (reverse (cadr res))) + (let* ((fres (hfyview-frame-to-html sub)) + (h (nth 0 fres)) + (c (nth 1 fres))) + (when first (setq h (concat "<tr>\n" h "</tr>\n"))) + (setq html (concat html h)) + (setq css (concat css c)))) + (unless first + (setq html (concat "<tr>" html "</tr>\n"))) + (setq html (concat "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n" html "</table>\n")) + (setq html (concat td html "</td>\n")) + ) + ((bufferp first) + ;; (buf start end) + (let* ((buf (nth 0 res)) + (sta (nth 1 res)) + (end (nth 2 res)) + (cst (nth 3 res)) + (cnd (nth 4 res)) + (h + ;;(concat "<td>" "temp" "</td>\n") + (with-current-buffer buf (buffer-substring-no-properties sta end))) + (c + ;;(concat "<td>" "temp" "</td>\n") + (with-current-buffer buf (buffer-substring-no-properties cst cnd)))) + (setq h (concat td h + "</td>\n")) + (setq html (concat html h)) + (setq css c) + (kill-buffer buf))) + (t + (error "Uh?"))) + (list html css))) + +(defconst hfyview-xhtml-header + "<?xml version=\"1.0\" encoding=\"utf-8\"?> +<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" +\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"> +<html xmlns=\"http://www.w3.org/1999/xhtml\"> + <head> + <title>%s</title> +<style type=\"text/css\"><!-- +body { font-family: outline-courier new; font-stretch: normal; font-weight: 500; font-style: normal; color: rgb(0, 0, 0); font-size: 10pt; text-decoration: none; } + --></style> +%s + </head> + <body>\n") + +(defvar hfyview-xhtml-footer "</body>\n</html>\n") + +(defun hfyview-wm-border-color () + "Return CSS code for color to use in window borders." + (or (hfy-triplet "SystemActiveTitle") + (hfy-triplet "blue"))) + +(defvar hfy-grabbed-echo-content nil) +(defvar hfy-grabbed-minibuffer-content nil) +(defvar hfyview-prompt-face nil) + +(defun hfyview-frame-minibuff (use-grabbed) + "Return html code for minibuffer. +If USE-GRABBED is non-nil use what has been grabbed by +`hfy-grab-echo-content' or `hfy-grab-minibuffer-content'. +Otherwise make a default content for the minibuffer." + (if (and use-grabbed + (or hfy-grabbed-echo-content + hfy-grabbed-minibuffer-content)) + (let* ((str (if hfy-grabbed-echo-content + hfy-grabbed-echo-content + hfy-grabbed-minibuffer-content)) + (tmpbuf (get-buffer-create "*hfy-minibuff-temp*")) + (hbuf (with-current-buffer tmpbuf + (let ((inhibit-read-only t)) + (erase-buffer) + ;; Fix-me: move the propertize to a new + ;; copy-buffer in hfy-fontify-buffer. Explained + ;; in mail to Vivek. + (insert (propertize str + 'read-only nil + 'intangible nil + 'field nil + 'modification-hooks nil + 'insert-in-front-hooks nil + 'insert-behind-hooks nil + 'point-entered nil + 'point-left nil + 'font-sticky nil + 'rear-nonsticky nil + )) + (htmlfontify-buffer)))) + bdy-start + bdy-end + bdy-txt + css-start + css-end + css-txt) + (with-current-buffer hbuf + (goto-char (point-min)) + (search-forward "<style type=\"text/css\"><!--") + (beginning-of-line) + (setq css-start (point)) + (search-forward "--></style>") + (setq css-end (point)) + (goto-char (point-min)) + (search-forward "<pre>") + (setq bdy-start (point)) + (goto-char (point-max)) + (search-backward "</pre>") + (setq bdy-end (point)) + (list (buffer-substring css-start css-end) + (buffer-substring bdy-start bdy-end)))) + (let ((mini-bg (face-attribute hfyview-prompt-face :background)) + (mini-fg (face-attribute hfyview-prompt-face :foreground))) + (if (eq mini-fg 'unspecified) + (setq mini-fg "") + (setq mini-fg (concat "color:" (hfy-triplet mini-fg) "; "))) + (if (eq mini-bg 'unspecified) + (setq mini-bg "") + (setq mini-bg (concat "background:" (hfy-triplet mini-bg) "; "))) + (list nil + (concat + "<span style=\"" mini-fg mini-bg "\">" + " M-x " + "</span>" + " " + "hfyview-frame" + ))))) + +(defun hfyview-frame-1(whole-buffers frame-title) + "Return buffer with html code for current frame. +If WHOLE-BUFFERS is non-nil then make scrollable buffers in the +html output. Otherwise just make html code for the currently +visible part of the buffers. + +FRAME-TITLE is the title to show on the resulting html page." + (let* ((wt (window-tree)) + (hfyview-selected-window (selected-window)) + (res (hfyview-fontify-tree (car wt) whole-buffers)) + (title-bg-color (hfyview-wm-border-color)) + (title-color (or (hfy-triplet "SystemHilightText") + "white")) + (title-style (concat (format "background-color:%s; color:%s;" title-bg-color title-color) + "border: none; padding:4px; vertical-align: middle;")) + (outbuf (get-buffer-create "frame")) + html + css + ;; (face-attribute 'minibuffer-prompt :foreground) + (hfyview-prompt-face (plist-get minibuffer-prompt-properties 'face)) + minibuf + (frame-width (* 0.56 (frame-width))) + table-style + (icon-file (expand-file-name "../etc/images/icons/emacs_16.png" exec-directory)) + (img-tag (if (file-exists-p icon-file) + (concat "<img src=\"file://" icon-file "\" height=\"16\" width=\"16\" />"))) + mini-css + mini-html + ) + (setq table-style + (format "border: solid %s; width:%sem;" + (hfyview-wm-border-color) + frame-width + )) + (setq minibuf (hfyview-frame-minibuff hfyview-frame-mode)) + (setq mini-css (nth 0 minibuf)) + (setq mini-html (nth 1 minibuf)) + (when (string= mini-html "") (setq mini-html " ")) + (setq res (hfyview-frame-to-html res)) + (setq html (nth 0 res)) + (setq css (nth 1 res)) + (with-current-buffer outbuf + ;;(lwarn t :warning "outbuf=%s" outbuf) + (erase-buffer) + (insert (format hfyview-xhtml-header + (concat "Emacs frame dump - " frame-title) + css) + (if mini-css mini-css "") + (format "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"%s\">\n" table-style) + "<tr>\n" + (format "<td style=\"%s\">%s %s</td>\n" title-style img-tag + (hfyview-dekludge-string frame-title)) + "</tr>\n" + "<tr>\n" + html + "</tr>\n" + "<tr>\n" + "<td style=\"padding:1px;\">\n" + mini-html + "</td>\n" + "</tr>\n" + "</table>\n" + hfyview-xhtml-footer) + (browse-url-of-buffer) + outbuf))) + +(defun hfy-grab-echo-content () + "Return echo area content." + (setq hfy-grabbed-echo-content (current-message))) + +(defun hfy-grab-minibuffer-content () + "Return minibuffer content." + ;;(interactive) + (let* ((mw (minibuffer-window)) + (mb (window-buffer mw))) + (setq hfy-grabbed-minibuffer-content + (with-current-buffer mb + (buffer-substring + (point-min) (point-max))) + ))) + +;;(add-hook 'pre-command-hook 'grab-minibuffer-content nil t) +;;(remove-hook 'pre-command-hook 'grab-minibuffer-content) t) + +(provide 'hfyview) +;;; hfyview.el ends here diff --git a/emacs/nxhtml/util/hl-needed.el b/emacs/nxhtml/util/hl-needed.el new file mode 100644 index 0000000..7a160b6 --- /dev/null +++ b/emacs/nxhtml/util/hl-needed.el @@ -0,0 +1,402 @@ +;;; hl-needed.el --- Turn on highlighting of line and column when needed +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Fri Nov 30 21:19:18 2007 +;; Version: 0.60 +;; Last-Updated: 2010-03-19 Fri +;; URL: http://www.emacswiki.org/cgi-bin/wiki/hl-needed.el +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `hl-line', `vline'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This is yet another highlight line and/or column idea. The idea is +;; to try to show line and column only when it is probably most +;; needed. See `hl-needed-mode' for more info. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(require 'hl-line) +(require 'vline nil t) + +;;;###autoload +(defgroup hl-needed nil + "Customization group for `hl-needed-mode'." + :group 'convenience) + +(defcustom hl-needed-always nil + "Highlight always. +This is similar to turning on `vline-mode' and `hl-line-mode'" + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-mark-line t + "Highlight line." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-mark-column t + "Highlight column." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-in-readonly-buffers nil + "Do not highlight in read-only buffers unless non-nil." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-not-in-modes + '(wab-compilation-mode + custom-mode) + "List of modes where highlighting should not be done." + :type '(repeat function) + :group 'hl-needed) + +;;(setq hl-needed-idle-time 5) +(defcustom hl-needed-idle-time 20 + "Highligh current line and/or column if Emacs is idle for more seconds. +If nil do not turn on `hl-line-mode' when Emacs is idle." + :type '(choice (const :tag "Don't turn on when Emacs is idle" nil) + (integer :tag "Turn on after (seconds)")) + :group 'hl-needed) + +(defcustom hl-needed-on-mouse t + "Highlight current line and/or column on clicks." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-new-window t + "Highlight current line and/or column on new window selection." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-new-buffer t + "Highlight current line and/or column on new buffer selection." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-config-change t + "Highlight current line and/or column on window conf change." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-scrolling t + "Highlight current line and/or column after scrolling." + :type 'boolean + :group 'hl-needed) + +(defvar hl-needed-face 'hl-needed-face) +(defface hl-needed-face + '((t (:inherit highlight))) + "Face for flashing." + :group 'hl-needed) + +(defcustom hl-needed-flash-delay 0.0 + "Time to wait before turning on flash highlighting. +If a key is pressed before this flash highlighting is not done." + :type 'float + :group 'hl-needed) + +(defcustom hl-needed-flash-duration 1.0 + "Turn off flash highlighting after this number of second. +Highlighting is turned off only if it was turned on because of +some change. It will not be turned off if it was turned on +because Emacs was idle for more than `hl-needed-idle-time'. + +The default time is choosen to not disturb too much. I believe +human short attention may often be of this time. \(Compare eye +contact time.)" + :type 'float + :group 'hl-needed) + +(defcustom hl-needed-currently-fun 'hl-needed-currently + "Function that checks if highlighting should be done. +The function should return nil if not needed and non-nil +otherwise." + :type 'function + :group 'hl-needed) + +(defvar hl-needed-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?? ??] 'hl-needed-show) + map)) + +;;;###autoload +(define-minor-mode hl-needed-mode + "Try to highlight current line and column when needed. +This is a global minor mode. It can operate in some different +ways: + +- Highlighting can be on always, see `hl-needed-always'. + +Or, it can be turned on depending on some conditions. In this +case highlighting is turned off after each command and turned on +again in the current window when either: + +- A new window was selected, see `hl-needed-on-new-window'. +- A new buffer was selected, see `hl-needed-on-new-buffer'. +- Window configuration was changed, see `hl-needed-on-config-change'. +- Buffer was scrolled see `hl-needed-on-scrolling'. +- A window was clicked with the mouse, see `hl-needed-on-mouse'. + +After this highlighting may be turned off again, normally after a +short delay, see `hl-needed-flash'. + +If either highlighting was not turned on or was turned off again +it will be turned on when + +- Emacs has been idle for `hl-needed-idle-time' seconds. + +See also `hl-needed-not-in-modes' and `hl-needed-currently-fun'. + +Note 1: For columns to be highlighted vline.el must be available. + +Note 2: This mode depends on `hl-line-mode' and `vline-mode' and +tries to cooperate with them. If you turn on either of these that +overrides the variables for turning on the respective +highlighting here." + :global t + :group 'hl-needed + ;;:keymap hl-needed-mode-map + (if hl-needed-mode + (progn + ;;(unless (memq major-mode hl-needed-not-in-modes) (setq hl-needed-window t)) + (when (featurep 'hl-needed) (hl-needed-show)) + (add-hook 'post-command-hook 'hl-needed-post-command) + (add-hook 'pre-command-hook 'hl-needed-pre-command) + (add-hook 'window-configuration-change-hook 'hl-needed-config-change) + ) + (remove-hook 'post-command-hook 'hl-needed-post-command) + (remove-hook 'pre-command-hook 'hl-needed-pre-command) + (remove-hook 'window-configuration-change-hook 'hl-needed-config-change) + (hl-needed-cancel-timer) + (hl-needed-cancel-flash-timer) + (hl-needed-hide))) + +(defvar hl-needed-timer nil) +(defvar hl-needed-flash-timer nil) +(defvar hl-needed-window nil) +(defvar hl-needed-buffer nil) +(defvar hl-needed-window-start nil) +(defvar hl-needed-flash-this nil) +(defvar hl-needed-config-change nil) + +(defvar hl-needed-old-blink nil) +(defun hl-needed-show () + "Highlight current line and/or column now." + (interactive) + (when (with-no-warnings (called-interactively-p)) + (setq hl-needed-flash-this nil) + (unless hl-needed-mode + (message "Use hl-needed-hide to remove highlighting"))) + (setq hl-needed-old-blink nil) ;; So blink is not turned on by hl-needed-hide + (hl-needed-hide) + (unless (active-minibuffer-window) + (setq hl-needed-old-blink blink-cursor-mode) + (when blink-cursor-mode + (blink-cursor-mode -1) + ;;(when (timerp blink-cursor-timer) (cancel-timer blink-cursor-timer)) + (blink-cursor-end) + ) + (unless hl-line-mode + (when hl-needed-mark-line + (let ((hl-line-mode t) + (hl-line-sticky-flag nil) + (hl-line-face hl-needed-face)) + (hl-line-highlight)))) + (unless vline-mode + (when hl-needed-mark-column + (when (featurep 'vline) + (let ((vline-style 'face) + (vline-face hl-line-face) + (vline-current-window-only t)) + (vline-show))))))) + +(defun hl-needed-hide () + (interactive) + (when (and hl-needed-old-blink + (not blink-cursor-mode)) + (blink-cursor-mode 1)) + (setq hl-needed-old-blink nil) + (unless hl-line-mode + (hl-line-unhighlight)) + (when (featurep 'vline) + (unless vline-mode + (vline-clear)))) + +(defun hl-needed-cancel-timer () + (when (timerp hl-needed-timer) (cancel-timer hl-needed-timer)) + (setq hl-needed-timer nil)) + +(defun hl-needed-start-timer (wait) + (hl-needed-cancel-timer) + (setq hl-needed-timer + (run-with-idle-timer wait + nil 'hl-needed-show-in-timer))) + +(defun hl-needed-show-in-timer () + "Turn on with special error handling. +Erros may go unnoticed in timers. This should prevent it." + (condition-case err + (save-match-data ;; runs in timer + (hl-needed-show)) + (error + (lwarn 'hl-needed-show + :error "%s" (error-message-string err))))) + +(defun hl-needed-hide-in-timer () + "Turn off with special error handling. +Erros may go unnoticed in timers. This should prevent it." + (condition-case err + (unless hl-needed-always + (hl-needed-hide)) + (error + (lwarn 'hl-needed-hide + :error "%s" (error-message-string err))))) + +(defun hl-needed-hide-flash-in-timer () + "Turn off with special error handling. +Erros may go unnoticed in timers. This should prevent it." + (condition-case err + (unless hl-needed-always + (hl-needed-hide) + (hl-needed-start-timer hl-needed-idle-time)) + (error + (lwarn 'hl-needed-hide + :error "%s" (error-message-string err))))) + +(defun hl-needed-currently () + "Check if `hl-line-mode' is needed in buffer." + ;; Check for change of buffer and window + (if hl-needed-always + t + (unless (or (memq major-mode hl-needed-not-in-modes) + isearch-mode + (and buffer-read-only + (not hl-needed-in-readonly-buffers))) + (or (and hl-needed-on-new-window + (not (eq hl-needed-window (selected-window)))) + ;;(progn (message "here1") nil) + (and hl-needed-on-new-buffer + (not (eq hl-needed-buffer (current-buffer)))) + ;;(progn (message "here2") nil) + (and hl-needed-on-config-change + hl-needed-config-change) + ;;(progn (message "here3") nil) + (and hl-needed-on-mouse + (listp last-input-event) + (memq (car last-input-event) '(mouse-1 mouse-2 mouse-3))) + ;;(progn (message "here4") nil) + (and hl-needed-on-scrolling + (and (not (eq hl-needed-window-start (window-start))) + (< 1 + (abs + (- (line-number-at-pos hl-needed-window-start) + (line-number-at-pos (window-start))))))))))) + +(defun hl-needed-cancel-flash-timer () + (when (timerp hl-needed-flash-timer) (cancel-timer hl-needed-flash-timer)) + (setq hl-needed-flash-timer nil)) + +(defun hl-needed-start-maybe-flash-timer () + (when (and hl-needed-flash-this + (not hl-needed-always)) + (hl-needed-cancel-flash-timer) + (setq hl-needed-flash-timer + (run-with-timer (+ hl-needed-flash-delay hl-needed-flash-duration) + nil 'hl-needed-hide-flash-in-timer)))) + +(defvar hl-needed-pre-command-time (current-time)) + +(defun hl-needed-check () + ;; Cancel `hl-line-mode' and timer + (unless (active-minibuffer-window) + (if (funcall hl-needed-currently-fun) + (progn + ;; Some time calc for things that pause to show us where we are: + (let* ((time-pre hl-needed-pre-command-time) + (time-now (current-time)) + (pre (+ (nth 1 time-pre) (* 0.0000001 (nth 2 time-pre)))) + (now (+ (nth 1 time-now) (* 0.0000001 (nth 2 time-now))))) + (if (< 1 (- now pre)) ;; Fix-me: option? + nil ;; Don't show anything here, it just disturbs + ;;(hl-needed-show) + (hl-needed-start-timer hl-needed-flash-delay) + (hl-needed-start-maybe-flash-timer)))) + ;; Submit an idle timer that can turn highlighting on. + (hl-needed-start-timer hl-needed-idle-time))) + (setq hl-needed-config-change nil) + (unless (active-minibuffer-window) + (setq hl-needed-window (selected-window)) + (setq hl-needed-buffer (current-buffer)) + (setq hl-needed-window-start (window-start)))) + +(defvar hl-needed-after-active-minibuffer nil) + +(defun hl-needed-pre-command () + ;;(message "active-minibuffer-window=%s" (active-minibuffer-window)) + (setq hl-needed-after-active-minibuffer (active-minibuffer-window)) + (condition-case err + (progn + (hl-needed-cancel-timer) + (hl-needed-cancel-flash-timer) + (hl-needed-hide) + (setq hl-needed-flash-this hl-needed-flash-duration) + (setq hl-needed-pre-command-time (current-time))) + (error + (message "hl-needed-pre-command error: %s" err)))) + +(defun hl-needed-post-command () + (condition-case err + (if (eq last-command 'keyboard-quit) + (hl-needed-hide) + (hl-needed-check)) + (error + (message "hl-needed-post-command error: %s" err)))) + +(defvar hl-needed-minibuffer-active nil) + +(defun hl-needed-config-change () + (condition-case err + (if (active-minibuffer-window) + (setq hl-needed-minibuffer-active t) + ;; Changing buffer in the echo area is a config change. Catch this: + (setq hl-needed-config-change (not hl-needed-after-active-minibuffer)) + (setq hl-needed-after-active-minibuffer nil) + (setq hl-needed-minibuffer-active nil)) + (error + (message "hl-needed-config-change error: %s" err)))) + +(provide 'hl-needed) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; hl-needed.el ends here diff --git a/emacs/nxhtml/util/html-write.el b/emacs/nxhtml/util/html-write.el new file mode 100644 index 0000000..c7a7c76 --- /dev/null +++ b/emacs/nxhtml/util/html-write.el @@ -0,0 +1,455 @@ +;;; html-write.el --- Hide some tags for writing text in XHTML +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-10-03T01:29:44+0200 Thu +(defconst html-write:version "0.6") ;; Version: +;; Last-Updated: 2009-08-11 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; The minor mode `html-write-mode' displays simple tags like <i>, +;; <b>, <em>, <strong> or <a> with appropriate faces (for example bold +;; and italic) instead of displaying the tags. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +;; Silence byte compiler +(defvar jit-lock-start) +(defvar jit-lock-end) + +(eval-when-compile (require 'mumamo)) ;; Just for the defmacro ... +(eval-when-compile (require 'mlinks nil t)) + +;;;###autoload +(defgroup html-write nil + "Customization group for html-write." + :group 'nxhtml + :group 'convenience) + +(defface html-write-base + '((t (:inherit font-lock-type-face))) + "Face from which other faces inherits." + :group 'html-write) + +(defface html-write-em + '((t (:inherit html-write-base :slant italic))) + "Face used for <em> tags." + :group 'html-write) + +(defface html-write-strong + '((t (:inherit html-write-base :weight bold))) + "Face used for <strong> tags." + :group 'html-write) + +(defface html-write-link + '((t (:inherit html-write-base :underline t))) + "Face used for <a> tags." + :group 'html-write) + +(defconst html-write-tag-list + '(("i" html-write-em-tag-actions) + ("b" html-write-strong-tag-actions) + ("em" html-write-em-tag-actions) + ("strong" html-write-strong-tag-actions) + ("a" html-write-a-tag-actions) + ;;("img" html-write-img-tag-actions t) + ) + "List of tags that should be hidden. +A record in the list has the format + + \(TAG HANDLE [SINGLE]) + +where +- TAG is the tag name string. + +- HANDLE is a function to call when hiding the tag. It takes + three parameters, TAG-BEGIN, TAG-END and OVERLAY. TAG-BEGIN + and TAG-END are start and end of the start tag. OVERLAY is an + overlay used for faces, keymaps etc that covers the whole tag." + ) + +(defun html-write-em-tag-actions (tag-begin tag-end overlay) + "Do actions for <em> tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (overlay-put overlay 'face 'html-write-em)) + +(defun html-write-strong-tag-actions (tag-begin tag-end overlay) + "Do actions for <strong> tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (overlay-put overlay 'face 'html-write-strong)) + +;; Fix-me +(defun html-write-img-tag-actions (tag-begin tag-end overlay) + "Do actions for <img> tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (save-match-data + (let ((here (point-marker)) + href) + (save-restriction + (narrow-to-region tag-begin tag-end) + (goto-char tag-begin) + (when (looking-at (rx (*? anything) + (1+ space) + "src=\"" + (submatch + (+ (not (any "\"\n")))) + "\"")) + (setq href (match-string-no-properties 1)))) + (when href + (overlay-put overlay 'display (concat "image " href)) + (overlay-put overlay 'html-write-url href)) + (goto-char (point))))) + +(defun html-write-point-entered-echo (left entered) + (let ((msg (get-char-property entered 'help-echo))) + (when msg (message "%s" msg)))) + +(defun html-write-a-tag-actions (tag-begin tag-end overlay) + "Do actions for <a> tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (save-match-data + (let ((here (point-marker)) + href) + (save-restriction + (narrow-to-region tag-begin tag-end) + (goto-char tag-begin) + (when (looking-at (rx (*? anything) + (1+ space) + "href=\"" + (submatch + (+ (not (any "\"\n")))) + "\"")) + (setq href (match-string-no-properties 1)))) + (when href + (overlay-put overlay 'face 'html-write-link) + (overlay-put overlay 'help-echo href) + ;; Fix-me: Seems like point-entered must be a text prop + (overlay-put overlay 'point-entered 'html-write-point-entered-echo) + (overlay-put overlay 'mouse-face 'highlight) + (if (eq ?# (string-to-char href)) + (setq href (concat "file:///" buffer-file-name href)) + (when (file-exists-p href) + (setq href (expand-file-name href)))) + (overlay-put overlay 'html-write-url href)) + (goto-char (point))))) + +(defun html-write-get-tag-ovl () + "Get tag overlay at current point." + (catch 'ranges + (dolist (ovl (overlays-at (point))) + (let ((ranges (overlay-get ovl 'html-write))) + (when ranges + (throw 'ranges ovl)))))) + +(defun html-write-toggle-current-tag () + "Toggle display of tag at current point." + (interactive) + (let* ((ovl (html-write-get-tag-ovl)) + (hiding-ranges (overlay-get ovl 'html-write)) + (invis (get-text-property (caar hiding-ranges) 'invisible)) + (ovl-start (overlay-start ovl)) + (ovl-end (overlay-end ovl))) + (if invis + (progn + (overlay-put ovl 'html-face (overlay-get ovl 'face)) + (overlay-put ovl 'face 'highlight) + (dolist (range hiding-ranges) + (let ((start (car range)) + (end (cdr range))) + (mumamo-with-buffer-prepared-for-jit-lock + (put-text-property start end 'invisible nil))))) + (delete-overlay ovl) + (html-write-hide-tags ovl-start ovl-end)))) + +(defun html-write-browse-link () + "Browse link in current tag." + (interactive) + (let* ((ovl (html-write-get-tag-ovl)) + (url (overlay-get ovl 'html-write-url))) + (unless url + (error "No link in this tag")) + (browse-url url) + )) + +(defvar html-write-keymap + (let ((map (make-sparse-keymap)) + keys) + (define-key map [(control ?c) ?+] 'html-write-toggle-current-tag) + (define-key map [(control ?c) ?!] 'html-write-browse-link) + (define-key map [mouse-1] 'html-write-browse-link) + (when (featurep 'mlinks) + (setq keys (where-is-internal 'mlinks-goto mlinks-mode-map)) + (dolist (key keys) + (define-key map key 'html-write-mlinks-goto)) + (setq keys (where-is-internal 'mlinks-goto-other-window mlinks-mode-map)) + (dolist (key keys) + (define-key map key 'html-write-mlinks-goto-other-window)) + (setq keys (where-is-internal 'mlinks-goto-other-frame mlinks-mode-map)) + (dolist (key keys) + (define-key map key 'html-write-mlinks-goto-other-frame)) + ) + map)) + +(defun html-write-mlinks-goto () + "Goto link." + (interactive) + (html-write-mlinks-goto-1 'mlinks-goto)) + +(defun html-write-mlinks-goto-other-window () + "Goto link in other window." + (interactive) + (html-write-mlinks-goto-1 'mlinks-goto-other-window)) + +(defun html-write-mlinks-goto-other-frame () + "Goto link in other frame." + (interactive) + (html-write-mlinks-goto-1 'mlinks-goto-other-frame)) + +(defun html-write-mlinks-goto-1 (goto-fun) + (let* ((ovl (html-write-get-tag-ovl)) + (ovl-start (overlay-start ovl)) + (ovl-end (overlay-end ovl)) + (here (point-marker))) + (goto-char ovl-start) + (skip-chars-forward "^\"" ovl-end) + (forward-char) + (unless (funcall goto-fun) (goto-char here)) + )) + +;;(html-write-make-hide-tags-regexp) +(defun html-write-make-hide-tags-regexp () + "Make regexp used for finding tags to hide." + ;; fix-me: single tags. Fix-me: what did I mean??? Maybe < etc... + (let ((tags-re + (mapconcat 'identity + (mapcar (lambda (elt) + (if (stringp elt) + elt + (car elt))) + html-write-tag-list) + "\\|"))) + (concat + "<\\(?1:" + "\\(?:" tags-re "\\)" + "\\)[^>]*>\\(?3:[^<]*\\)\\(?2:</\\1>\\)" + ))) + +(defvar html-write-pending-changes nil) +(make-variable-buffer-local 'html-write-pending-changes) +(put 'html-write-pending-changes 'permanent-local t) + + +(defun html-write-hide-tags (start end) + "Hide tags matching `html-write-tag-list' between START and END." + ;;(message "html-write-hide-tags %s %s" start end) + (let ((here (point-marker)) + (buffer-name (buffer-file-name)) + (dbg nil)) + (save-restriction + (widen) + (goto-char start) + (save-match-data + (let ((hide-tags-regexp (html-write-make-hide-tags-regexp))) + (when dbg (message "before search start=%s end=%s, point=%s" start end (point))) + (while (re-search-forward hide-tags-regexp end t) + (let* ((ovl (make-overlay (match-beginning 0) (match-end 0) + nil t nil)) + (tag-fun (cadr (assoc (match-string-no-properties 1) + html-write-tag-list))) + hiding-ranges) + ;;(overlay-put ovl 'face 'font-lock-variable-name-face) + (overlay-put ovl 'keymap html-write-keymap) + (setq hiding-ranges + (list (cons (1- (match-beginning 1)) (match-beginning 3)) + (cons (match-beginning 2) (match-end 2)))) + (overlay-put ovl 'html-write hiding-ranges) + (mumamo-with-buffer-prepared-for-jit-lock + (dolist (range hiding-ranges) + (let ((start (car range)) + (end (cdr range))) + (put-text-property start end 'invisible 'html-write) + ;; Fix-me: more careful rear-nonsticky? + (put-text-property (1- end) end + 'rear-nonsticky '(invisible))))) + ;; Let tag-fun override + (when tag-fun + (funcall tag-fun (match-end 1) (match-beginning 3) ovl)) + ))))) + (goto-char here))) + +(defun html-write-reveal-tags (start end) + "Reveal tags between START and END." + (let ((here (point-marker))) + (save-restriction + (widen) + (goto-char (point-min)) + (save-match-data + (mumamo-with-buffer-prepared-for-jit-lock + (remove-text-properties start + end + '(invisible html-write)) + (dolist (ovl (overlays-in start end)) + (when (overlay-get ovl 'html-write) + (let ((end (overlay-end ovl))) + (remove-list-of-text-properties (1- end) end '(rear-nonsticky)) + (delete-overlay ovl))))))) + (goto-char here))) + +;;;###autoload +(define-minor-mode html-write-mode + "Minor mode for convenient display of some HTML tags. +When this mode is on a tag in `html-write-tag-list' is displayed as +the inner text of the tag with a face corresponding to the tag. +By default for example <i>...</i> is displayed as italic and +<a>...</a> is displayed as an underlined clickable link. + +Only non-nested tags are hidden. The idea is just that it should +be easier to read and write, not that it should look as html +rendered text. + +See the customization group `html-write' for more information about +faces. + +The following keys are defined when you are on a tag handled by +this minor mode: + +\\{html-write-keymap} + +IMPORTANT: Most commands you use works also on the text that is +hidden. The movement commands is an exception, but as soon as +you edit the buffer you may also change the hidden parts. + +Hint: Together with `wrap-to-fill-column-mode' this can make it +easier to see what text you are actually writing in html parts of +a web file." + :group 'html-write + (if t + (if html-write-mode + (html-write-font-lock t) + (html-write-font-lock nil) + (save-restriction + (widen) + (html-write-reveal-tags (point-min) (point-max)))))) +(put html-write-mode 'permanent-local t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font lock + +(defun html-write-jit-extend-after-change (start end old-len) + "For JIT lock extending. +Should be on `jit-lock-after-change-extend-region-functions'. + +START, END and OLD-LEN are the parameters from after change." + (let ((our-ovls nil)) + (dolist (ovl (append (overlays-in start end) + (overlays-at start) + nil)) + ;; Leave the overlays until re-fontification time, but note their extent. + (when (overlay-get ovl 'html-write) + (setq jit-lock-start (min jit-lock-start (overlay-start ovl))) + (setq jit-lock-end (max jit-lock-end (overlay-end ovl))))))) + + +(defun html-write-fontify (bound) + ;;(message "html-write-fontify %s" bound) + (let (tag-ovl) + ;;(save-match-data + (let* ((hide-tags-regexp (html-write-make-hide-tags-regexp)) + (next-tag (re-search-forward hide-tags-regexp bound t)) + (tag-beg (when next-tag (match-beginning 0))) + (tag-end (when next-tag (match-end 0))) + (tag-nam (when next-tag (match-string-no-properties 1))) + (tag-fun (when next-tag (cadr (assoc tag-nam html-write-tag-list)))) + tag-hid + (old-start (next-single-char-property-change (max (point-min) (1- (point))) 'html-write nil bound))) + ;;(message "here a old-start=%s, tag-beg/end=%s/%s" old-start tag-beg tag-end) + (setq tag-ovl (when next-tag (make-overlay tag-beg tag-end))) + (when old-start + ;; Fix-me: maybe valid, perhaps better keep it then? + (let ((ovl (catch 'ovl + (dolist (o (append (overlays-at old-start) + (overlays-in old-start (1+ old-start)) + nil)) + (when (overlay-get o 'html-write) + (throw 'ovl o)))))) + (when ovl ;; fix-me: there should be one... + ;;(message "here b") + (mumamo-with-buffer-prepared-for-jit-lock + (remove-list-of-text-properties (overlay-start ovl) (overlay-end ovl) '(invisible html-write))) + (delete-overlay ovl)))) + ;;(html-write-hide-tags start end) + ;;(message "here d, tag-ovl=%s" tag-ovl) + (when tag-ovl + (overlay-put tag-ovl 'face 'font-lock-variable-name-face) + (overlay-put tag-ovl 'keymap html-write-keymap) + (setq tag-hid + (list (cons (1- (match-beginning 1)) (match-beginning 3)) + (cons (match-beginning 2) (match-end 2)))) + (overlay-put tag-ovl 'html-write tag-hid) + (when tag-fun + (funcall tag-fun (match-end 1) (match-beginning 3) tag-ovl)) + (mumamo-with-buffer-prepared-for-jit-lock + (dolist (range tag-hid) + (let ((start (car range)) + (end (cdr range))) + (put-text-property start end 'invisible 'html-write) + ;;(put-text-property start end 'html-write t) + ;; Fix-me: more careful rear-nonsticky? + (put-text-property (1- end) end + 'rear-nonsticky '(invisible))))))) + ;;) + (when tag-ovl + (set-match-data (list (copy-marker (overlay-start tag-ovl)) + (copy-marker (overlay-end tag-ovl)))) + (goto-char (1+ (overlay-end tag-ovl))) + t))) + +(defun html-write-font-lock (on) + ;; See mlinks.el + (let* ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords)) + (fontify-fun 'html-write-fontify) + (args (list nil `(( ,fontify-fun ( 0 'html-write-base t )))))) + (when fontify-fun + (when on (setq args (append args (list t)))) + (apply add-or-remove args) + (font-lock-mode -1) + (font-lock-mode 1) + ))) + +(provide 'html-write) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-write.el ends here diff --git a/emacs/nxhtml/util/idn.el b/emacs/nxhtml/util/idn.el new file mode 100644 index 0000000..21f7a4c --- /dev/null +++ b/emacs/nxhtml/util/idn.el @@ -0,0 +1,151 @@ +;;; idn.el --- Recommended Identifier Profiles for IDN +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2010-03-24 Wed +;; Version: 0.1 +;; Last-Updated: 2010-03-26 Fri +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `nxhtml-base'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Functions for handling IDN chars defined by +;; `http://www.unicode.org/reports/tr39/'. +;; +;; See `idn-is-recommended'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +;; Fix-me: You have to change this if you are not using nXhtml: +(require 'nxhtml-base) +(defvar uts39-datadir (expand-file-name "etc/uts39/" nxhtml-install-dir)) + +(defun idn-init (bv) + (save-match-data + (let* ((idnchars-file (expand-file-name "idnchars.txt" uts39-datadir)) + (idnchars-old (find-buffer-visiting idnchars-file)) + (idnchars-buf (or idnchars-old + (if (not (file-exists-p idnchars-file)) + (message "Can't find file %S" idnchars-file) + (find-file-noselect idnchars-file)))) + here + (range-patt (rx bol + (group (repeat 4 (any xdigit))) + (optional ".." + (group (repeat 4 (any xdigit)))))) + (num-idn 0)) + (when idnchars-buf + (with-current-buffer idnchars-buf + (setq here (point)) + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward range-patt nil t) + (let* ((str-beg (match-string 0)) + (str-end (match-string 2)) + (beg (string-to-number str-beg 16)) + (end (or (when str-end (string-to-number str-end 16)) + beg))) + ;;(message "str-beg=%S str-end=%S" str-beg str-end) + (dotimes (ii (1+ (- end beg))) + (let ((num (+ ii beg))) + ;;(message "setting idn-char %s #%4x" num num) + (setq num-idn (1+ num-idn)) + (aset bv num t)))))) + (goto-char here)) + (unless idnchars-old (kill-buffer idnchars-buf)) + (message "Found %d IDN chars" num-idn) + t)))) + +(defconst idn-char-vector + (let ((bv (make-bool-vector (* 256 256) nil))) + (when (idn-init bv) + ;; (string-to-number "002D" 16) + ;; Make a quick sanity check: + (unless (and (not (aref bv 44)) + (aref bv 45)) + (message "idn-char-vector: Bad idn data in file idnchars.txt")) + bv)) + "Boolean vector with recommended IDN chars.") + + +;;(idn-is-recommended 0) +;;(idn-is-recommended 65535) +(defsubst idn-is-recommended (char) + "Return t if character CHAR is a recommended IDN char. +See URL `http://www.unicode.org/reports/tr39/'. + +Data is initialized from the file idnchars.txt in the directory +`uts39-datadir'. This file is fetched from the above URL." + (aref idn-char-vector char)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Below are some help functions that can be commented out. + +;;(global-set-key [f9] 'idn-char-at-point) +(defun idn-char-at-point (pos) + "Tell if char at POS is an recommended IDN char. +Default POS is current point." + (interactive "d") + (let* ((this-char (char-after pos)) + (recommended (idn-is-recommended this-char))) + (message "IDN char at point: %s (#%000x)" recommended this-char))) + +(defun idn-list-chars () + "Show all IDN chars. +For more info see `idn-is-recommended'. + +Note: This may crash Emacs currently, at least on w32." + (interactive) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'idn-list-chars) (interactive-p)) + (with-current-buffer (help-buffer) + (insert + "Recommended Identifier Characters for IDN:\n\n") + (let ((col 0) + (cnt 0)) + (dotimes (nn (length idn-char-vector)) + (when (aref idn-char-vector nn) + (setq cnt (1+ cnt)) + (setq col (mod (1+ col) 20)) + (when (= col 0) (insert "\n ")) + (insert " " (char-to-string nn)))) + (insert "\n\n" + (format "There were %d IDN chars defined in `idn-char-vector'." cnt)) + )))) + +(provide 'idn) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; idn.el ends here diff --git a/emacs/nxhtml/util/inlimg.el b/emacs/nxhtml/util/inlimg.el new file mode 100644 index 0000000..9b07fb3 --- /dev/null +++ b/emacs/nxhtml/util/inlimg.el @@ -0,0 +1,429 @@ +;;; inlimg.el --- Display images inline +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-09-27 +(defconst inlimg:version "0.7") ;; Version: +;; Last-Updated: 2009-07-14 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Display images inline. See `inlimg-mode' for more information. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) + +(defvar inlimg-assoc-ext + '((png (".png")) + (gif (".gif")) + (tiff (".tiff")) + (jpeg (".jpg" ".jpeg")) + (xpm (".xpm")) + (xbm (".xbm")) + (pbm (".pbm")))) + +(defvar inlimg-img-regexp nil) +(make-variable-buffer-local 'inlimg-img-regexp) +(put 'inlimg-img-regexp 'permanent-local t) + +(defvar inlimg-img-regexp-html + (rx (or (and "<img" + (1+ space) + (0+ (1+ (not (any " <>"))) + (1+ space)) + "src=\"" + (group (1+ (not (any "\"")))) + "\"" + (*? anything) + "/>") + (and "url(" + ?\" + (group (1+ (not (any "\)")))) + ?\" + ")" + ) + (and "url(" + (group (+? (not (any ")")))) + ")" + ) + ))) + +(defvar inlimg-img-regexp-org + (rx-to-string + `(and "[[file:" + (group (+? (not (any "\]"))) + ,(let ((types nil)) + (dolist (typ image-types) + (when (image-type-available-p typ) + (dolist (ext (cadr (assoc typ inlimg-assoc-ext))) + (setq types (cons ext types))))) + (cons 'or types))) + "]" + (optional "[" + (+? (not (any "\]"))) + "]") + "]" + ))) + +(defconst inlimg-modes-img-values + '( + (html-mode inlimg-img-regexp-html) + (org-mode inlimg-img-regexp-org) + )) + +(defun inlimg-img-spec-p (spec) + (assoc spec inlimg-modes-img-values)) + +;;;###autoload +(defgroup inlimg nil + "Customization group for inlimg." + :group 'nxhtml) + +(defcustom inlimg-margins '(50 . 5) + "Margins when displaying image." + :type '(cons (integer :tag "Left margin") + (integer :tag "Top margin")) + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'inlimg-update-all-buffers) + (inlimg-update-all-buffers))) + :group 'inlimg) + +(defcustom inlimg-slice '(0 0 400 100) + "How to slice images." + :type '(choice (const :tag "Show whole images" nil) + (list :tag "Show slice of image" + (integer :tag "Top") + (integer :tag "Left") + (integer :tag "Width") + (integer :tag "Height"))) + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'inlimg-update-all-buffers) + (inlimg-update-all-buffers))) + :group 'inlimg) + +(define-widget 'inlimg-spec-widget 'symbol + "An inline image specification." + :complete-function (lambda () + (interactive) + (lisp-complete-symbol 'inlimg-img-spec-p)) + :prompt-match 'inlimg-img-spec-p + :prompt-history 'widget-function-prompt-value-history + :match-alternatives '(inlimg-img-spec-p) + :validate (lambda (widget) + (unless (inlimg-img-spec-p (widget-value widget)) + (widget-put widget :error (format "Invalid function: %S" + (widget-value widget))) + widget)) + :value 'org-mode + :tag "Inlimg image values spec name") + +;; (customize-option 'inlimg-mode-specs) +(defcustom inlimg-mode-specs + '( + (xml-mode html-mode) + (sgml-mode html-mode) + (nxml-mode html-mode) + (php-mode html-mode) + (css-mode html-mode) + ) + "Equivalent mode for image tag search. +Note that derived modes \(see info) are recognized by default. + +To add new image tag patterns modify `inlimg-modes-img-values'." + :type '(repeat + (list (major-mode-function :tag "Major mode") + (inlimg-spec-widget :tag "Use tags as specified in"))) + :group 'inlimg) + +(defface inlimg-img-tag '((t :inherit 'lazy-highlight)) + "Face added to img tag when displaying image." + :group 'inlimg) + +(defface inlimg-img-remote '((t :inherit 'isearch-fail)) + "Face used for notes telling image is remote." + :group 'inlimg) + +(defface inlimg-img-missing '((t :inherit 'trailing-whitespace)) + "Face used for notes telling image is missing." + :group 'inlimg) + +(defvar inlimg-img-keymap + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?+] 'inlimg-toggle-display) + (define-key map [(control ?c) ?%] 'inlimg-toggle-slicing) + map) + "Keymap on image overlay.") + +(eval-after-load 'gimp + '(gimp-add-point-bindings inlimg-img-keymap)) + +(defsubst inlimg-ovl-p (ovl) + "Return non-nil if OVL is an inlimg image overlay." + (overlay-get ovl 'inlimg-img)) + +(defun inlimg-ovl-valid-p (ovl) + (and (overlay-get ovl 'inlimg-img) + inlimg-img-regexp + (save-match-data + (let ((here (point))) + (goto-char (overlay-start ovl)) + (prog1 + (looking-at (symbol-value inlimg-img-regexp)) + (goto-char here)))))) + +(defun inlimg-next (pt display-image) + "Display or hide next image after point PT. +If DISPLAY-IMAGE is non-nil then display image, otherwise hide it. + +Return non-nil if an img tag was found." + (when inlimg-img-regexp + (let (src dir beg end img ovl remote beg-face) + (goto-char pt) + (save-match-data + (when (re-search-forward (symbol-value inlimg-img-regexp) nil t) + (setq src (or (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3))) + (setq beg (match-beginning 0)) + (setq beg-face (get-text-property beg 'face)) + (setq remote (string-match "^https?://" src)) + (setq end (- (line-end-position) 0)) + (setq ovl (catch 'old-ovl + (dolist (ovl (overlays-at beg)) + (when (inlimg-ovl-p ovl) + (throw 'old-ovl ovl))) + nil)) + (unless ovl + (setq ovl (make-overlay beg end)) + (overlay-put ovl 'inlimg-img t) + (overlay-put ovl 'priority 100) + (overlay-put ovl 'face 'inlimg-img-tag) + (overlay-put ovl 'keymap inlimg-img-keymap)) + (overlay-put ovl 'image-file src) + (overlay-put ovl 'inlimg-slice inlimg-slice) + (if display-image + (unless (memq beg-face '(font-lock-comment-face font-lock-string-face)) + (unless remote + (setq dir (if (buffer-file-name) + (file-name-directory (buffer-file-name)) + default-directory)) + (setq src (expand-file-name src dir))) + (if (or remote (not (file-exists-p src))) + (setq img (propertize + (if remote " Image is on the web " " Image not found ") + 'face (if remote 'inlimg-img-remote 'inlimg-img-missing))) + (setq img (create-image src nil nil + :relief 5 + :margin inlimg-margins)) + (setq img (inlimg-slice-img img inlimg-slice))) + (let ((str (copy-sequence "\nX"))) + (setq str (propertize str 'face 'inlimg-img-tag)) + (put-text-property 1 2 'display img str) + (overlay-put ovl 'after-string str))) + (overlay-put ovl 'after-string nil)))) + ovl))) + +(defun inlimg-slice-img (img slice) + (if (not slice) + img + (let* ((sizes (image-size img t)) + (width (car sizes)) + (height (cdr sizes)) + (sl-left (nth 0 slice)) + (sl-top (nth 1 slice)) + (sl-width (nth 2 slice)) + (sl-height (nth 3 slice))) + (when (> sl-left width) (setq sl-left 0)) + (when (> (+ sl-left sl-width) width) (setq sl-width (- width sl-left))) + (when (> sl-top height) (setq sl-top 0)) + (when (> (+ sl-top sl-height) height) (setq sl-height (- height sl-top))) + (setq img (list img)) + (setq img (cons (append '(slice) + slice + (list sl-top sl-left sl-width sl-height) + nil) + img))))) + +;;;###autoload +(define-minor-mode inlimg-mode + "Display images inline. +Search buffer for image tags. Display found images. + +Image tags are setup per major mode in `inlimg-mode-specs'. + +Images are displayed on a line below the tag referencing them. +The whole image or a slice of it may be displayed, see +`inlimg-slice'. Margins relative text are specified in +`inlimg-margins'. + +See also the commands `inlimg-toggle-display' and +`inlimg-toggle-slicing'. + +Note: This minor mode uses `font-lock-mode'." + :keymap nil + :group 'inlimg + (if inlimg-mode + (progn + (let ((major-mode (or (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode + (fboundp 'mumamo-main-major-mode) + (mumamo-main-major-mode)) + major-mode))) + (inlimg-get-buffer-img-values) + (unless inlimg-img-regexp + (message "inlim-mode: No image spec, can't do anything")) + (add-hook 'font-lock-mode-hook 'inlimg-on-font-lock-off)) + (inlimg-font-lock t)) + (inlimg-font-lock nil) + (inlimg-delete-overlays))) +(put 'inlimg-mode 'permanent-local t) + +(defun inlimg-delete-overlays () + (save-restriction + (widen) + (let (ovl) + (dolist (ovl (overlays-in (point-min) (point-max))) + (when (inlimg-ovl-p ovl) + (delete-overlay ovl)))))) + +(defun inlimg-get-buffer-img-values () + (let* (rec + (spec (or (catch 'spec + (dolist (rec inlimg-mode-specs) + (when (derived-mode-p (car rec)) + (throw 'spec (nth 1 rec))))) + major-mode)) + (values (when spec (nth 1 (assoc spec inlimg-modes-img-values)))) + ) + (setq inlimg-img-regexp values) + )) + +(defun inlimg--global-turn-on () + (inlimg-get-buffer-img-values) + (when inlimg-img-regexp + (inlimg-mode 1))) + +;;;###autoload +(define-globalized-minor-mode inlimg-global-mode inlimg-mode inlimg--global-turn-on) + +;;;###autoload +(defun inlimg-toggle-display (point) + "Toggle display of image at point POINT. +See also the command `inlimg-mode'." + (interactive (list (point))) + (let ((here (point)) + (ovl + (catch 'ovl + (dolist (ovl (overlays-at (point))) + (when (inlimg-ovl-p ovl) + (throw 'ovl ovl))))) + is-displayed) + (if (not ovl) + (message "No image at point %s" here) + (setq is-displayed (overlay-get ovl 'after-string)) + (inlimg-next (overlay-start ovl) (not is-displayed)) + (goto-char here)))) + +;;;###autoload +(defun inlimg-toggle-slicing (point) + "Toggle slicing of image at point POINT. +See also the command `inlimg-mode'." + (interactive (list (point))) + (let* ((here (point)) + (ovl + (catch 'ovl + (dolist (ovl (overlays-at (point))) + (when (inlimg-ovl-p ovl) + (throw 'ovl ovl))))) + (inlimg-slice inlimg-slice) + is-displayed) + (if (not ovl) + (message "No image at point %s" here) + (setq is-displayed (overlay-get ovl 'after-string)) + (when (overlay-get ovl 'inlimg-slice) + (setq inlimg-slice nil)) + (inlimg-next (overlay-start ovl) is-displayed) + (goto-char here)))) + + +(defun inlimg-font-lock-fun (bound) + (let ((here (point)) + old-ovls new-ovls ovl) + (goto-char (line-beginning-position)) + (dolist (ovl (overlays-in (point) bound)) + (when (inlimg-ovl-p ovl) + (setq old-ovls (cons ovl old-ovls)))) + (while (and (< (point) bound) + (setq ovl (inlimg-next (point) t))) + (setq new-ovls (cons ovl new-ovls))) + (dolist (ovl old-ovls) + (unless (inlimg-ovl-valid-p ovl) + (delete-overlay ovl) + )))) + +;; Fix-me: This stops working for changes with nxhtml-mumamo-mode, but +;; works for nxhtml-mode and html-mumamo-mode... +(defvar inlimg-this-is-not-font-lock-off nil) +(defun inlimg-font-lock (on) + (let ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords)) + (link-fun)) + (funcall add-or-remove nil + `((inlimg-font-lock-fun + 1 + mlinks-link + prepend))) + (let ((inlimg-this-is-not-font-lock-off t) + (mumamo-multi-major-mode nil)) + (font-lock-mode -1) + (font-lock-mode 1)))) + +(defun inlimg-on-font-lock-off () + (unless (or inlimg-this-is-not-font-lock-off + (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode)) + (when inlimg-mode + (inlimg-mode -1) + ))) +(put 'inlimg-on-font-lock-off 'permanent-local-hook t) + + +(provide 'inlimg) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; inlimg.el ends here diff --git a/emacs/nxhtml/util/key-cat.el b/emacs/nxhtml/util/key-cat.el new file mode 100644 index 0000000..ac4938c --- /dev/null +++ b/emacs/nxhtml/util/key-cat.el @@ -0,0 +1,329 @@ +;;; key-cat.el --- List key bindings by category +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Jan 28 2006 +;; Version: 0.25 +;; Last-Updated: 2009-05-09 Sat +;; Keywords: +;; Compatibility: +;; +;; Requires Emacs 22. +;; +;; Features that might be required by this library: +;; + ;; `cl'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Display help that looks like a reference sheet for common +;; commands. +;; +;; To use this in your .emacs put +;; +;; (require 'key-cat) +;; +;; Then use the command +;; +;; M-x key-cat-help +;; +;; For more information see that command. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) + +(defconst key-cat-cmd-list + '( + (error-testing + (commands + :visible nil + hallo + key-cat-help + key-cat-where-is + )) + ("Help" + (commands + help-for-help + info-emacs-manual + info + )) + ("Special Functions and Keys" + ;; For similar functions that are most often bound to a specific key + (commands + key-cat-tab + key-cat-complete + ) + ) + ("Files, Buffers and Windows" + (commands + find-file + save-buffer + write-file + split-window-vertically + split-window-horizontally + delete-other-windows + other-window + buffer-menu + )) + ("Search and replace" + (commands + isearch-forward + isearch-backward + query-replace + isearch-forward-regexp + isearch-backward-regexp + query-replace-regexp + occur + lgrep + rgrep + )) + ("Lines" + (commands + move-beginning-of-line + move-end-of-line + kill-line + )) + ("Words" + (commands + forward-word + backward-word + kill-word + )) + ("Region" + (commands + set-mark-command + ;;cua-set-mark + kill-region + copy-region-as-kill + yank + yank-pop + )) + ("Undo" + (commands + undo + )) + ("Viper" + (commands + :visible (lambda() + (and (featurep 'viper) + viper-mode)) + viper-next-line + viper-previous-line + viper-forward-word + viper-backward-word + viper-forward-Word + viper-backward-Word + viper-repeat + viper-forward-char + viper-backward-char + viper-next-line-at-bol + viper-previous-line-at-bol + viper-command-argument + viper-digit-argument + )) + ) + "List with common commands to display by `key-cat-help'. +The elements of this list corresponds to sections to show in the +help. Each element consists of sublists beginning with the +keyword 'commands. The sublists may after 'command contain the +keyword :visible which takes a variable or function as argument. +If the argument evaluates to non-nil the list is shown." + ) + + +(defvar key-cat-cmd-list-1 nil) + +(defun key-cat-help() + "Display reference sheet style help for common commands. +See also `key-cat-cmd-list'." + (interactive) + (if (> 22 emacs-major-version) + (message "Sorry, this requires Emacs 22 or later") + ;; Delay to get correct bindings when running through M-x + (setq key-cat-cmd-list-1 key-cat-cmd-list) + (run-with-timer 0.1 nil 'key-cat-help-internal))) + +(defun key-cat-help-internal() ;(category) + (message "Please wait ...") + (condition-case err + (save-match-data ;; runs in timer + (let ((result)) + (help-setup-xref (list #'key-cat-help) + (interactive-p)) + ;; (push (list "Changing commands" + ;; (list + ;; 'command + ;; indent-line-function + ;; )) + ;; key-cat-cmd-list-1) + (dolist (catentry key-cat-cmd-list-1) + (let ((category (car catentry)) + (commands (cdr catentry)) + (cmds) + (keyw) + (visible) + (visible-fun) + (cmdstr) + (doc)) + (dolist (cmdlist commands) + (setq cmdlist (cdr cmdlist)) + (setq visible t) + (while (keywordp (setq keyw (car cmdlist))) + (setq cmdlist (cdr cmdlist)) + (case keyw + (:visible (setq visible-fun (pop cmdlist)) + (setq visible (if (symbolp visible-fun) + (progn + (symbol-value visible-fun)) + (funcall visible-fun))) + ) + )) + (when visible + (dolist (cmd cmdlist) + (setq cmds (cons cmd cmds))))) + (when cmds + (push (format "\n%s:\n" + (let ((s (format "%s" category))) + (put-text-property 0 (length s) + 'face (list + 'bold + ) + s) + s)) + result)) + (setq cmds (reverse cmds)) + (dolist (cmd cmds) + (setq cmdstr + (let ((s "Where to find it:" )) + (put-text-property 0 (length s) + 'face '(:slant italic + :background "RGB:dd/dd/ff" + ) s) s)) + (if (not (functionp cmd)) + (cond + ((eq 'key-cat-tab cmd) + (let ((s "Indent line")) + (put-text-property 0 (length s) 'face '(:foreground "blue") s) + (push s result)) + (push ":\n" result) + (push (concat + " " + "Indent current line (done by specific major mode function).\n") + result) + (push (format " %17s %s\n" cmdstr (key-description [tab])) result) + ) + ((eq 'key-cat-complete cmd) + (let ((s "Completion")) + (put-text-property 0 (length s) 'face '(:foreground "blue") s) + (push s result)) + (push ":\n" result) + (push (concat + " " + "Performe completion at point (done by specific major mode function).\n") + result) + (push (format " %17s %s\n" cmdstr (key-description [meta tab])) result) + ) + (t + (let ((s (format "`%s': (not a function)\n" cmd))) + (put-text-property 0 (length s) 'face '(:foreground "red") s) + (push s result)))) + (let ((keys (key-cat-where-is cmd))) + (push (format "`%s':\n" cmd) result) + (setq doc (documentation cmd t)) + (push + (concat + " " + (if doc + (substring doc 0 (string-match "\n" doc)) + "(not documented)") + "\n") + result) + (if (not keys) + (if (interactive-form cmd) + (push (format " %17s M-x %s\n" cmdstr cmd) result) + (let ((s "(not an interactive command)")) + (put-text-property 0 (length s) 'face '(:foreground "red") s) + (push (format " %17s %s\n" cmdstr s) result))) + (dolist (key keys) + (push (format " %17s " cmdstr) result) + (push (format "%s\n" + (if (eq (elt key 0) 'xmenu-bar) + "Menus" + (key-description key))) + result) + (setq cmdstr "")))))))) + (save-excursion + (with-current-buffer (help-buffer) + (with-output-to-temp-buffer (help-buffer) + (insert + (let ((s "Some important commands\n")) + (put-text-property 0 (length s) + 'face '(:weight bold + :height 1.5 + :foreground "RGB:00/00/66") s) + s)) + (setq result (reverse result)) + (dolist (r result) + (insert r)) + ))) + (message ""))) + (error (message "%s" (error-message-string err))))) + +;; Mostly copied from `where-is': +(defun key-cat-where-is (definition) + "Return key sequences that invoke the command DEFINITION. +Argument is a command definition, usually a symbol with a function definition." + (let ((func (indirect-function definition)) + (defs nil) + (all-keys)) + ;; In DEFS, find all symbols that are aliases for DEFINITION. + (mapatoms (lambda (symbol) + (and (fboundp symbol) + (not (eq symbol definition)) + (eq func (condition-case () + (indirect-function symbol) + (error symbol))) + (push symbol defs)))) + ;; Look at all the symbols--first DEFINITION, + ;; then its aliases. + (dolist (symbol (cons definition defs)) + (let* ((remapped (command-remapping symbol)) + (keys (where-is-internal + ;;symbol overriding-local-map nil nil remapped))) + symbol nil nil nil remapped))) + (when keys + (dolist (key keys) + (setq all-keys (cons key all-keys)))))) + all-keys)) + + + +(provide 'key-cat) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; key-cat.el ends here diff --git a/emacs/nxhtml/util/majmodpri.el b/emacs/nxhtml/util/majmodpri.el new file mode 100644 index 0000000..7bdbea6 --- /dev/null +++ b/emacs/nxhtml/util/majmodpri.el @@ -0,0 +1,448 @@ +;;; majmodpri.el --- Major mode priorities handling +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-26 +(defconst majmodpri:version "0.62") ;;Version: +;; Last-Updated: 2009-04-30 Thu +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Different elisp libraries may try to handle the same type of files. +;; They normally do that by entering their major mode for a file type +;; in `auto-mode-alist' or the other lists affecting `normal-mode'. +;; Since the libraries may be loaded in different orders in different +;; Emacs sessions this can lead to rather stochastic choices of major +;; mode. +;; +;; This library tries to give the control of which major modes will be +;; used back to the user. It does that by letting the user set up +;; priorities among the major modes. This priorities are used to sort +;; the lists used by `normal-mode'. +;; +;; To setup this libray and get more information do +;; +;; M-x customize-group RET majmodpri RET +;; +;; Or, see the commands `majmodpri-sort-lists'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'ourcomments-indirect-fun nil t)) + +;;;; Idle sorting + +(defvar majmodpri-idle-sort-timer nil) + +(defun majmodpri-cancel-idle-sort () + "Cancel idle sorting request." + (when majmodpri-idle-sort-timer + (cancel-timer majmodpri-idle-sort-timer) + (setq majmodpri-idle-sort-timer nil))) + +(defun majmodpri-start-idle-sort () + "Request idle sorting." + (majmodpri-cancel-idle-sort) + (setq majmodpri-idle-sort-timer + (run-with-idle-timer 0 nil 'majmodpri-sort-lists-in-timer))) + +(defun majmodpri-sort-lists-in-timer () + (condition-case err + (save-match-data ;; runs in timer + (majmodpri-sort-lists)) + (error (message "(majmodpri-sort-lists): %s" err)))) + + +;;;; Sorting + +(defvar majmodpri-schwarzian-ordnum nil) +(defun majmodpri-schwarzian-in (rec) + "Transform REC before sorting." + (setq majmodpri-schwarzian-ordnum (1+ majmodpri-schwarzian-ordnum)) + (let ((mode (cdr rec))) + (list + (list mode majmodpri-schwarzian-ordnum) + rec))) + +(defun majmodpri-schwarzian-out (rec) + "Get original value of REC after sorting." + (cadr rec)) + +;; Fix-me: default for Emacs 22?? +(defcustom majmodpri-no-nxml (< emacs-major-version 23) + "Don't use multi major modes with nxml if non-nil. +The default for Emacs prior to version 23 is to not use this +multi major modes by default since there are some problems. + +This gives those multi major mode lower priority, but it does not +prevent use of them." + :type 'boolean + :group 'majmodpri) + +;; (majmodpri-priority 'html-mumamo-mode) +;; (majmodpri-priority 'nxhtml-mumamo-mode) +(defsubst majmodpri-priority (mode) + "Return major mode MODE priority." + (if (and majmodpri-no-nxml + ;; (symbolp mode) + ;; (save-match-data + ;; (string-match "nxhtml-mumamo" (symbol-name mode)))) + (let* ((real (or (ourcomments-indirect-fun mode) + mode)) + (chunk (when real (get real 'mumamo-chunk-family))) + (major-mode (when chunk + (cadr chunk)))) + (when major-mode + (derived-mode-p 'nxml-mode)))) + 0 + (length (memq mode majmodpri-mode-priorities)))) + +(defun majmodpri-compare-auto-modes (rec1 rec2) + "Compare record REC1 and record REC2. +Comparision: + +- First check `majmodpri-mode-priorities'. +- Then use old order in list." + (let* ((schw1 (car rec1)) + (schw2 (car rec2)) + (mod1 (nth 0 schw1)) + (mod2 (nth 0 schw2)) + (ord1 (nth 1 schw1)) + (ord2 (nth 1 schw2)) + (pri1 (majmodpri-priority mod1)) + (pri2 (majmodpri-priority mod2))) + (cond + ((/= pri1 pri2) (> pri1 pri2)) + (t (> ord1 ord2))))) + +;;(benchmark 100 (quote (majmodpri-sort-lists))) +;;(defvar my-auto-mode-alist nil) +(defun majmodpri-sort-auto-mode-alist () + "Sort `auto-mode-alist' after users priorities." + (setq majmodpri-schwarzian-ordnum 0) + ;; Do not reorder function part, but put it first. + (let (fun-list + mod-list) + (dolist (rec auto-mode-alist) + (if (listp (cdr rec)) + (setq fun-list (cons rec fun-list)) + (setq mod-list (cons rec mod-list)))) + (setq fun-list (nreverse fun-list)) + (setq auto-mode-alist + (append + fun-list + (mapcar 'majmodpri-schwarzian-out + (sort + (mapcar 'majmodpri-schwarzian-in mod-list) + 'majmodpri-compare-auto-modes)))))) + +(defun majmodpri-sort-magic-list (magic-mode-list-sym) + "Sort list MAGIC-MODE-LIST-SYM after users priorities." + (let ((orig-ordnum 0)) + (set magic-mode-list-sym + ;; S out + (mapcar (lambda (rec) + (cadr rec)) + ;; Sort + (sort + ;; S in + (mapcar (lambda (rec) + (setq orig-ordnum (1+ orig-ordnum)) + (let ((mode (cdr rec))) + (list + (list mode orig-ordnum) + rec))) + (symbol-value magic-mode-list-sym)) + (lambda (rec1 rec2) + (let* ((schw1 (car rec1)) + (schw2 (car rec2)) + (mod1 (nth 0 schw1)) + (mod2 (nth 0 schw2)) + (ord1 (nth 1 schw1)) + (ord2 (nth 1 schw2)) + (pri1 (majmodpri-priority mod1)) + (pri2 (majmodpri-priority mod2))) + (cond + ((/= pri1 pri2) (> pri1 pri2)) + (t (> ord1 ord2)))))))))) + +;;;###autoload +(defun majmodpri-sort-lists () + "Sort the list used when selecting major mode. +Only sort those lists choosen in `majmodpri-lists-to-sort'. +Sort according to priorities in `majmodpri-mode-priorities'. +Keep the old order in the list otherwise. + +The lists can be sorted when loading elisp libraries, see +`majmodpri-sort-after-load'. + +See also `majmodpri-apply-priorities'." + (interactive) + ;;(message "majmodpri-sort-lists running ...") + (majmodpri-cancel-idle-sort) + (when (memq 'magic-mode-alist majmodpri-lists-to-sort) + (majmodpri-sort-magic-list 'magic-mode-alist)) + (when (memq 'auto-mode-alist majmodpri-lists-to-sort) + (majmodpri-sort-auto-mode-alist)) + (when (memq 'magic-fallback-mode-alist majmodpri-lists-to-sort) + (majmodpri-sort-magic-list 'magic-fallback-mode-alist)) + ;;(message "majmodpri-sort-lists running ... (done)") + ) + + +;;;###autoload +(defun majmodpri-apply () + "Sort major mode lists and apply to existing buffers. +Note: This function is suitable to add to +`desktop-after-read-hook'. It will restore the multi major modes +in buffers." + (majmodpri-apply-priorities t)) + +(defun majmodpri-sort-apply-to-current () + "Sort lists and apply to current buffer." + (majmodpri-sort-lists) + (add-hook 'find-file-hook 'normal-mode t t)) + +(defun majmodpri-check-normal-mode () + "Like `normal-mode', but keep major mode if same." + (let ((keep-mode-if-same t) + (old-major-mode major-mode) + (old-mumamo-multi-major-mode (when (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode))) + (report-errors "File mode specification error: %s" + (set-auto-mode t)) + ;;(msgtrc "majmodpri-check %s %s %s" (current-buffer) major-mode mumamo-multi-major-mode) + (unless (and (eq old-major-mode major-mode) + (or (not old-mumamo-multi-major-mode) + (eq old-mumamo-multi-major-mode mumamo-multi-major-mode))) + (msgtrc "majmodpri-check changing") + (report-errors "File local-variables error: %s" + (hack-local-variables)) + ;; Turn font lock off and on, to make sure it takes account of + ;; whatever file local variables are relevant to it. + (when (and font-lock-mode + ;; Font-lock-mode (now in font-core.el) can be ON when + ;; font-lock.el still hasn't been loaded. + (boundp 'font-lock-keywords) + (eq (car font-lock-keywords) t)) + (setq font-lock-keywords (cadr font-lock-keywords)) + (font-lock-mode 1)) + (message "majmodpri-apply-priorities: buffer=%s, %s,%s => %s,%s" + (current-buffer) + old-major-mode + old-mumamo-multi-major-mode + major-mode + (when (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode))))) + +;;;###autoload +(defun majmodpri-apply-priorities (change-modes) + "Apply major mode priorities. +First run `majmodpri-sort-lists' and then if CHANGE-MODES is +non-nil apply to existing file buffers. If interactive ask +before applying." + (interactive '(nil)) + (message "majmodpri-apply-priorities running ...") + (majmodpri-sort-lists) + (when (or change-modes + (with-no-warnings (called-interactively-p))) + (let (file-buffers) + (dolist (buffer (buffer-list)) + (with-current-buffer buffer + (let ((name (buffer-name)) + (file buffer-file-name)) + (or (string= (substring name 0 1) " ") ;; Internal + (not file) + (setq file-buffers (cons buffer file-buffers)))))) + (if (not file-buffers) + (when change-modes + ;;(message "majmodpri-apply-priorities: No file buffers to change modes in") + ) + (when (with-no-warnings (called-interactively-p)) + (setq change-modes + (y-or-n-p "Check major mode in all file visiting buffers? "))) + (when change-modes + (dolist (buffer file-buffers) + (with-current-buffer buffer + (let ((old-major major-mode)) + (majmodpri-check-normal-mode) + ))))))) + (message "majmodpri-apply-priorities running ... (done)")) + + +;;;; Custom + +;;;###autoload +(defgroup majmodpri nil + "Customization group for majmodpri.el" + :group 'nxhtml + ) + +(defcustom majmodpri-mode-priorities + '( + cperl-mumamo-mode + csound-sgml-mumamo-mode + django-nxhtml-mumamo-mode + django-html-mumamo-mode + embperl-nxhtml-mumamo-mode + embperl-html-mumamo-mode + eruby-nxhtml-mumamo-mode + eruby-html-mumamo-mode + genshi-nxhtml-mumamo-mode + genshi-html-mumamo-mode + jsp-nxhtml-mumamo-mode + jsp-html-mumamo-mode + laszlo-nxml-mumamo-mode + metapost-mumamo-mode + mjt-nxhtml-mumamo-mode + mjt-html-mumamo-mode + noweb2-mumamo-mode + ;;org-mumamo-mode + perl-mumamo-mode + smarty-nxhtml-mumamo-mode + smarty-html-mumamo-mode + ;;tt-html-mumamo-mode + + nxhtml-mumamo-mode + html-mumamo-mode + nxml-mumamo-mode + nxml-mode + + javascript-mode + ;;espresso-mode + rhtml-mode + ) + "Priority list for major modes. +Modes that comes first have higher priority. +See `majmodpri-sort-lists' for more information." + :type '(repeat symbol) + :set (lambda (sym val) + (set-default sym val) + (when (and (boundp 'majmodpri-sort-after-load) + majmodpri-sort-after-load) + (majmodpri-start-idle-sort))) + :group 'majmodpri) + +(defcustom majmodpri-lists-to-sort + '(magic-mode-alist auto-mode-alist magic-fallback-mode-alist) + ;;nil + "Which major mode lists to sort. +See `majmodpri-sort-lists' for more information." + :type '(set (const magic-mode-alist) + (const auto-mode-alist) + (const magic-fallback-mode-alist)) + :set (lambda (sym val) + (set-default sym val) + (when (and (boundp 'majmodpri-sort-after-load) + majmodpri-sort-after-load) + (majmodpri-start-idle-sort))) + :group 'majmodpri) + +(defcustom majmodpri-sort-after-load + '( + chart + gpl + ;;nxhtml-autoload + php-mode + rnc-mode + ruby-mode + ) + "Sort major mode lists after loading elisp libraries if non-nil. +This should not really be needed since just loading a library +should not change how Emacs behaves. There are however quite a +few thirt party libraries that does change `auto-mode-alist' +\(including some of my own) since that sometimes seems +reasonable. Some of them are in the default value of this +variable. + +There are two possibilities for sorting here: + +- Value=list of features (default). Sort immediately after loading a + library in the list. Apply to current buffer. + +- Value=t. Sort after loading any library. Sorting is then not + done immediately. Instead it runs in an idle timer. This + means that if several elisp libraries are loaded in a command + then the sorting will only be done once, after the command has + finished. After sorting apply to all buffers. + +Note that the default does break Emacs rule that loading a +library should not change how Emacs behave. On the other hand +the default tries to compensate for that the loaded libraries +breaks this rule by changing `auto-mode-alist'. + +See `majmodpri-sort-lists' for more information." + :type '(choice (const :tag "Never" nil) + (const :tag "After loading any elisp library" t) + (repeat :tag "After loading specified features" symbol)) + :set (lambda (sym val) + (set-default sym val) + ;; Clean up `after-load-alist' first. + (setq after-load-alist + (delq nil + (mapcar (lambda (rec) + (unless (member (cadr rec) + '((majmodpri-start-idle-sort) + (majmodpri-sort-lists))) + rec)) + after-load-alist))) + (when val + ;;(message "majmodpri-sort-after-load: val=%s" val) + (let ((sort-and-apply nil)) + (if (not (listp val)) + (add-to-list 'after-load-alist + (if (eq val t) + '(".*" (majmodpri-start-idle-sort)) + '("." (majmodpri-sort-lists)))) + (dolist (feat val) + ;;(message "feat=%s" feat) + (if (featurep feat) + (setq sort-and-apply t) + (if (eq val t) + (eval-after-load feat '(majmodpri-start-idle-sort)) + (eval-after-load feat '(majmodpri-sort-apply-to-current)))))) + (when sort-and-apply + ;;(message "majmodpri-sort-after-load: sort-and-apply") + (majmodpri-apply-priorities t)) + (if (eq val t) + (majmodpri-start-idle-sort) + (majmodpri-apply-priorities t))))) + :group 'majmodpri) + + +(provide 'majmodpri) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; majmodpri.el ends here diff --git a/emacs/nxhtml/util/markchars.el b/emacs/nxhtml/util/markchars.el new file mode 100644 index 0000000..e1179b7 --- /dev/null +++ b/emacs/nxhtml/util/markchars.el @@ -0,0 +1,151 @@ +;;; markchars.el --- Mark chars fitting certain characteristics +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2010-03-22 Mon +;; Version: +;; Last-Updated: 2010-03-25 Thu +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; Required feature `markchars' was not provided. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Mark special chars, by default non-ascii, non-IDN chars. See +;; `markchars-mode'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(require 'idn) + +;;;###autoload +(defgroup markchars nil + "Customization group for `markchars-mode'." + :group 'convenience) + +(defface markchars-light + '((t (:underline "light blue"))) + "Light face for `markchars-mode' char marking." + :group 'markchars) + +(defface markchars-heavy + '((t (:underline "magenta"))) + "Heavy face for `markchars-mode' char marking." + :group 'markchars) + +(defcustom markchars-face 'markchars-heavy + "Pointer to face used for marking chars." + :type 'face + :group 'markchars) + +;; (markchars-nonidn-fun (point-max)) +;; åäö +;; character: Ã¥ (229, #o345, #xe5) +;; (idn-is-recommended 229) => t +;; 152F ; 00B7 0034 ; SL # ( ᯠâ ·4 ) CANADIAN SYLLABICS YWE â MIDDLE DOT, DIGIT FOUR # {source:835} á§4 {[source:696]} + +(defun markchars-nonidn-fun (bound) + "Font lock matcher for non-IDN, non-ascii chars." + (let* ((beg (catch 'beg + (while (< (point) bound) + (let ((char (char-after))) + (unless (or (< char 256) + (idn-is-recommended char)) + (throw 'beg (point))) + (forward-char))))) + (end (when beg + (catch 'end + (while (< (point) bound) + (let ((char (char-after (point)))) + (when (or (< char 256) + (idn-is-recommended char)) + (throw 'end (point))) + (forward-char))))))) + (when beg + (setq end (or end bound)) + (set-match-data (list (copy-marker beg) (copy-marker end))) + t))) + +(defcustom markchars-keywords (or (when (fboundp 'idn-is-recommended) 'markchars-nonidn-fun) + "[[:nonascii:]]+") + "Regexp or function for font lock to use for characters to mark. +By default it matches non-IDN, non-ascii chars." + :type '(choice (const :tag "Non-ascii chars" "[[:nonascii:]]+") + (const :tag "Non IDN chars (Unicode.org tr39 suggestions)" markchars-nonidn-fun)) + :group 'markchars) + +(defvar markchars-used-keywords nil + "Keywords currently used for font lock.") +(put 'markchars-used-keywords 'permanent-local t) + +(defun markchars-set-keywords () + "Set `markchars-used-keywords' from options." + (set (make-local-variable 'markchars-used-keywords) + (list + (list markchars-keywords + (list 0 '(put-text-property (match-beginning 0) (match-end 0) + 'face markchars-face)))))) + +;;;###autoload +(define-minor-mode markchars-mode + "Mark special characters. +Which characters to mark are defined by `markchars-keywords'. + +The default is to mark non-IDN, non-ascii chars with a magenta +underline. + +For information about IDN chars see `idn-is-recommended'. + +If you change anything in the customization group `markchars' you +must restart this minor mode for the changes to take effect." + :group 'markchars + :lighter " ø" + (if markchars-mode + (progn + (markchars-set-keywords) + (font-lock-add-keywords nil markchars-used-keywords)) + (font-lock-remove-keywords nil markchars-used-keywords)) + ;; Fix-me: Something like mumamo-mark-for-refontification should be in Emacs. + (if (fboundp 'mumamo-mark-for-refontification) + (save-restriction + (widen) + (mumamo-mark-for-refontification (point-min) (point-max))) + (font-lock-fontify-buffer))) + +;;;###autoload +(define-globalized-minor-mode markchars-global-mode markchars-mode + (lambda () (markchars-mode 1)) + :group 'markchars) + +(provide 'markchars) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; markchars.el ends here diff --git a/emacs/nxhtml/util/mlinks.el b/emacs/nxhtml/util/mlinks.el new file mode 100644 index 0000000..0f81654 --- /dev/null +++ b/emacs/nxhtml/util/mlinks.el @@ -0,0 +1,1367 @@ +;;; mlinks.el --- Minor mode making major mode dependent links +;; +;; Author: Lennar Borgman +;; Created: Tue Jan 16 2007 +(defconst mlinks:version "0.28") ;;Version: +;; Last-Updated: 2010-01-05 Tue +;; Keywords: +;; Compatibility: +;; +;; Fxeatures that might be required by this library: +;; +;; `appmenu', `cl', `mail-prsvr', `mm-util', `ourcomments-util', +;; `url-expand', `url-methods', `url-parse', `url-util', +;; `url-vars'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file implements the minor mode `mlinks-mode' that create +;; hyperlinks for different major modes. Such links can be visible or +;; invisible. The meanings of the links are defined per mode. +;; +;; Examples: +;; +;; - In in html style modes the links are visible they can mean either +;; open a file for editing, go to an achnor or view the link in a +;; web browser etc. +;; +;; - In emacs lisp mode the links are invisible, but maybe highlighed +;; when point or mouse is on them. (Having them highlighted when +;; point is on them can be a quick way to check that you have +;; spelled a symbol correct.) The meanings of the links in emacs +;; lisp mode are go to definition. +;; +;; Common to links that open a buffer in Emacs is that you can the +;; buffer opened in the same window, the other window or in a new +;; frame. The same key binding is used in all major modes for this. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; FIX-ME: url-hexify-string etc +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'appmenu nil t)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) + +(require 'rx) +(require 'url-parse) +(require 'url-expand) + +(defvar mlinks-point-hilighter-overlay nil) +(make-variable-buffer-local 'mlinks-point-hilighter-overlay) +(put 'mlinks-point-hilighter-overlay 'permanent-local t) + +;;;###autoload +(defgroup mlinks nil + "Customization group for `mlinks-mode'." + :group 'nxhtml + :group 'hypermedia) + +(defvar mlinks-link-face 'mlinks-link-face) +(defface mlinks-link-face + '((t (:inherit highlight))) + "Face normally active links have on them." + :group 'mlinks) + +(defvar mlinks-hyperactive-link-face 'mlinks-hyperactive-link-face) +(defface mlinks-hyperactive-link-face + '((t (:inherit isearch))) + "Face hyper active links have on them." + :group 'mlinks) + +(defvar mlinks-font-lock-face 'mlinks-font-lock-face) +(defface mlinks-font-lock-face + '((t :inherit link)) + "Default face for MLinks' links." + :group 'mlinks) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mode function bindings + +;;(customize-option mlinks-mode-functions) +(defcustom mlinks-mode-functions + '( + ;; For message buffer etc. + (fundamental-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (emacs-lisp-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + ;; *scractch* + (lisp-interaction-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (help-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (Info-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (Custom-mode + ((goto mlinks-elisp-custom-goto) + (hili mlinks-elisp-hili) + (hion t) + (fontify mlinks-custom-fontify) + ) + ) + (text-mode + ((goto mlinks-goto-plain-url) + (hion t) + (fontify mlinks-plain-urls-fontify) + ) + ) + (nxhtml-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + (nxml-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + (sgml-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + (html-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + ) + "Defines MLinks hyperlinks for major modes. +" + ;; Each element in the list is a list with two elements + + ;; \(MAJOR-MODE SETTINGS) + + ;; where MAJOR-MODE is the major mode for which the settings SETTINGS should be used. + ;; SETTINGS is an association list which can have the following element types + + ;; \(hili HILIGHT-FUN) ;; Mandatory + ;; \(goto GOTO-FUN) ;; Mandatory + ;; \(hion HION-BOOL) ;; Optional + ;; \(next NEXT-FUN) ;; Optional + ;; \(prev PREV-FUN) ;; Optional + + ;; Where + ;; - HILIGHT-FUN is the function to hilight a link when point is + ;; inside the link. This is done when Emacs is idle. + ;; - GOTO-FUN is the function to follow the link at point. + ;; - HION-BOOL is t or nil depending on if hilighting should be on + ;; by default. + ;; - NEXT-FUN is the function to go to the next link. + ;; - PREV-FUN is the function to go to the previous link." + ;; ;;:type '(repeat (alist :key-type symbol :value-type (alist :key-type symbol :value symbol))) + :type '(alist :key-type major-mode-function + :value-type (list + (set + (const :tag "Enable MLinks in this major mode" hion) + (const :tag "Mark All Links" mark) + (list :tag "Enable" (const :tag "Hilighting" hili) function) + (list :tag "Enable" (const :tag "Follow Link" goto) function) + (list :tag "Enable" (const :tag "Goto Next Link" next) function) + (list :tag "Enable" (const :tag "Goto Previous Link" prev) function) + ))) + :group 'mlinks) + + +(defun mlinks-get-mode-value (which) + (let* ((major major-mode) + (mode-rec (assoc major mlinks-mode-functions))) + (catch 'mode-rec + (while (and major + (not mode-rec)) + (setq major (get major 'derived-mode-parent)) + (setq mode-rec (assoc major mlinks-mode-functions)) + (when mode-rec (throw 'mode-rec nil)))) + (when mode-rec + (let* ((mode (car mode-rec)) + (funs-alist (cadr mode-rec)) + (funs (assoc which funs-alist))) + (cdr funs))))) + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Minor modes + +;; (appmenu-dump-keymap mlinks-mode-map) +(defvar mlinks-mode-map + (let ((m (make-sparse-keymap "mlinks"))) + (define-key m [(control ?c) ?\r ?\r] 'mlinks-goto) + (define-key m [(control ?c) ?\r ?w] 'mlinks-goto-other-window) + (define-key m [(control ?c) ?\r ?f] 'mlinks-goto-other-frame) + (define-key m [(control ?c) ?\r ?n] 'mlinks-next-saved-position) + (define-key m [(control ?c) ?\r ?p] 'mlinks-prev-saved-position) + (define-key m [(control ?c) ?\r S-tab] 'mlinks-backward-link) + (define-key m [(control ?c) ?\r tab] 'mlinks-forward-link) + (define-key m [(control ?c) ?\r ?h] 'mlinks-toggle-hilight) + (define-key m [(control ?c) ?\r ?c] 'mlinks-copy-link-text) + m)) + +;;;###autoload +(define-minor-mode mlinks-mode + "Recognizes certain parts of a buffer as hyperlinks. +The hyperlinks are created in different ways for different major +modes with the help of the functions in the list +`mlinks-mode-functions'. + +The hyperlinks can be hilighted when point is over them. Use +`mlinks-toggle-hilight' to toggle this feature for the current +buffer. + +All keybindings in this mode are by default done under the prefi§x +key + + C-c RET + +which is supposed to be a kind of mnemonic for link (alluding to +the RET key commonly used in web browser to follow a link). +\(Unfortunately this breaks the rules in info node `Key Binding +Conventions'.) Below are the key bindings defined by this mode: + +\\{mlinks-mode-map} + +For some major modes `mlinks-backward-link' and +`mlinks-forward-link' will take you to the previous/next link. +By default the link moved to will be active, see +`mlinks-active-links'. + +" + nil + " L" + nil + :keymap mlinks-mode-map + :group 'mlinks + (if mlinks-mode + (progn + (mlinks-add-appmenu) + (mlinks-start-point-hilighter) + (mlinks-add-font-lock)) + (mlinks-stop-point-hilighter) + (when mlinks-point-hilighter-overlay + (when (overlayp mlinks-point-hilighter-overlay) + (delete-overlay mlinks-point-hilighter-overlay)) + (setq mlinks-point-hilighter-overlay nil)) + (mlinks-remove-font-lock))) +(put 'mlinks-mode 'permanent-local t) + +(defun mlinks-turn-on-in-buffer () + (let ((hion (unless (and (boundp 'mumamo-set-major-running) + mumamo-set-major-running) + (mlinks-get-mode-value 'hion)))) + (when hion (mlinks-mode 1)))) + +;;;###autoload +(define-globalized-minor-mode mlinks-global-mode mlinks-mode + mlinks-turn-on-in-buffer + "Turn on `mlink-mode' in all buffer where it is specified. +This is specified in `mlinks-mode-functions'." + :group 'mlinks) + +;; The problem with global minor modes: +(when (and mlinks-global-mode + (not (boundp 'define-global-minor-mode-bug))) + (mlinks-global-mode 1)) + +;;(define-toggle mlinks-active-links t +(define-minor-mode mlinks-active-links + "Use quick movement keys on active links if non-nil. +When moving to an mlink with `mlinks-forward-link' or +`mlinks-backward-link' the link moved to will be in an active +state. This is marked with a new color \(the face `isearch'). +When the new color is shown the following keys are active + +\\{mlinks-hyperactive-point-hilighter-keymap} +Any command cancels this state." + :global t + :init-value t + :group 'mlinks) + + + +(defun mlinks-link-text-prop-range (pos) + (let* ((link-here (get-text-property pos 'mlinks-link)) + (beg (when link-here (previous-single-char-property-change (+ pos 1) 'mlinks-link))) + (end (when link-here (next-single-char-property-change (- pos 0) 'mlinks-link)))) + (when (and beg end) + (cons beg end)))) + +(defun mlinks-link-range (pos) + (or (mlinks-link-text-prop-range pos) + (let ((funs-- (mlinks-get-mode-value 'hili))) + (when funs-- + (save-match-data + (run-hook-with-args-until-success 'funs--)))))) + +(defun mlinks-link-at-point () + "Get link at point." + (mlinks-point-hilighter-1) + (when (and mlinks-point-hilighter-overlay + (overlay-buffer mlinks-point-hilighter-overlay)) + (let* ((ovl mlinks-point-hilighter-overlay) + (beg (overlay-start ovl)) + (end (overlay-end ovl))) + (buffer-substring-no-properties beg end)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; At point highligher + +(defvar mlinks-point-hilighter-timer nil) + +(defun mlinks-stop-point-hilighter () + (when (timerp mlinks-point-hilighter-timer) + (cancel-timer mlinks-point-hilighter-timer) + (setq mlinks-point-hilighter-timer nil))) + +(defun mlinks-start-point-hilighter () + (mlinks-stop-point-hilighter) + (setq mlinks-point-hilighter-timer + (run-with-idle-timer 0.1 t 'mlinks-point-hilighter))) + +(defvar mlinks-link-overlay-priority 100) + +(defun mlinks-make-point-hilighter-overlay (bounds) + (unless mlinks-point-hilighter-overlay + (setq mlinks-point-hilighter-overlay + (make-overlay (car bounds) (cdr bounds))) + (overlay-put mlinks-point-hilighter-overlay 'priority mlinks-link-overlay-priority) + (overlay-put mlinks-point-hilighter-overlay 'mouse-face 'highlight) + (mlinks-set-normal-point-hilight) + )) + +(defun mlinks-point-hilighter () + "Mark link at point if any. +This moves the hilight point overlay to point or deletes it." + ;; This runs in a timer, protect it. + (condition-case err + (let ((inhibit-point-motion-hooks t)) + (mlinks-point-hilighter-1)) + (error "mlinks-point-hilighter error: %s" (error-message-string err)))) + +(defun mlinks-point-hilighter-1 () + (when mlinks-mode + (let ((bounds-- (mlinks-link-range (point)))) + (if bounds-- + (if mlinks-point-hilighter-overlay + (move-overlay mlinks-point-hilighter-overlay (car bounds--) (cdr bounds--)) + (mlinks-make-point-hilighter-overlay bounds--)) + (when mlinks-point-hilighter-overlay + (delete-overlay mlinks-point-hilighter-overlay)))))) + +(defvar mlinks-hyperactive-point-hilighter-keymap + (let ((m (make-sparse-keymap "mlinks"))) + (define-key m [S-tab] 'mlinks-backward-link) + (define-key m [tab] 'mlinks-forward-link) + (define-key m "\t" 'mlinks-forward-link) + (define-key m [?\r] 'mlinks-goto) + (define-key m [?w] 'mlinks-goto-other-window) + (define-key m [?f] 'mlinks-goto-other-frame) + (define-key m [mouse-1] 'mlinks-goto) + (set-keymap-parent m mlinks-mode-map) + m)) + +(defvar mlinks-point-hilighter-keymap + (let ((m (make-sparse-keymap "mlinks"))) + (define-key m [mouse-1] 'mlinks-goto) + (set-keymap-parent m mlinks-mode-map) + m)) + +(defun mlinks-point-hilighter-pre-command () + (condition-case err + (unless (let ((map (overlay-get mlinks-point-hilighter-overlay 'keymap))) + (where-is-internal this-command + (list + map))) + (mlinks-set-normal-point-hilight) + (unless mlinks-point-hilighter-timer + (delete-overlay mlinks-point-hilighter-overlay))) + (error (message "mlinks-point-hilighter-pre-command: %s" err)))) +(put 'mlinks-point-hilighter-pre-command 'permanent-local t) + +(defun mlinks-set-hyperactive-point-hilight () + "Make link hyper active, ie add some special key binding. +Used after jumping specifically to a link. The idea is that the +user may want to easily jump between links in this state." + (add-hook 'pre-command-hook 'mlinks-point-hilighter-pre-command nil t) + (mlinks-point-hilighter) + (overlay-put mlinks-point-hilighter-overlay 'face mlinks-hyperactive-link-face) + (overlay-put mlinks-point-hilighter-overlay 'keymap mlinks-hyperactive-point-hilighter-keymap)) + +(defun mlinks-set-normal-point-hilight () + "Make link normally active as if you happened to be on it." + (remove-hook 'pre-command-hook 'mlinks-point-hilighter-pre-command t) + (mlinks-point-hilighter) + (overlay-put mlinks-point-hilighter-overlay 'face mlinks-link-face) + (overlay-put mlinks-point-hilighter-overlay 'keymap mlinks-point-hilighter-keymap)) + +(defun mlinks-set-point-hilight-after-jump-to () + "Set hilight style after jump to link." + (if mlinks-active-links + (mlinks-set-hyperactive-point-hilight) + (mlinks-set-normal-point-hilight))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Jumping around + +(defvar mlinks-places nil) +(make-variable-buffer-local 'mlinks-placesn) +(put 'mlinks-places 'permanent-local t) + +(defvar mlinks-places-n 0) +(make-variable-buffer-local 'mlinks-places-n) +(put 'mlinks-places-n 'permanent-local t) + +(defun mlinks-has-links () + (or (mlinks-get-mode-value 'fontify) + (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + ;; Fix-me: just assume multi major has it... Need a list of + ;; major modes. There is no way to get such a list for the + ;; multi major mode (since you can't know what the chunk + ;; functions will return. However you can get a list of + ;; current chunks major mode. + t + ))) + +(defun mlinks-backward-link () + "Go to previous `mlinks-mode' link in buffer." + (interactive) + (if (not (mlinks-has-links)) + (message "There is no way to go to previous link for this major mode") + (let ((res (mlinks-prev-link))) + (if res + (progn + (goto-char res) + (mlinks-set-point-hilight-after-jump-to)) + (message "No previous link found"))))) + +(defun mlinks-forward-link () + "Go to next `mlinks-mode' link in buffer." + (interactive) + (if (not (mlinks-has-links)) + (message "There is no way to go to next link for this major mode") + (let ((res (mlinks-next-link))) + (if res + (progn + (goto-char res) + (mlinks-set-point-hilight-after-jump-to)) + (message "No next link found"))))) + + +(defun mlinks-goto () + "Follow `mlinks-mode' link at current point. +Save the current position so that they can be move to again by +`mlinks-prev-saved-position' and `mlinks-next-saved-position'. + +Return non-nil if link was followed, otherewise nil." + (interactive) + (mlinks-goto-1 nil)) + +(defun mlinks-goto-other-window () + "Like `mlinks-goto' but opens in other window. +Uses `switch-to-buffer-other-window'." + (interactive) + (mlinks-goto-1 'other-window)) + +(defun mlinks-goto-other-frame () + "Like `mlinks-goto' but opens in other frame. +Uses `switch-to-buffer-other-frame'." + (interactive) + (mlinks-goto-1 'other-frame)) + +(defun mlinks-goto-1(where) + (push-mark) + (let* ((funs (mlinks-get-mode-value 'goto)) + (old (point-marker)) + (mlinks-temp-buffer-where where) + (res (run-hook-with-args-until-success 'funs))) + (if (not res) + (progn + (message "Don't know how to follow this MLink link") + nil) + (unless (= old (point-marker)) + (let* ((prev (car mlinks-places))) + (when (or (not prev) + ;;(not (markerp prev)) + (not (marker-buffer prev)) + (/= old prev)) + (setq mlinks-places (cons old mlinks-places)) + (setq mlinks-places-n (length mlinks-places)))))))) + + +(defun mlinks-prev-saved-position () + "Go to previous position saved by `mlinks-goto'." + (interactive) + (unless (mlinks-goto-n (1- mlinks-places-n)) + (message "No previous MLink position"))) + +(defun mlinks-next-saved-position () + "Go to next position saved by `mlinks-goto'." + (interactive) + (unless (mlinks-goto-n (1+ mlinks-places-n)) + (message "No next MLink position"))) + +(defun mlinks-goto-n (to) + (if (not mlinks-places) + (message "No saved MLinks positions") + (let ((minp 1) + (maxp (length mlinks-places))) + (if (<= to minp) + (progn + (setq to minp) + (message "Going to first MLinks position")) + (if (>= to maxp) + (progn + (setq to maxp) + (message "Going to last MLinks position")))) + (setq mlinks-places-n to) + (let ((n (- maxp to)) + (places mlinks-places) + place + buffer + point) + (while (> n 0) + (setq places (cdr places)) + (setq n (1- n))) + (setq place (car places)) + (mlinks-switch-to-buffer (marker-buffer place)) + (goto-char place))))) + +(defvar mlinks-temp-buffer-where nil) +(defun mlinks-switch-to-buffer (buffer) + (mlinks-switch-to-buffer-1 buffer mlinks-temp-buffer-where)) + +(defun mlinks-switch-to-buffer-1(buffer where) + (cond + ((null where) + (switch-to-buffer buffer)) + ((eq where 'other-window) + (switch-to-buffer-other-window buffer)) + ((eq where 'other-frame) + (switch-to-buffer-other-frame buffer)) + (t + (error "Invalid argument, where=%s" where)))) + +;; FIXME: face, var +(defun mlinks-custom (var) + (customize-option var) + ) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; AppMenu support + +(defun mlinks-appmenu () + (when mlinks-mode + ;; Fix-me: reverse the list + (let ((link-val (mlinks-link-at-point)) + (map (make-sparse-keymap "mlinks")) + (num 2)) + (when (mlinks-get-mode-value 'prev) + (define-key map [mlinks-next-link] + (list 'menu-item "Next Link" 'mlinks-forward-link))) + (when (mlinks-get-mode-value 'next) + (define-key map [mlinks-prev-link] + (list 'menu-item "Previous Link" 'mlinks-backward-link))) + (when link-val + (let* ((possible (when (member major-mode '(html-mode nxhtml-mode nxml-mode sqml-mode text-mode)) + (mlinks-html-possible-href-actions link-val))) + (mailto (assoc 'mailto possible)) + (view-web (assoc 'view-web possible)) + (view-web-base (assoc 'view-web-base possible)) + (edit (assoc 'edit possible)) + (file (nth 1 edit)) + (anchor (nth 2 edit)) + (choices) + (answer) + ) + (when (> (length map) num) + (define-key map [mlinks-href-sep] (list 'menu-item "--"))) + (setq num (length map)) + (when view-web + (define-key map [mlinks-href-view-web] + (list 'menu-item "Browse Link Web Url" + `(lambda () (interactive) + (browse-url ,link-val))))) + (when view-web-base + (define-key map [mlinks-href-view-web-based] + (list 'menu-item "Browse Link Web Url (base URL found)" + `(lambda () (interactive) + (browse-url (cdr ,view-web-base)))))) + (when mailto + (define-key map [mlinks-href-mail] + (list 'menu-item (concat "&Mail to " (substring link-val 7)) + `(lambda () (interactive) + (mlinks-html-mail-to ,link-val))))) + (when edit + (when (and (file-exists-p file) + (not anchor) + (assoc 'upload possible)) + (let ((abs-file (expand-file-name file))) + (define-key map [mlinks-href-upload] + (list 'menu-item "Upload Linked File" + `(lambda () (interactive) + (html-upl-upload-file ,abs-file)))))) + (when (and (file-exists-p file) + (not anchor) + (assoc 'edit-gimp possible)) + (let ((abs-file (expand-file-name file))) + (define-key map [mlinks-href-edit-gimp] + (list 'menu-item "Edit Linked File with GIMP" + `(lambda () (interactive) + (gimpedit-edit-file ,abs-file)))))) + (when (and (file-exists-p file) + (assoc 'view-local possible)) + (let ((url (concat "file:///" (expand-file-name file)))) + (when anchor + (let ((url-anchor (concat url "#" anchor))) + (define-key map [mlinks-href-view-file-at] + (list 'menu-item (concat "Browse Linked File URL at #" anchor) + `(lambda () (interactive) + (browse-url ,url-anchor)))))) + (define-key map [mlinks-href-view-file] + (list 'menu-item "&Browse Linked File URL" + `(lambda () (interactive) + (browse-url ,url)))))) + (when (> (length map) num) + (define-key map [mlinks-href-sep-2] (list 'menu-item "--"))) + (setq num (length map)) + (unless (equal file (buffer-file-name)) + (define-key map [mlinks-href-edit] + (list 'menu-item "&Open Linked File" + `(lambda () (interactive) (mlinks-goto)))) + (define-key map [mlinks-href-edit-window] + (list 'menu-item "&Open Linked File in Other Window" + `(lambda () (interactive) (mlinks-goto-other-window)))) + (define-key map [mlinks-href-edit-frame] + (list 'menu-item "&Open Linked File in New Frame" + `(lambda () (interactive) (mlinks-goto-other-frame)))) + ) + (when (and (file-exists-p file) anchor) + (define-key map [mlinks-href-edit-at] + (list 'menu-item (concat "Open Linked File &at #" anchor) + `(lambda () (interactive) + (mlinks-goto))))) + ) + (when (> (length map) num) + (define-key map [mlinks-href-sep-1] (list 'menu-item "--"))) + (setq num (length map)) + (when link-val + (define-key map [mlinks-href-copy-link] + (list 'menu-item "&Copy Link Text" + 'mlinks-copy-link-text))))) + (when (> (length map) 2) + map)))) + +(defun mlinks-add-appmenu () + "Add entries for MLinks to AppMenu." + (when (featurep 'appmenu) + (appmenu-add 'mlinks 100 'mlinks-mode "Current MLink" 'mlinks-appmenu))) + +(defun mlinks-copy-link-text () + "Copy text of `mlinks-mode' link at point to clipboard." + (interactive) + (mlinks-point-hilighter) + (let ((ovl mlinks-point-hilighter-overlay)) + (if (and ovl + (overlayp ovl) + (overlay-buffer ovl) + (eq (current-buffer) + (overlay-buffer ovl)) + (<= (overlay-start ovl) + (point)) + (>= (overlay-end ovl) + (point))) + (let* ((beg (overlay-start ovl)) + (end (overlay-end ovl)) + (str (buffer-substring beg end))) + (copy-region-as-kill beg end) + (message "Copied %d chars to clipboard" (length str))) + (message "No link here to copy")))) + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; text-mode etc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defvar mlinks-plain-urls-regexp + (rx-to-string `(or (submatch (optional "mailto:") + (regexp ,(concat + ;;"[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*" + "[a-z0-9$%(*=?[_-][^<>\")!;:,{}]*" + "\@" + "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}"))) + (submatch (or (regexp "https?://") + "www.") + (1+ (any ,url-get-url-filename-chars)) + ) + ))) + +(defun mlinks-plain-urls-fontify (bound) + (mlinks-fontify bound mlinks-plain-urls-regexp 0)) + +(defun mlinks-goto-plain-url () + (let* ((range (mlinks-link-range (point))) + (link (when range (buffer-substring-no-properties (car range) (cdr range))))) + ;;(mlinks-html-href-act-on link) + (when (= 0 (string-match mlinks-plain-urls-regexp link)) + (let ((which (if (match-end 1) 1 2))) + (cond + ((= 1 which) + (mlinks-html-mail-to link) + t) + ((= 2 which) + (browse-url link) + t) + (t nil)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; nxhtml-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun mlinks-html-style-goto () + (mlinks-html-style-mode-fun t)) + +(defvar mlinks-html-link-regexp + ;; This value takes care of nxhtml-strval-mode (and is therefore a little bit incorrect ...) + ;;"\\(?:^\\|[[:space:]]\\)\\(?:href\\|src\\)[[:space:]]*=[[:space:]]*\"\\([^<«\"]*\\)\"" + (rx (or "^" space) + (or "href" "src") + (0+ space) + "=" + (0+ space) + (submatch + (or + (seq "\"" + (and + (0+ (not (any "\"")))) + "\"") + (seq "'" + (and + (0+ (not (any "\'")))) + "'"))))) + +(defun mlinks-html-style-mode-fun (goto) + (let (start + end + bounds) + (save-excursion + (forward-char) + (when (< 0 (skip-chars-forward "^\"'" (line-end-position))) + (forward-char) + (save-match-data + (when (looking-back + mlinks-html-link-regexp + (line-beginning-position -1)) + (let ((which (if (match-beginning 1) 1 2))) + (setq start (1+ (match-beginning which))) + (setq end (1- (match-end which)))) + (setq bounds (cons start end)))))) + (when start + (if (not goto) + bounds + (let ((href-val (buffer-substring-no-properties start end))) + (mlinks-html-href-act-on href-val)) + t)))) + +(defun mlink-check-file-to-edit (file) + (assert (file-name-absolute-p file)) + (let ((file-dir (file-name-directory file))) + (unless (file-directory-p file-dir) + (if (file-directory-p (file-name-directory file)) + (if (yes-or-no-p (format "Directory %s does not exist. Create it? " file-dir)) + (make-directory file-dir) + (setq file nil)) + (if (yes-or-no-p (format "Directory %s and its parent does not exist. Create them? " file-dir)) + (make-directory file-dir t) + (setq file nil)))) + file)) + +(defun mlinks-html-edit-at (file &optional anchor) + (let ((abs-file (if (file-name-absolute-p file) + file + (expand-file-name file)))) + (if (or (file-directory-p abs-file) + (string= abs-file + (file-name-as-directory abs-file))) + (if (file-directory-p abs-file) + (when (y-or-n-p (format "Do you want to edit the directory %s? : " abs-file)) + (dired abs-file)) + (message "Can't find directory %s" abs-file)) + (when (mlink-check-file-to-edit abs-file) + (let ((b (find-file-noselect abs-file))) + (mlinks-switch-to-buffer b)) + (when anchor + (let ((here (point)) + (anchor-regexp (concat "\\(?:id\\|name\\)[[:space:]]*=[[:space:]]*\"" anchor "\""))) + (goto-char (point-min)) + (if (search-forward-regexp anchor-regexp nil t) + (backward-char 2) + (message "Anchor \"%s\" not found" anchor) + (goto-char here)))))))) + +(defun mlinks-html-mail-to (addr) + (browse-url addr)) + +(defun mlinks-html-href-act-on (href-val) + (if href-val + (let* ((possible (mlinks-html-possible-href-actions href-val)) + (edit (assoc 'edit possible)) + (file (nth 1 edit)) + (anchor (nth 2 edit)) + ) + (cond (edit + (mlinks-html-edit-at file anchor) + t) + ((assoc 'mailto possible) + (when (y-or-n-p "This is a mail address. Do you want to send a message to this mail address? ") + (mlinks-html-mail-to href-val))) + ((assoc 'view-web possible) + (when (y-or-n-p "Can't edit this URL, it is on the web. View the URL in your web browser? ") + (browse-url href-val))) + ((assoc 'view-web-base possible) + (when (y-or-n-p "Can't edit, based URL is to the web. View resulting URL in your web browser? ") + (browse-url (cdr (assoc 'view-web-base possible))))) + (t + (message "Do not know how to handle this URL")) + )) + (message "No value for href attribute"))) + +(defun mlinks-html-possible-href-actions (link) + (let ((urlobj (url-generic-parse-url link)) + (edit nil) + (possible nil)) + (cond ((member (url-type urlobj) '("http" "https")) + (add-to-list 'possible (cons 'view-web link))) + ((member (url-type urlobj) '("mailto")) + (add-to-list 'possible (cons 'mailto link))) + ((url-host urlobj) + (message "Do not know how to handle this URL")) + (t (setq edit t))) + (when edit + (let ((base-href (mlinks-html-find-base-href))) + (when base-href + (let ((baseobj (url-generic-parse-url base-href))) + (setq edit nil) + (cond ((member (url-type baseobj) '("http" "https")) + (add-to-list 'possible (cons 'view-web-base (url-expand-file-name link base-href)))) + ((url-host urlobj) + (message "Do not know how to handle this URL")) + (t (setq edit t))))) + (when edit + (let* ((full (split-string (url-filename urlobj) "#")) + (file (nth 0 full)) + (anchor (nth 1 full)) + ) + (when (equal file "") + (setq file (buffer-file-name))) + (when base-href + ;; We know at this point it is not a http url + (setq file (expand-file-name file base-href))) + (let ((ext (downcase (file-name-extension file)))) + (when (member ext '("htm" "html")) + (add-to-list 'possible (cons 'view-local (list file anchor)))) + (when (and (featurep 'gimpedit) + (member ext '("gif" "png" "jpg" "jpeg"))) + (add-to-list 'possible (cons 'edit-gimp (list file anchor))))) + (when (featurep 'html-upl) + (add-to-list 'possible (cons 'upload (list file anchor)))) + (add-to-list 'possible (cons 'edit (list file anchor))))))) + possible)) + +(defun mlinks-html-find-base-href () + "Return base href found in the current file." + (let ((base-href)) + (save-excursion + (goto-char (point-min)) + (while (and (not base-href) + (search-forward-regexp "<!--[^!]*-->\\|<base[[:space:]]" nil t)) + (when (equal " " (char-to-string (char-before))) + (backward-char 6) + (when (looking-at "<base [^>]*href *= *\"\\(.*?\\)\"") + (setq base-href (match-string-no-properties 1)))))) + base-href)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; Custom-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun mlinks-elisp-custom-goto () + (mlinks-elisp-mode-fun 'custom)) + +(defvar mlinks-custom-link-regexp + (rx "`" + (group + (1+ (not (any "'")))) + "'")) + +(defun mlinks-custom-fontify (bound) + (mlinks-fontify bound mlinks-custom-link-regexp 0)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; emacs-lisp-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun mlinks-elisp-goto () + (mlinks-elisp-mode-fun 'source)) + +(defun mlinks-elisp-hili () + (mlinks-elisp-mode-fun nil)) + +(defun mlinks-elisp-mode-fun (goto) + (let ((symbol-name (thing-at-point 'symbol))) + (when symbol-name + (let ((bounds-- (bounds-of-thing-at-point 'symbol)) + ret--) + (if (save-excursion + (goto-char (cdr bounds--)) + (looking-back (concat "(\\(?:require\\|featurep\\)\s+'" symbol-name) + (line-beginning-position))) + (progn + (setq ret-- bounds--) + (when goto + (mlinks-elisp-mode-require symbol-name))) + (when (mlinks-elisp-mode-symbol symbol-name goto) + (setq ret-- bounds--))) + ret--)))) + +(defun mlinks-elisp-function (symbol) + "Go to an elisp function." + (interactive "aElisp function: ") + (mlinks-elisp-mode-symbol (symbol-name symbol) 'source)) + +(defun mlinks-elisp-mode-symbol (symbol-name-- goto--) + ;; Fix-me: use uninterned variables (see mail from Miles) + ;; Make these names a bit strange because they are boundp at the time of checking: + (let ((symbol-- (intern-soft symbol-name--)) + defs--) + (when (and symbol-- (boundp symbol--)) + (add-to-list 'defs-- 'variable)) + (when (fboundp symbol--) + (add-to-list 'defs-- 'function)) + (when (facep symbol--) + (add-to-list 'defs-- 'face)) + ;; Avoid some fails hits + (when (memq symbol-- + '(goto t + bounds-- funs-- ret-- + symbol-- defs-- symbol-name-- goto--)) + (setq defs-- nil)) + (let (defs-places + def) + (if (not goto--) + (progn + defs--) + (if (not defs--) + (progn + (message "Could not find definition of '%s" symbol-name--) + nil) + (dolist (type (cond + ((eq goto-- 'source) + '(nil defvar defface)) + ((eq goto-- 'custom) + '(defvar defface)) + (t + (error "Bad goto-- value: %s" goto--)))) + (condition-case err + (add-to-list 'defs-places + (cons + type + (save-excursion + (let* ((bp (find-definition-noselect symbol-- type)) + (b (car bp)) + (p (cdr bp))) + (unless p + (with-current-buffer b + (save-restriction + (widen) + (setq bp (find-definition-noselect symbol-- type))))) + bp)))) + (error + ;;(lwarn '(mlinks) :error "%s" (error-message-string err)) + (when t + (cond + ((eq (car err) 'search-failed)) + ((and (eq (car err) 'error) + (string= (error-message-string err) + (format "Don't know where `%s' is defined" symbol--)))) + (t + (message "%s: %s" (car err) (error-message-string err)))))))) + (if (= 1 (length defs-places)) + (setq def (car defs-places)) + (let ((many nil) + lnk) + (dolist (d defs-places) + (if (not lnk) + (setq lnk (cdr d)) + (unless (equal lnk (cdr d)) + (setq many t)))) + (if (not many) + (setq def (car defs-places)) + (let* ((alts (mapcar (lambda (elt) + (let ((type (car elt)) + str) + (setq str + (cond + ((not type) + "Function") + ((eq type 'defvar) + "Variable") + ((eq type 'defface) + "Face"))) + (cons str elt))) + defs-places)) + (stralts (mapcar (lambda (elt) + (car elt)) + alts)) + (completion-ignore-case t) + (stralt (completing-read "Type: " stralts nil t)) + (alt (assoc stralt alts))) + (setq def (cdr alt)))))) + (when def + (cond + ((eq goto-- 'source) + ;; Be sure to go to the real sources from CVS: + (let* ((buf (car (cdr def))) + ;; Avoid going to source + ;;(file (find-source-lisp-file (with-current-buffer buf buffer-file-name)) ) + (file (with-current-buffer buf buffer-file-name)) + (orig-buf (find-file-noselect file))) + (mlinks-switch-to-buffer orig-buf) + (let ((p (cdr (cdr def)))) + ;; Fix-me: Move this test to a more general place. + (if (or (< p (point-min)) + (> p (point-max))) + ;; Check for cloned indirect buffers. + (progn + (setq orig-buf + (catch 'view-in-buf + (dolist (indirect-buf (buffer-list)) + ;;(message "base-buffer=%s, orig-buf=%s, eq => %s" (buffer-base-buffer indirect-buf) orig-buf (eq (buffer-base-buffer indirect-buf) orig-buf)) + (when (eq (buffer-base-buffer indirect-buf) orig-buf) + (with-current-buffer indirect-buf + ;;(message "indirect-buf=%s" indirect-buf) + (unless (or (< p (point-min)) + (> p (point-max))) + ;;(message "switching") + ;;(mlinks-switch-to-buffer indirect-buf) + (message "mlinks: Switching to indirect buffer because of narrowing") + (throw 'view-in-buf indirect-buf) + )) + )))) + (when orig-buf + (mlinks-switch-to-buffer orig-buf)) + ;;(message "cb=%s" (current-buffer)) + (if (or (< p (point-min)) + (> p (point-max))) + (when (y-or-n-p (format "%s is invisible because of narrowing. Widen? " symbol--)) + (widen) + (goto-char p)) + (goto-char p))) + (goto-char p))))) + ((eq goto-- 'custom) + (mlinks-custom symbol--)) + (t + (error "Back goto-- value again: %s" goto--))))))))) + +(defun mlinks-elisp-mode-require (module) + (let ((where mlinks-temp-buffer-where)) + (cond + ((null where) + (find-library module)) + ((eq where 'other-window) + (other-window 1) + (find-library module)) + ((eq where 'other-frame) + (make-frame-command) + (find-library module)) + (t + (error "Invalid argument, where=%s" where))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;; Helpers when adopting for modes ;;;;;;;;;;;;;;;;; + +;;; Save this, do not delete this comment: + +;; (defun mlinks-hit-test () +;; "Just a helper function for adding support for new modes." +;; (let* ( +;; (s0 (if (match-string 0) (match-string 0) "")) +;; (s1 (if (match-string 1) (match-string 1) "")) +;; (s2 (if (match-string 2) (match-string 2) "")) +;; (s3 (if (match-string 3) (match-string 3) "")) +;; ) +;; (message "match0=%s, match1=%s, match2=%s, match3=%s" s0 s1 s2 s3))) + +;; (defun mlinks-handle-reg-fun-list (reg-fun-list) +;; "Just a helper function." +;; (let (done +;; regexp +;; hitfun +;; m +;; p +;; b +;; ) +;; (dolist (rh reg-fun-list) +;; (message "rh=%s" rh);(sit-for 2) +;; (unless done +;; (setq regexp (car rh)) +;; (setq hitfun (cadr rh)) +;; (message "regexp=%s, hitfun=%s" regexp hitfun);(sit-for 1) +;; (when (and (save-match-data +;; (setq m (re-search-backward regexp (line-beginning-position) t)) +;; (> p (match-beginning 0)))) +;; (setq done t) +;; (setq b (match-beginning 0)) +;; (setq e (match-end 0)) +;; ) +;; (if (not (and b e +;; (< b p) +;; (< p e))) +;; (message "MLinks Mode did not find any link here") +;; (goto-char b) +;; (if (not (looking-at regexp)) +;; (error "Internal error, regexp %s, no match looking-at" regexp) +;; (let ((last (car mlinks-places)) +;; (m (make-marker))) +;; (set-marker m (line-beginning-position)) +;; (when (or (not last) +;; (/= m last)) +;; (setq mlinks-places (cons m mlinks-places)))) +;; (funcall hitfun)) +;; ))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font Lock use + +(defvar mlinks-link-update-pos-max nil) +(make-variable-buffer-local 'mlinks-link-update-pos-max) +(put 'mlinks-link-update-pos-max 'permanent-local t) + +(defun mlinks-remove-font-lock () + "Remove info from font-lock." + (when (mlinks-want-font-locking) + (mlink-font-lock nil))) + +(defun mlinks-add-font-lock () + "Add info to font-lock." + (when (mlinks-want-font-locking) + (mlink-font-lock t))) + +(defun mlinks-want-font-locking () + (or (mlinks-get-mode-value 'fontify) + (mlinks-get-mode-value 'next-mark))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font Lock integration + +(defun mlink-font-lock (on) + (let* ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords)) + (fontify-fun (car (mlinks-get-mode-value 'fontify))) + (args (list nil `(( ,fontify-fun ( 0 mlinks-font-lock-face t )))))) + (when fontify-fun + ;; Note: Had a lot of trouble with this which I modelled first + ;; after dlink. Using hi-lock as a model made it work with + ;; mumamo too. + ;; + ;; Next arg, HOW, is needed to get it to work with mumamo. This + ;; adds it last, like hi-lock. + (when on (setq args (append args (list t)))) + (apply add-or-remove args) + (font-lock-mode -1) + (font-lock-mode 1)))) + +(defun mlinks-html-fontify (bound) + (mlinks-fontify bound mlinks-html-link-regexp 1)) + +(defun mlinks-fontify (bound regexp border) + (let ((start (point)) + end-start + stop next-stop + (more t) + old-beg old-end + (wn 1) + ret) + ;; Note: we shouldnot use save-match-data here. Instead + ;; set-match-data is called below! + (if (not (re-search-forward regexp bound t)) + (setq end-start bound) + (setq ret t) + (setq end-start (- (point) 2)) + (let* ((which (if (match-beginning 1) 1 2)) + (beg (+ (match-beginning which) border)) + (end (- (match-end which) border))) + (put-text-property beg end 'mlinks-link t) + (set-match-data (list (copy-marker end) (copy-marker beg))))) + (setq stop start) + (setq next-stop -1) + (while (and (> 100 (setq wn (1+ wn))) + (setq next-stop (next-single-char-property-change stop 'mlinks-link nil end-start)) + (/= next-stop stop)) + (setq stop next-stop) + (if (get-text-property stop 'mlinks-link) + (setq old-beg stop) + (when old-beg + (remove-list-of-text-properties old-beg stop '(mlinks-link 'mouse-face))))) + ret)) + +(defun mlinks-next-link () + "Find next link, fontify as necessary." + (let* ((here (point)) + (prev-pos (point)) + (fontified-here (get-text-property (max (point-min) (1- prev-pos)) 'fontified)) + (fontified-to (next-single-char-property-change prev-pos 'fontified)) + (pos (next-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-to (point-max)))) + (fontified-all (and fontified-here (not fontified-to))) + ready + next-fontified-to) + (while (not (or ready + (and fontified-all + (not pos)))) + (if pos + (progn + (unless (get-text-property pos 'mlinks-link) + ;; Get to next link + (setq prev-pos pos) + (setq pos (next-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-to (point-max))))) + (when pos + (setq ready (get-text-property pos 'mlinks-link)) + (setq prev-pos pos) + (unless ready (setq pos nil)))) + (unless (or fontified-all fontified-to) + (if (get-text-property prev-pos 'fontified) + (setq fontified-all + (not (setq fontified-to + (next-single-char-property-change prev-pos 'fontified)))) + (setq fontified-to ( or (previous-single-char-property-change prev-pos 'fontified) + 1)))) + (setq next-fontified-to (min (+ fontified-to 5000) + (point-max))) + (mumamo-with-buffer-prepared-for-jit-lock + (progn + (put-text-property fontified-to next-fontified-to 'fontified t) + (font-lock-fontify-region fontified-to next-fontified-to))) + (setq fontified-to (next-single-char-property-change (1- next-fontified-to) + 'fontified)) + (setq fontified-all (not fontified-to)) + (setq pos (next-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-to (point-max)))))) + (when ready prev-pos))) + +(defun mlinks-prev-link () + "Find previous link, fontify as necessary." + (let* ((prev-pos (point)) + (fontified-from (previous-single-char-property-change prev-pos 'fontified)) + (fontified-here (get-text-property (max (point-min) (1- prev-pos)) 'fontified)) + (fontified-all (and fontified-here (not fontified-from))) + (pos (when fontified-here + (previous-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-from 1)))) + ready + next-fontified-from) + (while (not (or ready + (and fontified-all + (not pos)))) + (assert (numberp prev-pos) t) + (if pos + (progn + (when (and (> (1- pos) (point-min)) + (get-text-property (1- pos) 'mlinks-link)) + ;; Get out of current link + (setq prev-pos pos) + (setq pos (previous-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-from 1)))) + (when pos + (setq prev-pos pos) + (setq ready (and (get-text-property pos 'fontified) + (or (= 1 pos) + (not (get-text-property (1- pos) 'mlinks-link))) + (get-text-property pos 'mlinks-link))) + (unless ready (setq pos nil)))) + (setq next-fontified-from (max (- fontified-from 5000) + (point-min))) + (mumamo-with-buffer-prepared-for-jit-lock + (progn + (put-text-property next-fontified-from fontified-from 'fontified t) + (font-lock-fontify-region next-fontified-from fontified-from))) + (setq fontified-from (previous-single-char-property-change + (1+ next-fontified-from) 'fontified)) + (setq fontified-all (not fontified-from)) + (setq pos (previous-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-from 1))))) + (when ready pos))) + + +;;; This is for the problem reported by some Asian users: +;;; +;;; Lisp error: (invalid-read-syntax "] in a list") +;;; +;; Local Variables: +;; coding: utf-8 +;; End: + +(provide 'mlinks) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mlinks.el ends here diff --git a/emacs/nxhtml/util/mumamo-aspnet.el b/emacs/nxhtml/util/mumamo-aspnet.el new file mode 100644 index 0000000..c6bb2c7 --- /dev/null +++ b/emacs/nxhtml/util/mumamo-aspnet.el @@ -0,0 +1,227 @@ +;;; mumamo-aspnet.el --- Support for ASP .Net in `mumamo-mode'. +;; +;;;;; John: Please change here to what you want: +;; Author: John J Foerch (jjfoerch A earthlink O net) +;; Maintainer: +;; Created: ?? +;; Version: == +;; Last-Updated: Wed Dec 12 21:55:11 2007 (3600 +0100) +;; URL: http://OurComments.org/Emacs/Emacs.html +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Support for ASP .Net in `mumamo-mode'. If you want to use VB then +;; you have to get the vb mode that this is written for here: +;; +;; http://www.emacswiki.org/cgi-bin/wiki/VbDotNetMode +;; +;; A C# mode is already included in nXhtml. That is the one that this +;; library has been tested with. +;; +;; +;;; Usage: +;; +;; Put this file in you Emacs `load-path' and add in your .emacs: +;; +;; (eval-after-load 'mumamo +;; (require 'mumamo-aspnet) +;; (mumamo-aspnet-add-me)) +;; +;; A file with the extension .aspx will no be opened with nxhtml-mode +;; as the main major mode and with chunks in csharp-mode etc. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(eval-when-compile (require 'mumamo)) + +;;; + +;; (defun mumamo-aspnet-add-me() +;; "Make mumamo aware of the ASP.Net extension." +;; (add-to-list 'mumamo-chunk-family-list +;; '("ASP.Net nXhtml Family" nxhtml-mode +;; (mumamo-chunk-aspnet +;; mumamo-chunk-aspnet-script +;; mumamo-chunk-inlined-style +;; mumamo-chunk-inlined-script +;; mumamo-chunk-style= +;; mumamo-chunk-onjs= +;; )) +;; t) +;; (add-to-list 'mumamo-chunk-family-list +;; '("ASP.Net XHTML Family" html-mode +;; (mumamo-chunk-aspnet +;; mumamo-chunk-aspnet-script +;; mumamo-chunk-inlined-style +;; mumamo-chunk-inlined-script +;; mumamo-chunk-style= +;; mumamo-chunk-onjs= +;; )) +;; t) + + +;; (add-to-list 'mumamo-filenames-list +;; '("\\.aspx\\'" "ASP.Net nXhtml Family")) +;; ;; Make it SET for current session in Custom. +;; (customize-set-variable 'mumamo-filenames-list mumamo-filenames-list) +;; (customize-set-value 'mumamo-filenames-list mumamo-filenames-list) + +;; ;; this is how to set up mode aliases, should we need them. +;; (add-to-list 'mumamo-major-modes '(csharp-mode csharp-mode)) +;; (add-to-list 'mumamo-major-modes '(vbnet-mode vbnet-mode)) +;; ;; Make it SET for current session in Custom. +;; (customize-set-variable 'mumamo-major-modes mumamo-major-modes) +;; (customize-set-value 'mumamo-major-modes mumamo-major-modes) +;; ) + + +;;; aspnet + +(defvar mumamo-aspnet-page-language-mode-spec nil + "A mumamo mode-spec for the default language of an ASP.Net page. +This is what is set with the directive `@ Page Language' on the +page. + +Internal variable.") +(make-variable-buffer-local 'mumamo-aspnet-page-language-mode-spec) +;;(add-to-list 'mumamo-survive 'mumamo-aspnet-page-language-mode-spec) +(put 'mumamo-aspnet-page-language-mode-spec 'permanent-local t) + +(defconst mumamo-aspnet-language-regex + (rx (0+ (not (any ">"))) + word-start "language" (0+ space) "=" (0+ space) ?\" (submatch (0+ (not (any ?\" ?>)))) ?\" + )) + +(defun mumamo-aspnet-get-page-language-mode-spec () + (or mumamo-aspnet-page-language-mode-spec + (save-excursion + (goto-char (point-min)) + (when (search-forward "<%@ Page") + (let ((case-fold-search t)) + (when (looking-at mumamo-aspnet-language-regex) + (mumamo-aspnet-mode-spec-for-language (match-string 1)))))) + 'fundamental-mode)) + +(defun mumamo-aspnet-get-mode-for-chunk (&optional chunk-type) + (cond ((eq chunk-type 'script) + (mumamo-get-major-mode-substitute + (or (if (looking-at mumamo-aspnet-language-regex) + (mumamo-aspnet-mode-spec-for-language (match-string 1)) + (mumamo-aspnet-get-page-language-mode-spec)) + 'fundamental-mode) + 'fontification)) + ((eq chunk-type 'directive) + 'fundamental-mode) + ;;(t (mumamo-mode-from-modespec + (t (mumamo-get-major-mode-substitute + (mumamo-aspnet-get-page-language-mode-spec) + 'fontification + )))) + + +(defun mumamo-chunk-aspnet(pos min max) + "Find <% ... %>." + (mumamo-find-possible-chunk pos min max + 'mumamo-search-bw-exc-start-aspnet + 'mumamo-search-bw-exc-end-jsp + 'mumamo-search-fw-exc-start-jsp + 'mumamo-search-fw-exc-end-jsp)) + +(defun mumamo-search-bw-exc-start-aspnet(pos min) + ;;(let ((exc-start (mumamo-search-bw-exc-start-str pos min "<%"))) + (let ((exc-start (mumamo-chunk-start-bw-str pos min "<%"))) + (when (and exc-start + (<= exc-start pos)) + (cons exc-start + (mumamo-aspnet-get-mode-for-chunk + (if (eq (char-after exc-start) ?@) + 'directive)))))) + +(defconst mumamo-aspnet-script-tag-start-regex + (rx "<script" word-end + (0+ (not (any ">"))) + word-start "runat" (0+ space) "=" (0+ space) ?\" "server" ?\" + (0+ (not (any ">"))) + ">" + )) + +(defun mumamo-aspnet-mode-spec-for-language (language) + (let ((language (downcase language))) + (cond ((equal language "c#") 'csharp-mode) + ((equal language "vb") 'vbnet-mode) + (t 'fundamental-mode)))) + +(defun mumamo-search-bw-exc-start-aspnet-script(pos min) + (goto-char (+ pos 7)) + (let ((marker-start (search-backward "<script" min t)) + exc-mode + exc-start) + (when marker-start + (when (looking-at mumamo-aspnet-script-tag-start-regex) + (setq exc-start (match-end 0)) + (setq exc-mode (mumamo-aspnet-get-mode-for-chunk 'script)) + (goto-char exc-start) + (when (<= exc-start pos) + (cons (point) exc-mode)))))) + +(defun mumamo-search-fw-exc-start-aspnet-script(pos max) + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle <![CDATA[ + (when (and + (eq ?< (char-before)) + (eq ?! (char-after)) + (not (bobp))) + (backward-char) + (skip-chars-backward "^<")) + (unless (bobp) + (backward-char 1)) + (let ((exc-start (search-forward "<script" max t)) + exc-mode) + (when exc-start + (goto-char (- exc-start 7)) + (when (looking-at mumamo-aspnet-script-tag-start-regex) + (goto-char (match-end 0)) + (point) + )))) + +(defun mumamo-chunk-aspnet-script(pos min max) + "Find inlined script, <script runat=\"server\">...</script>." + (mumamo-find-possible-chunk pos min max + 'mumamo-search-bw-exc-start-aspnet-script + 'mumamo-search-bw-exc-end-inlined-script + 'mumamo-search-fw-exc-start-aspnet-script + 'mumamo-search-fw-exc-end-inlined-script)) + +;; Fix-me: define a multi major mode for asp. Or maybe just drop this +;; file? + +(provide 'mumamo-aspnet) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo-aspnet.el ends here diff --git a/emacs/nxhtml/util/mumamo-fun.el b/emacs/nxhtml/util/mumamo-fun.el new file mode 100644 index 0000000..eb3c5c2 --- /dev/null +++ b/emacs/nxhtml/util/mumamo-fun.el @@ -0,0 +1,3333 @@ +;;; mumamo-fun.el --- Multi major mode functions +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-03-09T01:35:21+0100 Sun +;; Version: 0.51 +;; Last-Updated: 2008-08-04T17:54:29+0200 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `backquote', `bytecomp', `cl', `flyspell', `ispell', `mumamo', +;; `sgml-mode'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Defines some "multi major modes" functions. See mumamo.el for more +;; information. +;; +;;;; Usage: +;; +;; See mumamo.el for how to use the multi major mode functions +;; defined here. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (add-to-list 'load-path default-directory)) +(eval-when-compile (require 'mumamo)) +(eval-when-compile (require 'sgml-mode)) +;;(mumamo-require) + +;;;#autoload +;;(defun mumamo-fun-require ()) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; File wide key bindings + +(defun mumamo-multi-mode-map () + "Return mumamo multi mode keymap." + (symbol-value + (intern-soft (concat (symbol-name mumamo-multi-major-mode) "-map")))) + +;; (defun mumamo-multi-mode-hook-symbol () +;; "Return mumamo multi mode hook symbol." +;; (intern-soft (concat (symbol-name mumamo-multi-major-mode) "-hook"))) + +;;;###autoload +(defun mumamo-define-html-file-wide-keys () + "Define keys in multi major mode keymap for html files." + (let ((map (mumamo-multi-mode-map))) + (define-key map [(control ?c) (control ?h) ?b] 'nxhtml-browse-file) + )) +;; (defun mumamo-add-html-file-wide-keys (hook) +;; (add-hook hook 'mumamo-define-html-file-wide-keys) +;; ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Chunk search routines for XHTML things + +(defun mumamo-chunk-attr= (pos min max attr= attr=is-regex attr-regex submode) + "This should work similar to `mumamo-find-possible-chunk'. +See `mumamo-chunk-style=' for an example of use. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-chunk-attr=-new pos max attr= attr=is-regex attr-regex submode)) + +(defun mumamo-chunk-attr=-new-fw-exc-fun (pos max) + ;;(msgtrc "(mumamo-chunk-attr=-new-fw-exc-fun %s %s)" pos max) + (save-match-data + (let ((here (point)) + first-dq + next-dq + (this-chunk (mumamo-get-existing-new-chunk-at pos))) + (if this-chunk + (goto-char (overlay-end this-chunk)) + (goto-char (overlay-end mumamo-last-chunk))) + (setq first-dq (search-forward "\"" max t)) + (unless (bobp) + (backward-char) + (condition-case err + (with-syntax-table (standard-syntax-table) + (setq next-dq (scan-sexps (point) 1))) + (error nil))) + (prog1 + next-dq + (goto-char here))))) + +(defun mumamo-chunk-attr=-new-find-borders-fun (start-border end-border dummy) + ;;(setq borders (funcall find-borders-fun start-border end-border exc-mode)) + (save-match-data + (let ((here (point)) + (end2 (when end-border (1- end-border))) + start2) + (goto-char start-border) + (save-match-data + (setq start2 (search-forward "\"" (+ start-border 200) t))) + (goto-char here) + (list start2 end2)))) + +(defun mumamo-chunk-attr=-new (pos + ;;min + max + attr= + attr=is-regex + attr-regex + submode) + ;;(message "\n(mumamo-chunk-attr=-new %s %s %s %s %s %s)" pos max attr= attr=is-regex attr-regex submode) + ;;(mumamo-condition-case err + (condition-case err + (save-match-data + (let ((here (point)) + (next-attr= (progn + ;; fix-me: + (if (not attr=is-regex) + (goto-char (+ pos (length attr=))) + (goto-char pos) + (skip-chars-forward "a-zA-Z=")) + (goto-char pos) + (if attr=is-regex + (re-search-forward attr= max t) + (search-forward attr= max t)))) + next-attr-sure + ;;next-attr= + start start-border + end end-border + exc-mode + borders + exc-start-next + exc-end-next + exc-start-next + exc-end-next + (tries 0) + (min (1- pos)) + look-max + ) + ;; make sure if we have find prev-attr= or not + (unless (eq (char-after) ?\") + (setq next-attr= nil)) + (when next-attr= + (forward-char) + (skip-chars-forward "^\"") + (setq look-max (+ (point) 2))) + (while (and next-attr= + (< min (point)) + (not next-attr-sure) + (< tries 5)) + ;;(msgtrc "attr=-new: min=%s, point=%s" min (point)) + (setq tries (1+ tries)) + ;;(if (not (re-search-backward "<[^?]" (- min 300) t)) + (if (not (re-search-backward "<[^?]\\|\?>" (- min 300) t)) + (setq next-attr= nil) + ;;(if (looking-at attr-regex) + (if (let ((here (point))) + (prog1 + (re-search-forward attr-regex look-max t) + (goto-char here))) + ;;(if (mumamo-end-in-code (point) next-attr= 'php-mode) + (setq next-attr-sure 'found) + (unless (bobp) + (backward-char) + ;;(msgtrc "attr=-new 1: min=%s, point=%s" min (point)) + (setq next-attr= (if attr=is-regex + (re-search-backward attr= (- min 300) t) + (search-backward attr= (- min 300) t))))))) + (unless next-attr-sure (setq next-attr= nil)) + + + ;; find prev change and if inside style= the next change + (when next-attr= + (setq exc-start-next (match-beginning 1)) + (setq exc-end-next (match-end 2)) + (when (>= exc-start-next pos) + (if (> pos exc-end-next) + (progn + (setq start (+ (match-end 2) 1)) + ;;(setq start-border (+ (match-end 2) 2)) + ) + (setq exc-mode submode) + (setq start (match-beginning 1)) + (setq start-border (match-beginning 2)) + (setq end (1+ (match-end 2))) + (setq end-border (1- end))) + )) + ;; find next change + (unless end + (if start + (goto-char start) + (goto-char pos) + (search-backward "<" min t)) + ;;(msgtrc "attr=-new 2: min=%s, point=%s" min (point)) + (setq next-attr= (if attr=is-regex + (re-search-forward attr= max t) + (search-forward attr= max t))) + (when (and next-attr= + (search-backward "<" min t)) + (when (looking-at attr-regex) + (setq end (match-beginning 1))))) + (when start (assert (>= start pos) t)) + (when end (assert (<= pos end) t)) + ;;(message "start-border=%s end-border=%s" start-border end-border) + (when (or start-border end-border) + (setq borders (list start-border end-border nil))) + ;; (message "mumamo-chunk-attr=-new: %s" + ;; (list start + ;; end + ;; exc-mode + ;; borders + ;; nil ;; parseable-by + ;; 'mumamo-chunk-attr=-new-fw-exc-fun ;; fw-exc-fun + ;; 'mumamo-chunk-attr=-new-find-borders-fun ;; find-borders-fun + ;; )) + (goto-char here) + (setq end nil) + (when (or start end) + (list start + end + exc-mode + borders + nil ;; parseable-by + 'mumamo-chunk-attr=-new-fw-exc-fun ;; fw-exc-fun + 'mumamo-chunk-attr=-new-find-borders-fun ;; find-borders-fun + )))) + (error (mumamo-display-error 'mumamo-chunk-attr=-new "%s" (error-message-string err))) + )) + +;;;; xml pi + +(defvar mumamo-xml-pi-mode-alist + '(("php" . php-mode) + ("python" . python-mode)) + "Alist used by `mumamo-chunk-xml-pi' to get exception mode." ) + +;; Fix-me: make it possible to make the borders part of the php chunk +;; so that parsing of them by nxml may be skipped. Or, rather if the +;; borders are not part of the chunk then assume nxml can not parse +;; the chunk and the borders. +;; (defun mumamo-search-bw-exc-start-xml-pi-1 (pos min lt-chars) +;; "Helper for `mumamo-chunk-xml-pi'. +;; POS is where to start search and MIN is where to stop. +;; LT-CHARS is just <?. + +;; Actual use is in `mumamo-search-bw-exc-start-xml-pi'." +;; (let ((exc-start (mumamo-chunk-start-bw-str (+ pos 2) min lt-chars)) +;; spec +;; exc-mode +;; hit) +;; (when exc-start +;; (goto-char exc-start) +;; (when (and (not (looking-at "xml")) +;; (looking-at (rx (0+ (any "a-z"))))) +;; ;; (setq exc-start (match-end 0)) include it in sub chunk instead +;; (setq exc-start (- exc-start 2)) +;; (setq spec (match-string-no-properties 0)) +;; (setq exc-mode (assoc spec mumamo-xml-pi-mode-alist)) +;; (when exc-mode (setq exc-mode (cdr exc-mode))) +;; (setq hit t) +;; ) +;; (when hit +;; (unless exc-mode +;; ;;(setq exc-mode 'fundamental-mode) +;; ;; Fix-me: Better assume php-mode +;; (setq exc-mode 'php-mode)) +;; (when (<= exc-start pos) +;; ;;(cons exc-start exc-mode) +;; (list exc-start exc-mode nil) +;; ))))) + +;; (defun mumamo-search-bw-exc-start-xml-pi (pos min) +;; "Helper for `mumamo-chunk-xml-pi'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-search-bw-exc-start-xml-pi-1 pos min "<?")) + +(defun mumamo-search-fw-exc-start-xml-pi-new (pos max) + (let ((here (point)) + start + spec + exc-mode + ret) + (setq start (search-forward "<?" max t)) + (when (and start + (looking-at (rx (0+ (any "a-z"))))) + (setq spec (match-string-no-properties 0)) + (unless (string= spec "xml") + (when (= 0 (length spec)) + (setq spec "php")) + (setq exc-mode (assoc spec mumamo-xml-pi-mode-alist)) + (if exc-mode + (setq exc-mode (cdr exc-mode)) + (setq exc-mode 'mumamo-bad-mode)) + (setq ret (list (- start 2) exc-mode nil)))) + (goto-char here) + ret)) + +(defun mumamo-xml-pi-end-is-xml-end (pos) + "Return t if the ?> at pos is end of <?xml." + (when (> 1000 pos) +;;; (assert (and (= (char-after pos) ??) +;;; (= (char-after (1+ pos)) ?>))) + (save-excursion + (save-restriction + (widen) + (save-match-data + (when (search-backward "<" (- pos 150) t) + (when (looking-at (rx line-start "<\?xml" (1+ space))) + (mumamo-msgfntfy "mumamo-xml-pi-end-is-xml-end %s => t" pos) + t))))))) + +;; (defun mumamo-search-bw-exc-end-xml-pi (pos min) +;; "Helper for `mumamo-chunk-xml-pi'. +;; POS is where to start search and MIN is where to stop." +;; ;; Fix me: merge xml header +;; (mumamo-msgfntfy "mumamo-search-bw-exc-end-xml-pi %s %s" pos min) +;; ;;(let ((end-pos (mumamo-chunk-end-bw-str pos min "?>"))) +;; (let ((end-pos (mumamo-chunk-end-bw-str-inc pos min "?>"))) +;; (mumamo-msgfntfy " end-pos=%s" end-pos) +;; (when end-pos +;; (unless (or (mumamo-xml-pi-end-is-xml-end end-pos) +;; (= (save-restriction +;; (widen) +;; (char-after (- end-pos 1))) +;; ?<)) +;; (mumamo-msgfntfy " returning end-pos") +;; end-pos)))) + +(defun mumamo-search-fw-exc-end-xml-pi (pos max) + "Helper for `mumamo-chunk-xml-pi'. +POS is where to start search and MAX is where to stop." + ;; Fix me: merge xml header + ;;(let ((end-pos (mumamo-chunk-end-fw-str pos max "?>"))) + (save-match-data + (let ((end-pos (mumamo-chunk-end-fw-str-inc pos max "?>"))) + (when end-pos + (unless (mumamo-xml-pi-end-is-xml-end end-pos) + end-pos))))) + +(defun mumamo-search-fw-exc-start-xml-pi-1 (pos max lt-chars) + "Helper for `mumamo-chunk-xml-pi'. +POS is where to start search and MAX is where to stop. + +Used in `mumamo-search-fw-exc-start-xml-pi'. For an explanation +of LT-CHARS see `mumamo-search-bw-exc-start-xml-pi-1'." + (goto-char pos) + (skip-chars-backward "a-zA-Z") + ;;(let ((end-out (mumamo-chunk-start-fw-str (point) max lt-chars))) + (let ((end-out (mumamo-chunk-start-fw-str-inc (point) max lt-chars)) + spec + exc-mode + hit) + (when (looking-at "xml") + (if t ;(= 1 pos) + (setq end-out (mumamo-chunk-start-fw-str-inc (1+ (point)) max lt-chars)) + (setq end-out nil))) + (when end-out + ;; Get end-out: + (if (looking-at (rx (0+ (any "a-z")))) + (progn + ;;(setq end-out (match-end 0)) + (setq end-out (- (match-beginning 0) 2)) + (setq spec (match-string-no-properties 0)) + (setq exc-mode (assoc spec mumamo-xml-pi-mode-alist)) + (if exc-mode + (setq exc-mode (cdr exc-mode)) + (setq exc-mode 'php-mode)) + (setq end-out (list end-out exc-mode nil)) + ) + (setq end-out nil)) + end-out))) + +(defun mumamo-search-fw-exc-start-xml-pi-old (pos max) + "Helper for `mumamo-chunk-xml-pi'. +POS is where to start search and MAX is where to stop." + (mumamo-search-fw-exc-start-xml-pi-1 pos max "<?")) + +;; Add a find-borders-fun here so that for example src="<?php some +;; code ?>" can be handled. +;; +;; Fix-me: Maybe generalize for other values than <?php +(defun mumamo-find-borders-xml-pi (start end exc-mode) + (let (start-border + end-border + (inc t) + ;;(begin-mark "<?php") + (begin-mark "<?") + (end-mark "?>") + (here (point))) + (if (and inc) ;; exc-mode) + (progn + (when start + ;;(setq start-border (+ start (length begin-mark))) + (goto-char (+ start (length begin-mark))) + (skip-chars-forward "=a-zA-Z") + (setq start-border (point)) + ) + (when end + (setq end-border + (- end (length end-mark))))) + (if (and (not inc) (not exc-mode)) + (progn + (when start + (setq start-border + (+ start (length end-mark)))) + (when end + (setq end-border (- end (length begin-mark))) + ;;(goto-char end) + ;;(skip-chars-forward "=a-zA-Z") + ;;(setq end-border (point)) + )))) + (goto-char here) + (when (or start-border end-border) + (list start-border end-border)))) + +(defun mumamo-chunk-xml-pi (pos min max) + "Find process instruction, <? ... ?>. Return range and wanted mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-xml-pi + ;; 'mumamo-search-bw-exc-end-xml-pi + ;; 'mumamo-search-fw-exc-start-xml-pi-old + ;; 'mumamo-search-fw-exc-end-xml-pi + ;; 'mumamo-find-borders-xml-pi) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-xml-pi-new + 'mumamo-search-fw-exc-end-xml-pi + 'mumamo-find-borders-xml-pi)) + + +;;;; <style ...> + +(defconst mumamo-style-tag-start-regex + (rx "<style" + space + (0+ (not (any ">"))) + "type" + (0+ space) + "=" + (0+ space) + ?\" + "text/css" + ?\" + (0+ (not (any ">"))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "<![CDATA[") + )) + +;; (defun mumamo-search-bw-exc-start-inlined-style (pos min) +;; "Helper for `mumamo-chunk-inlined-style'. +;; POS is where to start search and MIN is where to stop." +;; (goto-char (+ pos 6)) +;; (let ((marker-start (search-backward "<style" min t)) +;; exc-mode +;; exc-start) +;; (when marker-start +;; (when (looking-at mumamo-style-tag-start-regex) +;; (setq exc-start (match-end 0)) +;; (goto-char exc-start) +;; (when (<= exc-start pos) +;; ;;(cons (point) 'css-mode) +;; ;;(list (point) 'css-mode '(nxml-mode)) +;; ;; Fix-me: Kubica looping problem +;; (list (point) 'css-mode) +;; ) +;; )))) + +;; (defun mumamo-search-bw-exc-end-inlined-style (pos min) +;; "Helper for `mumamo-chunk-inlined-style'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "</style>")) + +;; (defun mumamo-search-fw-exc-start-inlined-style-old (pos max) +;; "Helper for `mumamo-chunk-inlined-style'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle <![CDATA[ +;; (when (and +;; (eq ?< (char-before)) +;; (eq ?! (char-after)) +;; (not (bobp))) +;; (backward-char) +;; (skip-chars-backward "^<")) +;; (unless (bobp) +;; (backward-char 1)) +;; (let ((exc-start (search-forward "<style" max t)) +;; exc-mode) +;; (when exc-start +;; (goto-char (- exc-start 6)) +;; (when (looking-at mumamo-style-tag-start-regex) +;; (goto-char (match-end 0)) +;; (point) +;; )))) + +(defun mumamo-search-fw-exc-end-inlined-style (pos max) + "Helper for `mumamo-chunk-inlined-style'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "</style>"))) + +;; (defun mumamo-chunk-inlined-style-old (pos min max) +;; "Find <style>...</style>. Return range and 'css-mode. +;; See `mumamo-find-possible-chunk' for POS, MIN and MAX." +;; (mumamo-find-possible-chunk pos min max +;; 'mumamo-search-bw-exc-start-inlined-style +;; 'mumamo-search-bw-exc-end-inlined-style +;; 'mumamo-search-fw-exc-start-inlined-style-old +;; 'mumamo-search-fw-exc-end-inlined-style)) + +(defun mumamo-search-fw-exc-start-inlined-style (pos max) + "Helper for `mumamo-chunk-inlined-style'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle <![CDATA[ + (when (and + (eq ?< (char-before)) + (eq ?! (char-after)) + (not (bobp))) + (backward-char) + (skip-chars-backward "^<")) + (unless (bobp) + (backward-char 1)) + (let ((exc-start (search-forward "<style" max t)) + exc-mode) + (when exc-start + (goto-char (- exc-start 6)) + (when (looking-at mumamo-style-tag-start-regex) + (goto-char (match-end 0)) + (list (point) 'css-mode nil) + )))) + +(defun mumamo-chunk-inlined-style (pos min max) + "Find <style>...</style>. Return range and 'css-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-style + 'mumamo-search-fw-exc-end-inlined-style)) + +;;;; <script ...> + +(defconst mumamo-script-tag-start-regex + (rx "<script" + space + (0+ (not (any ">"))) + "type" + (0+ space) + "=" + (0+ space) + ?\" + ;;(or "text" "application") + ;;"/" + ;;(or "javascript" "ecmascript") + "text/javascript" + ?\" + (0+ (not (any ">"))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "<![CDATA[" ) + )) + +;; (defun mumamo-search-bw-exc-start-inlined-script (pos min) +;; "Helper for `mumamo-chunk-inlined-script'. +;; POS is where to start search and MIN is where to stop." +;; (goto-char (+ pos 7)) +;; (let ((marker-start (when (< min (point)) (search-backward "<script" min t))) +;; exc-mode +;; exc-start) +;; (when marker-start +;; (when (looking-at mumamo-script-tag-start-regex) +;; (setq exc-start (match-end 0)) +;; (goto-char exc-start) +;; (when (<= exc-start pos) +;; ;;(cons (point) 'javascript-mode) +;; (list (point) 'javascript-mode '(nxml-mode)) +;; ) +;; )))) + +;; (defun mumamo-search-bw-exc-end-inlined-script (pos min) +;; "Helper for `mumamo-chunk-inlined-script'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "</script>")) + +;; (defun mumamo-search-fw-exc-start-inlined-script-old (pos max) +;; "Helper for `mumamo-chunk-inlined-script'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle <![CDATA[ +;; (when (and +;; (eq ?< (char-before)) +;; (eq ?! (char-after)) +;; (not (bobp))) +;; (backward-char) +;; (skip-chars-backward "^<")) +;; (unless (bobp) +;; (backward-char 1)) +;; (let ((exc-start (search-forward "<script" max t)) +;; exc-mode) +;; (when exc-start +;; (goto-char (- exc-start 7)) +;; (when (looking-at mumamo-script-tag-start-regex) +;; (goto-char (match-end 0)) +;; (point) +;; )))) + +(defun mumamo-search-fw-exc-end-inlined-script (pos max) + "Helper for `mumamo-chunk-inlined-script'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "</script>"))) + +;; (defun mumamo-chunk-inlined-script-old (pos min max) +;; "Find <script>...</script>. Return range and 'javascript-mode. +;; See `mumamo-find-possible-chunk' for POS, MIN and MAX." +;; (mumamo-find-possible-chunk pos min max +;; 'mumamo-search-bw-exc-start-inlined-script +;; 'mumamo-search-bw-exc-end-inlined-script +;; 'mumamo-search-fw-exc-start-inlined-script-old +;; 'mumamo-search-fw-exc-end-inlined-script)) + +(defun mumamo-search-fw-exc-start-inlined-script (pos max) + "Helper for `mumamo-chunk-inlined-script'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle <![CDATA[ + (when (and + (eq ?< (char-before)) + (eq ?! (char-after)) + (not (bobp))) + (backward-char) + (skip-chars-backward "^<")) + (unless (bobp) + (backward-char 1)) + (let ((exc-start (search-forward "<script" max t)) + exc-mode) + (when exc-start + (goto-char (- exc-start 7)) + (when (looking-at mumamo-script-tag-start-regex) + (goto-char (match-end 0)) + (list (point) 'javascript-mode '(nxml-mode)) + )))) + +(defun mumamo-chunk-inlined-script (pos min max) + "Find <script>...</script>. Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-script + 'mumamo-search-fw-exc-end-inlined-script)) + +;;;; on[a-z]+=\"javascript:" + +(defconst mumamo-onjs=-attr= + (rx + ;;"on[a-z]+=" + (or "onclick" "ondblclick" "onmousedown" "onmousemove" "onmouseout" "onmouseover" "onmouseup" "onkeydown" "onkeypress" "onkeyup") + "=")) + +(defconst mumamo-onjs=-attr-regex + (rx point + (or "<" "?>") + (* (not (any ">"))) + space + (submatch + ;;"on" (1+ (any "a-za-z")) + (or "onclick" "ondblclick" "onmousedown" "onmousemove" "onmouseout" "onmouseover" "onmouseup" "onkeydown" "onkeypress" "onkeyup") + "=") + (0+ space) + ?\" + (submatch + (opt "javascript:") + (0+ + (not (any "\"")))) + )) + +(defun mumamo-chunk-onjs=(pos min max) + "Find javascript on...=\"...\". Return range and 'javascript-mode." + (mumamo-chunk-attr= pos min max mumamo-onjs=-attr= t mumamo-onjs=-attr-regex + 'javascript-mode)) + +;;;; py:somthing=\"python\" + +(defconst mumamo-py:=-attr= "py:[a-z]+=") + +(defconst mumamo-py:=-attr-regex + (rx point + (or "<" "?>") + (* (not (any ">"))) + space + (submatch + "py:" (1+ (any "a-za-z")) + "=") + (0+ space) + ?\" + (submatch + (0+ + (not (any "\"")))) + )) + +(defun mumamo-chunk-py:=(pos min max) + "Find python py:...=\"...\". Return range and 'python-mode." + (mumamo-chunk-attr= pos min max mumamo-py:=-attr= t mumamo-py:=-attr-regex + 'python-mode)) + +(defun mumamo-chunk-py:match (pos min max) + (save-match-data + (let ((here (point)) + (py:match (progn + (goto-char pos) + (re-search-forward (rx "py:match" + (1+ space) + (0+ (not (any ">"))) + word-start + (submatch "path=") + (0+ space) + ?\" + (submatch + (0+ + (not (any "\""))))) + max t))) + start end borders + ) + (when py:match + (setq start (match-beginning 1)) + (setq end (match-end 2)) + (setq borders (list (match-end 1) (1- end))) + ) + (goto-char here) + (when start + (list start + end + 'python-mode + borders + nil ;; parseable-by + 'mumamo-chunk-attr=-new-fw-exc-fun ;; fw-exc-fun + 'mumamo-chunk-attr=-new-find-borders-fun ;; find-borders-fun + ))))) + +;;;; style= + +(defconst mumamo-style=start-regex + (rx "<" + (0+ (not (any ">"))) + space + (submatch "style=") + (0+ space) + ?\" + (submatch + (0+ + (not (any "\"")))) + )) + +(defun mumamo-chunk-style=(pos min max) + "Find style=\"...\". Return range and 'css-mode." + (mumamo-chunk-attr= pos min max "style=" nil mumamo-style=start-regex + 'css-mode)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; HTML w html-mode + +(put 'mumamo-alt-php-tags-mode 'permanent-local t) +(define-minor-mode mumamo-alt-php-tags-mode + "Minor mode for using '(?php' instead of '<?php' in buffer. +When turning on this mode <?php is replace with (?php in the buffer. +If you write the buffer to file (?php is however written as <?php. + +When turning off this mode (?php is replace with <?php in the buffer. + +The purpose of this minor mode is to work around problems with +using the `nxml-mode' parser in php files. `nxml-mode' knows +damned well that you can not have the character < in strings and +I can't make it forget that. For PHP programmers it is however +very convient to use <?php ... ?> in strings. + +There is no reason to use this minor mode unless you want XML +validation and/or completion in your php file. If you do not +want that then you can simply use a multi major mode based on +`html-mode' instead of `nxml-mode'/`nxhtml-mode'. Or, of course, +just `php-mode' if there is no html code in the file." + :lighter "<?php " + (if mumamo-alt-php-tags-mode + (progn + ;;(unless mumamo-multi-major-mode (error "Only for mumamo multi major modes")) + (unless (let ((major-mode (mumamo-main-major-mode))) + (derived-mode-p 'nxml-mode)) + ;;(error "Mumamo multi major mode must be based on nxml-mode") + ) + (unless (memq 'mumamo-chunk-alt-php (caddr mumamo-current-chunk-family)) + (error "Mumamo multi major must have chunk function mumamo-chunk-alt-php")) + + ;; Be paranoid about the file/content write hooks + (when (<= emacs-major-version 22) + (with-no-warnings + (when local-write-file-hooks ;; obsolete, but check! + (error "Will not do this because local-write-file-hooks is non-nil")))) + (remove-hook 'write-contents-functions 'mumamo-alt-php-write-contents t) + (when write-contents-functions + (error "Will not do this because write-contents-functions is non-nil")) + (when (delq 'recentf-track-opened-file (copy-sequence write-file-functions)) + (error "Will not do this because write-file-functions is non-nil")) + + (add-hook 'write-contents-functions 'mumamo-alt-php-write-contents t t) + (put 'write-contents-functions 'permanent-local t) + (save-restriction + (let ((here (point))) + (widen) + (goto-char (point-min)) + (while (search-forward "<?php" nil t) + (replace-match "(?php")) + (goto-char (point-min)) + (while (search-forward "<?=" nil t) + (replace-match "(?=")) + (goto-char (point-min)) + (while (search-forward "?>" nil t) + (replace-match "?)")) + (goto-char here)))) + (save-restriction + (let ((here (point))) + (widen) + (goto-char (point-min)) + (while (search-forward "(?php" nil t) + (replace-match "<?php")) + (goto-char (point-min)) + (while (search-forward "(?=" nil t) + (replace-match "<?=")) + (goto-char (point-min)) + (while (search-forward "?)" nil t) + (replace-match "?>")) + (goto-char here))) + (remove-hook 'write-contents-functions 'mumamo-alt-php-write-contents t))) + +(defun mumamo-chunk-alt-php (pos min max) + "Find (?php ... ?), return range and `php-mode'. +Workaround for the problem that I can not tame `nxml-mode' to recognize <?php. + +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (when mumamo-alt-php-tags-mode + (mumamo-quick-static-chunk pos min max "(?php" "?)" t 'php-mode t))) + +(defun mumamo-chunk-alt-php= (pos min max) + "Find (?= ... ?), return range and `php-mode'. +Workaround for the problem that I can not tame `nxml-mode' to recognize <?php. + +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (when mumamo-alt-php-tags-mode + (mumamo-quick-static-chunk pos min max "(?=" "?)" t 'php-mode t))) + +;;;###autoload +(define-mumamo-multi-major-mode html-mumamo-mode + "Turn on multiple major modes for (X)HTML with main mode `html-mode'. +This covers inlined style and javascript and PHP." + ("HTML Family" html-mode + (mumamo-chunk-xml-pi + mumamo-chunk-alt-php + mumamo-chunk-alt-php= + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'html-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) +(mumamo-inherit-sub-chunk-family 'html-mumamo-mode) + +;; (define-mumamo-multi-major-mode xml-pi-only-mumamo-mode +;; "Test" +;; ("HTML Family" html-mode +;; (mumamo-chunk-xml-pi +;; ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; XHTML w nxml-mode + +(defun mumamo-alt-php-write-contents () + "For `write-contents-functions' when `mumamo-chunk-alt-php' is used." + (let ((here (point))) + (save-match-data + (save-restriction + (widen) + (condition-case nil + (atomic-change-group + (progn + (goto-char (point-min)) + (while (search-forward "(?php" nil t) + (replace-match "<?php")) + (goto-char (point-min)) + (while (search-forward "(?=" nil t) + (replace-match "<?=")) + (goto-char (point-min)) + (while (search-forward "?)" nil t) + (replace-match "?>")) + (basic-save-buffer-1) + (signal 'mumamo-error-ind-0 nil))) + (mumamo-error-ind-0))) + (set-buffer-modified-p nil)) + (goto-char here)) + ;; saved, return t + t) + +;;;###autoload +(define-mumamo-multi-major-mode nxml-mumamo-mode + "Turn on multiple major modes for (X)HTML with main mode `nxml-mode'. +This covers inlined style and javascript and PHP. + +See also `mumamo-alt-php-tags-mode'." + ("nXml Family" nxml-mode + (mumamo-chunk-xml-pi + mumamo-chunk-alt-php + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'nxml-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Mason (not ready) +;; http://www.masonhq.com/docs/manual/Devel.html#examples_and_recommended_usage + +(defun mumamo-chunk-mason-perl-line (pos min max) + (mumamo-whole-line-chunk pos min max "%" 'perl-mode)) + +(defun mumamo-chunk-mason-perl-single (pos min max) + (mumamo-quick-static-chunk pos min max "<% " " %>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-block (pos min max) + (mumamo-quick-static-chunk pos min max "<%perl>" "</%perl>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-init (pos min max) + (mumamo-quick-static-chunk pos min max "<%init>" "</%init>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-once (pos min max) + (mumamo-quick-static-chunk pos min max "<%once>" "</%once>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-cleanup (pos min max) + (mumamo-quick-static-chunk pos min max "<%cleanup>" "</%cleanup>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-shared (pos min max) + (mumamo-quick-static-chunk pos min max "<%shared>" "</%shared>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-simple-comp (pos min max) + (mumamo-quick-static-chunk pos min max "<& " " &>" t 'text-mode t)) + +(defun mumamo-chunk-mason-args (pos min max) + ;; Fix-me: perl-mode is maybe not the best here? + (mumamo-quick-static-chunk pos min max "<%args>" "</%args>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-doc (pos min max) + (mumamo-quick-static-chunk pos min max "<%doc>" "</%doc>" t 'mumamo-comment-mode t)) + +(defun mumamo-chunk-mason-text (pos min max) + (mumamo-quick-static-chunk pos min max "<%text>" "</%text>" t 'text-mode t)) + +;; component calls with content + +;; (defun mumamo-chunk-mason-compcont-bw-exc-start-fun (pos min) +;; (let ((exc-start (mumamo-chunk-start-bw-str-inc pos min "<&| "))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'html-mode)))) + +;; (defun mumamo-chunk-mason-compcont-fw-exc-start-fun-old (pos max) +;; (mumamo-chunk-start-fw-str-inc pos max "<&| ")) + +(defun mumamo-chunk-mason-compcont-fw-exc-end-fun (pos max) + (mumamo-chunk-end-fw-str-inc pos max "</&>")) + +(defun mumamo-chunk-mason-compcont-find-borders-fun (start end dummy) + (when dummy + (list + (when start + (save-match-data + (let ((here (point)) + ret) + (goto-char start) + (when (re-search-forward "[^>]* &>" end t) + (setq ret (point)) + (goto-char here) + ret)) + )) + (when end (- end 4)) + dummy))) + +;; (defun mumamo-chunk-mason-compcont-old (pos min max) +;; (mumamo-find-possible-chunk-new pos +;; max +;; 'mumamo-chunk-mason-compcont-bw-exc-start-fun +;; 'mumamo-chunk-mason-compcont-fw-exc-start-fun-old +;; 'mumamo-chunk-mason-compcont-fw-exc-end-fun +;; 'mumamo-chunk-mason-compcont-find-borders-fun)) + +(defun mumamo-chunk-mason-compcont-fw-exc-start-fun (pos max) + (let ((where (mumamo-chunk-start-fw-str-inc pos max "<&| "))) + (when where + (list where 'html-mode nil)))) + +(defun mumamo-chunk-mason-compcont (pos min max) + (mumamo-possible-chunk-forward pos max + 'mumamo-chunk-mason-compcont-fw-exc-start-fun + 'mumamo-chunk-mason-compcont-fw-exc-end-fun + 'mumamo-chunk-mason-compcont-find-borders-fun)) + +;;;###autoload +(define-mumamo-multi-major-mode mason-html-mumamo-mode + "Turn on multiple major modes for Mason using main mode `html-mode'. +This covers inlined style and javascript." + ("Mason html Family" html-mode + ( + mumamo-chunk-mason-perl-line + mumamo-chunk-mason-perl-single + mumamo-chunk-mason-perl-block + mumamo-chunk-mason-perl-init + mumamo-chunk-mason-perl-once + mumamo-chunk-mason-perl-cleanup + mumamo-chunk-mason-perl-shared + mumamo-chunk-mason-simple-comp + mumamo-chunk-mason-compcont + mumamo-chunk-mason-args + mumamo-chunk-mason-doc + mumamo-chunk-mason-text + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'mason-html-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) +(mumamo-inherit-sub-chunk-family-locally 'mason-html-mumamo-mode 'mason-html-mumamo-mode) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Embperl + +(defun mumamo-chunk-embperl-<- (pos min max) + "Find [- ... -], return range and `perl-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "[-" "-]" t 'perl-mode t)) + +(defun mumamo-chunk-embperl-<+ (pos min max) + "Find [+ ... +], return range and `perl-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "[+" "+]" t 'perl-mode nil)) + +(defun mumamo-chunk-embperl-<! (pos min max) + "Find [! ... !], return range and `perl-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "[!" "!]" t 'perl-mode t)) + +(defun mumamo-chunk-embperl-<$ (pos min max) + "Find [$ ... $], return range and `perl-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; This is a bit tricky since [$var] etc must be avoided. + (let* ((begin-mark "[$") + (end-mark "$]") + (good-chars '(32 ;space + 10 ;line feed + 9 ;tab + )) + ;; (search-bw-exc-start (lambda (pos min) + ;; (let ((not-found t) + ;; (next-char nil) + ;; (exc-start (mumamo-chunk-start-bw-str + ;; pos min begin-mark)) + ;; (here (point))) + ;; (while (and not-found + ;; exc-start) + ;; (setq next-char (char-after (+ (point) 2))) + ;; (if (memq next-char good-chars) + ;; (setq not-found nil) + ;; (setq exc-start + ;; (search-backward begin-mark + ;; min t)))) + ;; (when (and exc-start + ;; (<= exc-start pos)) + ;; (cons exc-start 'perl-mode))))) + ;; (search-bw-exc-end (lambda (pos min) + ;; (mumamo-chunk-end-bw-str pos min end-mark))) + ;; (search-fw-exc-start-old (lambda (pos max) + ;; (let ((not-found t) + ;; (next-char nil) + ;; (exc-start (mumamo-chunk-start-fw-str + ;; pos max begin-mark)) + ;; (here (point))) + ;; (while (and not-found + ;; exc-start) + ;; (setq next-char (char-after)) + ;; (if (memq next-char good-chars) + ;; (setq not-found nil) + ;; (setq exc-start + ;; (search-forward begin-mark + ;; max t)))) + ;; exc-start))) + (search-fw-exc-start (lambda (pos max) + (let ((not-found t) + (next-char nil) + (exc-start (mumamo-chunk-start-fw-str + pos max begin-mark)) + (here (point))) + (while (and not-found + exc-start) + (setq next-char (char-after)) + (if (memq next-char good-chars) + (setq not-found nil) + (setq exc-start + (search-forward begin-mark + max t)))) + (list exc-start 'perl-mode)))) + (search-fw-exc-end (lambda (pos max) + (save-match-data + (mumamo-chunk-end-fw-str pos max end-mark)))) + ) + ;; (mumamo-find-possible-chunk pos min max + ;; search-bw-exc-start + ;; search-bw-exc-end + ;; search-fw-exc-start-old + ;; search-fw-exc-end) + (mumamo-possible-chunk-forward pos max + search-fw-exc-start + search-fw-exc-end) + )) + +;;;###autoload +(define-mumamo-multi-major-mode embperl-html-mumamo-mode + "Turn on multiple major modes for Embperl files with main mode `html-mode'. +This also covers inlined style and javascript." + ("Embperl HTML Family" html-mode + (mumamo-chunk-embperl-<- + mumamo-chunk-embperl-<+ + mumamo-chunk-embperl-<! + mumamo-chunk-embperl-<$ + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; django + +(defun mumamo-chunk-django4(pos min max) + "Find {% comment %}. Return range and `django-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{% comment %}" "{% endcomment %}" t 'mumamo-comment-mode t)) + +(defun mumamo-chunk-django3(pos min max) + "Find {# ... #}. Return range and `django-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{#" "#}" t 'mumamo-comment-mode t)) + +(defun mumamo-chunk-django2(pos min max) + "Find {{ ... }}. Return range and `django-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{{" "}}" t 'django-variable-mode t)) + +(defun mumamo-chunk-django (pos min max) + "Find {% ... %}. Return range and `django-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((chunk (mumamo-quick-static-chunk pos min max "{%" "%}" t 'django-mode t))) + (when chunk + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +;; (defun mumamo-search-bw-exc-start-django (pos min) +;; "Helper for `mumamo-chunk-django'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str-inc pos min "{%"))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'django-mode)))) + +;; (defun mumamo-search-bw-exc-start-django2(pos min) +;; "Helper for `mumamo-chunk-django2'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str-inc pos min "{{"))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'django-mode)))) + +;; (defun mumamo-search-bw-exc-start-django3(pos min) +;; "Helper for `mumamo-chunk-django3'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str-inc pos min "{#"))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'mumamo-comment-mode)))) + +;; (defun mumamo-search-bw-exc-start-django4(pos min) +;; "Helper for `mumamo-chunk-django4'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str-inc pos min +;; "{% comment %}"))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'mumamo-comment-mode)))) + +;; (defun mumamo-search-bw-exc-end-django (pos min) +;; "Helper for `mumamo-chunk-django'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str-inc pos min "%}")) + +;; (defun mumamo-search-bw-exc-end-django2(pos min) +;; "Helper for `mumamo-chunk-django2'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str-inc pos min "}}")) + +;; (defun mumamo-search-bw-exc-end-django3(pos min) +;; "Helper for `mumamo-chunk-django3'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str-inc pos min "#}")) + +;; (defun mumamo-search-bw-exc-end-django4(pos min) +;; "Helper for `mumamo-chunk-django4'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str-inc pos min "{% endcomment %}")) + +(defun mumamo-search-fw-exc-start-django (pos max) + "Helper for `mumamo-chunk-django'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-start-fw-str-inc pos max "{%")) + +(defun mumamo-search-fw-exc-start-django2(pos max) + "Helper for `mumamo-chunk-django2'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-start-fw-str-inc pos max "{{")) + +(defun mumamo-search-fw-exc-start-django3(pos max) + "Helper for `mumamo-chunk-django3'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-start-fw-str-inc pos max "{#")) + +(defun mumamo-search-fw-exc-start-django4(pos max) + "Helper for `mumamo-chunk-django4'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-start-fw-str-inc pos max "{% comment %}")) + +(defun mumamo-search-fw-exc-end-django (pos max) + "Helper for `mumamo-chunk-django'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-end-fw-str-inc pos max "%}")) + +(defun mumamo-search-fw-exc-end-django2(pos max) + "Helper for `mumamo-chunk-django2'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-end-fw-str-inc pos max "}}")) + +(defun mumamo-search-fw-exc-end-django3(pos max) + "Helper for `mumamo-chunk-django3'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-end-fw-str-inc pos max "#}")) + +(defun mumamo-search-fw-exc-end-django4(pos max) + "Helper for `mumamo-chunk-django4'. +POS is where to start search and MAX is where to stop." + (mumamo-chunk-end-fw-str-inc pos max "{% endcomment %}")) + +;;;###autoload +(define-mumamo-multi-major-mode django-html-mumamo-mode + "Turn on multiple major modes for Django with main mode `html-mode'. +This also covers inlined style and javascript." + ("Django HTML Family" html-mode + (mumamo-chunk-django4 + mumamo-chunk-django + mumamo-chunk-django2 + mumamo-chunk-django3 + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Genshi / kid + +;; {% python ... %} +(defun mumamo-chunk-genshi%(pos min max) + "Find {% python ... %}. Return range and `genshi-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{% python" "%}" t 'python-mode t)) + +;; ${expr} +(defun mumamo-chunk-genshi$(pos min max) + "Find ${ ... }, return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((chunk + (mumamo-quick-static-chunk pos min max "${" "}" t 'python-mode t))) + (when chunk + ;; Test for clash with %} + (let ((sub-mode (nth 2 chunk)) + (start (nth 0 chunk))) + (if sub-mode + chunk + ;;(message "point.1=%s" (point)) + (when (and start + (eq ?% (char-before start))) + ;;(message "point.2=%s" (point)) + ;;(message "clash with %%}, chunk=%s" chunk) + ;;(setq chunk nil) + (setcar chunk (1- start)) + ) + ;;(message "chunk.return=%s" chunk) + chunk))))) + +;; Fix-me: Because of the way chunks currently are searched for there +;; is an error when a python chunk is used. This is because mumamo +;; gets confused by the %} ending and the } ending. This can be +;; solved by running a separate phase to get the chunks first and +;; during that phase match start and end of the chunk. + + +;; Note: You will currently get fontification errors if you use +;; python chunks + +;; {% python ... %} + +;; The reason is that the chunk routines currently do not know when +;; to just look for the } or %} endings. However this should not +;; affect your editing normally. + +;;;###autoload +(define-mumamo-multi-major-mode genshi-html-mumamo-mode + "Turn on multiple major modes for Genshi with main mode `html-mode'. +This also covers inlined style and javascript." + ("Genshi HTML Family" html-mode + ( + ;;mumamo-chunk-genshi% + mumamo-chunk-genshi$ + mumamo-chunk-py:= + mumamo-chunk-py:match + mumamo-chunk-xml-pi + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; MJT + +;; ${expr} +(defun mumamo-chunk-mjt$(pos min max) + "Find ${ ... }, return range and `javascript-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "${" "}" t 'javascript-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode mjt-html-mumamo-mode + "Turn on multiple major modes for MJT with main mode `html-mode'. +This also covers inlined style and javascript." + ("MJT HTML Family" html-mode + ( + mumamo-chunk-mjt$ + mumamo-chunk-xml-pi + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; smarty + +(defun mumamo-chunk-smarty-literal (pos min max) + "Find {literal} ... {/literal}. Return range and 'html-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{literal}" "{/literal}" t 'html-mode t)) + +(defun mumamo-chunk-smarty-t (pos min max) + "Find {t} ... {/t}. Return range and 'html-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{t}" "{/t}" t 'text-mode t)) + +(defun mumamo-chunk-smarty-comment (pos min max) + "Find {* ... *}. Return range and 'mumamo-comment-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{*" "*}" t 'mumamo-comment-mode nil)) + +(defun mumamo-chunk-smarty (pos min max) + "Find { ... }. Return range and 'smarty-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "{" "}" t 'smarty-mode nil)) + +;;;###autoload +(define-mumamo-multi-major-mode smarty-html-mumamo-mode + "Turn on multiple major modes for Smarty with main mode `html-mode'. +This also covers inlined style and javascript." + ("Smarty HTML Family" html-mode + (mumamo-chunk-xml-pi + mumamo-chunk-style= + mumamo-chunk-onjs= + ;;mumamo-chunk-inlined-style + ;;mumamo-chunk-inlined-script + mumamo-chunk-smarty-literal + mumamo-chunk-smarty-t + mumamo-chunk-smarty-comment + mumamo-chunk-smarty + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; ssjs - server side javascript + +;; http://www.sitepoint.com/blogs/2009/03/10/server-side-javascript-will-be-as-common-as-php/ +;; +;; It looks like there are different syntaxes, both +;; +;; <script runat="server">...</script> and <% ... %>. + +(defun mumamo-chunk-ssjs-% (pos min max) + "Find <% ... %>. Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "<%" "%>" t 'javascript-mode t)) + +(defconst mumamo-ssjs-tag-start-regex + (rx "<script" + space + (0+ (not (any ">"))) + "runat" + (0+ space) + "=" + (0+ space) + ?\" + ;;(or "text" "application") + ;;"/" + ;;(or "javascript" "ecmascript") + (or "server" "both" "server-proxy") + ?\" + (0+ (not (any ">"))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "<![CDATA[" ) + )) + +;; (defun mumamo-search-bw-exc-start-inlined-ssjs (pos min) +;; "Helper for `mumamo-chunk-inlined-ssjs'. +;; POS is where to start search and MIN is where to stop." +;; (goto-char (+ pos 7)) +;; (let ((marker-start (when (< min (point)) (search-backward "<script" min t))) +;; exc-mode +;; exc-start) +;; (when marker-start +;; (when (looking-at mumamo-ssjs-tag-start-regex) +;; (setq exc-start (match-end 0)) +;; (goto-char exc-start) +;; (when (<= exc-start pos) +;; ;;(cons (point) 'javascript-mode) +;; (list (point) 'javascript-mode '(nxml-mode)) +;; ) +;; )))) + +;; (defun mumamo-search-fw-exc-start-inlined-ssjs-old (pos max) +;; "Helper for `mumamo-chunk-inlined-ssjs'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle <![CDATA[ +;; (when (and +;; (eq ?< (char-before)) +;; (eq ?! (char-after)) +;; (not (bobp))) +;; (backward-char) +;; (skip-chars-backward "^<")) +;; (unless (bobp) +;; (backward-char 1)) +;; (let ((exc-start (search-forward "<script" max t)) +;; exc-mode) +;; (when exc-start +;; (goto-char (- exc-start 7)) +;; (when (looking-at mumamo-ssjs-tag-start-regex) +;; (goto-char (match-end 0)) +;; (point) +;; )))) + +(defun mumamo-search-fw-exc-start-inlined-ssjs (pos max) + "Helper for `mumamo-chunk-inlined-ssjs'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle <![CDATA[ + (when (and + (eq ?< (char-before)) + (eq ?! (char-after)) + (not (bobp))) + (backward-char) + (skip-chars-backward "^<")) + (unless (bobp) + (backward-char 1)) + (let ((exc-start (search-forward "<script" max t)) + exc-mode) + (when exc-start + (goto-char (- exc-start 7)) + (when (looking-at mumamo-ssjs-tag-start-regex) + (goto-char (match-end 0)) + (list (point) 'javascript-mode) + )))) + +(defun mumamo-chunk-inlined-ssjs (pos min max) + "Find <script runat=...>...</script>. Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-inlined-ssjs + ;; 'mumamo-search-bw-exc-end-inlined-script + ;; 'mumamo-search-fw-exc-start-inlined-ssjs-old + ;; 'mumamo-search-fw-exc-end-inlined-script) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-ssjs + 'mumamo-search-fw-exc-end-inlined-script)) + +;;;###autoload +(define-mumamo-multi-major-mode ssjs-html-mumamo-mode + "Turn on multiple major modes for SSJS with main mode `html-mode'. +This covers inlined style and javascript." + ("HTML Family" html-mode + (mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-inlined-ssjs + mumamo-chunk-ssjs-% + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'html-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) +(mumamo-inherit-sub-chunk-family 'ssjs-html-mumamo-mode) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; gsp + +(defun mumamo-chunk-gsp (pos min max) + "Find <% ... %>. Return range and 'groovy-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "<%" "%>" t 'groovy-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode gsp-html-mumamo-mode + "Turn on multiple major modes for GSP with main mode `html-mode'. +This also covers inlined style and javascript." + ("GSP HTML Family" html-mode + (mumamo-chunk-gsp + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; jsp - Java Server Pages + +(defun mumamo-chunk-jsp (pos min max) + "Find <% ... %>. Return range and 'java-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "<%" "%>" t 'java-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode jsp-html-mumamo-mode + "Turn on multiple major modes for JSP with main mode `html-mode'. +This also covers inlined style and javascript." + ("JSP HTML Family" html-mode + (mumamo-chunk-jsp + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; eruby + +;; Fix-me: Maybe take care of <%= and <%- and -%>, but first ask the +;; ruby people if this is worth doing. +;; +;; See also http://wiki.rubyonrails.org/rails/pages/UnderstandingViews +(defun mumamo-chunk-eruby (pos min max) + "Find <% ... %>. Return range and 'ruby-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((chunk (mumamo-quick-static-chunk pos min max "<%" "%>" t 'ruby-mode t))) + (when chunk + ;; Put indentation type on 'mumamo-next-indent on the chunk: + ;; Fix-me: use this! + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-chunk-eruby-quoted (pos min max) + "Find \"<%= ... %>\". Return range and 'ruby-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +This is a workaround for problems with strings." + (let ((chunk (mumamo-quick-static-chunk pos min max "\"<%=" "%>\"" t 'ruby-mode t))) + (when chunk + ;; Put indentation type on 'mumamo-next-indent on the chunk: + ;; Fix-me: use this! + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-chunk-eruby-comment (pos min max) + "Find <%# ... %>. Return range and 'ruby-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +This is needed since otherwise the end marker is thought to be +part of a comment." + (mumamo-quick-static-chunk pos min max "<%#" "%>" t 'mumamo-comment-mode t)) + +;; (defun mumamo-search-bw-exc-start-ruby (pos min) +;; "Helper for `mumamo-chunk-ruby'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "<%"))) +;; (when (and exc-start +;; (<= exc-start pos)) +;; (cons exc-start 'ruby-mode)))) + +;;;###autoload +(define-mumamo-multi-major-mode eruby-mumamo-mode + "Turn on multiple major mode for eRuby with unspecified main mode. +Current major-mode will be used as the main major mode." + ("eRuby Family" nil + (mumamo-chunk-eruby-comment + mumamo-chunk-eruby + ))) + +;;;###autoload +(define-mumamo-multi-major-mode eruby-html-mumamo-mode + "Turn on multiple major modes for eRuby with main mode `html-mode'. +This also covers inlined style and javascript." + ("eRuby Html Family" html-mode + ( + mumamo-chunk-eruby-comment + mumamo-chunk-eruby + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;###autoload +(define-mumamo-multi-major-mode eruby-javascript-mumamo-mode + "Turn on multiple major modes for eRuby with main mode `javascript-mode'." + ("eRuby Html Family" javascript-mode + ( + mumamo-chunk-eruby-comment + mumamo-chunk-eruby-quoted + mumamo-chunk-eruby + ;;mumamo-chunk-inlined-style + ;;mumamo-chunk-inlined-script + ;;mumamo-chunk-style= + ;;mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; heredoc + +(defcustom mumamo-heredoc-modes + '( + ("HTML" html-mode) + ("CSS" css-mode) + ("JAVASCRIPT" javascript-mode) + ("JAVA" java-mode) + ("GROOVY" groovy-mode) + ("SQL" sql-mode) + ) + "Matches for heredoc modes. +The entries in this list have the form + + (REGEXP MAJOR-MODE-SPEC) + +where REGEXP is a regular expression that should match the +heredoc marker line and MAJOR-MODE-SPEC is the major mode spec to +use in the heredoc part. + +The major mode spec is translated to a major mode using +`mumamo-major-mode-from-modespec'." + :type '(repeat + (list + regexp + (function :tag "Major mode"))) + :group 'mumamo-modes) + +(defun mumamo-mode-for-heredoc (marker) + "Return major mode associated with MARKER. +Use first match in `mumamo-heredoc-modes'. +If no match use `text-mode'." + (let ((mode (catch 'mode + (save-match-data + (dolist (rec mumamo-heredoc-modes) + (let ((regexp (nth 0 rec)) + (mode (nth 1 rec))) + (when (string-match regexp marker) + (throw 'mode mode)))))))) + (if mode + (mumamo-major-mode-from-modespec mode) + 'text-mode))) + +(defun mumamo-chunk-heredoc (pos min max lang) + "This should work similar to `mumamo-find-possible-chunk'. +POS, MIN and MAX have the same meaning as there. + +LANG is the programming language. +Supported values are 'perl." + ;; Fix-me: LANG + ;; Fix-me: use mumamo-end-in-code + (mumamo-condition-case err + (let ((old-point (point))) + (goto-char pos) + (beginning-of-line) + (let (next-<< + (want-<< t) + heredoc-mark + end-mark-len + heredoc-line + delimiter + skipped + (skip-b "") + start-inner + end + exc-mode + fw-exc-fun + border-fun + allow-code-after + start-outer + ps + ) + (goto-char pos) + (beginning-of-line) + (case lang + ('sh + (setq allow-code-after t) + (while want-<< + (setq next-<< (search-forward "<<" max t)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (point))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 2)) + (when (= (char-after) ?-) + (setq skip-b "\t*") + (unless (eolp) (forward-char))) + ;; fix-me: space + (setq skipped (skip-chars-forward " \t")) + (when (memq (char-after) '(?\" ?\')) + (setq delimiter (list (char-after)))) + (if (and (> skipped 0) (not delimiter)) + (setq heredoc-mark "") + (when (looking-at (rx-to-string + `(and (regexp ,(if delimiter + (concat delimiter "\\([^\n<>;]+\\)" delimiter) + "\\([^ \t\n<>;]+\\)")) + (or blank line-end)))) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 1) + (match-end 1))))) + (when heredoc-mark + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + (setq start-inner (1+ (point-at-eol))) + (setq end-mark-len (length heredoc-mark)) + ))) + ('w32-ps (error "No support for windows power shell yet")) + ('php + (while want-<< + (setq next-<< (search-forward "<<<" max t)) + ;; Check inside string or comment. + (if (not next-<<) + (setq want-<< nil) ;; give up + (setq ps (parse-partial-sexp (line-beginning-position) (- (point) 0))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 3)) + (skip-chars-forward " \t") + (when (looking-at (concat "\\([^\n;]*\\)[[:blank:]]*\n")) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 1) + (match-end 1))) + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + ;; fix-me: nowdoc + (when (and (= ?\' (string-to-char heredoc-mark)) + (= ?\' (string-to-char (substring heredoc-mark (1- (length heredoc-mark)))))) + (setq heredoc-mark (substring heredoc-mark 1 (- (length heredoc-mark) 1)))) + (setq end-mark-len (1+ (length heredoc-mark))) + (setq start-inner (match-end 0))))) + ('perl + (setq allow-code-after t) + (while want-<< + (setq next-<< (search-forward "<<" max t)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (point))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 2)) + ;; fix-me: space + (setq skipped (skip-chars-forward " \t")) + (when (memq (char-after) '(?\" ?\')) + (setq delimiter (list (char-after)))) + (if (and (> skipped 0) (not delimiter)) + (setq heredoc-mark "") ;; blank line + (when (looking-at (rx-to-string + `(and (regexp ,(if delimiter + (concat delimiter "\\([^\n;]*\\)" delimiter) + "\\([^ \t\n<>;]+\\)")) + (or blank ";")))) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 1) + (match-end 1))))) + (when heredoc-mark + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + ;;(setq start-inner (1+ (match-end 0))) + (setq start-inner (1+ (point-at-eol))) + (setq end-mark-len (length heredoc-mark)) + ))) + ('python + (unless (eobp) (forward-char)) + (while want-<< + (setq next-<< (re-search-forward "\"\"\"\\|'''" max t)) + (setq start-outer (- (point) 3)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (- (point) 3))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil))))) + ('ruby + (while want-<< + (setq next-<< (search-forward "<<" max t)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (point))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 2)) + (when (= (char-after) ?-) + (setq skip-b "[ \t]*") + (forward-char)) + (when (looking-at (concat "[^\n[:blank:]]*")) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 0) + (match-end 0))) + (setq end-mark-len (length heredoc-mark)) + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + (setq start-inner (match-end 0))))) + (t (error "next-<< not implemented for lang %s" lang))) + (when start-inner (assert (<= pos start-inner) t)) + (goto-char old-point) + (when (or start-inner end) + (let ((endmark-regexp + (case lang + ('sh (concat "^" skip-b heredoc-mark "$")) + ('php (concat "^" heredoc-mark ";?$")) + ('perl (concat "^" heredoc-mark "$")) + ('python (concat "^" heredoc-mark "[[:space:]]*")) + ('ruby (concat "^" skip-b heredoc-mark "$")) + (t (error "mark-regexp not implemented for %s" lang))))) + ;; Fix-me: rename start-inner <=> start-outer... + (setq border-fun `(lambda (start end exc-mode) + ;; Fix-me: use lengths... + (list + (if ,allow-code-after nil (+ start (- ,start-inner ,start-outer 1))) + (when end (- end ,end-mark-len))))) + (setq fw-exc-fun `(lambda (pos max) + (save-match-data + (let ((here (point))) + (goto-char pos) + (prog1 + (when (re-search-forward ,endmark-regexp max t) + (- (point) 1 ,(length heredoc-mark)) + (- (point) 0) + ) + (goto-char here))))))) + (setq exc-mode (mumamo-mode-for-heredoc heredoc-line)) + (list start-inner end exc-mode nil nil fw-exc-fun nil) + ;; Fix me: Add overriding for inner chunks (see + ;; http://www.emacswiki.org/emacs/NxhtmlMode#toc13). Maybe + ;; make fw-exc-fun a list (or a cons, since overriding is + ;; probably all that I want to add)? And make the + ;; corresponding chunk property a list too? + ;;(list start-outer end exc-mode (list start-inner end) nil fw-exc-fun border-fun 'heredoc) + (list (if allow-code-after start-inner start-outer) + end exc-mode (list start-inner end) nil fw-exc-fun border-fun 'heredoc) + ))) + (error (mumamo-display-error 'mumamo-chunk-heredoc + "%s" (error-message-string err))))) + + +;;;; Unix style sh heredoc + +(defun mumamo-chunk-sh-heredoc (pos min max) + "Find sh here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'sh))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode sh-heredoc-mumamo-mode + "Turn on multiple major modes for sh heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("SH HereDoc" sh-mode + (mumamo-chunk-sh-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'sh-heredoc-mumamo-mode) + + +;;;; PHP heredoc + +(defun mumamo-chunk-php-heredoc (pos min max) + "Find PHP here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'php))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode php-heredoc-mumamo-mode + "Turn on multiple major modes for PHP heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("PHP HereDoc" php-mode + (mumamo-chunk-php-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'php-heredoc-mumamo-mode) +(mumamo-inherit-sub-chunk-family-locally 'php-heredoc-mumamo-mode 'html-mumamo-mode) + + +;;;; Perl heredoc + +(defun mumamo-chunk-perl-heredoc (pos min max) + "Find perl here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'perl))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode perl-heredoc-mumamo-mode + "Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Perl HereDoc" perl-mode + (mumamo-chunk-perl-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'perl-heredoc-mumamo-mode) + +;;;###autoload +(define-mumamo-multi-major-mode cperl-heredoc-mumamo-mode + "Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Perl HereDoc" cperl-mode + (mumamo-chunk-perl-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'cperl-heredoc-mumamo-mode) + + +;;;; Python heredoc + +(defun mumamo-chunk-python-heredoc (pos min max) + "Find python here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'python))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode python-heredoc-mumamo-mode + "Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Python HereDoc" python-mode + (mumamo-chunk-python-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'python-heredoc-mumamo-mode) + + +;;;; Ruby heredoc + +(defun mumamo-chunk-ruby-heredoc (pos min max) + "Find Ruby here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'ruby))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode ruby-heredoc-mumamo-mode + "Turn on multiple major modes for Ruby heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Ruby HereDoc" ruby-mode + (mumamo-chunk-ruby-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'ruby-heredoc-mumamo-mode) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Tex meta + +;; (defun mumamo-search-bw-textext-start (pos min) +;; "Helper for `mumamo-chunk-textext'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "textext(\"")) +;; (exc-mode 'plain-tex-mode)) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +(defconst mumamo-textext-end-regex + (rx "textext(" + (0+ + (0+ (not (any "\"()"))) + ?\" + (0+ (not (any "\""))) + ?\" + ) + (0+ (not (any "\"()"))) + ")")) + +(defun mumamo-textext-test-is-end (pos) + "Helper for `mumamo-chunk-textext'. +Return POS if POS is at the end of textext chunk." + (when pos + (let ((here (point)) + hit) + (goto-char (+ 2 pos)) + (when (looking-back mumamo-textext-end-regex) + (setq hit t)) + (goto-char here) + (when hit pos)))) + +;; (defun mumamo-search-bw-textext-end (pos min) +;; "Helper for `mumamo-chunk-textext'. +;; POS is where to start search and MIN is where to stop." +;; (let ((end (mumamo-chunk-end-bw-str pos min "\")")) +;; res) +;; (while (and end +;; (not (setq res (mumamo-textext-test-is-end end)))) +;; (setq end (mumamo-chunk-end-bw-str (1- end) min "\")"))) +;; res)) + +;; (defun mumamo-search-fw-textext-start-old (pos max) +;; "Helper for `mumamo-chunk-textext'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "textext(\"")) + +(defun mumamo-search-fw-textext-start (pos max) + "Helper for `mumamo-chunk-textext'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "textext(\""))) + (when where + (list where 'plain-tex-mode)))) + +(defun mumamo-search-fw-textext-end (pos max) + "Helper for `mumamo-chunk-textext'. +POS is where to start search and MAX is where to stop." + (save-match-data + (let ((end (mumamo-chunk-end-fw-str pos max "\")"))) + (mumamo-textext-test-is-end end)))) + +(defun mumamo-chunk-textext (pos min max) + "Find textext or TEX chunks. Return range and 'plain-tex-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-textext-start + ;; 'mumamo-search-bw-textext-end + ;; 'mumamo-search-fw-textext-start-old + ;; 'mumamo-search-fw-textext-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-textext-start + 'mumamo-search-fw-textext-end)) + +;; (defun mumamo-search-bw-verbatimtex-start (pos min) +;; "Helper for `mumamo-chunk-verbatimtextext'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "\nverbatimtex")) +;; (exc-mode 'plain-tex-mode)) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +;; (defun mumamo-search-bw-verbatimtex-end (pos min) +;; "Helper for `mumamo-chunk-verbatimtextext'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "\netex")) + +;; (defun mumamo-search-fw-verbatimtex-start-old (pos max) +;; "Helper for `mumamo-chunk-verbatimtextext'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "\nverbatimtex")) + +(defun mumamo-search-fw-verbatimtex-start (pos max) + "Helper for `mumamo-chunk-verbatimtextext'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "\nverbatimtex"))) + (when where + (list where 'plain-tex-mode)))) + +(defun mumamo-search-fw-verbatimtex-end (pos max) + "Helper for `mumamo-chunk-verbatimtextext'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "\netex"))) + +(defun mumamo-chunk-verbatimtex (pos min max) + "Find verbatimtex - etex chunks. Return range and 'plain-tex-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-verbatimtex-start + ;; 'mumamo-search-bw-verbatimtex-end + ;; 'mumamo-search-fw-verbatimtex-start-old + ;; 'mumamo-search-fw-verbatimtex-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-verbatimtex-start + 'mumamo-search-fw-verbatimtex-end)) + +;; (defun mumamo-search-bw-btex-start (pos min) +;; "Helper for `mumamo-chunk-btex'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "\nverbatimtex")) +;; (exc-mode 'plain-tex-mode)) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +;; (defun mumamo-search-bw-btex-end (pos min) +;; "Helper for `mumamo-chunk-btex'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "\netex")) + +;; (defun mumamo-search-fw-btex-start-old (pos max) +;; "Helper for `mumamo-chunk-btex'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "\nverbatimtex")) + +(defun mumamo-search-fw-btex-start (pos max) + "Helper for `mumamo-chunk-btex'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "\nverbatimtex"))) + (when where + (list where 'plain-tex-mode)))) + +(defun mumamo-search-fw-btex-end (pos max) + "Helper for `mumamo-chunk-btex'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "\netex"))) + +(defun mumamo-chunk-btex (pos min max) + "Find btex - etex chunks. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-btex-start + ;; 'mumamo-search-bw-btex-end + ;; 'mumamo-search-fw-btex-start-old + ;; 'mumamo-search-fw-btex-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-btex-start + 'mumamo-search-fw-btex-end)) + +;;;###autoload +(define-mumamo-multi-major-mode metapost-mumamo-mode + "Turn on multiple major modes for MetaPost." + ("MetaPost TeX Family" metapost-mode + (mumamo-chunk-textext + mumamo-chunk-verbatimtex + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; OpenLaszlo + +(defconst mumamo-lzx-method-tag-start-regex + (rx "<method" + (optional + space + (0+ (not (any ">")))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "<![CDATA[" ) + )) + +(defun mumamo-search-bw-exc-start-inlined-lzx-method (pos min) + "Helper for `mumamo-chunk-inlined-lzx-method'. +POS is where to start search and MIN is where to stop." + (goto-char (+ pos 7)) + (let ((marker-start (search-backward "<method" min t)) + exc-mode + exc-start) + (when marker-start + (when (looking-at mumamo-lzx-method-tag-start-regex) + (setq exc-start (match-end 0)) + (goto-char exc-start) + (when (<= exc-start pos) + (cons (point) 'javascript-mode)) + )))) + +;; (defun mumamo-search-bw-exc-end-inlined-lzx-method (pos min) +;; "Helper for `mumamo-chunk-inlined-lzx-method'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "</method>")) + +;; (defun mumamo-search-fw-exc-start-inlined-lzx-method-old (pos max) +;; "Helper for `mumamo-chunk-inlined-lzx-method'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle <![CDATA[ +;; (when (and +;; (eq ?< (char-before)) +;; (eq ?! (char-after)) +;; (not (bobp))) +;; (backward-char) +;; (skip-chars-backward "^<")) +;; (unless (bobp) +;; (backward-char 1)) +;; (let ((exc-start (search-forward "<method" max t)) +;; exc-mode) +;; (when exc-start +;; (goto-char (- exc-start 7)) +;; (when (looking-at mumamo-lzx-method-tag-start-regex) +;; (goto-char (match-end 0)) +;; (point) +;; )))) + +(defun mumamo-search-fw-exc-start-inlined-lzx-method (pos max) + "Helper for `mumamo-chunk-inlined-lzx-method'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle <![CDATA[ + (when (and + (eq ?< (char-before)) + (eq ?! (char-after)) + (not (bobp))) + (backward-char) + (skip-chars-backward "^<")) + (unless (bobp) + (backward-char 1)) + (let ((exc-start (search-forward "<method" max t)) + exc-mode) + (when exc-start + (goto-char (- exc-start 7)) + (when (looking-at mumamo-lzx-method-tag-start-regex) + (goto-char (match-end 0)) + (list (point) 'javascript-mode) + )))) + +(defun mumamo-search-fw-exc-end-inlined-lzx-method (pos max) + "Helper for `mumamo-chunk-inlined-lzx-method'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "</method>"))) + +(defun mumamo-chunk-inlined-lzx-method (pos min max) + "Find <method>...</method>. Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-inlined-lzx-method + ;; 'mumamo-search-bw-exc-end-inlined-lzx-method + ;; 'mumamo-search-fw-exc-start-inlined-lzx-method-old + ;; 'mumamo-search-fw-exc-end-inlined-lzx-method) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-lzx-method + 'mumamo-search-fw-exc-end-inlined-lzx-method)) + +(defconst mumamo-lzx-handler-tag-start-regex + (rx "<handler" + (optional + space + (0+ (not (any ">")))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "<![CDATA[" ) + )) + +;; (defun mumamo-search-bw-exc-start-inlined-lzx-handler (pos min) +;; "Helper for `mumamo-chunk-inlined-lzx-handler'. +;; POS is where to start search and MIN is where to stop." +;; (goto-char (+ pos 8)) +;; (let ((marker-start (search-backward "<handler" min t)) +;; exc-mode +;; exc-start) +;; (when marker-start +;; (when (looking-at mumamo-lzx-handler-tag-start-regex) +;; (setq exc-start (match-end 0)) +;; (goto-char exc-start) +;; (when (<= exc-start pos) +;; (cons (point) 'javascript-mode)) +;; )))) + +;; (defun mumamo-search-bw-exc-end-inlined-lzx-handler (pos min) +;; "Helper for `mumamo-chunk-inlined-lzx-handler'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "</handler>")) + +;; (defun mumamo-search-fw-exc-start-inlined-lzx-handler-old (pos max) +;; "Helper for `mumamo-chunk-inlined-lzx-handler'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle <![CDATA[ +;; (when (and +;; (eq ?< (char-before)) +;; (eq ?! (char-after)) +;; (not (bobp))) +;; (backward-char) +;; (skip-chars-backward "^<")) +;; (unless (bobp) +;; (backward-char 1)) +;; (let ((exc-start (search-forward "<handler" max t)) +;; exc-mode) +;; (when exc-start +;; (goto-char (- exc-start 8)) +;; (when (looking-at mumamo-lzx-handler-tag-start-regex) +;; (goto-char (match-end 0)) +;; (point) +;; )))) + +(defun mumamo-search-fw-exc-start-inlined-lzx-handler (pos max) + "Helper for `mumamo-chunk-inlined-lzx-handler'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle <![CDATA[ + (when (and + (eq ?< (char-before)) + (eq ?! (char-after)) + (not (bobp))) + (backward-char) + (skip-chars-backward "^<")) + (unless (bobp) + (backward-char 1)) + (let ((exc-start (search-forward "<handler" max t)) + exc-mode) + (when exc-start + (goto-char (- exc-start 8)) + (when (looking-at mumamo-lzx-handler-tag-start-regex) + (goto-char (match-end 0)) + (list (point) 'javascript-mode) + )))) + +(defun mumamo-search-fw-exc-end-inlined-lzx-handler (pos max) + "Helper for `mumamo-chunk-inlined-lzx-handler'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "</handler>"))) + +(defun mumamo-chunk-inlined-lzx-handler (pos min max) + "Find <handler>...</handler>. Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-inlined-lzx-handler + ;; 'mumamo-search-bw-exc-end-inlined-lzx-handler + ;; 'mumamo-search-fw-exc-start-inlined-lzx-handler-old + ;; 'mumamo-search-fw-exc-end-inlined-lzx-handler) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-lzx-handler + 'mumamo-search-fw-exc-end-inlined-lzx-handler)) + + +;;;###autoload +(define-mumamo-multi-major-mode laszlo-nxml-mumamo-mode + "Turn on multiple major modes for OpenLaszlo." + ("OpenLaszlo Family" nxml-mode + (mumamo-chunk-inlined-script + mumamo-chunk-inlined-lzx-method + mumamo-chunk-inlined-lzx-handler + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; csound + +;; (defun mumamo-search-bw-exc-start-csound-orc (pos min) +;; "Helper for `mumamo-chunk-csound-orc'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "<csinstruments>"))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'csound-orc-mode)))) + +;; (defun mumamo-search-bw-exc-end-csound-orc (pos min) +;; "Helper for `mumamo-chunk-csound-orc'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "</csinstruments>")) + +;; (defun mumamo-search-fw-exc-start-csound-orc-old (pos max) +;; "Helper for `mumamo-chunk-csound-orc'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "<csinstruments>")) + +(defun mumamo-search-fw-exc-start-csound-orc (pos max) + "Helper for `mumamo-chunk-csound-orc'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "<csinstruments>"))) + (when where + (list where 'csound-orc-mode)))) + +(defun mumamo-search-fw-exc-end-csound-orc (pos max) + "Helper for `mumamo-chunk-csound-orc'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "</csinstruments>"))) + +(defun mumamo-chunk-csound-orc (pos min max) + "Find <csinstruments>...</...>. Return range and 'csound-orc-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-csound-orc + ;; 'mumamo-search-bw-exc-end-csound-orc + ;; 'mumamo-search-fw-exc-start-csound-orc-old + ;; 'mumamo-search-fw-exc-end-csound-orc) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-csound-orc + 'mumamo-search-fw-exc-end-csound-orc)) + +;; (defun mumamo-search-bw-exc-start-csound-sco (pos min) +;; "Helper for `mumamo-chunk-csound-sco'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "<csscore>"))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'csound-sco-mode)))) + +;; (defun mumamo-search-bw-exc-end-csound-sco (pos min) +;; "Helper for `mumamo-chunk-csound-sco'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "</csscore>")) + +;; (defun mumamo-search-fw-exc-start-csound-sco-old (pos max) +;; "Helper for `mumamo-chunk-csound-sco'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "<csscore>")) + +(defun mumamo-search-fw-exc-start-csound-sco (pos max) + "Helper for `mumamo-chunk-csound-sco'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "<csscore>"))) + (when where + (list where 'csound-sco-mode)))) + +(defun mumamo-search-fw-exc-end-csound-sco (pos max) + "Helper for `mumamo-chunk-csound-sco'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "</csscore>"))) + +(defun mumamo-chunk-csound-sco (pos min max) + "Found <csscore>...</csscore>. Return range and 'csound-sco-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-csound-sco + ;; 'mumamo-search-bw-exc-end-csound-sco + ;; 'mumamo-search-fw-exc-start-csound-sco-old + ;; 'mumamo-search-fw-exc-end-csound-sco) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-csound-sco + 'mumamo-search-fw-exc-end-csound-sco)) + +;;;###autoload +(define-mumamo-multi-major-mode csound-sgml-mumamo-mode + "Turn on mutiple major modes for CSound orc/sco Modes." + ("CSound orc/sco Modes" sgml-mode + (mumamo-chunk-csound-sco + mumamo-chunk-csound-orc + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; noweb + +;;;###autoload +(defgroup mumamo-noweb2 nil + "Customization group for `noweb2-mumamo-mode'." + :group 'mumamo-modes) + +(defcustom mumamo-noweb2-mode-from-ext + '( + ("php" . php-mode) + ("c" . c-mode) + ) + "File extension regexp to major mode mapping. +Used by `noweb2-mumamo-mode'." + :type '(repeat + (cons regexp major-mode-function)) + :group 'mumamo-noweb2) + +(defvar mumamo-noweb2-found-mode-from-ext nil + "Major modes determined from file names. Internal use.") + +(defun mumamo-noweb2-chunk-start-fw (pos max) + "Helper for `mumamo-noweb2-chunk'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-re pos max "^<<\\(.*?\\)>>=")) + (exc-mode 'text-mode)) + (when where + (let* ((file-name (match-string-no-properties 1)) + (file-ext (when file-name (file-name-extension file-name)))) + (when file-ext + (setq exc-mode (catch 'major + (dolist (rec mumamo-noweb2-mode-from-ext) + (when (string-match (car rec) file-ext) + (throw 'major (cdr rec)))) + nil)))) + (list where exc-mode)))) + +;; (defun mumamo-noweb2-chunk-start-bw (pos min) +;; "Helper for `mumamo-noweb2-chunk'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-re pos min "^<<\\(.*?\\)>>=")) +;; (exc-mode 'text-mode)) +;; (when exc-start +;; (let* ((file-name (match-string 1)) +;; (file-ext (when file-name (file-name-extension file-name)))) +;; (when file-ext +;; (setq exc-mode (catch 'major +;; (dolist (rec mumamo-noweb2-mode-from-ext) +;; (when (string-match (car rec) file-ext) +;; (throw 'major (cdr rec)))) +;; nil)) +;; (unless exc-mode +;; (setq exc-mode +;; (cdr (assoc file-ext mumamo-noweb2-found-mode-from-ext))) +;; (unless exc-mode +;; ;; Get the major mode from file name +;; (with-temp-buffer +;; (setq buffer-file-name file-name) +;; (condition-case err +;; (normal-mode) +;; (error (message "error (normal-mode): %s" +;; (error-message-string err)))) +;; (setq exc-mode (or major-mode +;; 'text-mode)) +;; (add-to-list 'mumamo-noweb2-found-mode-from-ext +;; (cons file-ext exc-mode))) +;; )))) +;; (cons exc-start exc-mode)))) + +(defun mumamo-noweb2-chunk-end-fw (pos max) + "Helper for `mumamo-noweb2-chunk'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-re pos max "^@"))) + +;; (defun mumamo-noweb2-chunk-end-bw (pos min) +;; "Helper for `mumamo-noweb2-chunk'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-re pos min "^@")) + +(defun mumamo-noweb2-code-chunk (pos min max) + "Find noweb chunks. Return range and found mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (save-match-data + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-noweb2-chunk-start-bw + ;; 'mumamo-noweb2-chunk-end-bw + ;; 'mumamo-noweb2-chunk-start-fw-old + ;; 'mumamo-noweb2-chunk-end-fw) + (mumamo-possible-chunk-forward pos max + 'mumamo-noweb2-chunk-start-fw + 'mumamo-noweb2-chunk-end-fw))) + + +;;;###autoload +(define-mumamo-multi-major-mode noweb2-mumamo-mode + "Multi major mode for noweb files." + ("noweb Family" latex-mode + (mumamo-noweb2-code-chunk))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Template-Toolkit + + + +;; (setq auto-mode-alist +;; (append '(("\\.tt2?$" . tt-mode)) auto-mode-alist )) + +;;(require 'tt-mode) +(defun mumamo-chunk-tt (pos min max) + "Find [% ... %], return range and `tt-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +This is for Template Toolkit. +See URL `http://dave.org.uk/emacs/' for `tt-mode'." + (mumamo-quick-static-chunk pos min max "[%" "%]" t 'tt-mode nil)) + +(define-mumamo-multi-major-mode tt-html-mumamo-mode + "Turn on multiple major modes for TT files with main mode `nxhtml-mode'. +TT = Template-Toolkit. + +This also covers inlined style and javascript." + ("TT HTML Family" html-mode + (mumamo-chunk-tt + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Asp + +;;;; asp <%@language="javscript"%> + +(defvar mumamo-asp-default-major 'asp-js-mode) +(make-variable-buffer-local 'mumamo-asp-default-major) +(put 'mumamo-asp-default-major 'permanent-local t) + +(defconst mumamo-asp-lang-marker + (rx "<%@" + (0+ space) + "language" + (0+ space) + "=" + (0+ space) + "\"" + (submatch (1+ (not (any "\"")))) + "\"" + (0+ space))) + +(defun mumamo-search-fw-exc-start-jsp (pos min max) + ;; fix-me + ) +(defun mumamo-chunk-asp (pos min max) + "Find <% ... %>. Return range and 'asp-js-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; Fix-me: this is broken! + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-asp + ;; 'mumamo-search-bw-exc-end-jsp + ;; 'mumamo-search-fw-exc-start-jsp-old + ;; 'mumamo-search-fw-exc-end-jsp) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-asp + 'mumamo-search-fw-exc-end-jsp)) + + +;;;; asp <% ...> + +(defun mumamo-chunk-asp% (pos min max) + "Find <% ... %>. Return range and 'asp-js-mode or 'asp-vb-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let* ((chunk (mumamo-quick-static-chunk pos min max "<%" "%>" t 'java-mode t)) + (beg (nth 0 chunk)) + (here (point)) + glang) + (when chunk + (goto-char beg) + (if (looking-at mumamo-asp-lang-marker) + (progn + (setq glang (downcase (match-string 1))) + (cond + ((string= glang "javascript") + (setq mumamo-asp-default-major 'asp-js-mode)) + ((string= glang "vbscript") + (setq mumamo-asp-default-major 'asp-vb-mode)) + ) + (setcar (nthcdr 2 chunk) 'mumamo-comment-mode)) + (setcar (nthcdr 2 chunk) mumamo-asp-default-major)) + chunk))) + +;;;; asp <script ...> + +(defconst mumamo-asp-script-tag-start-regex + (rx "<script" + space + (0+ (not (any ">"))) + "language" + (0+ space) + "=" + (0+ space) + ?\" + ;;(or "text" "application") + ;;"/" + ;;(or "javascript" "ecmascript") + ;; "text/javascript" + (submatch + (or "javascript" "vbscript")) + ?\" + (0+ (not (any ">"))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "<![CDATA[" ) + )) + +;; (defun mumamo-asp-search-bw-exc-start-inlined-script (pos min) +;; "Helper function for `mumamo-asp-chunk-inlined-script'. +;; POS is where to start search and MIN is where to stop." +;; (goto-char (+ pos 7)) +;; (let ((marker-start (search-backward "<script" min t)) +;; (exc-mode 'asp-vb-mode) +;; exc-start +;; lang) +;; (when marker-start +;; (when (looking-at mumamo-asp-script-tag-start-regex) +;; (setq lang (downcase (match-string-no-properties 1))) +;; (cond +;; ((string= lang "javascript") +;; (setq exc-mode 'asp-js-mode)) +;; ((string= lang "vbscript") +;; (setq exc-mode 'asp-vb-mode)))) +;; (setq exc-start (match-end 0)) +;; (goto-char exc-start) +;; (when (<= exc-start pos) +;; (cons (point) exc-mode)) +;; ))) + +;; (defun mumamo-asp-search-fw-exc-start-inlined-script-old (pos max) +;; "Helper for `mumamo-chunk-inlined-script'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle <![CDATA[ +;; (when (and +;; (eq ?< (char-before)) +;; (eq ?! (char-after)) +;; (not (bobp))) +;; (backward-char) +;; (skip-chars-backward "^<")) +;; (unless (bobp) +;; (backward-char 1)) +;; (let ((exc-start (search-forward "<script" max t)) +;; exc-mode) +;; (when exc-start +;; (goto-char (- exc-start 7)) +;; (when (looking-at mumamo-asp-script-tag-start-regex) +;; (goto-char (match-end 0)) +;; (point) +;; )))) + +(defun mumamo-asp-search-fw-exc-start-inlined-script (pos max) + "Helper for `mumamo-chunk-inlined-script'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle <![CDATA[ + (when (and + (eq ?< (char-before)) + (eq ?! (char-after)) + (not (bobp))) + (backward-char) + (skip-chars-backward "^<")) + (unless (bobp) + (backward-char 1)) + (let ((exc-start (search-forward "<script" max t)) + (exc-mode 'asp-vb-mode) + (lang "vbscript")) + (when exc-start + (goto-char (- exc-start 7)) + (when (looking-at mumamo-asp-script-tag-start-regex) + (goto-char (match-end 0)) + (setq lang (downcase (match-string-no-properties 1))) + (cond + ((string= lang "javascript") + (setq exc-mode 'asp-js-mode)) + ((string= lang "vbscript") + (setq exc-mode 'asp-vb-mode))) + (list (point) exc-mode) + )))) + +(defun mumamo-asp-chunk-inlined-script (pos min max) + "Find <script language=... runat=...>...</script>. Return 'asp-js-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-asp-search-bw-exc-start-inlined-script + ;; 'mumamo-search-bw-exc-end-inlined-script + ;; 'mumamo-asp-search-fw-exc-start-inlined-script-old + ;; 'mumamo-search-fw-exc-end-inlined-script) + (mumamo-possible-chunk-forward pos max + 'mumamo-asp-search-fw-exc-start-inlined-script + 'mumamo-search-fw-exc-end-inlined-script)) + +;;;###autoload +(define-mumamo-multi-major-mode asp-html-mumamo-mode + "Turn on multiple major modes for ASP with main mode `html-mode'. +This also covers inlined style and javascript." + ("ASP Html Family" html-mode + (mumamo-chunk-asp% + mumamo-asp-chunk-inlined-script + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Org-mode + +(defcustom mumamo-org-submodes + '( + (emacs-lisp emacs-lisp-mode) + (ruby ruby-mode) + (python python-mode) + (sh sh-mode) + (R R-mode) + (ditaa picture-mode) + ) + "Alist for conversion of org #+BEGIN_SRC specifier to major mode. +Works kind of like `mumamo-major-modes'. + +This may be used for example for org-babel \(see URL +`http://orgmode.org/worg/org-contrib/babel/')." + :type '(alist + :key-type (symbol :tag "Symbol in #BEGIN_SRC specifier") + :value-type (repeat (choice + (command :tag "Major mode") + (symbol :tag "Major mode (not yet loaded)"))) + ) + :group 'mumamo-modes) + +(defun mumamo-org-mode-from-spec (major-spec) + "Translate MAJOR-SPEC to a major mode. +Translate MAJOR-SPEC used in #BEGIN_SRC to a major mode. + +See `mumamo-org-submodes' for an explanation." + (mumamo-major-mode-from-spec major-spec mumamo-org-submodes)) + +(defun mumamo-chunk-org-html (pos min max) + "Find #+BEGIN_HTML ... #+END_HTML, return range and `html-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "#+BEGIN_HTML" "#+END_HTML" nil 'html-mode nil)) + +;; (defun mumamo-search-bw-org-src-start (pos min) +;; "Helper for `mumamo-chunk-org-src'. +;; POS is where to start search and MIN is where to stop." +;; (let* ((exc-start (mumamo-chunk-start-bw-str pos min "#+BEGIN_SRC")) +;; (exc-mode (when exc-start +;; (let ((here (point))) +;; (goto-char exc-start) +;; (prog1 +;; (read (current-buffer)) +;; (goto-char here)))))) +;; (setq exc-mode (mumamo-org-mode-from-spec exc-mode)) +;; ;;(setq exc-mode (eval exc-mode)) +;; ;;(setq exc-mode 'text-mode) +;; ;;(when exc-mode (setq exc-mode (quote exc-mode))) +;; ;;(assert (eq exc-mode 'emacs-lisp-mode) t) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +;; (defun mumamo-search-bw-org-src-end (pos min) +;; "Helper for `mumamo-chunk-org-src'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "#+END_SRC")) + +;; (defun mumamo-search-fw-org-src-start-old (pos max) +;; "Helper for `mumamo-chunk-org-src'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "#+BEGIN_SRC")) + +(defun mumamo-search-fw-org-src-start (pos max) + "Helper for `mumamo-chunk-org-src'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "#+BEGIN_SRC"))) + (when where + (let ((exc-mode (let ((here (point))) + (goto-char where) + (prog1 + (read (current-buffer)) + (goto-char here))))) + (setq exc-mode (mumamo-org-mode-from-spec exc-mode)) + (list where exc-mode))))) + +(defun mumamo-search-fw-org-src-end (pos max) + "Helper for `mumamo-chunk-org-src'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "#+END_SRC"))) + +(defun mumamo-chunk-org-src (pos min max) + "Find #+BEGIN_SRC ... #+END_SRC, return range and choosen major mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +See Info node `(org) Literal Examples' for how to specify major +mode." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-org-src-start + ;; 'mumamo-search-bw-org-src-end + ;; 'mumamo-search-fw-org-src-start-old + ;; 'mumamo-search-fw-org-src-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-org-src-start + 'mumamo-search-fw-org-src-end)) + +;;;###autoload +(define-mumamo-multi-major-mode org-mumamo-mode + "Turn on multiple major modes for `org-mode' files with main mode `org-mode'. +** Note about HTML subchunks: +Unfortunately this only allows `html-mode' (not `nxhtml-mode') in +sub chunks." + ("Org Mode + Html" org-mode + (mumamo-chunk-org-html + mumamo-chunk-org-src + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Mako + +;; See http://www.makotemplates.org/docs/syntax.html + +;;; Comments mode +;; Fix-me: move to mumamo.el +(defconst mumamo-comment-font-lock-keywords + (list + (cons "\\(.*\\)" (list 1 font-lock-comment-face)) + )) +(defvar mumamo-comment-font-lock-defaults + '(mumamo-comment-font-lock-keywords t t)) + +(define-derived-mode mumamo-comment-mode nil "Comment chunk" + "For comment blocks." + (set (make-local-variable 'font-lock-defaults) mumamo-comment-font-lock-defaults)) + + + +(defun mumamo-chunk-mako-<% (pos min max) + "Find <% ... %> and <%! ... %>. Return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-mako-<%-bw-start + ;; 'mumamo-mako-<%-bw-end + ;; 'mumamo-mako-<%-fw-start-old + ;; 'mumamo-mako-<%-fw-end + ;; 'mumamo-mako-<%-find-borders) + (let ((chunk (mumamo-possible-chunk-forward pos max + 'mumamo-mako-<%-fw-start + 'mumamo-mako-<%-fw-end + 'mumamo-mako-<%-find-borders + ))) + (when chunk + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-mako-<%-find-borders (start end exc-mode) + (when exc-mode + (list + (when start + (+ start + (if (eq ?! (char-after (+ start 2))) + 3 + 2))) + (when end (- end 2)) + exc-mode))) + +;; (defun mumamo-mako-<%-bw-start (pos min) +;; (let ((here (point)) +;; start +;; ret +;; ) +;; (goto-char (+ pos 3)) +;; (setq start (re-search-backward "<%!?\\(?:[ \t]\\|$\\)" min t)) +;; (when (and start (<= start pos)) +;; (setq ret (list start 'python-mode))) +;; (goto-char here) +;; ret)) + +;; (defun mumamo-mako-<%-bw-end (pos min) +;; (mumamo-chunk-end-bw-str-inc pos min "%>")) ;; ok + +;; (defun mumamo-mako-<%-fw-start-old (pos max) +;; (let ((here (point)) +;; start +;; ret) +;; (goto-char pos) +;; (setq start +;; (re-search-forward "<%!?\\(?:[ \t]\\|$\\)" max t)) +;; (when start +;; (setq ret (match-beginning 0))) +;; (goto-char here) +;; ret)) + +(defun mumamo-mako-<%-fw-start (pos max) + (let ((here (point)) + start + ret) + (goto-char pos) + (setq start + (re-search-forward "<%!?\\(?:[ \t]\\|$\\)" max t)) + (when start + (setq ret (match-beginning 0))) + (goto-char here) + (when ret + (list ret 'python-mode)))) + +(defun mumamo-mako-<%-fw-end (pos max) + (save-match-data + (mumamo-chunk-end-fw-str-inc pos max "%>"))) ;; ok + + + +(defun mumamo-chunk-mako-% (pos min max) + "Find % python EOL. Return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((chunk (mumamo-whole-line-chunk pos min max "%" 'python-mode))) + (when chunk + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-chunk-mako-one-line-comment (pos min max) + "Find ## comment EOL. Return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-whole-line-chunk pos min max "##" 'mumamo-comment-mode)) + +;; Fix-me: Move this to mumamo.el +;; Fix-me: does not work with new chunk div +(defun mumamo-whole-line-chunk-fw-exc-end-fun (pos max) + (let ((here (point))) + (goto-char pos) + (prog1 + (line-end-position) + (goto-char here)))) + +(defun mumamo-whole-line-chunk (pos min max marker mode) + (let* ((here (point)) + (len-marker (length marker)) + (pattern (rx-to-string `(and bol (0+ blank) ,marker blank) t)) + (whole-line-chunk-borders-fun + `(lambda (start end dummy) + (let ((start-border (+ start ,len-marker))) + (list start-border nil)))) + beg + end + ret) + (goto-char pos) + (setq beg (re-search-forward pattern max t)) + (when beg + (setq beg (- beg len-marker 1)) + (setq end (line-end-position)) + (setq ret (list beg + end + mode + (let ((start-border (+ beg len-marker))) + (list start-border nil)) + nil + 'mumamo-whole-line-chunk-fw-exc-end-fun + whole-line-chunk-borders-fun + ))) + (goto-char here) + ret)) + +;; (defun mumamo-single-regexp-chunk (pos min max begin-mark end-mark mode) +;; "Not ready yet. `mumamo-quick-static-chunk'" +;; (let ((here (point)) +;; (len-marker (length marker)) +;; beg +;; end +;; ret) +;; (goto-char pos) +;; (setq beg (line-beginning-position)) +;; (setq end (line-end-position)) +;; (unless (or (when min (< beg min)) +;; (when max (> end max)) +;; (= pos end)) +;; (goto-char beg) +;; (skip-chars-forward " \t") +;; (when (and +;; (string= marker (buffer-substring-no-properties (point) (+ (point) len-marker))) +;; (memq (char-after (+ (point) len-marker)) +;; '(?\ ?\t ?\n)) +;; (>= pos (point))) +;; (setq ret +;; (list (point) +;; end +;; mode +;; (let ((start-border (+ (point) len-marker))) +;; (list start-border nil)))))) +;; (unless ret +;; (let ((range-regexp +;; (concat "^[ \t]*" +;; "\\(" +;; (regexp-quote marker) +;; "[ \t\n].*\\)$"))) +;; ;; Backward +;; (goto-char pos) +;; (unless (= pos (line-end-position)) +;; (goto-char (line-beginning-position))) +;; (setq beg (re-search-backward range-regexp min t)) +;; (when beg (setq beg (match-end 1))) +;; ;; Forward, take care of indentation part +;; (goto-char pos) +;; (unless (= pos (line-end-position)) +;; (goto-char (line-beginning-position))) +;; (setq end (re-search-forward range-regexp max t)) +;; (when end (setq end (match-beginning 1)))) +;; (setq ret (list beg end))) +;; (goto-char here) +;; ;;(setq ret nil) +;; ret)) + + +(defun mumamo-chunk-mako-<%doc (pos min max) + (mumamo-quick-static-chunk pos min max "<%doc>" "</%doc>" t 'mumamo-comment-mode t)) + +(defun mumamo-chunk-mako-<%include (pos min max) + (mumamo-quick-static-chunk pos min max "<%include" "/>" t 'html-mode t)) + +(defun mumamo-chunk-mako-<%inherit (pos min max) + (mumamo-quick-static-chunk pos min max "<%inherit" "/>" t 'html-mode t)) + +(defun mumamo-chunk-mako-<%namespace (pos min max) + (mumamo-quick-static-chunk pos min max "<%namespace" "/>" t 'html-mode t)) + +(defun mumamo-chunk-mako-<%page (pos min max) + (mumamo-quick-static-chunk pos min max "<%page" "/>" t 'html-mode t)) + +;; Fix-me: this is not correct +(defun mumamo-chunk-mako-<%def (pos min max) + (mumamo-quick-static-chunk pos min max "<%def" "</%def>" t 'html-mode t)) + +(defun mumamo-chunk-mako$(pos min max) + "Find ${ ... }, return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "${" "}" t 'python-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode mako-html-mumamo-mode + "Turn on multiple major modes for Mako with main mode `html-mode'. +This also covers inlined style and javascript." +;; Fix-me: test case +;; +;; Fix-me: Add chunks for the tags, but make sure these are made +;; invisible to nxml-mode parser. +;; +;; Fix-me: Maybe finally add that indentation support for one-line chunks? + ("Mako HTML Family" html-mode + ( + mumamo-chunk-mako-one-line-comment + mumamo-chunk-mako-<%doc + mumamo-chunk-mako-<%include + mumamo-chunk-mako-<%inherit + mumamo-chunk-mako-<%namespace + mumamo-chunk-mako-<%page + + mumamo-chunk-mako-<%def + ;;mumamo-chunk-mako-<%namesp:name + ;;mumamo-chunk-mako-<%call + ;;mumamo-chunk-mako-<%text + + mumamo-chunk-mako-<% + mumamo-chunk-mako-% + mumamo-chunk-mako$ + + mumamo-chunk-xml-pi + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(mumamo-inherit-sub-chunk-family-locally 'mako-html-mumamo-mode 'mako-html-mumamo-mode) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; XSL + +;;;###autoload +(define-mumamo-multi-major-mode xsl-nxml-mumamo-mode + "Turn on multi major mode for XSL with main mode `nxml-mode'. +This covers inlined style and javascript." + ("XSL nXtml Family" nxml-mode + ( + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + ))) + +;;;###autoload +(define-mumamo-multi-major-mode xsl-sgml-mumamo-mode + "Turn on multi major mode for XSL with main mode `sgml-mode'. +This covers inlined style and javascript." + ("XSL SGML Family" sgml-mode + ( + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Markdown + +(defun mumamo-chunk-markdown-html-1 (pos min max) + (save-restriction + (goto-char pos) + (narrow-to-region (or min (point)) (or max (point-max))) + (save-match-data + (let ((here (point))) + (when (re-search-forward (rx (* space) + (submatch "<") + (* (any "a-z")) + (or ">" (any " \t\n"))) + nil t) + (let ((beg (match-beginning 1)) + (end)) + (goto-char beg) + (condition-case err + (progn + (while (not (sgml-skip-tag-forward 1))) + (setq end (point))) + (error (message "mumamo-chunk-markdown-html-1: %s" err))) + (goto-char here) + (when (and beg end) + (cons beg end)))))))) + +(defun mumamo-chunk-markdown-html-fw-exc-fun (pos max) + (let ((beg-end (mumamo-chunk-markdown-html-1 pos nil max))) + (cdr beg-end))) + +(defun mumamo-chunk-markdown-html (pos min max) + "Find a chunk of html code in `markdown-mode'. +Return range and `html-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((beg-end (mumamo-chunk-markdown-html-1 pos nil max))) + (when beg-end + (let ((beg (car beg-end)) + (end (cdr beg-end))) + (list beg end 'html-mode + nil ;; borders + nil ;; parseable y + 'mumamo-chunk-markdown-html-fw-exc-fun + nil ;; find-borders fun + ))))) + +;;;###autoload +(define-mumamo-multi-major-mode markdown-html-mumamo-mode + "Turn on multi major markdown mode in buffer. +Main major mode will be `markdown-mode'. +Inlined html will be in `html-mode'. + +You need `markdown-mode' which you can download from URL +`http://jblevins.org/projects/markdown-mode/'." + ("Markdown HTML Family" markdown-mode + ( + mumamo-chunk-markdown-html + ))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Latex related + +(defun mumamo-latex-closure-chunk (pos min max) + (mumamo-quick-static-chunk pos min max "\\begin{clojure}" "\\end{clojure}" t 'clojure-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode latex-clojure-mumamo-mode + "Turn on multi major mode latex+clojure. +Main major mode will be `latex-mode'. +Subchunks will be in `clojure-mode'. + +You will need `clojure-mode' which you can download from URL +`http://github.com/jochu/clojure-mode/tree'." + ("Latex+clojur Family" latex-mode + ( + mumamo-latex-closure-chunk + ))) + +(add-to-list 'auto-mode-alist '("\\.lclj\\'" . latex-clojure-mumamo-mode)) + + +(defun mumamo-latex-haskell-chunk (pos min max) + (mumamo-quick-static-chunk pos min max "\\begin{code}" "\\end{code}" t 'haskell-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode latex-haskell-mumamo-mode + "Turn on multi major mode latex+haskell. +Main major mode will be `latex-mode'. +Subchunks will be in `haskell-mode'. + +You will need `haskell-mode' which you can download from URL +`http://projects.haskell.org/haskellmode-emacs/'." + ("Latex+haskell Family" latex-mode + ( + mumamo-latex-haskell-chunk + ))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Python + ReST + +;; From Martin Soto + +(defun python-rst-long-string-chunk (pos min max) + "Find Python long strings. Return range and 'mumamo-comment-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;;(mumamo-quick-static-chunk pos min max "\"\"\"((" "))\"\"\"" nil 'rst-mode nil)) + (mumamo-quick-static-chunk pos min max "\"\"\"" "\"\"\"" t 'rst-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode python-rst-mumamo-mode + "Turn on multiple major modes for Python with RestructuredText docstrings." + ("Python ReST Family" python-mode + ( + python-rst-long-string-chunk + ))) + + +(provide 'mumamo-fun) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo-fun.el ends here diff --git a/emacs/nxhtml/util/mumamo-regions.el b/emacs/nxhtml/util/mumamo-regions.el new file mode 100644 index 0000000..077be60 --- /dev/null +++ b/emacs/nxhtml/util/mumamo-regions.el @@ -0,0 +1,311 @@ +;;; mumamo-regions.el --- user defined regions with mumamo +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-05-31 Sun +;; Version: 0.5 +;; Last-Updated: 2009-06-01 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Add temporary mumamo chunks (called mumamo regions). This are +;; added interactively from a highlighted region. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'mumamo)) +(eval-when-compile (require 'ourcomments-widgets)) +(require 'ps-print) ;; For ps-print-ensure-fontified + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Internal side functions etc + +(defvar mumamo-regions nil + "List of active mumamo regions. Internal use only. +The entries in this list should be like this + + \(OVL-DEF OVL-CHUNK) + +where OVL-DEF is an overlay containing the definitions, ie `major-mode'. +OVL-CHUNK is the definitions set up temporarily for mumamo chunks. + +The fontification functions in mumamo looks in this list, but the +chunk dividing functions defined by +`define-mumamo-multi-major-mode' does not. The effect is that +the normal chunks exists regardless of what is in this list, but +fontification etc is overridden by what this list says.") +(make-variable-buffer-local 'mumamo-regions) +(put 'mumamo-regions 'permanent-local t) + +(defun mumamo-add-region-1 (major start end buffer) + "Add a mumamo region with major mode MAJOR from START to END. +Return the region. The returned value can be used in +`mumamo-clear-region'. + +START and END should be markers in the buffer BUFFER. They may +also be nil in which case they extend the region to the buffer +boundaries." + (unless mumamo-multi-major-mode + (mumamo-temporary-multi-major)) + (or (not start) + (markerp start) + (eq (marker-buffer start) buffer) + (error "Bad arg start: %s" start)) + (or (not end) + (markerp end) + (eq (marker-buffer end) buffer) + (error "Bad arg end: %s" end)) + (let ((ovl (make-overlay start end))) + (overlay-put ovl 'mumamo-region 'defined) + (overlay-put ovl 'face 'mumamo-region) + (overlay-put ovl 'priority 2) + (mumamo-region-set-major ovl major) + (setq mumamo-regions (cons (list ovl nil) mumamo-regions)) + (mumamo-mark-for-refontification (overlay-start ovl) (overlay-end ovl)) + (message "Added mumamo region from %d to %d" (+ 0 start) (+ 0 end)) + ovl)) + +(defun mumamo-clear-region-1 (region-entry) + "Clear mumamo region REGION-ENTRY. +The entry must have been returned from `mumamo-add-region-1'." + (let ((buffer (overlay-buffer (car region-entry))) + (entry (cdr region-entry))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (let ((ovl1 (car region-entry)) + (ovl2 (cadr region-entry))) + (delete-overlay ovl1) + (when ovl2 + (mumamo-mark-for-refontification (overlay-start ovl2) (overlay-end ovl2)) + (delete-overlay ovl2)) + (setq mumamo-regions (delete region-entry mumamo-regions))))))) + +(defvar mumamo-region-priority 0) +(make-variable-buffer-local 'mumamo-region-priority) +(put 'mumamo-region-priority 'permanent-local t) + +(defun mumamo-get-region-from-1 (point) + "Return mumamo region values for POINT. +The return value is either mumamo chunk or a cons with +information about where regions starts to hide normal chunks. +Such a cons has the format \(BELOW . OVER) where each of them is +a position or nil." + (when mumamo-regions + (save-restriction + (widen) + (let* ((start nil) + (end nil) + (major nil) + hit-reg + ret-val) + (catch 'found-major + (dolist (reg mumamo-regions) + (assert (eq (overlay-get (car reg) 'mumamo-region) 'defined) t) + (assert (or (not (cadr reg)) (overlayp (cadr reg)))) + (let* ((this-ovl (car reg)) + (this-start (overlay-start this-ovl)) + (this-end (overlay-end this-ovl))) + (when (<= this-end point) + (setq start this-end)) + (when (< point this-start) + (setq end this-start)) + (when (and (<= this-start point) + (< point this-end)) + (setq major (overlay-get this-ovl 'mumamo-major-mode)) + (setq start (max this-start (or start this-start))) + (setq end (min this-end (or end this-end))) + (setq hit-reg reg) + (throw 'found-major nil))))) + (if major + (progn + (setq ret-val (nth 1 hit-reg)) + (when ret-val (assert (eq (overlay-get ret-val 'mumamo-region) 'used) t)) + (if ret-val + (move-overlay ret-val start end) + (setq ret-val (make-overlay start end nil t nil)) ;; fix-me + (setcar (cdr hit-reg) ret-val) + (overlay-put ret-val 'mumamo-region 'used) + (overlay-put ret-val 'priority ;; above normal chunks + chunks on chunks + (setq mumamo-region-priority (1+ mumamo-region-priority))) + ;;(overlay-put ret-val 'face '(:background "chocolate")) ;; temporary + (overlay-put ret-val 'mumamo-major-mode + (overlay-get (car hit-reg) 'mumamo-major-mode)))) + (setq ret-val (cons start end))) + ;;(message "mumamo-get-region-from-1, point=%s ret-val=%s" point ret-val) + ret-val)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; User side functions + +(defun mumamo-temporary-multi-major () + "Turn on a temporary multi major mode from buffers current mode. +Define one if no one exists. It will have no chunk dividing +routines. It is meant mainly to be used with mumamo regions when +there is no mumamo multi major mode in the buffer and the user +wants to add a mumamo region \(which requires a multi major mode +to work)." + (when mumamo-multi-major-mode + (error "Mumamo is already active in buffer")) + (let* ((temp-mode-name (concat "mumamo-1-" + (symbol-name major-mode))) + (temp-mode-sym (intern-soft temp-mode-name))) + (unless (and temp-mode-sym + (fboundp temp-mode-sym)) + (setq temp-mode-sym (intern temp-mode-name)) + (eval + `(define-mumamo-multi-major-mode ,temp-mode-sym + "Temporary multi major mode." + ("Temporary" ,major-mode nil)))) + (put temp-mode-sym 'mumamo-temporary major-mode) + (funcall temp-mode-sym))) + +(defface mumamo-region + '((t (:background "white"))) + "Face for mumamo-region regions." + :group 'mumamo) + +;;;###autoload +(defun mumamo-add-region () + "Add a mumamo region from selection. +Mumamo regions are like another layer of chunks above the normal chunks. +They does not affect the normal chunks, but they overrides them. + +To create a mumamo region first select a visible region and then +call this function. + +If the buffer is not in a multi major mode a temporary multi +major mode will be created applied to the buffer first. +To get out of this and get back to a single major mode just use + + M-x normal-mode" + (interactive) + (if (not mark-active) + (message (propertize "Please select a visible region first" 'face 'secondary-selection)) + (let ((beg (region-beginning)) + (end (region-end)) + (maj (mumamo-region-read-major))) + (mumamo-add-region-1 maj (copy-marker beg) (copy-marker end) (current-buffer)) + (setq deactivate-mark t)))) + +;;;###autoload +(defun mumamo-add-region-from-string () + "Add a mumamo region from string at point. +Works as `mumamo-add-region' but for string or comment at point. + +Buffer must be fontified." + (interactive) + ;; assure font locked. + (require 'ps-print) + (ps-print-ensure-fontified (point-min) (point-max)) + (let ((the-face (get-text-property (point) 'face))) + (if (not (memq the-face + '(font-lock-doc-face + font-lock-string-face + font-lock-comment-face))) + (message "No string or comment at point") + (let ((beg (previous-single-property-change (point) 'face)) + (end (next-single-property-change (point) 'face)) + (maj (mumamo-region-read-major))) + (setq beg (or (when beg (1+ beg)) + (point-min))) + (setq end (or (when end (1- end)) + (point-max))) + (mumamo-add-region-1 maj (copy-marker beg) (copy-marker end) (current-buffer)))))) +;; (dolist (o (overlays-in (point-min) (point-max))) (delete-overlay o)) +(defun mumamo-clear-all-regions () + "Clear all mumamo regions in buffer. +For information about mumamo regions see `mumamo-add-region'." + (interactive) + (unless mumamo-multi-major-mode + (error "There can be no mumamo regions to clear unless in multi major modes")) + (while mumamo-regions + (mumamo-clear-region-1 (car mumamo-regions)) + (setq mumamo-regions (cdr mumamo-regions))) + (let ((old (get mumamo-multi-major-mode 'mumamo-temporary))) + (when old (funcall old))) + (message "Cleared all mumamo regions")) + +(defun mumamo-region-read-major () + "Prompt user for major mode. +Accept only single major mode, not mumamo multi major modes." + (let ((major (read-command "Major mode: "))) + (unless (major-modep major) (error "Not a major mode: %s" major)) + (when (mumamo-multi-major-modep major) (error "Multi major modes not allowed: %s" major)) + (when (let ((major-mode major)) + (derived-mode-p 'nxml-mode)) + (error "%s is based on nxml-mode and can't be used here" major)) + major)) + +(defun mumamo-region-at (point) + "Return mumamo region at POINT." + (let ((ovls (overlays-at (point)))) + (catch 'overlay + (dolist (o ovls) + (when (overlay-get o 'mumamo-region) + (throw 'overlay o))) + nil))) + +(defun mumamo-region-set-major (ovl major) + "Change major mode for mumamo region at point. +For information about mumamo regions see `mumamo-add-region'. + +If run non-interactively then OVL should be a mumamo region and +MAJOR the major mode to set for that region." + (interactive + (list (or (mumamo-region-at (point)) + (error "There is no mumamo region at point")) + (mumamo-region-read-major))) + (overlay-put ovl 'mumamo-major-mode `(,major)) + (overlay-put ovl 'help-echo (format "Mumamo region, major mode `%s'" major))) + +(defun mumamo-clear-region (ovl) + "Clear the mumamo region at point. +For information about mumamo regions see `mumamo-add-region'. + +If run non-interactively then OVL should be the mumamo region to +clear." + (interactive + (list (or (mumamo-region-at (point)) + (error "There is no mumamo region at point")))) + (let ((region-entry (rassoc (list ovl) mumamo-regions))) + (unless region-entry + (error "No mumamo region found at point")) + (mumamo-clear-region-1 region-entry))) + + +(provide 'mumamo-regions) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo-regions.el ends here diff --git a/emacs/nxhtml/util/mumamo-trace.el b/emacs/nxhtml/util/mumamo-trace.el new file mode 100644 index 0000000..72b839b --- /dev/null +++ b/emacs/nxhtml/util/mumamo-trace.el @@ -0,0 +1,6 @@ +(trace-function-background 'mumamo-fontify-region-1) +(trace-function-background 'mumamo-fontify-region-with) +(trace-function-background 'mumamo-mark-for-refontification) +(trace-function-background 'syntax-ppss-flush-cache) + +;;(untrace-all) diff --git a/emacs/nxhtml/util/mumamo.el b/emacs/nxhtml/util/mumamo.el new file mode 100644 index 0000000..3fefa1a --- /dev/null +++ b/emacs/nxhtml/util/mumamo.el @@ -0,0 +1,9100 @@ +;;; mumamo.el --- Multiple major modes in a buffer +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Maintainer: +;; Created: Fri Mar 09 2007 +(defconst mumamo:version "0.91") ;;Version: +;; Last-Updated: 2009-10-19 Mon +;; URL: http://OurComments.org/Emacs/Emacs.html +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `appmenu', `apropos', `backquote', `button', `bytecomp', `cl', +;; `comint', `compile', `easymenu', `flyspell', `grep', `ido', +;; `ispell', `mail-prsvr', `mlinks', `mm-util', `nxml-enc', +;; `nxml-glyph', `nxml-mode', `nxml-ns', `nxml-outln', +;; `nxml-parse', `nxml-rap', `nxml-util', `ourcomments-util', +;; `recentf', `ring', `rng-dt', `rng-loc', `rng-match', +;; `rng-parse', `rng-pttrn', `rng-uri', `rng-util', `rng-valid', +;; `rx', `sgml-mode', `timer', `tool-bar', `tree-widget', +;; `url-expand', `url-methods', `url-parse', `url-util', +;; `url-vars', `wid-edit', `xmltok'. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Commentary: +;; +;; In some cases you may find that it is quite hard to write one major +;; mode that does everything for the type of file you want to handle. +;; That is the case for example for a PHP file where there comes +;; useful major modes with Emacs for the html parts, and where you can +;; get a major mode for PHP from other sources (see EmacsWiki for +;; Aaron Hawleys php-mode.el, or the very similar version that comes +;; with nXhtml). +;; +;; Using one major mode for the HTML part and another for the PHP part +;; sounds like a good solution. But this means you want to use (at +;; least) two major modes in the same buffer. +;; +;; This file implements just that, support for MUltiple MAjor MOdes +;; (mumamo) in a buffer. +;; +;; +;;;; Usage: +;; +;; The multiple major mode support is turned on by calling special +;; functions which are used nearly the same way as major modes. See +;; `mumamo-defined-multi-major-modes' for more information about those +;; functions. +;; +;; Each such function defines how to take care of a certain mix of +;; major functions in the buffer. We call them "multi major modes". +;; +;; You may call those functions directly (like you can with major mode +;; functions) or you may use them in for example `auto-mode-alist'. +;; +;; You can load mumamo in your .emacs with +;; +;; (require 'mumamo-fun) +;; +;; or you can generate an autoload file from mumamo-fun.el +;; +;; Note that no multi major mode functions are defined in this file. +;; Together with this file comes the file mumamo-fun.el that defines +;; some such functions. All those functions defined in that file are +;; marked for autoload. +;; +;; +;; +;; Thanks to Stefan Monnier for beeing a good and knowledgeable +;; speaking partner for some difficult parts while I was trying to +;; develop this. +;; +;; Thanks to RMS for giving me support and ideas about the programming +;; interface. That simplified the code and usage quite a lot. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; How to add support for a new mix of major modes +;; +;; This is done by creating a new function using +;; `define-mumamo-multi-major-mode'. See that function for more +;; information. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Information for major mode authors +;; +;; There are a few special requirements on major modes to make them +;; work with mumamo: +;; +;; - fontification-functions should be '(jit-lock-function). However +;; nxml-mode derivates can work too, see the code for more info. +;; +;; - narrowing should be respected during fontification and +;; indentation when font-lock-dont-widen is non-nil. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Information for minor mode authors +;; +;; Some minor modes are written to be specific for the file edited in +;; the buffer and some are written to be specific for a major +;; modes. Others are emulating another editor. Those are probably +;; global, but might still have buffer local values. +;; +;; Those minor modes that are not meant to be specific for a major +;; mode should probably survive changing major mode in the +;; buffer. That is mostly not the case in Emacs today. +;; +;; There are (at least) two type of values for those minor modes that +;; sometimes should survive changing major mode: buffer local +;; variables and functions added locally to hooks. +;; +;; * Some buffer local variables are really that - buffer local. Other +;; are really meant not for the buffer but for the major mode or +;; some minor mode that is local to the buffer. +;; +;; If the buffer local variable is meant for the buffer then it is +;; easy to make them survive changing major mode: just add +;; +;; (put 'VARIABLE 'permanent-local t) +;; +;; to those variables. That will work regardless of the way major +;; mode is changed. +;; +;; If one only wants the variables to survive the major mode change +;; that is done when moving between chunks with different major +;; modes then something different must be used. To make a variable +;; survive this, but not a major mode change for the whole buffer, +;; call any the function `mumamo-make-variable-buffer-permanent': +;; +;; (mumamo-make-variable-buffer-permanent 'VARIABLE) +;; +;; * For functions entered to local hooks use this +;; +;; (put 'FUNSYM 'permanent-local-hook t) +;; (add-hook 'HOOKSYM 'FUNSYM nil t) +;; +;; where HOOKSYM is the hook and FUNSYM is the function. +;; +;; * Some functions that are run in `change-major-mode' and dito +;; after- must be avoided when mumamo changes major mode. The +;; functions to avoid should be listed in +;; +;; `mumamo-change-major-mode-no-nos' +;; `mumamo-after-change-major-mode-no-nos' +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Comments on code etc: +;; +;; This is yet another way to try to get different major modes for +;; different chunks of a buffer to work. (I borrowed the term "chunk" +;; here from multi-mode.el.) I am aware of two main previous elisp +;; packages that tries to do this, multi-mode.el and mmm-mode.el. +;; (See http://www.emacswiki.org/cgi-bin/wiki/MultipleModes where +;; there are also some other packages mentioned.) The solutions in +;; those are a bit different from the approach here. +;; +;; The idea of doing it the way mumamo does it is of course based on a +;; hope that switching major mode when moving between chunks should be +;; quick. I found that it took from 0 - 62 000 ms, typically 0 - 16 +;; 000 ms on a 3ghz cpu. However unfortunately this is not the whole +;; truth. It could take longer time, depending on what is run in the +;; hooks: The major mode specific hook, `after-change-major-mode-hook' +;; and `change-major-mode-hook'. +;; +;; Because it currently may take long enough time switching major mode +;; when moving between chunks to disturb smooth moving around in the +;; buffer I have added a way to let the major mode switching be done +;; after moving when Emacs is idle. This is currently the default, but +;; see the custom variable `mumamo-set-major-mode-delay'. +;; +;; Since the intention is to set up the new major mode the same way as +;; it should have been done if this was a major mode for the whole +;; buffer these hooks must be run. However if this idea is developed +;; further some of the things done in these hooks (like switching on +;; minor modes) could perhaps be streamlined so that switching minor +;; modes off and then on again could be avoided. In fact there is +;; already tools for this in mumamo.el, see the section below named +;; "Information for minor mode authors". +;; +;; Another problem is that the major modes must use +;; `font-lock-fontify-region-function'. Currently the only major +;; modes I know that does not do this are `nxml-mode' and its +;; derivatives. +;; +;; The indentation is currently working rather ok, but with the price +;; that buffer modified is sometimes set even though there are no +;; actual changes. That seems a bit unnecessary and it could be +;; avoided if the indentation functions for the the various major +;; modes were rewritten so that you could get the indentation that +;; would be done instead of actually doing the indentation. (Or +;; mumamo could do this better, but I do not know how right now.) +;; +;; See also "Known bugs and problems etc" below. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Known bugs: +;; +;; - See the various FIX-ME for possible bugs. See also below. +;; +;; +;;;; Known problems and ideas: +;; +;; - There is no way in Emacs to tell a mode not to change +;; fontification when changing to or from that mode. +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'cc-engine)) +(eval-when-compile (require 'desktop)) +(eval-when-compile (require 'flyspell)) +(eval-when-compile (require 'rngalt nil t)) +(eval-when-compile (require 'nxml-mode nil t)) +(eval-when-compile + (when (featurep 'nxml-mode) + (require 'rng-valid nil t) + ;;(require 'rngalt nil t) + )) +(eval-when-compile (require 'sgml-mode)) ;; For sgml-xml-mode +;; For `define-globalized-minor-mode-with-on-off': +;;(require 'ourcomments-util) + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; rng-valid.el support + +(defvar rng-get-major-mode-chunk-function nil + "Function to use to get major mode chunk. +It should take one argument, the position where to get the major +mode chunk. + +This is to be set by multiple major mode frame works, like +mumamo. + +See also `rng-valid-nxml-major-mode-chunk-function' and +`rng-end-major-mode-chunk-function'. Note that all three +variables must be set.") +(make-variable-buffer-local 'rng-get-major-mode-chunk-function) +(put 'rng-get-major-mode-chunk-function 'permanent-local t) + +(defvar rng-valid-nxml-major-mode-chunk-function nil + "Function to use to check if nxml can parse major mode chunk. +It should take one argument, the chunk. + +For more info see also `rng-get-major-mode-chunk-function'.") +(make-variable-buffer-local 'rng-valid-nxml-major-mode-chunk-function) +(put 'rng-valid-nxml-major-mode-chunk-function 'permanent-local t) + +(defvar rng-end-major-mode-chunk-function nil + "Function to use to get the end of a major mode chunk. +It should take one argument, the chunk. + +For more info see also `rng-get-major-mode-chunk-function'.") +(make-variable-buffer-local 'rng-end-major-mode-chunk-function) +(put 'rng-end-major-mode-chunk-function 'permanent-local t) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Some variables + +(defvar mumamo-major-mode-indent-line-function nil) +(make-variable-buffer-local 'mumamo-major-mode-indent-line-function) + +(defvar mumamo-buffer-locals-per-major nil) +(make-variable-buffer-local 'mumamo-buffer-locals-per-major) +(put 'mumamo-buffer-locals-per-major 'permanent-local t) + +(defvar mumamo-just-changed-major nil + "Avoid refontification when switching major mode. +Set to t by `mumamo-set-major'. Checked and reset to nil by +`mumamo-jit-lock-function'.") +(make-variable-buffer-local 'mumamo-just-changed-major) + +(defvar mumamo-multi-major-mode nil + "The function that handles multiple major modes. +If this is nil then multiple major modes in the buffer is not +handled by mumamo. + +Set by functions defined by `define-mumamo-multi-major-mode'.") +(make-variable-buffer-local 'mumamo-multi-major-mode) +(put 'mumamo-multi-major-mode 'permanent-local t) + +(defvar mumamo-set-major-running nil + "Internal use. Handling of mumamo turn off.") + +(defun mumamo-chunk-car (chunk prop) + (car (overlay-get chunk prop))) + +(defun mumamo-chunk-cadr (chunk prop) + (cadr (overlay-get chunk prop))) + +;; (let ((l '(1 2))) (setcar (nthcdr 1 l) 10) l) +;; setters +(defsubst mumamo-chunk-value-set-min (chunk-values min) + "In CHUNK-VALUES set min value to MIN. +CHUNK-VALUES should have the format return by +`mumamo-create-chunk-values-at'." + (setcar (nthcdr 0 chunk-values) min)) +(defsubst mumamo-chunk-value-set-max (chunk-values max) + "In CHUNK-VALUES set max value to MAX. +See also `mumamo-chunk-value-set-min'." + (setcar (nthcdr 1 chunk-values) max)) +(defsubst mumamo-chunk-value-set-syntax-min (chunk-values min) + "In CHUNK-VALUES set min syntax diff value to MIN. +See also `mumamo-chunk-value-set-min'." + (setcar (nthcdr 3 chunk-values) min)) +(defsubst mumamo-chunk-value-set-syntax-max (chunk-values max) + "In CHUNK-VALUES set max syntax diff value to MAX. +See also `mumamo-chunk-value-set-min'." + (setcar (nthcdr 3 chunk-values) max)) +;; getters +(defsubst mumamo-chunk-value-min (chunk-values) + "Get min value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 0 chunk-values)) +(defsubst mumamo-chunk-value-max (chunk-values) + "Get max value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 1 chunk-values)) +(defsubst mumamo-chunk-value-major (chunk-values) + "Get major value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 2 chunk-values)) +(defsubst mumamo-chunk-value-syntax-min (chunk-values) + "Get min syntax diff value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 3 chunk-values)) +(defsubst mumamo-chunk-value-syntax-max (chunk-values) + "Get max syntax diff value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 4 chunk-values)) +(defsubst mumamo-chunk-value-parseable-by (chunk-values) + "Get parseable-by from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'. +For parseable-by see `mumamo-find-possible-chunk'." + (nth 5 chunk-values)) +;; (defsubst mumamo-chunk-prev-chunk (chunk-values) +;; "Get previous chunk from CHUNK-VALUES. +;; See also `mumamo-chunk-value-set-min'." +;; (nth 6 chunk-values)) +(defsubst mumamo-chunk-value-fw-exc-fun (chunk-values) + "Get function that find chunk end from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 6 chunk-values)) + +(defsubst mumamo-chunk-major-mode (chunk) + "Get major mode specified in CHUNK." + ;;(assert chunk) + ;;(assert (overlay-buffer chunk)) + (let ((mode-spec (if chunk + (mumamo-chunk-car chunk 'mumamo-major-mode) + (mumamo-main-major-mode)))) + (mumamo-major-mode-from-modespec mode-spec))) + +(defsubst mumamo-chunk-syntax-min-max (chunk no-obscure) + (when chunk + (let* ((ovl-end (overlay-end chunk)) + (ovl-start (overlay-start chunk)) + (syntax-min (min ovl-end + (+ ovl-start + (or (overlay-get chunk 'mumamo-syntax-min-d) + 0)))) + ;;(dummy (msgtrc "chunk-syntax-min-max:syntax-min=%s, chunk=%S" syntax-min chunk)) + (syntax-max + (max ovl-start + (- (overlay-end chunk) + (or (overlay-get chunk 'mumamo-syntax-max-d) + 0) + (if (= (1+ (buffer-size)) + (overlay-end chunk)) + 0 + ;; Note: We must subtract one here because + ;; overlay-end is +1 from the last point in the + ;; overlay. + ;; + ;; This cured the problem with + ;; kubica-freezing-i.html that made Emacs loop + ;; in `font-lock-extend-region-multiline'. But + ;; was it really this one, I can't find any + ;; 'font-lock-multiline property. So it should + ;; be `font-lock-extend-region-whole-lines'. + ;; + ;; Should not the problem then be the value of font-lock-end? + ;; + ;; Fix-me: however this is not correct since it + ;; leads to not fontifying the last character in + ;; the chunk, see bug 531324. + ;; + ;; I think this is cured by now. I have let + ;; bound `font-lock-extend-region-functions' + ;; once more before the call to + ;; `font-lock-fontify-region'. + 0 + ;;0 + )))) + (obscure (unless no-obscure (overlay-get chunk 'obscured))) + (region-info (cadr obscure)) + (obscure-min (car region-info)) + (obscure-max (cdr region-info)) + ;;(dummy (message "syn-mn-mx:obs=%s r-info=%s ob=%s/%s" obscure region-info obscure-min obscure-max )) + (actual-min (max (or obscure-min ovl-start) + (or syntax-min ovl-start))) + (actual-max (min (or obscure-max ovl-end) + (or syntax-max ovl-end))) + (maj (mumamo-chunk-car chunk 'mumamo-major-mode)) + ;;(dummy (message "syn-mn-mx:obs=%s r-info=%s ob=%s/%s ac=%s/%s" obscure region-info obscure-min obscure-max actual-min actual-max)) + ) + (cons actual-min actual-max)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Macros + +;; Borrowed from font-lock.el +(defmacro mumamo-save-buffer-state (varlist &rest body) + "Bind variables according to VARLIST and eval BODY restoring buffer state. +Do not record undo information during evaluation of BODY." + (declare (indent 1) (debug let)) + (let ((modified (make-symbol "modified"))) + `(let* ,(append varlist + `((,modified (buffer-modified-p)) + (buffer-undo-list t) + (inhibit-read-only t) + (inhibit-point-motion-hooks t) + (inhibit-modification-hooks t) + deactivate-mark + buffer-file-name + buffer-file-truename)) + (progn + ,@body) + (unless ,modified + (restore-buffer-modified-p nil))))) + +;; From jit-lock.el: +(defmacro mumamo-jit-with-buffer-unmodified (&rest body) + "Eval BODY, preserving the current buffer's modified state." + (declare (debug t)) + (let ((modified (make-symbol "modified"))) + `(let ((,modified (buffer-modified-p))) + (unwind-protect + (progn ,@body) + (unless ,modified + (restore-buffer-modified-p nil)))))) + +(defmacro mumamo-with-buffer-prepared-for-jit-lock (&rest body) + "Execute BODY in current buffer, overriding several variables. +Preserves the `buffer-modified-p' state of the current buffer." + (declare (debug t)) + `(mumamo-jit-with-buffer-unmodified + (let ((buffer-undo-list t) + (inhibit-read-only t) + (inhibit-point-motion-hooks t) + (inhibit-modification-hooks t) + deactivate-mark + buffer-file-name + buffer-file-truename) + ,@body))) + +(defmacro mumamo-condition-case (var body-form &rest handlers) + "Like `condition-case', but optional. +If `mumamo-use-condition-case' is non-nil then do + + (condition-case VAR + BODY-FORM + HANDLERS). + +Otherwise just evaluate BODY-FORM." + (declare (indent 2) (debug t)) + `(if (not mumamo-use-condition-case) + (let* ((debugger (or mumamo-debugger 'debug)) + (debug-on-error (if debugger t debug-on-error))) + ,body-form) + (condition-case ,var + ,body-form + ,@handlers))) + +(defmacro mumamo-msgfntfy (format-string &rest args) + "Give some messages during fontification. +This macro should just do nothing during normal use. However if +there are any problems you can uncomment one of the lines in this +macro and recompile/reeval mumamo.el to get those messages. + +You have to search the code to see where you will get them. All +uses are in this file. + +FORMAT-STRING and ARGS have the same meaning as for the function +`message'." + ;;(list 'apply (list 'quote 'msgtrc) format-string (append '(list) args)) + ;;(list 'apply (list 'quote 'message) format-string (append '(list) args)) + ;;(list 'progn 'apply (list 'quote 'message) format-string (append '(list) args) nil) + ;; (condition-case err + ;; (list 'apply (list 'quote 'message) format-string (append '(list) args)) ;; <-- + ;; (error (message "err in msgfntfy %S" err))) + ;;(message "%s %S" format-string args) + ;;(list 'apply (list 'quote 'message) (list 'concat "%s: " format-string) + ;; (list 'get-internal-run-time) (append '(list) args)) + ) +;;(mumamo-msgfntfy "my-format=%s" (get-internal-run-time)) + +(defmacro mumamo-msgindent (format-string &rest args) + "Give some messages during indentation. +This macro should just do nothing during normal use. However if +there are any problems you can uncomment one of the lines in this +macro and recompile/reeval mumamo.el to get those messages. + +You have to search the code to see where you will get them. All +uses are in this file. + +FORMAT-STRING and ARGS have the same meaning as for the function +`message'." + ;;(list 'apply (list 'quote 'msgtrc) format-string (append '(list) args)) + ;;(list 'apply (list 'quote 'message) format-string (append '(list) args)) ;; <--- + ;;(list 'apply (list 'quote 'message) (list 'concat "%s: " format-string) + ;; (list 'get-internal-run-time) (append '(list) args)) + ) + +(defmacro mumamo-with-major-mode-setup (major for-what &rest body) + "Run code with some local variables set as in specified major mode. +Set variables as needed for major mode MAJOR when doing FOR-WHAT +and then run BODY using `with-syntax-table'. + +FOR-WHAT is used to choose another major mode than MAJOR in +certain cases. It should be 'fontification or 'indentation. + +Note: We must let-bind the variables here instead of make them buffer +local since they otherwise could be wrong at \(point) in top +level \(ie user interaction level)." + (declare (indent 2) (debug t)) + `(let ((need-major-mode (mumamo-get-major-mode-substitute ,major ,for-what))) + ;;(msgtrc "mumamo-with-major-mode-setup %s => %s, modified=%s" ,major need-major-mode (buffer-modified-p)) + ;;(msgtrc "with-major-mode-setup <<<<<<<<<< body=%S\n>>>>>>>>>>" '(progn ,@body)) + ;;(msgtrc "with-major-mode-setup:in buffer %s after-chunk=%s" (current-buffer) (when (boundp 'after-chunk) after-chunk)) + (let ((major-mode need-major-mode) + (evaled-set-mode (mumamo-get-major-mode-setup need-major-mode))) + ;;(message ">>>>>> before %s" evaled-set-mode) + ;;(message ">>>>>> before %s, body=%s" evaled-set-mode (list ,@body)) + (funcall (symbol-value evaled-set-mode) + (list 'progn + ,@body)) + ;;(mumamo-msgfntfy "<<<<<< after evaled-set-mode modified=%s" (buffer-modified-p)) + ))) + +(defmacro mumamo-with-major-mode-fontification (major &rest body) + "With fontification variables set as major mode MAJOR eval BODY. +This is used during font locking and indentation. The variables +affecting those are set as they are in major mode MAJOR. + +See the code in `mumamo-fetch-major-mode-setup' for exactly which +local variables that are set." + (declare (indent 1) (debug t)) + `(mumamo-with-major-mode-setup ,major 'fontification + ,@body)) +;; Fontification disappears in for example *grep* if +;; font-lock-mode-major-mode is 'permanent-local t. +;;(put 'font-lock-mode-major-mode 'permanent-local t) + +(defmacro mumamo-with-major-mode-indentation (major &rest body) + "With indentation variables set as in another major mode do things. +Same as `mumamo-with-major-mode-fontification' but for +indentation. See that function for some notes about MAJOR and +BODY." + (declare (indent 1) (debug t)) + `(mumamo-with-major-mode-setup ,major 'indentation ,@body)) + +;; fix-me: tell no sub-chunks in sub-chunks +;;;###autoload +(defmacro define-mumamo-multi-major-mode (fun-sym spec-doc chunks) + "Define a function that turn on support for multiple major modes. +Define a function FUN-SYM that set up to divide the current +buffer into chunks with different major modes. + +The documentation string for FUN-SYM should contain the special +documentation in the string SPEC-DOC, general documentation for +functions of this type and information about chunks. + +The new function will use the definitions in CHUNKS \(which is +called a \"chunk family\") to make the dividing of the buffer. + +The function FUN-SYM can be used to setup a buffer instead of a +major mode function: + +- The function FUN-SYM can be called instead of calling a major + mode function when you want to use multiple major modes in a + buffer. + +- The defined function can be used instead of a major mode + function in for example `auto-mode-alist'. + +- As the very last thing FUN-SYM will run the hook FUN-SYM-hook, + just as major modes do. + +- There is also a general hook, `mumamo-turn-on-hook', which is + run when turning on mumamo with any of these functions. This + is run right before the hook specific to any of the functions + above that turns on the multiple major mode support. + +- The multi major mode FUN-SYM has a keymap named FUN-SYM-map. + This overrides the major modes' keymaps since it is handled as + a minor mode keymap. + +- There is also a special mumamo keymap, `mumamo-map' that is + active in every buffer with a multi major mode. This is also + handled as a minor mode keymap and therefor overrides the major + modes' keymaps. + +- However when this support for multiple major mode is on the + buffer is divided into chunks, each with its own major mode. + +- The chunks are fontified according the major mode assigned to + them for that. + +- Indenting is also done according to the major mode assigned to + them for that. + +- The actual major mode used in the buffer is changed to the one + in the chunk when moving point between these chunks. + +- When major mode is changed the hooks for the new major mode, + `after-change-major-mode-hook' and `change-major-mode-hook' are + run. + +- There will be an alias for FUN-SYM called mumamo-alias-FUN-SYM. + This can be used to check whic multi major modes have been + defined. + +** A little bit more technical description: + +The dividing of a buffer into chunks is done during fontification +by `mumamo-get-chunk-at'. + +The name of the function is saved in in the buffer local variable +`mumamo-multi-major-mode' when the function is called. + +All functions defined by this macro is added to the list +`mumamo-defined-multi-major-modes'. + +Basically Mumamo handles only major modes that uses jit-lock. +However as a special effort also `nxml-mode' and derivatives +thereof are handled. Since it seems impossible to me to restrict +those major modes fontification to only a chunk without changing +`nxml-mode' the fontification is instead done by +`html-mode'/`sgml-mode' for chunks using `nxml-mode' and its +derivates. + +CHUNKS is a list where each entry have the format + + \(CHUNK-DEF-NAME MAIN-MAJOR-MODE SUBMODE-CHUNK-FUNCTIONS) + +CHUNK-DEF-NAME is the key name by which the entry is recognized. +MAIN-MAJOR-MODE is the major mode used when there is no chunks. +If this is nil then `major-mode' before turning on this mode will +be used. + +SUBMODE-CHUNK-FUNCTIONS is a list of the functions that does the +chunk division of the buffer. They are tried in the order they +appear here during the chunk division process. + +If you want to write new functions for chunk divisions then +please see `mumamo-find-possible-chunk'. You can perhaps also +use `mumamo-quick-static-chunk' which is more easy-to-use +alternative. See also the file mumamo-fun.el where there are +many routines for chunk division. + +When you write those new functions you may want to use some of +the functions for testing chunks: + + `mumamo-test-create-chunk-at' `mumamo-test-create-chunks-at-all' + `mumamo-test-easy-make' `mumamo-test-fontify-region' + +These are in the file mumamo-test.el." + ;;(let ((c (if (symbolp chunks) (symbol-value chunks) chunks))) (message "c=%S" c)) + (let* (;;(mumamo-describe-chunks (make-symbol "mumamo-describe-chunks")) + (turn-on-fun (if (symbolp fun-sym) + fun-sym + (error "Parameter FUN-SYM must be a symbol"))) + (turn-on-fun-alias (intern (concat "mumamo-alias-" (symbol-name fun-sym)))) + ;; Backward compatibility nXhtml v 1.60 + (turn-on-fun-old (when (string= (substring (symbol-name fun-sym) -5) + "-mode") + (intern (substring (symbol-name fun-sym) 0 -5)))) + (turn-on-hook (intern (concat (symbol-name turn-on-fun) "-hook"))) + (turn-on-map (intern (concat (symbol-name turn-on-fun) "-map"))) + (turn-on-hook-doc (concat "Hook run at the very end of `" + (symbol-name turn-on-fun) "'.")) + (chunks2 (if (symbolp chunks) + (symbol-value chunks) + chunks)) + (docstring + (concat + spec-doc + " + + + +This function is called a multi major mode. It sets up for +multiple major modes in the buffer in the following way: + +" + ;; Fix-me: During byte compilation the next line is not + ;; expanded as I thought because the functions in CHUNKS + ;; are not defined. How do I fix this? Move out the + ;; define-mumamo-multi-major-mode calls? + (funcall 'mumamo-describe-chunks chunks2) + " +At the very end this multi major mode function runs first the hook +`mumamo-turn-on-hook' and then `" (symbol-name turn-on-hook) "'. + +There is a keymap specific to this multi major mode, but it is +not returned by `current-local-map' which returns the chunk's +major mode's local keymap. + +The multi mode keymap is named `" (symbol-name turn-on-map) "'. + + + +The main use for a multi major mode is to use it instead of a +normal major mode in `auto-mode-alist'. \(You can of course call +this function directly yourself too.) + +The value of `mumamo-multi-major-mode' tells you which multi +major mode if any has been turned on in a buffer. For more +information about multi major modes please see +`define-mumamo-multi-major-mode'. + +Note: When adding new font-lock keywords for major mode chunks +you should use the function `mumamo-refresh-multi-font-lock' +afterwards. +" ))) + `(progn + ;;(add-to-list 'mumamo-defined-multi-major-modes (cons (car ',chunks2) ',turn-on-fun)) + (mumamo-add-to-defined-multi-major-modes (cons (car ',chunks2) ',turn-on-fun)) + (defvar ,turn-on-hook nil ,turn-on-hook-doc) + (defvar ,turn-on-map (make-sparse-keymap) + ,(concat "Keymap for multi major mode function `" + (symbol-name turn-on-fun) "'")) + (defvar ,turn-on-fun nil) + (make-variable-buffer-local ',turn-on-fun) + (put ',turn-on-fun 'permanent-local t) + (put ',turn-on-fun 'mumamo-chunk-family (copy-tree ',chunks2)) + (put ',turn-on-fun-alias 'mumamo-chunk-family (copy-tree ',chunks2)) + (defun ,turn-on-fun nil ,docstring + (interactive) + (let ((old-major-mode (or mumamo-major-mode + major-mode))) + (kill-all-local-variables) + (run-hooks 'change-major-mode-hook) + (setq mumamo-multi-major-mode ',turn-on-fun) + (setq ,turn-on-fun t) + (mumamo-add-multi-keymap ',turn-on-fun ,turn-on-map) + (setq mumamo-current-chunk-family (copy-tree ',chunks2)) + (mumamo-turn-on-actions old-major-mode) + (run-hooks ',turn-on-hook))) + (defalias ',turn-on-fun-alias ',turn-on-fun) + (when (intern-soft ',turn-on-fun-old) + (defalias ',turn-on-fun-old ',turn-on-fun)) + ))) + +;;;###autoload +(defun mumamo-add-to-defined-multi-major-modes (entry) + (add-to-list 'mumamo-defined-multi-major-modes entry)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Debugging etc + +(defsubst mumamo-while (limit counter where) + (let ((count (symbol-value counter))) + (if (= count limit) + (progn + (msgtrc "Reached (while limit=%s, where=%s)" limit where) + nil) + (set counter (1+ count))))) + +;; (defun dbg-smarty-err () +;; ;; (insert "}{") + +;; ;; (insert "}{") +;; ;; (backward-char) +;; ;; (backward-char) +;; ;; (search-backward "}") + +;; ;; This gives an error rather often, but not always: +;; (delete-char 3) +;; (search-backward "}") +;; ) + +;; (defun dbg-smarty-err2 () +;; (forward-char 5) +;; (insert "}{") +;; ;; Start in nxhtml part and make sure the insertion is in smarty +;; ;; part. Gives reliably an error if moved backward so point stay in +;; ;; the new nxhtml-mode part, otherwise not. +;; ;; +;; ;; Eh, no. If chunk family is changed and reset there is no more an +;; ;; error. +;; ;; +;; ;; Seems to be some race condition, but I am unable to understand +;; ;; how. I believed that nxml always left in a reliable state. Is +;; ;; this a state problem in mumamo or nxml? I am unable to make it +;; ;; happen again now. +;; ;; +;; ;; I saw one very strange thing: The error message got inserted in +;; ;; the .phps buffer once. How could this happen? Is this an Emacs +;; ;; bug? Can't see how this could happen since it is the message +;; ;; function that outputs the message. A w32 race condition? Are +;; ;; people aware that the message queue runs in parallell? (I have +;; ;; tried to ask on the devel list, but got no answer at that time.) +;; (backward-char 2) +;; ) + + +(defvar msgtrc-buffer + "*Messages*" + ;;"*trace-output*" + "Buffer or name of buffer for trace messages. +See `msgtrc'." + ) + +(defun msgtrc (format-string &rest args) + "Print message to `msgtrc-buffer'. +Arguments FORMAT-STRING and ARGS are like for `message'." + (if nil + nil ;;(apply 'message format-string args) + ;; bug#3350 prevents use of this: + (let ((trc-buffer (get-buffer-create msgtrc-buffer)) + ;; Cure 3350: Stop insert from deactivating the mark + (deactivate-mark)) + (with-current-buffer trc-buffer + (goto-char (point-max)) + (insert "MU:" (apply 'format format-string args) "\n") + ;;(insert "constant string\n") + (when buffer-file-name (write-region nil nil buffer-file-name)))))) + +(defvar mumamo-message-file-buffer nil) +(defsubst mumamo-msgtrc-to-file () + "Start writing message to file. Erase `msgtrc-buffer' first." + (unless mumamo-message-file-buffer + (setq mumamo-message-file-buffer (find-file-noselect "c:/emacs/bugs/temp-messages.txt")) + (setq msgtrc-buffer mumamo-message-file-buffer) + (with-current-buffer mumamo-message-file-buffer + (erase-buffer)))) + +(defvar mumamo-display-error-lwarn nil + "Set to t to call `lwarn' on fontification errors. +If this is t then `*Warnings*' buffer will popup on fontification +errors.") +(defvar mumamo-display-error-stop nil + "Set to t to stop fontification on errors.") + +(defun mumamo-message-with-face (msg face) + "Put MSG with face FACE in *Messages* buffer." + (let ((start (+ (with-current-buffer msgtrc-buffer + (point-max)) + 1)) + ;; This is for the echo area: + (msg-with-face (propertize (format "%s" msg) + 'face face))) + + (msgtrc "%s" msg-with-face) + ;; This is for the buffer: + (with-current-buffer msgtrc-buffer + (goto-char (point-max)) + (backward-char) + (put-text-property start (point) + 'face face)))) + +;;(run-with-idle-timer 1 nil 'mumamo-show-report-message) +(defun mumamo-show-report-message () + "Tell the user there is a long error message." + (save-match-data ;; runs in timer + (mumamo-message-with-face + "MuMaMo error, please look in the *Messages* buffer" + 'highlight))) + +;; This code can't be used now because `debugger' is currently not +;; useable in timers. I keep it here since I hope someone will make it +;; possible in the future. +;; +;; (defmacro mumamo-get-backtrace-if-error (bodyform) +;; "Evaluate BODYFORM, return a list with error message and backtrace. +;; If there is an error in BODYFORM then return a list with the +;; error message and the backtrace as a string. Otherwise return +;; nil." +;; `(let* ((debugger +;; (lambda (&rest debugger-args) +;; (let ((debugger-ret (with-output-to-string (backtrace)))) +;; ;; I believe we must put the result in a buffer, +;; ;; otherwise `condition-case' might erase it: +;; (with-current-buffer (get-buffer-create "TEMP GET BACKTRACE") +;; (erase-buffer) +;; (insert debugger-ret))))) +;; (debug-on-error t) +;; (debug-on-signal t)) +;; (mumamo-condition-case err +;; (progn +;; ,bodyform +;; nil) +;; (error +;; (let* ((errmsg (error-message-string err)) +;; (dbg1-ret +;; (with-current-buffer +;; (get-buffer "TEMP GET BACKTRACE") (buffer-string))) +;; ;; Remove lines from this routine: +;; (debugger-lines (split-string dbg1-ret "\n")) +;; (dbg-ret (mapconcat 'identity (nthcdr 6 debugger-lines) "\n")) +;; ) +;; (list errmsg (concat errmsg "\n" dbg-ret))))))) + +;;(mumamo-display-error 'test-lwarn-type "testing 1=%s, 2=%s" "one" 'two) +(defun mumamo-display-error (lwarn-type format-string &rest args) + "Display a message plus traceback in the *Messages* buffer. +Use this for errors that happen during fontification or when +running a timer. + +LWARN-TYPE is used as the type argument to `lwarn' if warnings +are displayed. FORMAT-STRING and ARGS are used as the +corresponding arguments to `message' and `lwarn'. + +All the output from this function in the *Messages* buffer is +displayed with the highlight face. After the message printed by +`message' is traceback from where this function was called. +Note: There is no error generated, just a traceback that is put +in *Messages* as above. + +Display an error message using `message' and colorize it using +the `highlight' face to make it more prominent. Add a backtrace +colored with the `highlight' face to the buffer *Messages*. Then +display the error message once again after this so that the user +can see it. + +If `mumamo-display-error-lwarn' is non-nil, indicate the error by +calling `lwarn'. This will display the `*Warnings*' buffer and +thus makes it much more easy to spot that there was an error. + +If `mumamo-display-error-stop' is non-nil raise an error that may +stop fontification." + + ;; Warnings are sometimes disturbning, make it optional: + (when mumamo-display-error-lwarn + (apply 'lwarn lwarn-type :error format-string args)) + + (let ((format-string2 (concat "%s: " format-string)) + (bt (with-output-to-string (backtrace)))) + + (mumamo-message-with-face + (concat + (apply 'format format-string2 lwarn-type args) + "\n" + (format "** In buffer %s\n" (current-buffer)) + bt) + 'highlight) + + ;; Output message once again so the user can see it: + (apply 'message format-string2 lwarn-type args) + ;; But ... there might be more messages so wait until things has + ;; calmed down and then show a message telling that there was an + ;; error and that there is more information in the *Messages* + ;; buffer. + (run-with-idle-timer 1 nil 'mumamo-show-report-message) + + ;; Stop fontifying: + (when mumamo-display-error-stop + ;;(font-lock-mode -1) + (setq font-lock-mode nil) + (when (timerp jit-lock-context-timer) + (cancel-timer jit-lock-context-timer)) + (when (timerp jit-lock-defer-timer) + (cancel-timer jit-lock-defer-timer)) + (apply 'error format-string2 lwarn-type args)))) + + +(defun mumamo-debug-to-backtrace (&rest debugger-args) + "This function should give a backtrace during fontification errors. +The variable `debugger' should then be this function. See the +function `debug' for an explanation of DEBUGGER-ARGS. + +Fix-me: Can't use this function yet since the display routines +uses safe_eval and safe_call." + (mumamo-display-error 'mumamo-debug-to-backtrace + "%s" + (nth 1 debugger-args))) + +;; (defun my-test-err3 () +;; (interactive) +;; (let ((debugger 'mumamo-debug-to-backtrace) +;; (debug-on-error t)) +;; (my-err) +;; )) +;;(my-test-err3() + +;;(set-default 'mumamo-use-condition-case nil) +;;(set-default 'mumamo-use-condition-case t) +(defvar mumamo-use-condition-case t) +(make-variable-buffer-local 'mumamo-use-condition-case) +(put 'mumamo-use-condition-case 'permanent-local t) + +(defvar mumamo-debugger 'mumamo-debug-to-backtrace) +(make-variable-buffer-local 'mumamo-debugger) +(put 'mumamo-debugger 'permanent-local t) + +;; (defun my-test-err4 () +;; (interactive) +;; (mumamo-condition-case err +;; (my-errx) +;; (arith-error (message "here")) +;; (error (message "%s, %s" err (error-message-string err))) +;; )) + +(defvar mumamo-warned-once nil) +(make-variable-buffer-local 'mumamo-warned-once) +(put 'mumamo-warned-once 'permanent-local t) + + ; (append '(0 1) '(a b)) +(defun mumamo-warn-once (type message &rest args) + "Warn only once with TYPE, MESSAGE and ARGS. +If the same problem happens again then do not warn again." + (let ((msgrec (append (list type message) args))) + (unless (member msgrec mumamo-warned-once) + (setq mumamo-warned-once + (cons msgrec mumamo-warned-once)) + ;;(apply 'lwarn type :warning message args) + (apply 'message (format "%s: %s" type message) args) + ))) + +(defun mumamo-add-help-tabs () + "Add key bindings for moving between buttons. +Add bindings similar to those in `help-mode' for moving between +text buttons." + (local-set-key [tab] 'forward-button) + (local-set-key [(meta tab)] 'backward-button) + (local-set-key [(shift tab)] 'backward-button) + (local-set-key [backtab] 'backward-button)) + +(defun mumamo-insert-describe-button (symbol type) + "Insert a text button that describes SYMBOL of type TYPE." + (let ((func `(lambda (btn) + (funcall ',type ',symbol)))) + (mumamo-add-help-tabs) + (insert-text-button + (symbol-name symbol) + :type 'help-function + 'face 'link + 'action func))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Custom group + +;;;###autoload +(defgroup mumamo nil + "Customization group for multiple major modes in a buffer." + :group 'editing + :group 'languages + :group 'sgml + :group 'nxhtml + ) + +;;(setq mumamo-set-major-mode-delay -1) +;;(setq mumamo-set-major-mode-delay 5) +(defcustom mumamo-set-major-mode-delay idle-update-delay + "Delay this number of seconds before setting major mode. +When point enters a region where the major mode should be +different than the current major mode, wait until Emacs has been +idle this number of seconds before switching major mode. + +If negative switch major mode immediately. + +Ideally the switching of major mode should occur immediately when +entering a region. However this can make movements a bit unsmooth +for some major modes on a slow computer. Therefore on a slow +computer use a short delay. + +If you have a fast computer and want to use mode specific +movement commands then set this variable to -1. + +I tried to measure the time for switching major mode in mumamo. +For most major modes it took 0 ms, but for `nxml-mode' and its +derivate it took 20 ms on a 3GHz CPU." + :type 'number + :group 'mumamo) + + +(defgroup mumamo-display nil + "Customization group for mumamo chunk display." + :group 'mumamo) + +(defun mumamo-update-this-buffer-margin-use () + (mumamo-update-buffer-margin-use (current-buffer))) + +(define-minor-mode mumamo-margin-info-mode + "Display chunk info in margin when on. +Display chunk depth and major mode where a chunk begin in left or +right margin. \(The '-mode' part of the major mode is stripped.) + +See also `mumamo-margin-use'. + +Note: When `linum-mode' is on the right margin is always used +now \(since `linum-mode' uses the left)." + :group 'mumamo-display + (mumamo-update-this-buffer-margin-use) + (if mumamo-margin-info-mode + (progn + ;;(add-hook 'window-configuration-change-hook 'mumamo-update-this-buffer-margin-use nil t) + (add-hook 'linum-mode-hook 'mumamo-update-this-buffer-margin-use nil t) + ) + ;;(remove-hook 'window-configuration-change-hook 'mumamo-update-this-buffer-margin-use t) + (remove-hook 'linum-mode-hook 'mumamo-update-this-buffer-margin-use t) + )) +;;(put 'mumamo-margin-info-mode 'permanent-local t) + +(defun mumamo-margin-info-mode-turn-off () + (mumamo-margin-info-mode -1)) +(put 'mumamo-margin-info-mode-turn-off 'permanent-local-hook t) + +(define-globalized-minor-mode mumamo-margin-info-global-mode mumamo-margin-info-mode + (lambda () (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (mumamo-margin-info-mode 1))) + :group 'mumamo-display) + +(defcustom mumamo-margin-use '(left-margin 13) + "Display chunk info in left or right margin if non-nil." + :type '(list (radio (const :tag "Display chunk info in left margin" left-margin) + (const :tag "Display chunk info in right margin" right-margin)) + (integer :tag "Margin width (when used)" :value 13)) + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'mumamo-update-all-buffers-margin-use) + (mumamo-update-all-buffers-margin-use))) + :group 'mumamo-display) + +(defun mumamo-update-all-buffers-margin-use () + (dolist (buf (buffer-list)) + (mumamo-update-buffer-margin-use buf))) + +(define-minor-mode mumamo-no-chunk-coloring + "Use no background colors to distinguish chunks. +When this minor mode is on in a buffer no chunk coloring is done +in that buffer. This is overrides `mumamo-chunk-coloring'. It +is meant for situations when you temporarily need to remove the +background colors." + :lighter " ø" + :group 'mumamo-display + (font-lock-mode -1) + (font-lock-mode 1)) +(put 'mumamo-no-chunk-coloring 'permanent-local t) + + +;; (setq mumamo-chunk-coloring 4) +(defcustom mumamo-chunk-coloring 0 + "Color chunks with depth greater than or equal to this. +When 0 all chunks will be colored. If 1 all sub mode chunks will +be colored, etc." + :type '(integer :tag "Color chunks with depth greater than this") + :group 'mumamo-display) + +(defface mumamo-background-chunk-major + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "MidnightBlue") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "cornsilk") + (((class color) (min-colors 16) (background dark)) + :background "blue4") + (((class color) (min-colors 16) (background light)) + :background "cornsilk") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in sub modes. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode1 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "DarkGreen" + ;;:background "#081010" + ) + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "Azure") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "Blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode2 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "dark green") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "#e6ff96") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode3 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "dark green") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "#f7d1f4") + ;;:background "green") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode4 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "dark green") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "orange") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-major 'mumamo-background-chunk-major + "Background colors for chunks in major mode. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode1 'mumamo-background-chunk-submode1 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode2 'mumamo-background-chunk-submode2 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode3 'mumamo-background-chunk-submode3 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode4 'mumamo-background-chunk-submode4 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +;; Fix-me: use and enhance this +(defcustom mumamo-background-colors '(mumamo-background-chunk-major + mumamo-background-chunk-submode1 + mumamo-background-chunk-submode2 + mumamo-background-chunk-submode3 + mumamo-background-chunk-submode4 + ) + "List of background colors in order of use. +First color is for main major mode chunks, then for submode +chunks, sub-submode chunks etc. Colors are reused in cyclic +order. + +The default colors are choosen so that inner chunks has a more +standing out color the further in you get. This is supposed to +be helpful when you make mistakes and the chunk nesting is not +what you intended. + +Note: Only the light background colors have been set by me. The +dark background colors might currently be unuseful. +Contributions and suggestions are welcome! + +The values in the list should be symbols. Each symbol should either be + + 1: a variable symbol pointing to a face (or beeing nil) + 2: a face symbol + 3: a function with one argument (subchunk depth) returning a + face symbol" + :type '(repeat symbol) + :group 'mumamo-display) + +;;(mumamo-background-color 0) +;;(mumamo-background-color 1) +;;(mumamo-background-color 2) +(defun mumamo-background-color (sub-chunk-depth) + (when (and (not mumamo-no-chunk-coloring) + (or (not (integerp mumamo-chunk-coloring)) ;; Old values + (>= sub-chunk-depth mumamo-chunk-coloring))) + (let* ((idx (when mumamo-background-colors + (mod sub-chunk-depth (length mumamo-background-colors)))) + (sym (when idx (nth idx mumamo-background-colors))) + fac) + (when sym + (when (boundp sym) + (setq fac (symbol-value sym)) + (unless (facep fac) (setq fac nil))) + (unless fac + (when (facep sym) + (setq fac sym))) + (unless fac + (when (fboundp sym) + (setq fac (funcall sym sub-chunk-depth)))) + (when fac + (unless (facep fac) + (setq fac nil))) + fac + )))) + +(defface mumamo-border-face-in + '((t (:inherit font-lock-preprocessor-face :bold t :italic t :underline t))) + "Face for marking borders." + :group 'mumamo-display) + +(defface mumamo-border-face-out + '((t (:inherit font-lock-preprocessor-face :bold t :italic t :underline t))) + "Face for marking borders." + :group 'mumamo-display) + + +(defgroup mumamo-indentation nil + "Customization group for mumamo chunk indentation." + :group 'mumamo) + +(defcustom mumamo-submode-indent-offset 2 + "Indentation of submode relative outer major mode. +If this is nil then indentation first non-empty line in a +subchunk will \(normally) be 0. See however +`mumamo-indent-line-function-1' for special handling of first +line in subsequent subchunks. + +See also `mumamo-submode-indent-offset-0'." + :type '(choice integer + (const :tag "No special")) + :group 'mumamo-indentation) + +(defcustom mumamo-submode-indent-offset-0 0 + "Indentation of submode at column 0. +This value overrides `mumamo-submode-indent-offset' when the +outer major mode above has indentation 0." + :type '(choice integer + (const :tag "No special")) + :group 'mumamo-indentation) + +(defcustom mumamo-indent-major-to-use + '( + ;;(nxhtml-mode html-mode) + (html-mode nxhtml-mode) + ) + "Major mode to use for indentation. +This is normally the major mode specified for the chunk. Here you +can make exceptions." + :type '(repeat + (list (symbol :tag "Major mode symbol specified") + (command :tag "Major mode to use"))) + :group 'mumamo-indentation) + +;;(mumamo-indent-get-major-to-use 'nxhtml-mode) +;;(mumamo-indent-get-major-to-use 'html-mode) +(defun mumamo-indent-get-major-to-use (major depth) + (or (and (= depth 0) + (cadr (assq major mumamo-indent-major-to-use))) + major)) + +(defcustom mumamo-indent-widen-per-major + '( + (php-mode (use-widen)) + (nxhtml-mode (use-widen (html-mumamo-mode nxhtml-mumamo-mode))) + (html-mode (use-widen (html-mumamo-mode nxhtml-mumamo-mode))) + ) + "Wether do widen buffer during indentation. +If not then the buffer is narrowed to the current chunk when +indenting a line in a chunk." + :type '(repeat + (list (symbol :tag "Major mode symbol") + (set + (const :tag "Widen buffer during indentation" use-widen) + (repeat (command :tag "Widen if multi major is any of those")) + ))) + :group 'mumamo-indentation) + + +;;;###autoload +(defgroup mumamo-hi-lock-faces nil + "Faces for hi-lock that are visible in mumamo multiple modes. +This is a workaround for the problem that text properties are +always hidden behind overlay dito. + +This faces are not as visible as those that defines background +colors. However they use underlining so they are at least +somewhat visible." + :group 'hi-lock + :group 'mumamo-display + :group 'faces) + +(defface hi-mumamo-yellow + '((((min-colors 88) (background dark)) + (:underline "yellow1")) + (((background dark)) (:underline "yellow")) + (((min-colors 88)) (:underline "yellow1")) + (t (:underline "yellow"))) + "Default face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-pink + '((((background dark)) (:underline "pink")) + (t (:underline "pink"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-green + '((((min-colors 88) (background dark)) + (:underline "green1")) + (((background dark)) (:underline "green")) + (((min-colors 88)) (:underline "green1")) + (t (:underline "green"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-blue + '((((background dark)) (:underline "light blue")) + (t (:underline "light blue"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-black-b + '((t (:weight bold :underline t))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-blue-b + '((((min-colors 88)) (:weight bold :underline "blue1")) + (t (:weight bold :underline "blue"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-green-b + '((((min-colors 88)) (:weight bold :underline "green1")) + (t (:weight bold :underline "green"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-red-b + '((((min-colors 88)) (:weight bold :underline "red1")) + (t (:weight bold :underline "red"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + + +;; (defcustom mumamo-check-chunk-major-same nil +;; "Check if main major mode is the same as normal mode." +;; :type 'boolean +;; :group 'mumamo) + +;; (customize-option 'mumamo-major-modes) +;;(require 'django) + +(defgroup mumamo-modes nil + "Customization group for mumamo chunk modes." + :group 'mumamo) + +(defcustom mumamo-major-modes + '( + (asp-js-mode + js-mode ;; Not autoloaded in the pretest + javascript-mode + espresso-mode + ecmascript-mode) + (asp-vb-mode + visual-basic-mode) + ;;(css-mode fundamental-mode) + (javascript-mode + js-mode ;; Not autoloaded in the pretest + javascript-mode + espresso-mode + ;;js2-fl-mode + ecmascript-mode) + (java-mode + jde-mode + java-mode) + (groovy-mode + groovy-mode) + ;; For Emacs 22 that do not have nxml by default + ;; Fix me: fallback when autoload fails! + (nxhtml-mode + nxhtml-mode + html-mode) + ) + "Alist for conversion of chunk major mode specifier to major mode. +Each entry has the form + + \(MAJOR-SPEC MAJORMODE ...) + +where the symbol MAJOR-SPEC specifies the code type and should +match the value returned from `mumamo-find-possible-chunk'. The +MAJORMODE symbols are major modes that can be used for editing +that code type. The first available MAJORMODE is the one that is +used. + +The MAJOR-SPEC symbols are used by the chunk definitions in +`define-mumamo-multi-major-mode'. + +The major modes are not specified directly in the chunk +definitions. Instead a chunk definition contains a symbol that +is looked up in this list to find the chunk's major mode. + +The reason for doing it this way is to make it possible to use +new major modes with existing multi major modes. If for example +someone writes a new CSS mode that could easily be used instead +of the current one in `html-mumamo-mode'. + +Lookup in this list is done by `mumamo-major-mode-from-modespec'." + :type '(alist + :key-type (symbol :tag "Symbol for major mode spec in chunk") + :value-type (repeat (choice + (command :tag "Major mode") + (symbol :tag "Major mode (not yet loaded)"))) + ) + :group 'mumamo-modes) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; JIT lock functions + +(defun mumamo-jit-lock-function (start) + "This function is added to `fontification-functions' by mumamo. +START is a parameter given to functions in that hook." + (mumamo-msgfntfy "mumamo-jit-lock-function %s, ff=%s, just-changed=%s" + start + (when start + (save-restriction + (widen) + (get-text-property start 'fontified))) + mumamo-just-changed-major) + ;;(msgtrc "jit-lock-function %s, ff=%s, just-changed=%s" start (get-text-property start 'fontified) mumamo-just-changed-major) + ;;(msgtrc "mumamo-jit-lock-function enter: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + (if mumamo-just-changed-major + (setq mumamo-just-changed-major nil)) + (let ((ret (jit-lock-function start))) + (mumamo-msgfntfy "mumamo-jit-lock-function EXIT %s, ff=%s, just-changed=%s" + start + (when start + (save-restriction + (widen) + (get-text-property start 'fontified))) + mumamo-just-changed-major) + ;;(msgtrc "mumamo-jit-lock-function exit: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ret)) + +(defun mumamo-jit-lock-register (fun &optional contextual) + "Replacement for `jit-lock-register'. +Avoids refontification, otherwise same. FUN and CONTEXTUAL has +the some meaning as there." + (add-hook 'jit-lock-functions fun nil t) + (when (and contextual jit-lock-contextually) + (set (make-local-variable 'jit-lock-contextually) t)) + + ;;(jit-lock-mode t) + ;; + ;; Replace this with the code below from jit-lock-mode t part: + (setq jit-lock-mode t) + + ;; Mark the buffer for refontification. + ;; This is what we want to avoid in mumamo: + ;;(jit-lock-refontify) + + ;; Install an idle timer for stealth fontification. + (when (and jit-lock-stealth-time (null jit-lock-stealth-timer)) + (setq jit-lock-stealth-timer + (run-with-idle-timer jit-lock-stealth-time t + 'jit-lock-stealth-fontify))) + + ;; Create, but do not activate, the idle timer for repeated + ;; stealth fontification. + (when (and jit-lock-stealth-time (null jit-lock-stealth-repeat-timer)) + (setq jit-lock-stealth-repeat-timer (timer-create)) + (timer-set-function jit-lock-stealth-repeat-timer + 'jit-lock-stealth-fontify '(t))) + + ;; Init deferred fontification timer. + (when (and jit-lock-defer-time (null jit-lock-defer-timer)) + (setq jit-lock-defer-timer + (run-with-idle-timer jit-lock-defer-time t + 'jit-lock-deferred-fontify))) + + ;; Initialize contextual fontification if requested. + (when (eq jit-lock-contextually t) + (unless jit-lock-context-timer + (setq jit-lock-context-timer + (run-with-idle-timer jit-lock-context-time t + 'jit-lock-context-fontify))) + (setq jit-lock-context-unfontify-pos + (or jit-lock-context-unfontify-pos (point-max)))) + + ;; Setup our hooks. + ;;(add-hook 'after-change-functions 'jit-lock-after-change t t) + ;;(add-hook 'after-change-functions 'mumamo-jit-lock-after-change t t) + (add-hook 'after-change-functions 'mumamo-after-change t t) + ;; Set up fontification to call jit: + (let ((ff (reverse fontification-functions))) + (mapc (lambda (f) + ;;(unless (eq f 'jit-lock-function) + (remove-hook 'fontification-functions f t)) + ;;) + ff)) + (add-hook 'fontification-functions 'mumamo-jit-lock-function nil t) + ) + +;; Fix-me: integrate this with fontify-region! +(defvar mumamo-find-chunks-timer nil) +(make-variable-buffer-local 'mumamo-find-chunks-timer) +(put 'mumamo-find-chunks-timer 'permanent-local t) + +(defvar mumamo-find-chunk-delay idle-update-delay) +(make-variable-buffer-local 'mumamo-find-chunk-delay) +(put 'mumamo-find-chunk-delay 'permanent-local t) + +(defun mumamo-stop-find-chunks-timer () + "Stop timer that find chunks." + (when (and mumamo-find-chunks-timer + (timerp mumamo-find-chunks-timer)) + (cancel-timer mumamo-find-chunks-timer)) + (setq mumamo-find-chunks-timer nil)) + +(defun mumamo-start-find-chunks-timer () + "Start timer that find chunks." + (mumamo-stop-find-chunks-timer) + ;; (setq mumamo-find-chunks-timer + ;; (run-with-idle-timer mumamo-find-chunk-delay nil + ;; 'mumamo-find-chunks-in-timer (current-buffer))) + ) + +(defun mumamo-find-chunks-in-timer (buffer) + "Run `mumamo-find-chunks' in buffer BUFFER in a timer." + (mumamo-msgfntfy "mumamo-find-chunks-in-timer %s" buffer) + ;;(message "mumamo-find-chunks-in-timer %s" buffer) + (condition-case err + (when (buffer-live-p buffer) + (with-current-buffer buffer + (mumamo-find-chunks nil "mumamo-find-chunks-in-timer"))) + (error (message "mumamo-find-chunks error: %s" err)))) + + +(defvar mumamo-last-chunk nil) +(make-variable-buffer-local 'mumamo-last-chunk) +(put 'mumamo-last-chunk 'permanent-local t) + +(defvar mumamo-last-change-pos nil) +(make-variable-buffer-local 'mumamo-last-change-pos) +(put 'mumamo-last-change-pos 'permanent-local t) + +;; Fix-me: maybe this belongs to contextual fontification? Eh, +;; no. Unfortunately there is not way to make that handle more than +;; multiple lines. +(defvar mumamo-find-chunk-is-active nil + "Protect from recursive calls.") + +;; Fix-me: temporary things for testing new chunk routines. +(defvar mumamo-find-chunks-level 0) +(setq mumamo-find-chunks-level 0) + +(defvar mumamo-old-tail nil) +(make-variable-buffer-local 'mumamo-old-tail) +(put 'mumamo-old-tail 'permanent-local t) + +(defun mumamo-update-obscure (chunk pos) + "Update obscure cache." + (let ((obscured (overlay-get chunk 'obscured)) + region-info) + (unless (and obscured (= (car obscured) pos)) + (setq region-info (mumamo-get-region-from pos)) + ;;(msgtrc "update-obscure:region-info=%s" region-info) + ;; This should not be a chunk here + (mumamo-put-obscure chunk pos region-info)))) + +(defun mumamo-put-obscure (chunk pos region-or-chunk) + "Cache obscure info." + (assert (overlayp chunk) t) + (when pos (assert (or (markerp pos) (integerp pos)) t)) + (let* ((region-info (if (overlayp region-or-chunk) + (cons (overlay-start region-or-chunk) + (overlay-end region-or-chunk)) + region-or-chunk)) + (obscured (when pos (list pos region-info)))) + ;;(msgtrc "put-obscure:region-info=%s, obscured=%s" region-info obscured) + (when region-info (assert (consp region-info) t)) + (assert (not (overlayp region-info)) t) + (overlay-put chunk 'obscured obscured) + (setq obscured (overlay-get chunk 'obscured)) + ;;(msgtrc " obscured=%s" obscured) + )) + +(defun mumamo-get-region-from (point) + "Return mumamo region values for POINT." + ;; Note: `mumamo-get-region-from-1' is defined in mumamo-regions.el + (when (fboundp 'mumamo-get-region-from-1) + (mumamo-get-region-from-1 point))) + +(defun mumamo-clear-chunk-ppss-cache (chunk) + (overlay-put chunk 'mumamo-ppss-cache nil) + (overlay-put chunk 'mumamo-ppss-last nil) + (overlay-put chunk 'mumamo-ppss-stats nil)) + +(defun mumamo-find-chunks (end tracer) + "Find or create chunks from last known chunk. +Ie, start from the end of `mumamo-last-chunk' if this is +non-nil, otherwise 1. + +If END is nil then continue till end of buffer or until any input +is available. In this case the return value is undefined. + +Otherwise END must be a position in the buffer. Return the +mumamo chunk containing the position. If `mumamo-last-chunk' +ends before END then create chunks upto END." + (when mumamo-multi-major-mode + (let ((chunk (mumamo-find-chunks-1 end tracer)) + region-info) + (when (and end chunk (featurep 'mumamo-regions)) + (setq region-info (mumamo-get-region-from end)) + ;;(msgtrc "find-chunks:region-info=%s" region-info) + (if (overlayp region-info) + (setq chunk region-info) + ;;(overlay-put chunk 'obscured (list end region-info)))) + (mumamo-put-obscure chunk end region-info))) + ;;(msgtrc "find-chunks ret chunk=%s" chunk) + chunk))) + +(defun mumamo-move-to-old-tail (first-check-from) + "Divide the chunk list. +Make it two parts. The first, before FIRST-CHECK-FROM is still +correct but we want to check those after. Put thosie in +`mumamo-old-tail'." + (let ((while-n0 0)) + (while (and (mumamo-while 500 'while-n0 "mumamo-last-chunk first-check-from") + mumamo-last-chunk + first-check-from + (< first-check-from (overlay-end mumamo-last-chunk))) + (overlay-put mumamo-last-chunk 'mumamo-next-chunk mumamo-old-tail) + (setq mumamo-old-tail mumamo-last-chunk) + (overlay-put mumamo-old-tail 'mumamo-is-new nil) + (when nil ;; For debugging + (overlay-put mumamo-old-tail + 'face + (list :background + (format "red%d" (overlay-get mumamo-old-tail 'mumamo-depth))))) + (setq mumamo-last-chunk + (overlay-get mumamo-last-chunk 'mumamo-prev-chunk))))) + +(defun mumamo-delete-empty-chunks-at-end () + ;; fix-me: later? Delete empty chunks at end, will be recreated if really needed + (let ((while-n1 0)) + (while (and (mumamo-while 500 'while-n1 "mumamo-last-chunk del empty chunks") + mumamo-last-chunk + ;;(= (point-max) (overlay-end mumamo-last-chunk)) + (= (overlay-end mumamo-last-chunk) (overlay-start mumamo-last-chunk))) + ;;(msgtrc "delete-overlay at end") + (delete-overlay mumamo-last-chunk) + (setq mumamo-last-chunk (overlay-get mumamo-last-chunk 'mumamo-prev-chunk)) + (when mumamo-last-chunk (overlay-put mumamo-last-chunk 'mumamo-next-chunk nil))))) + + +(defun mumamo-delete-chunks-upto (ok-pos) + "Delete old chunks upto OK-POS." + (or (not mumamo-old-tail) + (overlay-buffer mumamo-old-tail) + (setq mumamo-old-tail nil)) + (let ((while-n2 0)) + (while (and (mumamo-while 500 'while-n2 "mumamo-old-tail") + (and mumamo-old-tail (< (overlay-start mumamo-old-tail) ok-pos))) + (mumamo-mark-for-refontification (overlay-start mumamo-old-tail) (overlay-end mumamo-old-tail)) + ;;(msgtrc "find-chunks:ok-pos=%s, not eq delete %s" ok-pos mumamo-old-tail) + (delete-overlay mumamo-old-tail) + (setq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk)) + (or (not mumamo-old-tail) + (overlay-buffer mumamo-old-tail) + (setq mumamo-old-tail nil))))) + +(defun mumamo-reuse-old-tail-head () + ;;(msgtrc "reusing %S" mumamo-old-tail) + (setq mumamo-last-chunk mumamo-old-tail) + (overlay-put mumamo-last-chunk 'mumamo-is-new t) + (mumamo-clear-chunk-ppss-cache mumamo-last-chunk) + (overlay-put mumamo-last-chunk 'face (mumamo-background-color (overlay-get mumamo-last-chunk 'mumamo-depth))) + (setq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk))) + +(defun mumamo-old-tail-fits (this-new-values) + (and mumamo-old-tail + (overlay-buffer mumamo-old-tail) + (mumamo-new-chunk-equal-chunk-values mumamo-old-tail this-new-values))) + +(defun mumamo-find-chunks-1 (end tracer) ;; min max) + ;; Note: This code must probably be reentrant. The globals changed + ;; here are `mumamo-last-chunk' and `mumamo-old-tail'. They must be + ;; handled as a pair. + (mumamo-msgfntfy "") + (setq mumamo-find-chunks-level (1+ mumamo-find-chunks-level)) + (unless (and (overlayp mumamo-last-chunk) (overlay-buffer mumamo-last-chunk)) (setq mumamo-last-chunk nil)) + (save-restriction + (widen) + (let* ((mumamo-find-chunks-1-active t) + (here (point)) + ;; Any changes? + (change-min (car mumamo-last-change-pos)) + (change-max (cdr mumamo-last-change-pos)) + (chunk-at-change-min (when change-min (mumamo-get-existing-new-chunk-at change-min nil))) + (chunk-at-change-min-start (when chunk-at-change-min (overlay-start chunk-at-change-min))) + ;; Check if change is near border + (this-syntax-min-max + (when chunk-at-change-min + (mumamo-update-obscure chunk-at-change-min chunk-at-change-min-start) + (mumamo-chunk-syntax-min-max chunk-at-change-min nil))) + (this-syntax-min (car this-syntax-min-max)) + (in-min-border (when this-syntax-min (>= this-syntax-min change-min))) + (first-check-from (if chunk-at-change-min + (if (or in-min-border + ;; Fix-me: 20? + (> 20 (- change-min chunk-at-change-min-start))) + (max 1 + (- chunk-at-change-min-start 1)) + chunk-at-change-min-start) + (when change-min + (goto-char change-min) + (skip-chars-backward "^\n") + (unless (bobp) (backward-char)) + (prog1 (point) (goto-char here)))))) + (when (and chunk-at-change-min (= 0 (- (overlay-end chunk-at-change-min) + (overlay-start chunk-at-change-min)))) + (assert in-min-border)) ;; 0 len must be in border + (setq mumamo-last-change-pos nil) + (when chunk-at-change-min + (mumamo-move-to-old-tail first-check-from) + (mumamo-delete-empty-chunks-at-end)) + ;; Now mumamo-last-chunk is the last in the top chain and + ;; mumamo-old-tail the first in the bottom chain. + + (let* ( + ;;(last-chunk-is-closed (when mumamo-last-chunk (overlay-get mumamo-last-chunk 'mumamo-is-closed))) + (last-chunk-is-closed t) + (ok-pos (or (and mumamo-last-chunk + (- (overlay-end mumamo-last-chunk) + ;;(or (and last-chunk-is-closed 1) + (or (and (/= (overlay-end mumamo-last-chunk) + (1+ (buffer-size))) + 1) + 0))) + 0)) + (end-param end) + (end (or end (point-max))) + this-new-values + this-new-chunk + prev-chunk + first-change-pos + interrupted + (while-n3 0)) + (when (>= ok-pos end) + (setq this-new-chunk (mumamo-get-existing-new-chunk-at end nil)) + (unless this-new-chunk + (error "Could not find new chunk ok-pos-new=%s > end=%s (ovls at end=%s), level=%d, old-tail=%s, %S" + ok-pos end (overlays-in end end) + mumamo-find-chunks-level mumamo-old-tail tracer))) + (unless this-new-chunk + (save-match-data + (unless mumamo-find-chunk-is-active + ;;(setq mumamo-find-chunk-is-active t) + (mumamo-stop-find-chunks-timer) + (mumamo-save-buffer-state nil + (progn + + ;; Loop forward until end or buffer end ... + (while (and (mumamo-while 1500 'while-n3 "until end") + (or (not end) + (<= ok-pos end)) + ;;(prog1 t (msgtrc "ok-pos=%s in while" ok-pos)) + (< ok-pos (point-max)) + (not (setq interrupted (and (not end) + (input-pending-p))))) + ;; Narrow to speed up. However the chunk divider may be + ;; before ok-pos here. Assume that the marker is not + ;; longer than 200 chars. fix-me. + (narrow-to-region (max (- ok-pos 200) 1) + (1+ (buffer-size))) + ;; If this was after a change within one chunk then tell that: + (let ((use-change-max (when (and change-max + chunk-at-change-min + (overlay-buffer chunk-at-change-min) + (< change-max + (overlay-end chunk-at-change-min)) + (or (not mumamo-last-chunk) + (> change-max (overlay-end mumamo-last-chunk)))) + change-max)) + (use-chunk-at-change-min (when (or (not mumamo-last-chunk) + (not (overlay-buffer mumamo-last-chunk)) + (not chunk-at-change-min) + (not (overlay-buffer chunk-at-change-min)) + (> (overlay-end chunk-at-change-min) + (overlay-end mumamo-last-chunk))) + chunk-at-change-min + ))) + (setq this-new-values (mumamo-find-next-chunk-values + mumamo-last-chunk + first-check-from + use-change-max + use-chunk-at-change-min))) + (if (not this-new-values) + (setq ok-pos (point-max)) + (setq first-check-from nil) + (setq ok-pos (or (mumamo-new-chunk-value-max this-new-values) ;;(overlay-end this-chunk) + (point-max))) + ;;(msgtrc "ok-pos=%s, point-max=%s max=%s" ok-pos (point-max) (mumamo-new-chunk-value-max this-new-values)) + ;; With the new organization all chunks are created here. + (if (mumamo-old-tail-fits this-new-values) + (mumamo-reuse-old-tail-head) + (mumamo-delete-chunks-upto ok-pos) + ;; Create chunk and chunk links + (setq mumamo-last-chunk (mumamo-new-create-chunk this-new-values)) + ;;(setq last-chunk-is-closed (overlay-get mumamo-last-chunk 'mumamo-is-closed)) + (unless first-change-pos + (setq first-change-pos (mumamo-new-chunk-value-min this-new-values)))))) + (setq this-new-chunk mumamo-last-chunk))) + (widen) + (when (or interrupted + (and mumamo-last-chunk + (overlayp mumamo-last-chunk) + (overlay-buffer mumamo-last-chunk) + (buffer-live-p (overlay-buffer mumamo-last-chunk)) + (< (overlay-end mumamo-last-chunk) (point-max)))) + (mumamo-start-find-chunks-timer) + ) + (when first-change-pos + (setq jit-lock-context-unfontify-pos + (if jit-lock-context-unfontify-pos + (min jit-lock-context-unfontify-pos first-change-pos) + first-change-pos)))) + (goto-char here) + (setq mumamo-find-chunk-is-active nil))) + + ;; fix-me: continue here + (when chunk-at-change-min (mumamo-clear-chunk-ppss-cache chunk-at-change-min)) + (setq mumamo-find-chunks-level (1- mumamo-find-chunks-level)) + ;; Avoid empty overlays at the end of the buffer. Those can + ;; come from for example deleting to the end of the buffer. + (when this-new-chunk + ;; Fix-me: can this happen now? + (setq prev-chunk (overlay-get this-new-chunk 'mumamo-prev-chunk)) + (when (and prev-chunk + (overlay-buffer prev-chunk) + (= (overlay-start this-new-chunk) (overlay-end this-new-chunk)) + (= (overlay-start prev-chunk) (overlay-end prev-chunk))) + (overlay-put prev-chunk 'mumamo-next-chunk nil) + (overlay-put prev-chunk 'mumamo-prev-chunk nil) + ;;(msgtrc "find-chunks:deleting this-new-chunk %s" this-new-chunk) + (delete-overlay this-new-chunk) + (setq this-new-chunk prev-chunk) + ) + (while (and mumamo-old-tail + (overlay-buffer mumamo-old-tail) + (= (overlay-start mumamo-old-tail) (overlay-end mumamo-old-tail))) + (assert (not (eq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk))) t) + (setq prev-chunk mumamo-old-tail) + (setq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk)) + ;;(msgtrc "mumamo-find-chunks-1:after mumamo-old-tail=%s" mumamo-old-tail) + (delete-overlay prev-chunk) + ) + ) + ;;(unless (overlay-get mumamo-last-chunk 'mumamo-is-closed) + (unless t ;(= (overlay-end mumamo-last-chunk) (save-restriction (widen) (point-max))) + ;; Check that there are no left-over old chunks + (save-restriction + (widen) + (dolist (o (overlays-in (point-min) (point-max))) + (when (and (overlay-get o 'mumamo-depth) + (not (overlay-get o 'mumamo-is-new))) + (error "mumamo-find-chunks: left over chunk: %s end=%s, last-chunk=%s" o end mumamo-last-chunk))))) + (when end-param + ;;(msgtrc "find-chunks:Exit.end-param=%s, this-new-chunk=%s, point-max=%s, last=%s" end-param this-new-chunk (point-max) mumamo-last-chunk) + (let* ((ret this-new-chunk) + (ret-beg (overlay-start ret)) + (ret-end (overlay-end ret))) + (unless (and (<= ret-beg end-param) + (<= end-param ret-end)) + (error "mumamo-find-chunks: Bad ret=%s, end=%s" ret end-param)) + ;;(msgtrc "find-chunks=>%S" ret) + ret)))))) + +(defun mumamo-find-chunk-after-change (min max) + "Save change position after a buffer change. +This should be run after a buffer change. For MIN see +`after-change-functions'." + ;; Fix-me: Maybe use a list of all min, max instead? + (mumamo-start-find-chunks-timer) + ;;(msgtrc "(mumamo-find-chunk-after-change %s %s)" min max) + (setq min (copy-marker min nil)) + (setq max (copy-marker max t)) + (setq mumamo-last-change-pos + (if mumamo-last-change-pos + (let* ((old-min (car mumamo-last-change-pos)) + (old-max (cdr mumamo-last-change-pos)) + (new-min (min min old-min)) + (new-max (max max old-max))) + (cons new-min new-max)) + (cons min max)))) + +(defun mumamo-after-change (min max old-len) + "Everything that needs to be done in mumamo after a change. +This is run in the `after-change-functions' hook. For MIN, MAX +and OLD-LEN see that variable." + ;;(msgtrc "mumamo-after-change BEGIN min/max/old-len=%s/%s/%s" min max old-len) + ;;(msgtrc "mumamo-after-change BEGIN") + (mumamo-find-chunk-after-change min max) + (mumamo-jit-lock-after-change min max old-len) + (mumamo-msgfntfy "mumamo-after-change EXIT") + ;;(msgtrc "mumamo-after-change EXIT mumamo-last-change-pos=%s" mumamo-last-change-pos) + ) + +(defun mumamo-jit-lock-after-change (min max old-len) + ;; Fix-me: Should not this be on + ;; jit-lock-after-change-externd-region-functions?? + "Replacement for `jit-lock-after-change'. +Does the nearly the same thing as that function, but takes +care of that there might be different major modes at MIN and MAX. +It also marks for refontification only in the current mumamo chunk. + +OLD-LEN is the pre-change length. + +Jit-lock after change functions is organized this way: + +`jit-lock-after-change' (doc: Mark the rest of the buffer as not +fontified after a change) is added locally to the hook +`after-change-functions'. This function runs +`jit-lock-after-change-extend-region-functions'." + (when (and jit-lock-mode (not memory-full)) + (mumamo-msgfntfy "mumamo-jit-lock-after-change ENTER %s %s %s" min max old-len) + ;; Why is this nil?: + (mumamo-msgfntfy " mumamo-jit-lock-after-change: font-lock-extend-after-change-region-function=%s" font-lock-extend-after-change-region-function) + (let* ((ovl-min (mumamo-get-existing-new-chunk-at min nil)) + (ovl-max (when (or (not ovl-min) + (< (overlay-end ovl-min) max)) + (mumamo-get-existing-new-chunk-at max nil))) + (major-min (when ovl-min (mumamo-chunk-major-mode ovl-min))) + (major-max (when ovl-max (mumamo-chunk-major-mode ovl-max))) + (r-min nil) + (r-max nil) + (new-min min) + (new-max max)) + (if (and major-min (eq major-min major-max)) + (setq r-min + (when major-min + (mumamo-jit-lock-after-change-1 min max old-len major-min))) + (setq r-min + (when major-min + (mumamo-jit-lock-after-change-1 min max old-len major-min))) + (setq r-max + (when major-max + (mumamo-jit-lock-after-change-1 min max old-len major-max)))) + (mumamo-msgfntfy "mumamo-jit-lock-after-change r-min,max=%s,%s major-min,max=%s,%s" r-min r-max major-min major-max) + (when r-min + (setq new-min (min new-min (car r-min))) + (setq new-max (max new-max (cdr r-min)))) + (when r-max + (setq new-min (min new-min (car r-max))) + (setq new-max (max new-max (cdr r-max)))) + (setq new-min (max new-min (point-min))) + (setq new-max (min new-max (point-max))) + ;; Make sure we change at least one char (in case of deletions). + (setq new-max (min (max new-max (1+ new-min)) (point-max))) + (mumamo-msgfntfy "mumamo-jit-lock-after-change new-min,max=%s,%s" new-min new-max) + (mumamo-mark-for-refontification new-min new-max) + + ;; Mark the change for deferred contextual refontification. + ;;(setq jit-lock-context-unfontify-pos nil) (setq message-log-max t) + (when jit-lock-context-unfontify-pos + (setq jit-lock-context-unfontify-pos + ;; Here we use `start' because nothing guarantees that the + ;; text between start and end will be otherwise refontified: + ;; usually it will be refontified by virtue of being + ;; displayed, but if it's outside of any displayed area in the + ;; buffer, only jit-lock-context-* will re-fontify it. + (min jit-lock-context-unfontify-pos new-min)) + ;;(with-current-buffer (get-buffer "*Messages*") (erase-buffer)) + (mumamo-msgfntfy "mumamo-jit-lock-after-change EXIT unfontify-pos=%s" jit-lock-context-unfontify-pos) + ;;(message "mumamo-jit-lock-after-change.unfontify-pos=%s" jit-lock-context-unfontify-pos) + )))) +;;(min jit-lock-context-unfontify-pos jit-lock-start)))))) +;;(put 'mumamo-jit-lock-after-change 'permanent-local-hook t) +(put 'mumamo-after-change 'permanent-local-hook t) + +(defun mumamo-jit-lock-after-change-1 (min max old-len major) + "Extend the region the same way jit-lock does it. +This function tries to extend the region between MIN and MAX the +same way jit-lock does it after a change. OLD-LEN is the +pre-change length. + +The extending of the region is done as if MAJOR was the major +mode." + (mumamo-with-major-mode-fontification major + `(progn + (let ((jit-lock-start ,min) + (jit-lock-end ,max)) + ;;(mumamo-msgfntfy "mumamo-mumamo-jit-lock-after-change-1 jlacer=%s" ,jit-lock-after-change-extend-region-functions) + (mumamo-with-buffer-prepared-for-jit-lock + ;;(font-lock-extend-jit-lock-region-after-change ,min ,max ,old-len) + (run-hook-with-args 'jit-lock-after-change-extend-region-functions min max old-len) + ;;(setq jit-lock-end (min (max jit-lock-end (1+ min)) (point-max))) + +;;; ;; Just run the buffer local function: +;;; (dolist (extend-fun jit-lock-after-change-extend-region-functions) +;;; (when (fboundp extend-fun) +;;; (funcall extend-fun ,min ,max ,old-len))) + ) + (setq min jit-lock-start) + (setq max jit-lock-end) + ;;(syntax-ppss-flush-cache min) + ))) + (mumamo-msgfntfy "mumamo-mumamo-jit-lock-after-change-1 EXIT %s" (cons min max)) + (cons min max)) + +(defun mumamo-mark-chunk () + "Mark chunk and move point to beginning of chunk." + (interactive) + (let ((chunk (mumamo-find-chunks (point) "mumamo-mark-chunk"))) + (unless chunk (error "There is no MuMaMo chunk here")) + (goto-char (overlay-start chunk)) + (push-mark (overlay-end chunk) t t))) + +(defun mumamo-narrow-to-chunk-inner () + (interactive) + (let* ((chunk (mumamo-find-chunks (point) "mumamo-narrow-to-chunk-innner")) + (syntax-min-max (mumamo-chunk-syntax-min-max chunk t)) + (syntax-min (car syntax-min-max)) + (syntax-max (cdr syntax-min-max))) + (narrow-to-region syntax-min syntax-max))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Font lock functions + +(defadvice hi-lock-set-pattern (around use-overlays activate) + (if mumamo-multi-major-mode + (let ((font-lock-fontified nil)) + ad-do-it) + ad-do-it)) + +;;;###autoload +(defun mumamo-mark-for-refontification (min max) + "Mark region between MIN and MAX for refontification." + ;;(msgtrc "mark-for-refontification A min,max=%s,%s point-min,max=%s,%s modified=%s" min max (point-min) (point-max) (buffer-modified-p) ) + ;;(mumamo-backtrace "mark-for-refontification") + (mumamo-msgfntfy "mumamo-mark-for-refontification A min,max=%s,%s point-min,max=%s,%s modified=%s" min max (point-min) (point-max) (buffer-modified-p) ) + (assert (<= min max)) + (when (< min max) + (save-restriction + (widen) + (mumamo-msgfntfy "mumamo-mark-for-refontification B min,max=%s,%s point-min,max=%s,%s modified=%s" min max (point-min) (point-max) (buffer-modified-p) ) + ;;(mumamo-with-buffer-prepared-for-jit-lock + (mumamo-save-buffer-state nil + (put-text-property min max 'fontified nil) + )))) + + +;; Fix me: The functions in this list must be replaced by variables +;; pointing to anonymous functions for buffer local values of +;; fontification keywords to be supported. And that is of course +;; necessary for things like hi-lock etc. (Or..., perhaps some kind of +;; with-variable-values... as RMS suggested once... but that will not +;; help here...) +;; +;; Seems like font-lock-add-keywords must be advised... +(defvar mumamo-internal-major-modes-alist nil + "Alist with info for different major modes. +Internal use only. This is automatically set up by +`mumamo-get-major-mode-setup'.") +(setq mumamo-internal-major-modes-alist nil) +(put 'mumamo-internal-major-modes-alist 'permanent-local t) + +(defvar mumamo-ppss-last-chunk nil + "Internal variable used to avoid unnecessary flushing.") +(defvar mumamo-ppss-last-major nil + "Internal variable used to avoid unnecessary flushing.") + +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'fontification) +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'indentation) +;;(mumamo-get-major-mode-substitute 'css-mode 'fontification) +;;(mumamo-get-major-mode-substitute 'css-mode 'indentation) +;; (assq 'nxml-mode mumamo-major-mode-substitute) +(defconst mumamo-major-mode-substitute + '( + (nxhtml-mode (html-mode nxhtml-mode)) + ;;(nxhtml-mode (html-mode)) + (nxhtml-genshi-mode (html-mode nxhtml-mode)) + (nxhtml-mjt-mode (html-mode nxhtml-mode)) + (nxml-mode (sgml-mode)) + ) + "Major modes substitute to use for fontification and indentation. +The entries in this list has either of the formats + + \(MAJOR (FONT-MODE INDENT-MODE)) + \(MAJOR (FONT-MODE)) + +where major is the major mode in a mumamo chunk and FONT-MODE is +the major mode for fontification of that chunk and INDENT-MODE is +dito for indentation. In the second form the same mode is used +for indentation as for fontification.") + +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'indentation) +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'fontification) +(defun mumamo-get-major-mode-substitute (major for-what) + "For major mode MAJOR return major mode to use for FOR-WHAT. +FOR-WHAT can be either 'fontification or indentation. + +mumamo must handle fontification and indentation for `major-mode' +by using other major mode if the functions for this in +`major-mode' are not compatible with mumamo. This functions +looks in the table `mumamo-major-mode-substitute' for get major +mode to use." + ;;(when (eq for-what 'indentation) (message "subst.major=%s" major)) + (let ((m (assq major mumamo-major-mode-substitute)) + ret-major) + (if (not m) + (setq ret-major major) + (setq m (nth 1 m)) + (setq ret-major + (cond + ((eq for-what 'fontification) + (nth 0 m)) + ((eq for-what 'indentation) + (nth 1 m)) + (t + (mumamo-display-error 'mumamo-get-major-mode-substitute + "Bad parameter, for-what=%s" for-what)))) + (unless ret-major (setq ret-major major))) + (unless (commandp ret-major) (setq ret-major 'mumamo-bad-mode)) + ;;(when (eq for-what 'indentation) (message "ret.ind=%s, major=%s, m=%s" ret major m)) + ret-major)) + +(defun mumamo-assert-fontified-t (start end) + "Assert that the region START to END has 'fontified t." + (let ((start-ok (get-text-property start 'fontified)) + (first-not-ok + (next-single-property-change (1+ start) 'fontified nil end))) + (when (not start-ok) + (message "==== mumamo-assert-fontified-t %s-%s start not ok" start end)) + (when (not (= first-not-ok end)) + (message "==== mumamo-assert-fontified-t %s-%s first not ok=%s" start end first-not-ok)))) + +;; Keep this separate for easier debugging. +(defun mumamo-do-fontify (start end verbose chunk-syntax-min chunk-syntax-max chunk-major) + "Fontify region between START and END. +If VERBOSE is non-nil then print status messages during +fontification. + +CHUNK-SYNTAX-MIN, CHUNK-SYNTAX-MAX and CHUNK-MAJOR are the +chunk's min point, max point and major mode. + +During fontification narrow the buffer to the chunk to make +syntactic fontification work. If chunks starts or end with \" +then the first respective last char then exclude those chars from +from the narrowed part, since otherwise the syntactic +fontification can't find out where strings start and stop. + +Note that this function is run under +`mumamo-with-major-mode-fontification'. + +This function takes care of `font-lock-dont-widen' and +`font-lock-extend-region-functions'. Normally +`font-lock-default-fontify-region' does this, but that function +is not called when mumamo is used! + +PS: `font-lock-fontify-syntactically-region' is the main function +that does syntactic fontification." + ;;(msgtrc "mumamo-do-fontify enter: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ;;(msgtrc "mumamo-do-fontify <<<<<<< %s %s %s %s %s %s" start end verbose chunk-syntax-min chunk-syntax-max chunk-major) + ;;(msgtrc "font-lock-keywords=%S" font-lock-keywords) + ;;(mumamo-assert-fontified-t start end) + (mumamo-condition-case err + (let* ((font-lock-dont-widen t) + (font-lock-extend-region-functions + ;; nil + font-lock-extend-region-functions + ) + ;; Extend like in `font-lock-default-fontify-region': + (funs font-lock-extend-region-functions) + (font-lock-beg (max chunk-syntax-min start)) + (font-lock-end (min chunk-syntax-max end)) + (while-n1 0)) + ;;(while (and (> 500 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 500 'while-n1 "funs") + funs) + (setq funs (if (or (not (funcall (car funs))) + (eq funs font-lock-extend-region-functions)) + (cdr funs) + ;; If there's been a change, we should go through + ;; the list again since this new position may + ;; warrant a different answer from one of the fun + ;; we've already seen. + font-lock-extend-region-functions))) + ;; But we must restrict to the chunk here: + (let ((new-start (max chunk-syntax-min font-lock-beg)) + (new-end (min chunk-syntax-max font-lock-end))) + ;;(msgtrc "do-fontify %s %s, chunk-syntax-min,max=%s,%s, new: %s %s" start end chunk-syntax-min chunk-syntax-max new-start new-end) + ;; A new condition-case just to catch errors easier: + (when (< new-start new-end) + (mumamo-condition-case err + (save-restriction + ;;(when (and (>= 625 (point-min)) (<= 625 (point-max))) (msgtrc "multi at 625=%s" (get-text-property 625 'font-lock-multiline))) + ;;(msgtrc "(narrow-to-region %s %s)" chunk-syntax-min chunk-syntax-max) + (when (< chunk-syntax-min chunk-syntax-max) + (narrow-to-region chunk-syntax-min chunk-syntax-max) + ;; Now call font-lock-fontify-region again but now + ;; with the chunk font lock parameters: + (setq font-lock-syntactically-fontified (1- new-start)) + (mumamo-msgfntfy "ENTER font-lock-fontify-region %s %s %s" new-start new-end verbose) + ;;(msgtrc "mumamo-do-fontify: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + (let (font-lock-extend-region-functions) + (font-lock-fontify-region new-start new-end verbose)) + (mumamo-msgfntfy "END font-lock-fontify-region %s %s %s" new-start new-end verbose) + ) + ) + (error + (mumamo-display-error 'mumamo-do-fontify-2 + "mumamo-do-fontify m=%s, s/e=%s/%s syn-min/max=%s/%s: %s" + chunk-major + start end + chunk-syntax-min chunk-syntax-max + (error-message-string err))))))) + (error + (mumamo-display-error 'mumamo-do-fontify + "mumamo-do-fontify m=%s, s=%s, e=%s: %s" + chunk-major start end (error-message-string err))) + ) + (mumamo-msgfntfy "mumamo-do-fontify exit >>>>>>> %s %s %s %s %s %s" start end verbose chunk-syntax-min chunk-syntax-max chunk-major) + ;;(msgtrc "mumamo-do-fontify exit: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ) + +(defun mumamo-do-unfontify (start end) + "Unfontify region between START and END." + (mumamo-condition-case err + (font-lock-unfontify-region start end) + (error + (mumamo-display-error 'mumamo-do-unfontify "%s" + (error-message-string err))))) + +(defun mumamo-fontify-region-with (start end verbose major chunk-syntax-min chunk-syntax-max) + "Fontify from START to END. +If VERBOSE is non-nil then print status messages during +fontification. + +Do the fontification as in major mode MAJOR. + +Narrow to region CHUNK-SYNTAX-MIN and CHUNK-SYNTAX-MAX during +fontification." + ;; The text property 'fontified is always t here due to the way + ;; jit-lock works! + + ;;(msgtrc "fontify-region-with %s %s %s %s, ff=%s" start end verbose major (get-text-property start 'fontified)) + ;;(mumamo-assert-fontified-t start end) + ;;(msgtrc "mumamo-fontify-region-with enter: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + (mumamo-condition-case err + (progn + ;;(msgtrc "mumamo-fontify-region-with: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + (mumamo-with-major-mode-fontification major + `(mumamo-do-fontify ,start ,end ,verbose ,chunk-syntax-min ,chunk-syntax-max major)) + ) + (error + (mumamo-display-error 'mumamo-fontify-region-with "%s" + (error-message-string err)))) + ;;(msgtrc "mumamo-fontify-region-with exit: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ) + +(defun mumamo-unfontify-region-with (start end major) + "Unfontify from START to END as in major mode MAJOR." + (mumamo-msgfntfy "mumamo-unfontify-region-with %s %s %s, ff=%s" + start + end + major + (when start + (save-restriction + (widen) + (get-text-property start 'fontified)))) + (mumamo-with-major-mode-fontification major + `(mumamo-do-unfontify ,start ,end))) + + + +(defun mumamo-backtrace (label) + (msgtrc "%s:backtrace in START buffer %s <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n%s" + label (current-buffer) (with-output-to-string (backtrace))) + (msgtrc "%s:backtrace in END buffer %s >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" label (current-buffer))) + +(defun mumamo-unfontify-buffer () + "Unfontify buffer. +This function is called when the minor mode function +`font-lock-mode' is turned off. \(It is the value of +`font-lock-unfontify-uffer-function')." + (when (and mumamo-multi-major-mode + (not (and (boundp 'mumamo-find-chunks-1-active) + mumamo-find-chunks-1-active))) + ;;(mumamo-backtrace "unfontify-buffer") + ;;(msgtrc "mumamo-unfontify-buffer:\n%s" (with-output-to-string (backtrace))) + (save-excursion + (save-restriction + (widen) + (let ((ovls (overlays-in (point-min) (point-max))) + (main-major (mumamo-main-major-mode))) + (dolist (o ovls) + (when (overlay-get o 'mumamo-is-new) + (let ((major (mumamo-chunk-major-mode o))) + (when major + (unless (mumamo-fun-eq major main-major) + (mumamo-unfontify-chunk o)) + ;;(msgtrc "delete-overlay 1") + (delete-overlay o) + )))) + (mumamo-unfontify-region-with (point-min) (point-max) + (mumamo-main-major-mode))))))) + + +(defun mumamo-fontify-buffer () + "For `font-lock-fontify-buffer-function' call. +Not sure when this normally is done. However some functions call +this to ensure that the whole buffer is fontified." + (mumamo-msgfntfy "===> mumamo-fontify-buffer-function called") + ;;(font-lock-default-fontify-buffer) + (unless mumamo-set-major-running + ;; This function is normally not called, but when new patterns + ;; have been added by hi-lock it will be called. In this case we + ;; need to make buffer local fontification variables: + (set (make-local-variable 'mumamo-internal-major-modes-alist) nil) + (jit-lock-refontify))) + + +(defun mumamo-unfontify-chunk (chunk) ; &optional start end) + "Unfontify mumamo chunk CHUNK." + (let* ((major (mumamo-chunk-major-mode chunk)) + ;;(start (overlay-start chunk)) + ;;(end (overlay-end chunk)) + (syntax-min-max (mumamo-chunk-syntax-min-max chunk t)) + (syntax-min (car syntax-min-max)) + (syntax-max (cdr syntax-min-max)) + (font-lock-dont-widen t)) + (when (< syntax-min syntax-max) + (save-restriction + (narrow-to-region syntax-min syntax-max) + (mumamo-unfontify-region-with syntax-min syntax-max major))))) + +(defun mumamo-fontify-region (start end &optional verbose) + "Fontify between START and END. +Take the major mode chunks into account while doing this. + +If VERBOSE do the verbously. + +The value of `font-lock-fontify-region-function' when +mumamo is used is this function." + (mumamo-msgfntfy "++++++ mumamo-fontify-regionX %s %s %s, skip=%s" start end verbose mumamo-just-changed-major) + ;;(msgtrc "mumamo-fontify-region: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ;;(mumamo-assert-fontified-t start end) + ;; If someone else tries to fontify the buffer ... + (if (and mumamo-just-changed-major + ;; The above variable is reset in `post-command-hook' so + ;; check if we are in a recursive search. (Note: There are + ;; other situation when this can occur. It might be best to + ;; remove this test later, or make it optional.) + ;; + ;; skip the test for now: + nil + (= 0 (recursion-depth))) + (mumamo-display-error 'mumamo-fontify-region + "Just changed major, should not happen") + (mumamo-condition-case err + (mumamo-fontify-region-1 start end verbose) + (error + (mumamo-display-error 'mumamo-fontify-region "%s" + (error-message-string err)))))) + +(defconst mumamo-dbg-pretend-fontified nil + "Set this to t to be able to debug more easily. +This is for debugging `mumamo-fontify-region-1' more easily by +just calling it. It will make that function believe that the text +has a non-nil 'fontified property.") + +(defun mumamo-exc-mode (chunk) + "Return sub major mode for CHUNK. +If chunk is a main major mode chunk return nil, otherwise return +the major mode for the chunk." + (let ((major (mumamo-chunk-major-mode chunk))) + (unless (mumamo-fun-eq major (mumamo-main-major-mode)) + major))) + +;;; Chunk in chunk needs push/pop relative prev chunk +(defun mumamo-chunk-push (chunk prop val) + (let* ((prev-chunk (overlay-get chunk 'mumamo-prev-chunk)) + (prev-val (when prev-chunk (overlay-get prev-chunk prop)))) + (overlay-put chunk prop (cons val prev-val)))) +(defun mumamo-chunk-pop (chunk prop) + (overlay-put chunk prop (cdr (overlay-get (overlay-get chunk 'mumamo-prev-chunk) + prop)))) + +;; (defvar mumamo-chunks-to-remove nil +;; "Internal. Chunk overlays marked for removal.") +;; (make-variable-buffer-local 'mumamo-chunks-to-remove) + +(defun mumamo-flush-chunk-syntax (chunk chunk-min chunk-max) + "Flush syntax cache for chunk CHUNK. +This includes removing text property 'syntax-table between +CHUNK-MIN and CHUNK-MAX." + ;; syntax-ppss-flush-cache + (overlay-put chunk 'syntax-ppss-last nil) + (overlay-put chunk 'syntax-ppss-cache nil) + (overlay-put chunk 'syntax-ppss-stats nil) + (mumamo-save-buffer-state nil + (remove-list-of-text-properties chunk-min chunk-max '(syntax-table)))) + +;; Fix-me: If I open nxhtml-changes.html and then go to the bottom of +;; the file at once syntax-ppss seems to be upset. It is however cured +;; by doing some change above the region that is badly fontified. +(defun mumamo-fontify-region-1 (start end verbose) + "Fontify region between START and END. +If VERBOSE is non-nil then print status messages during +fontification. + +This is called from `mumamo-fontify-region' which is the value of +`font-lock-fontify-region-function' when mumamo is used. \(This +means that it ties into the normal font lock framework in Emacs.) + +Note: The purpose of extracting this function from +`mumamo-fontify-region' \(which is the only place where it is +called) is to make debugging easier. Edebug will without this +function just step over the `condition-case' in +`mumamo-fontify-region'. + +The fontification is done in steps: + +- First a mumamo chunk is found or created at the start of the + region with `mumamo-get-chunk-at'. +- Then this chunk is fontified according to the major mode for + that chunk. +- If the chunk did not encompass the whole region then this + procedure is repeated with the rest of the region. + +If some mumamo chunk in the region between START and END has been +marked for removal \(for example by `mumamo-jit-lock-after-change') then +they are removed by this function. + +For some main major modes \(see `define-mumamo-multi-major-mode') the +main major modes is first used to fontify the whole region. This +is because otherwise the fontification routines for that mode may +have trouble finding the correct starting state in a chunk. + +Special care has been taken for chunks that are strings, ie +surrounded by \"...\" since they are fontified a bit special in +most major modes." + ;; Fix-me: unfontifying should be done using the correct syntax table etc. + ;; Fix-me: refontify when new chunk + ;;(msgtrc "fontify-region-1: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + (save-match-data + (let* ((old-point (point)) + (here start) + (main-major (mumamo-main-major-mode)) + (fontified-t ;;(or mumamo-dbg-pretend-fontified + ;; (get-text-property here 'fontified)) + t) + after-change-functions ;; Fix-me: tested adding this to avoid looping + (first-new-ovl nil) + (last-new-ovl nil) + (chunk-at-start-1 (mumamo-find-chunks start "mumamo-fontify-region-1")) + (while-n1 0) + ) + (when chunk-at-start-1 + (unless (= start (1- (overlay-end chunk-at-start-1))) + (setq chunk-at-start-1 nil))) + ;;(while (and (> 500 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 9000 'while-n1 "fontified-t") + fontified-t + (< here end)) + ;;(msgtrc "mumamo-fontify-region-1 heree 1, here=%s, end=%s" here end) + ;;(mumamo-assert-fontified-t here end) + ;;(mumamo-assert-fontified-t start end) + ;; Check where new chunks should be, adjust old chunks as + ;; necessary. Refontify inside end-start and outside of + ;; start-end mark for refontification when major-mode has + ;; changed or there was no old chunk. + ;; + ;; Fix-me: Join chunks! + (let* ((chunk (mumamo-find-chunks here "mumamo-fontify-region-1 2")) + (chunk-min (when chunk (overlay-start chunk))) + (chunk-max (when chunk (overlay-end chunk))) + (chunk-min-1 (when chunk (if (> chunk-min (point-min)) (1- chunk-min) (point-min)))) + (chunk-max-1 (when chunk (if (< chunk-max (point-max)) (1+ chunk-max) (point-max)))) + (chunk-min-face (when chunk (get-text-property chunk-min-1 'face))) + (chunk-max-face (when chunk (get-text-property chunk-max-1 'face))) + (chunk-major (when chunk (mumamo-chunk-major-mode chunk))) + max ; (min chunk-max end)) + ) + (assert chunk) + + (setq chunk-min (when chunk (overlay-start chunk))) + (setq chunk-max (when chunk (overlay-end chunk))) + (setq chunk-min-1 + (when chunk + (if (> chunk-min (point-min)) (1- chunk-min) (point-min)))) ;chunk-min + (setq chunk-max-1 + (when chunk + (if (< chunk-max (point-max)) (1+ chunk-max) (point-max)))) ;chunk-max + (setq chunk-min-face + (when chunk (get-text-property chunk-min-1 'face))) + (setq chunk-max-face + (when chunk (get-text-property chunk-max-1 'face))) + (setq chunk-major (when chunk (mumamo-chunk-major-mode chunk))) + + (if (and first-new-ovl (overlay-buffer first-new-ovl)) + (setq last-new-ovl chunk) + (setq last-new-ovl chunk) + (setq first-new-ovl chunk)) + ;;(mumamo-assert-fontified-t chunk-min chunk-max) + + (setq max (min chunk-max end)) + + (assert chunk) (assert (overlay-buffer chunk)) (assert chunk-min) + (assert chunk-max) (assert chunk-major) + ;; Fix-me: The next assertion sometimes fails. Could it be + ;; that this loop is continuing even after a change in the + ;; buffer? How do I stop that? When?: + ;;(assert (or (= here start) (= here chunk-min)) nil "h=%s, s=%s, cm=%s-%s, e=%s, chunk-major=%s" here start chunk-min chunk-max end chunk-major) + ;;(assert (not (mumamo-fun-eq prev-major chunk-major))) + ;;(when prev-chunk + ;; (assert (= (overlay-end prev-chunk) (overlay-start chunk)))) + + ;; Fontify + ;;(msgtrc "\nmumamo-fontify-region-1 before chunk=%s" chunk) + (mumamo-update-obscure chunk here) + (let* ((syntax-min-max (mumamo-chunk-syntax-min-max chunk nil)) + (syntax-min (car syntax-min-max)) + (syntax-max (cdr syntax-min-max)) + (chunk-min (overlay-start chunk)) + (chunk-max (overlay-end chunk)) + (border-min-max (mumamo-chunk-syntax-min-max chunk t)) + (border-min (car border-min-max)) + (border-max (cdr border-min-max)) + ) + ;;(msgtrc "fontify-region-1:syntax-min-max=%S, chunk=%S" syntax-min-max chunk) + ;;(msgtrc "chunk mumamo-border-face: %s" chunk) + (mumamo-msgfntfy "mumamo-fontify-region-1, here=%s chunk-min=%s syn-mn/mx=%s/%s" here chunk-min syntax-min syntax-max) + (when (<= here syntax-min) + (mumamo-flush-chunk-syntax chunk syntax-min syntax-max)) + (when (and (<= here syntax-min) + (< chunk-min border-min)) + ;;(msgtrc "face-in: %s-%s" chunk-min border-min) + (put-text-property chunk-min border-min 'face 'mumamo-border-face-in) + ) + (when (and (<= chunk-max max) + ;;(< (1+ border-max) chunk-max)) + (< border-max chunk-max)) + ;;(put-text-property (1+ border-max) chunk-max + (put-text-property border-max chunk-max + 'face 'mumamo-border-face-out)) + (mumamo-fontify-region-with here max verbose chunk-major + syntax-min syntax-max)) + + ;;(setq prev-major chunk-major) + ;;(setq prev-chunk chunk) + (setq here (if (= max here) (1+ max) max)) + ;;(setq fontified-t (or mumamo-dbg-pretend-fontified (get-text-property (1- here) 'fontified))) + ) + ;;(msgtrc "ft here end=%s %s %s" fontified-t here end) + ) + (goto-char old-point) + ;;(msgtrc "b first-new-ovl=%s last-new-ovl=%s" first-new-ovl last-new-ovl) + (unless fontified-t + ;; Fix-me: I am not sure what to do here. Probably just + ;; refontify the rest between start and end. But does not + ;; this lead to unnecessary refontification? + ;;(msgtrc "not sure, here=%s, end=%s" here end) + (unless (= here (point-max)) + (mumamo-mark-for-refontification here end))) + )) + ;;(msgtrc "EXIT mumamo-fontify-region-1") + ) + + +(defvar mumamo-known-buffer-local-fontifications + '( + font-lock-mode-hook + ;; + css-color-mode + hi-lock-mode + hi-lock-file-patterns + hi-lock-interactive-patterns + wrap-to-fill-column-mode + )) + +(defconst mumamo-irrelevant-buffer-local-vars + '( + ;; This list was fetched with + ;; emacs-Q, fundamental-mode + after-change-functions + ;;auto-composition-function + ;;auto-composition-mode + ;;auto-composition-mode-major-mode + buffer-auto-save-file-format + buffer-auto-save-file-name + buffer-backed-up + buffer-display-count + buffer-display-time + buffer-file-format + buffer-file-name + buffer-file-truename + buffer-invisibility-spec + buffer-read-only + buffer-saved-size + buffer-undo-list + change-major-mode-hook + ;;char-property-alias-alist + cursor-type + default-directory + delay-mode-hooks + enable-multibyte-characters + ;;font-lock-mode + ;;font-lock-mode-major-mode + ;;major-mode + mark-active + mark-ring + mode-name + point-before-scroll + ;; Handled by font lock etc + font-lock-defaults + font-lock-fontified + font-lock-keywords + ;;font-lock-keywords-only + font-lock-keywords-case-fold-search + font-lock-mode + ;;font-lock-mode-major-mode + font-lock-set-defaults + font-lock-syntax-table + font-lock-beginning-of-syntax-function + fontification-functions + jit-lock-context-unfontify-pos + jit-lock-mode + ;; Mumamo + font-lock-fontify-buffer-function + jit-lock-contextually + jit-lock-functions + ;; More symbols from visual inspection + before-change-functions + delayed-mode-hooks + isearch-mode + line-move-ignore-invisible + local-abbrev-table + ;;syntax-ppss-last + ;;syntax-ppss-cache + + ;; Cua + cua--explicit-region-start + ;; Viper + viper--intercept-key-maps + viper--key-maps + viper-ALPHA-char-class + viper-current-state + viper-emacs-global-user-minor-mode + viper-emacs-intercept-minor-mode + viper-emacs-kbd-minor-mode + viper-emacs-local-user-minor-mode + viper-emacs-state-modifier-minor-mode + viper-insert-basic-minor-mode + viper-insert-diehard-minor-mode + viper-insert-global-user-minor-mode + viper-insert-intercept-minor-mode + viper-insert-kbd-minor-mode + viper-insert-local-user-minor-mode + viper-insert-minibuffer-minor-mode + viper-insert-point + viper-insert-state-modifier-minor-mode + viper-intermediate-command + viper-last-posn-while-in-insert-state + viper-minibuffer-current-face + viper-mode-string + viper-non-word-characters + viper-replace-minor-mode + viper-replace-overlay + viper-undo-functions + viper-undo-needs-adjustment + viper-vi-basic-minor-mode + viper-vi-diehard-minor-mode + viper-vi-global-user-minor-mode + viper-vi-intercept-minor-mode + viper-vi-kbd-minor-mode + viper-vi-local-user-minor-mode + viper-vi-minibuffer-minor-mode + viper-vi-state-modifier-minor-mode + ;; hs minor mode + hs-adjust-block-beginning + hs-block-start-mdata-select + hs-block-start-regexp + hs-c-start-regexp + hs-forward-sexp-func + hs-minor-mode + ;; Imenu + imenu-case-fold-search + imenu-generic-expression + ;; Fix-me: add more here + )) + +(defun mumamo-get-relevant-buffer-local-vars () + "Get list of buffer local variables to save. +Like `buffer-local-variables', but remove variables that are +known to not be necessary to save for fontification, indentation +or filling \(or that can even disturb things)." + (let (var-vals) + (dolist (vv (buffer-local-variables)) + (unless (or (not (listp vv)) + (memq (car vv) mumamo-irrelevant-buffer-local-vars) + (let* ((sym (car vv)) + (val (symbol-value sym))) + (or (markerp val) + (overlayp val)))) + (let ((ent (list (car vv) (custom-quote (cdr vv))))) + (setq var-vals (cons ent var-vals))))) + ;; Sorting is for debugging/testing + (setq var-vals (sort var-vals + (lambda (a b) + (string< (symbol-name (car a)) + (symbol-name (car b)))))) + var-vals)) + +(defvar mumamo-major-modes-local-maps nil + "An alist with major mode and local map. +An entry in the list looks like + + \(MAJOR-MODE LOCAL-KEYMAP)") + +;; (defun mumamo-font-lock-keyword-hook-symbol (major) +;; "Return hook symbol for adding font-lock keywords to MAJOR." +;; (intern (concat "mumamo-" (symbol-name major) "-font-lock-keyword-hook"))) + +;; (defun mumamo-remove-font-lock-hook (major setup-fun) +;; "For mode MAJOR remove function SETUP-FUN. +;; See `mumamo-add-font-lock-hook' for more information." +;; (remove-hook (mumamo-font-lock-keyword-hook-symbol major) setup-fun)) + +(defun mumamo-refresh-multi-font-lock (major) + "Refresh font lock information for mode MAJOR in chunks. +If multi fontification functions for major mode MAJOR is already +setup up they will be refreshed. + +If MAJOR is nil then all font lock information for major modes +used in chunks will be refreshed. + +After calling font-lock-add-keywords or changing the +fontification in other ways you must call this function for the +changes to take effect. However already fontified buffers will +not be refontified. You can use `normal-mode' to refontify +them. + +Fix-me: Does not work yet." + + (setq mumamo-internal-major-modes-alist + (if (not major) + nil + (assq-delete-all major mumamo-internal-major-modes-alist)))) + +;; RMS had the following idea: +;; +;; Suppose we add a Lisp primitive to bind a set of variables under +;; the control of an alist. Would it be possible to eliminate these +;; helper functions and use that primitive instead? +;; +;;; But wouldn't it be better to test this version first? There is +;;; no hurry, this version works and someone might find that there +;;; is a better way to do this than with helper functions. +;; +;; OK with me, as long as this point doesn't get forgotten. +(defun mumamo-fetch-major-mode-setup (major keywords mode-keywords add-keywords how) + "Return a helper function to do fontification etc like in major mode MAJOR. +Fetch the variables affecting font locking, indentation and +filling by calling the major mode MAJOR in a temporary buffer. + +Make a function with one parameter BODY which is elisp code to +eval. The function should let bind the variables above, sets the +syntax table temporarily to the one used by the major mode +\(using the mode symbol name to find it) and then evaluates body. + +Name this function mumamo-eval-in-MAJOR. Put the code for this +function in the property `mumamo-defun' on this function symbol. + + +** Some notes about background etc. + +The function made here is used in `mumamo-with-major-mode-setup'. +The code in the function parameter BODY is typically involved in +fontification, indentation or filling. + +The main reasons for doing it this way is: + +- It is faster and than setting the major mode directly. +- It does not affect buffer local variables." + ;; (info "(elisp) Other Font Lock Variables") + ;; (info "(elisp) Syntactic Font Lock) + ;;(msgtrc "fetch-major 1: font-lock-keywords-only =%s" font-lock-keywords-only) + (let ((func-sym (intern (concat "mumamo-eval-in-" (symbol-name major)))) + (func-def-sym (intern (concat "mumamo-def-eval-in-" (symbol-name major)))) + ;;(add-keywords-hook (mumamo-font-lock-keyword-hook-symbol major)) + byte-compiled-fun + (fetch-func-definition `(lambda (body))) ;;`(defun ,func-sym (body))) + temp-buf-name + temp-buf) + ;; font-lock-mode can't be turned on in buffers whose names start + ;; with a char with white space syntax. Temp buffer names are + ;; such and it is not possible to change name of a temp buffer. + (setq temp-buf-name (concat "mumamo-fetch-major-mode-setup-" (symbol-name major))) + (setq temp-buf (get-buffer temp-buf-name)) + (when temp-buf (kill-buffer temp-buf)) + (setq temp-buf (get-buffer-create temp-buf-name)) + ;;(msgtrc "fetch-major-mode-setup in buffer %s, after-chunk=%s, before with-current-buffer" (current-buffer) (when (boundp 'after-chunk) after-chunk)) + (with-current-buffer temp-buf + + (mumamo-msgfntfy "mumamo-fetch-major-mode-setup %s" major) + (let ((mumamo-fetching-major t) + mumamo-multi-major-mode) + ;;(msgtrc "fetch-major-mode-setup in buffer %s, before (funcall %s)" (current-buffer) major) + (funcall major) + ) + + (mumamo-msgfntfy ">>> mumamo-fetch-major-mode-setup A font-lock-mode=%s" font-lock-mode) + (font-lock-mode 1) + (mumamo-msgfntfy "<<< mumamo-fetch-major-mode-setup B font-lock-mode=%s" font-lock-mode) + (mumamo-msgfntfy "mumamo-fetch-major-mode-setup: fetching jit-lock-after-change-extend-region-functions A=%s" jit-lock-after-change-extend-region-functions) + + ;; Note: font-lock-set-defaults must be called before adding + ;; keywords. Otherwise Emacs loops. I have no idea why. Hm, + ;; probably wrong, it is likely to be nxhtml-mumamo that is the + ;; problem. Does not loop in html-mumamo. + ;;(msgtrc "\n--------------------") + (font-lock-set-defaults) + ;; Fix-me: but hi-lock still does not work... what have I + ;; forgotten??? font-lock-keywords looks ok... + (when keywords + (if add-keywords + (progn + ;;(msgtrc "fetch:font-lock-add-keywords %S %S %S" (if mode-keywords major nil) keywords how) + (font-lock-add-keywords (if mode-keywords major nil) keywords how) + ;;(font-lock-add-keywords major keywords how) + ;;(msgtrc "fetch:font-lock-keywords=%S" font-lock-keywords) + ) + (font-lock-remove-keywords (if mode-keywords major nil) keywords) + ;;(font-lock-remove-keywords major keywords) + ) + (unless mode-keywords (font-lock-mode -1) (font-lock-mode 1)) + ;;(msgtrc "fetch-major-mode-setup:font-lock-keywords=%S" font-lock-keywords) + ) + ;;(run-hooks add-keywords-hook) + + (add-to-list 'mumamo-major-modes-local-maps + (let ((local-map (current-local-map))) + (cons major-mode (if local-map + (copy-keymap local-map) + 'no-local-map)))) + + (mumamo-msgfntfy "mumamo-fetch-major-mode-setup: fetching jit-lock-after-change-extend-region-functions B=%s" jit-lock-after-change-extend-region-functions) + (let* ((syntax-sym (intern-soft (concat (symbol-name major) "-syntax-table"))) + (fetch-func-definition-let + ;; Be XML compliant: + (list + (list 'sgml-xml-mode + ;;(when (mumamo-derived-from-mode ',major 'sgml-mode) t)) + (when (mumamo-derived-from-mode major 'sgml-mode) t)) + + ;; We need to copy the variables that we need and + ;; that are not automatically buffer local, but + ;; could be it. Arguably it is a bug if they are not + ;; buffer local though we have to adapt. + + ;; From cc-mode.el: + (list 'indent-line-function (custom-quote indent-line-function)) + (list 'indent-region-function (custom-quote indent-region-function)) + (list 'normal-auto-fill-function (custom-quote normal-auto-fill-function)) + (list 'comment-start (custom-quote comment-start)) + (list 'comment-end (custom-quote comment-end)) + (list 'comment-start-skip (custom-quote comment-start-skip)) + (list 'comment-end-skip (custom-quote comment-end-skip)) + (list 'comment-multi-line (custom-quote comment-multi-line)) + (list 'comment-line-break-function (custom-quote comment-line-break-function)) + (list 'paragraph-start (custom-quote paragraph-start)) + (list 'paragraph-separate (custom-quote paragraph-separate)) + (list 'paragraph-ignore-fill-prefix (custom-quote paragraph-ignore-fill-prefix)) + (list 'adaptive-fill-mode (custom-quote adaptive-fill-mode)) + (list 'adaptive-fill-regexp (custom-quote adaptive-fill-regexp)) + + ;;; Try doing the font lock things last, keywords really last + (list 'font-lock-multiline (custom-quote font-lock-multiline)) + (list 'font-lock-extend-after-change-region-function (custom-quote font-lock-extend-after-change-region-function)) + (list 'font-lock-extend-region-functions (custom-quote font-lock-extend-region-functions)) + (list 'font-lock-comment-start-skip (custom-quote font-lock-comment-start-skip)) + (list 'font-lock-comment-end-skip (custom-quote font-lock-comment-end-skip)) + (list 'font-lock-syntactic-keywords (custom-quote font-lock-syntactic-keywords)) + + (list 'font-lock-keywords (custom-quote font-lock-keywords)) + ;;(list 'font-lock-keywords-alist (custom-quote font-lock-keywords-alist)) + ;;(list 'font-lock-removed-keywords-alist (custom-quote font-lock-removed-keywords-alist)) + + ;; Fix-me: uncommenting this line (as it should be) + ;; sets font-lock-keywords-only to t globally...: bug 3467 + (list 'font-lock-keywords-only (custom-quote font-lock-keywords-only)) + + (list 'font-lock-keywords-case-fold-search (custom-quote font-lock-keywords-case-fold-search)) + + (list 'font-lock-set-defaults t) ; whether we have set up defaults. + + ;; Set from font-lock-defaults normally: + (list 'font-lock-defaults (custom-quote (copy-tree font-lock-defaults))) + ;; Syntactic Font Lock + (list 'font-lock-syntax-table (custom-quote font-lock-syntax-table)) ;; See nXhtml bug 400415 + (list 'font-lock-beginning-of-syntax-function (custom-quote font-lock-beginning-of-syntax-function)) + (list 'font-lock-syntactic-face-function (custom-quote font-lock-syntactic-face-function)) + + ;; Other Font Lock Variables + (list 'font-lock-mark-block-function (custom-quote font-lock-mark-block-function)) + (list 'font-lock-extra-managed-props (custom-quote font-lock-extra-managed-props)) + ;; This value is fetched from font-lock: + (list 'font-lock-fontify-buffer-function (custom-quote font-lock-fontify-buffer-function)) + (list 'font-lock-unfontify-buffer-function (custom-quote font-lock-unfontify-buffer-function)) + (list 'font-lock-fontify-region-function (custom-quote font-lock-fontify-region-function)) + (list 'font-lock-unfontify-region-function (custom-quote font-lock-unfontify-region-function)) + + ;; Jit Lock Variables + (list 'jit-lock-after-change-extend-region-functions (custom-quote jit-lock-after-change-extend-region-functions)) + + ;;(list 'syntax-table (custom-quote (copy-syntax-table (syntax-table)))) + ;;(list 'mumamo-original-syntax-begin-function (custom-quote syntax-begin-function)) + (list 'syntax-begin-function (custom-quote syntax-begin-function)) + (list 'fill-paragraph-function (custom-quote fill-paragraph-function)) + (list 'fill-forward-paragraph-function + (when (boundp 'fill-forward-paragraph-function) + (custom-quote fill-forward-paragraph-function))) + + ;; newcomment + (list 'comment-use-global-state (custom-quote (when (boundp 'comment-use-global-state) comment-use-global-state))) + + ;; parsing sexps + (list 'multibyte-syntax-as-symbol (custom-quote multibyte-syntax-as-symbol)) + (list 'parse-sexp-ignore-comments (custom-quote parse-sexp-ignore-comments)) + (list 'parse-sexp-lookup-properties (custom-quote parse-sexp-lookup-properties)) + ;; fix-me: does not the next line work? + (list 'forward-sexp-function (custom-quote forward-sexp-function)) + )) + (relevant-buffer-locals (mumamo-get-relevant-buffer-local-vars)) + ) + ;;(append '(1 2) '(3 4) '((eval body))) + (mumamo-msgfntfy "===========> before setq fetch-func-definition %s" func-sym) + ;; Avoid doublets + (dolist (fetched fetch-func-definition-let) + (let ((fvar (car fetched))) + (setq relevant-buffer-locals (assq-delete-all fvar relevant-buffer-locals)))) + (setq fetch-func-definition + (append fetch-func-definition + `((let ,(append fetch-func-definition-let + relevant-buffer-locals) + (with-syntax-table ,(if syntax-sym + syntax-sym + '(standard-syntax-table));;'syntax-table + ;; fix-me: Protect against font-lock-keywords-only to t globally...: bug 3467 + ;;(msgtrc "%s enter 1: font-lock-keywords-only def=%s, body=%S" ',major (default-value 'font-lock-keywords-only) body) + (let (;(font-lock-keywords-only font-lock-keywords-only) + ret) + ;;(msgtrc "%s enter 2: font-lock-keywords-only def=%s" ',major (default-value 'font-lock-keywords-only)) + (setq ret (eval body)) + ;;(msgtrc "%s exit 1: font-lock-keywords-only def=%s" ',major (default-value 'font-lock-keywords-only)) + ret)) + ;;(msgtrc "in %s 1: font-lock-keywords-only =%s in buffer %s, def=%s" ',func-sym font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ) + ;;(msgtrc "in %s 2: font-lock-keywords-only =%s in buffer %s, def=%s" ',func-sym font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ;;(message "backtrace there:\n%s" (with-output-to-string (backtrace))) + ))) + + (setq byte-compiled-fun (let ((major-syntax-table)) + (byte-compile fetch-func-definition))) + (assert (functionp byte-compiled-fun)) + (unless keywords + (eval `(defvar ,func-sym nil)) + (eval `(defvar ,func-def-sym ,fetch-func-definition)) + (set func-sym byte-compiled-fun) ;; Will be used as default + (assert (functionp (symbol-value func-sym)) t) + (funcall (symbol-value func-sym) nil) + (put func-sym 'permanent-local t) + (put func-def-sym 'permanent-local t)))) + (kill-buffer temp-buf) + ;; Use the new value in current buffer. + (when keywords + ;;(set (make-local-variable func-sym) (symbol-value func-sym)) + ;;(msgtrc "fetch: major=%s func-def-sym=%s cb=%s fetch-func-definition=%s" major func-def-sym (current-buffer) fetch-func-definition) + ;;(msgtrc "fetch: major=%s func-def-sym=%s cb=%s fetch-func-definition" major func-def-sym (current-buffer)) + (set (make-local-variable func-sym) byte-compiled-fun) + (set (make-local-variable func-def-sym) fetch-func-definition) + (put func-sym 'permanent-local t) + (put func-def-sym 'permanent-local t)) + (assert (functionp (symbol-value func-sym)) t) + ;; return a list def + fun + (cons func-sym func-def-sym))) + +;; Fix-me: maybe a hook in font-lock-add-keywords?? +(defun mumamo-ad-font-lock-keywords-helper (major keywords how add-keywords) + ;;(msgtrc "ad-font-lock-keywords-helper %s %s %s %s" major keywords how add-keywords) + (if major + (mumamo-fetch-major-mode-setup major keywords t t how) + ;; Fix-me: Can't do that, need a list of all + ;; mumamo-current-chunk-family chunk functions major + ;; modes. But this is impossible since the major modes might + ;; be determined dynamically. As a work around look in current + ;; chunks. + (let ((majors (list (mumamo-main-major-mode)))) + (dolist (entry mumamo-internal-major-modes-alist) + (let ((major (car entry)) + (fun-var-sym (caadr entry))) + (when (local-variable-p fun-var-sym) + (setq majors (cons (car entry) majors))))) + (dolist (major majors) + (setq major (mumamo-get-major-mode-substitute major 'fontification)) + ;;(msgtrc "(fetch-major-mode-setup %s %s %s %s %s)" major keywords nil t how) + (mumamo-fetch-major-mode-setup major keywords nil add-keywords how)) + ;;(font-lock-mode -1) (font-lock-mode 1) + ))) + +;; Fix-me: This has stopped working again 2009-11-04, but I do not know when it began... +(defadvice font-lock-add-keywords (around + mumamo-ad-font-lock-add-keywords + activate + compile) + (if (or (boundp 'mumamo-fetching-major) (boundp 'mumamo-add-font-lock-called) (not mumamo-multi-major-mode)) + ad-do-it + (let (mumamo-multi-major-mode + mumamo-add-font-lock-called + (major (ad-get-arg 0)) + (keywords (ad-get-arg 1)) + (how (ad-get-arg 2))) + (mumamo-ad-font-lock-keywords-helper major keywords how t)))) + +(defadvice font-lock-remove-keywords (around + mumamo-ad-font-lock-remove-keywords + activate + compile) + (if (or (boundp 'mumamo-fetching-major) (boundp 'mumamo-add-font-lock-called) (not mumamo-multi-major-mode)) + ad-do-it + (let (mumamo-multi-major-mode + mumamo-add-font-lock-called + (major (ad-get-arg 0)) + (keywords (ad-get-arg 1))) + (mumamo-ad-font-lock-keywords-helper major keywords nil nil)))) + +(defun mumamo-bad-mode () + "MuMaMo replacement for a major mode that could not be loaded." + (interactive) + (kill-all-local-variables) + (setq major-mode 'mumamo-bad-mode) + (setq mode-name + (propertize "Mumamo Bad Mode" + 'face 'font-lock-warning-face))) + +;;(mumamo-get-major-mode-setup 'css-mode) +;;(mumamo-get-major-mode-setup 'fundamental-mode) +(defun mumamo-get-major-mode-setup (use-major) + "Return function for evaluating code in major mode USE-MAJOR. +Fix-me: This doc string is wrong, old: + +Get local variable values for major mode USE-MAJOR. These +variables are used for indentation and fontification. The +variables are returned in a list with the same format as +`mumamo-fetch-major-mode-setup'. + +The list of local variable values which is returned by this +function is cached in `mumamo-internal-major-modes-alist'. This +avoids calling the major mode USE-MAJOR for each chunk during +fontification and speeds up fontification significantly." + ;; Fix-me: Problems here can cause mumamo to loop badly when this + ;; function is called over and over again. To avoid this add a + ;; temporary entry using mumamo-bad-mode while trying to fetch the + ;; correct mode. + + ;;(assq 'mumamo-bad-mode mumamo-internal-major-modes-alist) + (let ((use-major-entry (assq use-major mumamo-internal-major-modes-alist)) + bad-mode-entry + dummy-entry + fun-var-sym + fun-var-def-sym) + (unless use-major-entry + ;; Get mumamo-bad-mode entry and add a dummy entry based on + ;; this to avoid looping. + (setq bad-mode-entry + (assq 'mumamo-bad-mode mumamo-internal-major-modes-alist)) + (unless bad-mode-entry + ;; Assume it is safe to get the mumamo-bad-mode entry ;-) + (add-to-list 'mumamo-internal-major-modes-alist + (list 'mumamo-bad-mode + (mumamo-fetch-major-mode-setup 'mumamo-bad-mode nil nil nil nil))) + (setq bad-mode-entry + (assq 'mumamo-bad-mode mumamo-internal-major-modes-alist))) + (setq dummy-entry (list use-major (cadr bad-mode-entry))) + ;; Before fetching setup add the dummy entry and then + ;; immediately remove it. + (add-to-list 'mumamo-internal-major-modes-alist dummy-entry) + (setq use-major-entry (list use-major + (mumamo-fetch-major-mode-setup use-major nil nil nil nil))) + (setq mumamo-internal-major-modes-alist + (delete dummy-entry + mumamo-internal-major-modes-alist)) + (add-to-list 'mumamo-internal-major-modes-alist use-major-entry)) + (setq fun-var-sym (caadr use-major-entry)) + (setq fun-var-def-sym (cdadr use-major-entry)) + (assert (functionp (symbol-value fun-var-sym)) t) + (assert (eq 'lambda (car (symbol-value fun-var-def-sym))) t) + ;; Always make a buffer local value for keywords. + (unless (local-variable-p fun-var-sym) + (set (make-local-variable fun-var-sym) (symbol-value fun-var-sym)) + (set (make-local-variable fun-var-def-sym) (symbol-value fun-var-def-sym))) + (caadr (or (assq use-major mumamo-internal-major-modes-alist) + )))) +;; (assq use-major +;; (add-to-list 'mumamo-internal-major-modes-alist +;; (list use-major +;; (mumamo-fetch-major-mode-setup +;; use-major nil nil nil)))))))) + +(defun mumamo-remove-all-chunk-overlays () + "Remove all CHUNK overlays from the current buffer." + (save-restriction + (widen) + (mumamo-delete-new-chunks))) + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Creating and accessing chunks + +(defun mumamo-define-no-mode (mode-sym) + "Fallback major mode when no major mode for MODE-SYM is found." + (let ((mumamo-repl4 (intern (format "mumamo-4-%s" mode-sym))) + (lighter (format "No %s" mode-sym)) + (doc (format "MuMaMo replacement for %s which was not found." + mode-sym))) + (if (commandp mumamo-repl4) + mumamo-repl4 + (eval `(defun ,mumamo-repl4 () + ,doc + (interactive) + (kill-all-local-variables) + (setq major-mode ',mumamo-repl4) + (setq mode-name + (propertize ,lighter + 'face 'font-lock-warning-face))))))) +;;(mumamo-define-no-mode 'my-ownB-mode) + +;;(mumamo-major-mode-from-modespec 'javascript-mode) +(defun mumamo-major-mode-from-modespec (major-spec) + "Translate MAJOR-SPEC to a major mode. +Translate MAJOR-SPEC used in chunk definitions of multi major +modes to a major mode. + +See `mumamo-major-modes' for an explanation." + (mumamo-major-mode-from-spec major-spec mumamo-major-modes)) + +(defun mumamo-major-mode-from-spec (major-spec table) + (unless major-spec + (mumamo-backtrace "mode-from-modespec, major-spec is nil")) + (let ((modes (cdr (assq major-spec table))) + (mode 'mumamo-bad-mode)) + (setq mode + (catch 'mode + (dolist (m modes) + (when (functionp m) + (let ((def (symbol-function m))) + (when (and (listp def) + (eq 'autoload (car def))) + (mumamo-condition-case err + (load (nth 1 def)) + (error (setq m nil))))) + (when m (throw 'mode m)))) + nil)) + (unless mode + (if (functionp major-spec) + ;; As a last resort allow spec to be a major mode too: + (setq mode major-spec) + (if modes + (mumamo-warn-once '(mumamo-major-mode-from-modespec) + "Couldn't find an available major mode for specification %s,\n alternatives are:\n %s" + major-spec modes) + (mumamo-warn-once '(mumamo-major-mode-from-modespec) + "Couldn't find an available major mode for spec %s" + major-spec)) + ;;(setq mode 'fundamental-mode) + (setq mode (mumamo-define-no-mode major-spec)) + )) + (mumamo-msgfntfy " mumamo-major-mode-from-modespec %s => %s" major-spec mode) + mode)) + +(defun mumamo-get-existing-new-chunk-at (pos &optional first) + "Return last existing chunk at POS if any. +However if FIRST get first existing chunk at POS instead." + ;;(msgtrc "(mumamo-get-existing-new-chunk-at %s)" pos) + (let ((chunk-ovl) + (orig-pos pos)) + (when (= pos (point-max)) + (setq pos (1- pos))) + (when (= pos 0) (setq pos 1)) + (dolist (o (overlays-in pos (1+ pos))) + (when (and (overlay-get o 'mumamo-is-new) + ;; Because overlays-in need to have a range of length + ;; > 0 we might have got overlays that is after our + ;; orig-pos: + (<= (overlay-start o) orig-pos)) + ;; There can be two, choose the last or first depending on + ;; FIRST. + (if chunk-ovl + ;; (when (or (> (overlay-end o) (overlay-start o)) + ;; (overlay-get o 'mumamo-prev-chunk)) + (when (if first + (< (overlay-end o) (overlay-end chunk-ovl)) + (> (overlay-end o) (overlay-end chunk-ovl)) + ) + (setq chunk-ovl o)) + (setq chunk-ovl o)))) + chunk-ovl)) + +(defun mumamo-get-chunk-save-buffer-state (pos) + "Return chunk overlay at POS. Preserve state." + (let (chunk) + ;;(mumamo-save-buffer-state nil + ;;(setq chunk (mumamo-get-chunk-at pos))) + (setq chunk (mumamo-find-chunks pos "mumamo-get-chunk-save-buffer-state")) + ;;) + chunk)) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Chunk and chunk family properties + +(defun mumamo-syntax-maybe-completable (pnt) + "Return non-nil if at point PNT non-printable characters may occur. +This just considers existing chunks." + (let* ((chunk (mumamo-find-chunks pnt "mumamo-syntax-maybe-completable")) + syn-min-max) + (if (not chunk) + t + (mumamo-update-obscure chunk pnt) + (setq syn-min-max (mumamo-chunk-syntax-min-max chunk nil)) + ;;(and (> pnt (1+ (mumamo-chunk-syntax-min chunk))) + (and (> pnt (1+ (car syn-min-max))) + ;;(< pnt (1- (mumamo-chunk-syntax-max chunk))))))) + (< pnt (1- (cdr syn-min-max))))))) + +(defvar mumamo-current-chunk-family nil + "The currently used chunk family.") +(make-variable-buffer-local 'mumamo-current-chunk-family) +(put 'mumamo-current-chunk-family 'permanent-local t) + +;; (defvar mumamo-main-major-mode nil) +;; (make-variable-buffer-local 'mumamo-main-major-mode) +;; (put 'mumamo-main-major-mode 'permanent-local t) + +(defun mumamo-main-major-mode () + "Return major mode used when there are no chunks." + (let ((mm (cadr mumamo-current-chunk-family))) + (if mm mm + (msgtrc "main-major-mode => nil, mumamo-current-chunk-family=%s" mumamo-current-chunk-family)))) +;;; (let ((main (cadr mumamo-current-chunk-family))) +;;; (if main +;;; main +;;; mumamo-main-major-mode))) + +;; (defun mumamo-unset-chunk-family () +;; "Set chunk family to nil, ie undecided." +;; (interactive) +;; (setq mumamo-current-chunk-family nil)) + +;; (defun mumamo-define-chunks (chunk-family) +;; "Set the CHUNK-FAMILY used to divide the buffer." +;; (setq mumamo-current-chunk-family chunk-family)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; General chunk search routines + +;; search start forward + +;;(defun mumamo-search-fw-exc-start-str (pos max marker) +(defun mumamo-chunk-start-fw-str (pos max marker) + "General chunk function helper. +A chunk function helper like this can be used in +`mumamo-find-possible-chunk' to find the borders of a chunk. +There are several functions like this that comes with mumamo. +Their names tell what they do. Lets look at the parts of the +name of this function: + + mumamo-chunk: All this helper functions begins so + -start-: Search for the start of a chunk + -fw-: Search forward + -str: Search for a string + +Instead of '-start-' there could be '-end-', ie end. +Instead of '-fw-' there could be '-bw-', ie backward. +Instead of '-str' there could be '-re', ie regular expression. + +There could also be a '-inc' at the end of the name. If the name +ends with this then the markers should be included in the chunks, +otherwise not. + +The argument POS means where to start the search. MAX means how +far to search (when searching backwards the argument is called +'min' instead). MARKER is a string or regular expression (see +the name) to search for." + (assert (stringp marker)) + (let ((pm (point-min)) + (cb (current-buffer))) + (message "cb=%s" cb) + (goto-char (max pm (- pos (length marker))))) + (search-forward marker max t)) + +(defun mumamo-chunk-start-fw-re (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + (goto-char (- pos (length marker))) + (re-search-forward marker max t)) + +(defun mumamo-chunk-start-fw-str-inc (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + (goto-char pos) + (let ((start (search-forward marker max t))) + (when start (setq start (- start (length marker)))))) + +;; search start backward + +;; (defun mumamo-chunk-start-bw-str (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; ;;(assert (stringp marker)) +;; (let (start-in) +;; (goto-char pos) +;; (setq start-in (search-backward marker min t)) +;; (when start-in +;; ;; do not include the marker +;; (setq start-in (+ start-in (length marker)))) +;; start-in)) + +;; (defun mumamo-chunk-start-bw-re (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (let (start-in) +;; (goto-char pos) +;; (setq start-in (re-search-backward marker min t)) +;; (when start-in +;; ;; do not include the marker +;; (setq start-in (match-end 0))) +;; start-in)) + +;; (defun mumamo-chunk-start-bw-str-inc (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (goto-char (+ pos (length marker))) +;; (search-backward marker min t)) + +;; search end forward + +(defun mumamo-chunk-end-fw-str (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + ;;(goto-char (1+ pos)) ;; 1+ cause otherwise ?> is at point + (goto-char pos) + (let (end-in) + (setq end-in (search-forward marker max t)) + (when end-in + ;; do not include the marker + (setq end-in (- end-in (length marker)))) + end-in)) + +(defun mumamo-chunk-end-fw-re (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + (goto-char (1+ pos)) ;; 1+ cause otherwise ?> is at point + (let (end-in) + (setq end-in (re-search-forward marker max t)) + (when end-in + ;; do not include the marker + (setq end-in (match-beginning 0))) + end-in)) + +(defun mumamo-chunk-end-fw-str-inc (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + ;;(goto-char (1+ pos)) ;; 1+ cause otherwise ?> is at point + (goto-char (1+ (- pos (length marker)))) + ;;(msgtrc "mumamo-chunk-end-fw-str-inc %s %s %s, point=%s point-max=%s" pos max marker (point) (point-max)) + (search-forward marker max t)) + +;; search end backward + +;; (defun mumamo-chunk-end-bw-str (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (goto-char (+ pos (length marker))) +;; (search-backward marker min t)) + +;; (defun mumamo-chunk-end-bw-re (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (goto-char (+ pos (length marker))) +;; (re-search-backward marker min t)) + +(defun mumamo-chunk-end-bw-str-inc (pos min marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MIN and MARKER." + (assert (stringp marker)) + (goto-char pos) + (let ((end (search-backward marker min t))) + (when end (setq end (+ end (length marker)))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; General chunk routines + +;; (defvar mumamo-known-chunk-start nil "Internal use only!.") + +(defconst mumamo-string-syntax-table + (let ((tbl (copy-syntax-table))) + (modify-syntax-entry ?\" "\"" tbl) + (modify-syntax-entry ?\' "\"" tbl) + tbl) + "Just for \"..\" and '...'.") + +;; "..." '...' "..'.." '.."..' +(defun mumamo-guess-in-string (pos) + "If POS is in a string then return string start position. +Otherwise return nil." + (when (and (>= pos (point-min))) + (let ((here (point)) + (inhibit-field-text-motion t) + line-beg + parsed + str-char + str-pos) + (goto-char pos) + (setq line-beg (line-beginning-position)) + (setq parsed (with-syntax-table mumamo-string-syntax-table + (parse-partial-sexp line-beg pos))) + (setq str-char (nth 3 parsed)) + (when str-char + (skip-chars-backward (string ?^ str-char)) + (setq str-pos (point))) + (goto-char here) + str-pos))) + +;;; The main generic chunk routine + +;; Fix-me: new routine that really search forward only. Rewrite +;; `mumamo-quick-static-chunk' first with this. +(defun mumamo-possible-chunk-forward (pos + max + chunk-start-fun + chunk-end-fun + &optional borders-fun) + "Search forward from POS to MAX for possible chunk. +Return as a list with values + + \(START END CHUNK-MAJOR BORDERS PARSEABLE-BY CHUNK-END-FUN BORDERS-FUN) + +START and END are start and end of the possible chunk. +CHUNK-MAJOR is the major mode specifier for this chunk. \(Note +that this specifier is translated to a major mode through +`mumamo-major-modes'.) + +START-BORDER and END-BORDER may be nil. Otherwise they should be +the position where the border ends respectively start at the +corresponding end of the chunk. + +BORDERS is the return value of the optional BORDERS-FUN which +takes three parameters, START, END and EXCEPTION-MODE in the +return values above. BORDERS may be nil and otherwise has this +format: + + \(START-BORDER END-BORDER CHUNK-MAJOR CHUNK-END-FUN) + +PARSEABLE-BY is a list of major modes with parsers that can parse +the chunk. + +CHUNK-START-FUN and CHUNK-END-FUN should be functions that +searches forward from point for start and end of chunk. They +both take two parameters, POS and MAX above. If no possible +chunk is found both these functions should return nil, otherwise +see below. + +CHUNK-START-FUN should return a list of the form below if a +possible chunk is found: + + (START CHUNK-MAJOR PARSEABLE-BY) + +CHUNK-END-FUN should return the end of the chunk. + +" + ;;(msgtrc "possible-chunk-forward %s %s" pos max) + (let ((here (point)) + start-rec + start + end + chunk-major + parseable-by + borders + ret + ) + (goto-char pos) + ;; Fix-me: check valid. Should this perhaps be done in the + ;; function calling this instead? + ;;(mumamo-end-in-code syntax-min syntax-max curr-major) + (setq start-rec (funcall chunk-start-fun (point) max)) + (when start-rec + (setq start (nth 0 start-rec)) + (setq chunk-major (nth 1 start-rec)) + (setq parseable-by (nth 2 start-rec)) + (goto-char start) + ;; Fix-me: check valid + ;;(setq end (funcall chunk-end-fun (point) max)) + (when borders-fun + (let ((start-border (when start (unless (and (= 1 start) + (not chunk-major)) + start))) + (end-border (when end (unless (and (= (point-max) end) + (not chunk-major)) + end)))) + (setq borders (funcall borders-fun start-border end-border chunk-major)))) + (setq ret (list start end chunk-major borders parseable-by chunk-end-fun borders-fun))) + (goto-char here) + ret)) + +;; Fix-me: This routine has some difficulties. One of the more +;; problematic things is that chunk borders may depend on the +;; surrounding chunks syntax. Patterns that possibly could be chunk +;; borders might instead be parts of comments or strings in cases +;; where they should not be valid borders there. +(defun mumamo-find-possible-chunk (pos + min max + bw-exc-start-fun ;; obsolete + bw-exc-end-fun + fw-exc-start-fun + fw-exc-end-fun + &optional find-borders-fun) + (mumamo-find-possible-chunk-new pos + ;;min + max + bw-exc-start-fun + ;;bw-exc-end-fun + fw-exc-start-fun + fw-exc-end-fun + find-borders-fun)) + +(defun mumamo-find-possible-chunk-new (pos + ;;min + max + bw-exc-start-fun + ;;bw-exc-end-fun + fw-exc-start-fun + fw-exc-end-fun + &optional find-borders-fun) + ;; This should return no end value! + "Return list describing a possible chunk that starts after POS. +No notice is taken about existing chunks and no chunks are +created. The description returned is for the smallest possible +chunk which is delimited by the function parameters. + +POS must be less than MAX. + +The function BW-EXC-START-FUN takes two parameters, POS and +MIN. It should search backward from POS, bound by MIN, for +exception start and return a cons or a list: + + \(FOUND-POS . EXCEPTION-MODE) + \(FOUND-POS EXCEPTION-MODE PARSEABLE-BY) + +Here FOUND-POS is the start of the chunk. EXCEPTION-MODE is the +major mode specifier for this chunk. \(Note that this specifier +is translated to a major mode through `mumamo-major-modes'.) + +PARSEABLE-BY is a list of parsers that can handle the chunk +beside the one that may be used by the chunks major mode. +Currently only the XML parser in `nxml-mode' is recognized. In +this list it should be the symbol `nxml-mode'. + +The functions FW-EXC-START-FUN and FW-EXC-END-FUN should search +for exception start or end, forward resp backward. Those two +takes two parameters, start position POS and max position MAX, +and should return just the start respectively the end of the +chunk. + +For all three functions the position returned should be nil if +search fails. + + +Return as a list with values + + \(START END EXCEPTION-MODE BORDERS PARSEABLE-BY FR-EXC-FUN FIND-BORDERS-FUN) + +**Fix-me: FIND-BORDERS-FUN must be split for chunks-in-chunks! + +The bounds START and END are where the exception starts or stop. +Either of them may be nil, in which case this is equivalent to +`point-min' respectively `point-max'. + +If EXCEPTION-MODE is non-nil that is the submode for this +range. Otherwise the main major mode should be used for this +chunk. + +BORDERS is the return value of the optional FIND-BORDERS-FUN +which takes three parameters, START, END and EXCEPTION-MODE in +the return values above. BORDERS may be nil and otherwise has +this format: + + \(START-BORDER END-BORDER EXCEPTION-MODE FW-EXC-FUN) + +START-BORDER and END-BORDER may be nil. Otherwise they should be +the position where the border ends respectively start at the +corresponding end of the chunk. + +PARSEABLE-BY is a list of major modes with parsers that can parse +the chunk. + +FW-EXC-FUN is the function that finds the end of the chunk. This +is either FW-EXC-START-FUN or FW-EXC-END-FUN. + +---- * Note: This routine is used by to create new members for +chunk families. If you want to add a new chunk family you could +most often do that by writing functions for this routine. Please +see the many examples in mumamo-fun.el for how this can be done. +See also `mumamo-quick-static-chunk'." + ;;(msgtrc "====") + ;;(msgtrc "find-poss-new %s %s %s %s %s %s" pos max bw-exc-start-fun fw-exc-start-fun fw-exc-end-fun find-borders-fun) + + ;;(mumamo-condition-case err + (progn + (assert (and (<= pos max)) nil + "mumamo-chunk: pos=%s, max=%s, bt=%S" + pos max (with-output-to-string (backtrace))) + ;; "in" refers to "in exception" and "out" is then in main + ;; major mode. + (let (start-in-cons + exc-mode + fw-exc-mode + fw-exc-fun + parseable-by + start-in start-out + end-in end-out + start end + ;;end-of-exception + wants-end-type + found-valid-end + (main-major (mumamo-main-major-mode)) + borders + border-beg + border-end) + ;;;; find start of range + ;; + ;; start normal + ;; + ;;(setq start-out (funcall bw-exc-end-fun pos min)) + ;; Do not check end here! + ;;(setq start-out (funcall fw-exc-end-fun pos max)) + ;;(msgtrc "find-poss-new.start-out=%s" start-out) + ;; start exception + (setq start-in (funcall fw-exc-start-fun pos max)) + ;;(msgtrc "find-poss-new.start-in=%s" start-in) + (when (listp start-in) + (setq fw-exc-mode (nth 1 start-in)) + (setq start-in (car start-in))) + ;; compare + (when (and start-in start-out) + (if (> start-in start-out) + (setq start-in nil) + (setq start-out nil))) + (cond + (start-in + (setq start-in-cons (funcall bw-exc-start-fun start-in pos)) + ;;(msgtrc "find-poss-new.start-in=%s start-in-cons=%s" start-in start-in-cons) + (when start-in-cons + (assert (= start-in (car start-in-cons))) + (setq exc-mode (cdr start-in-cons))) + (setq start start-in)) + (start-out + (setq start start-out)) + ) + (when (and exc-mode + (listp exc-mode)) + (setq parseable-by (cadr exc-mode)) + (setq exc-mode (car exc-mode))) + ;; borders + (when find-borders-fun + (let ((start-border (when start (unless (and (= 1 start) + (not exc-mode)) + start))) + (end-border (when end (unless (and (= (point-max) end) + (not exc-mode)) + end)))) + (setq borders (funcall find-borders-fun start-border end-border exc-mode)))) + ;; check + (setq border-beg (nth 0 borders)) + (setq border-end (nth 1 borders)) + ;;(when start (assert (<= start pos))) + ;;(assert (or (not start) (= start pos))) + (when border-beg + (assert (<= start border-beg))) + ;; Fix-me: This is just totally wrong in some pieces and a + ;; desperate try after seeing the problems with wp-app.php + ;; around line 1120. Maybe this can be used when cutting chunks + ;; from top to bottom however. + (when nil ;end + (let ((here (point)) + end-line-beg + end-in-string + start-in-string + (start-border (or (nth 0 borders) start)) + (end-border (or (nth 1 borders) end))) + ;; Check if in string + ;; Fix-me: add comments about why and examples + tests + ;; Fix-me: must loop to find good borders .... + (when end + ;; Fix-me: more careful positions for guess + (setq end-in-string + (mumamo-guess-in-string + ;;(+ end 2) + (1+ end-border) + )) + (when end-in-string + (when start + (setq start-in-string + (mumamo-guess-in-string + ;;(- start 2) + (1- start-border) + ))) + (if (not start-in-string) + (setq end nil) + (if exc-mode + (if (and start-in-string end-in-string) + ;; If both are in a string and on the same line then + ;; guess this is actually borders, otherwise not. + (unless (= start-in-string end-in-string) + (setq start nil) + (setq end nil)) + (when start-in-string (setq start nil)) + (when end-in-string (setq end nil))) + ;; Fix-me: ??? + (when start-in-string (setq start nil)) + )) + (unless (or start end) + (setq exc-mode nil) + (setq borders nil) + (setq parseable-by nil)))))) + + (when (or start end exc-mode borders parseable-by) + (setq fw-exc-fun (if exc-mode + ;; Fix-me: this is currently correct, + ;; but will change if exc mode in exc + ;; mode is allowed. + fw-exc-end-fun + ;; Fix-me: these should be collected later + ;;fw-exc-start-fun + nil + )) + (mumamo-msgfntfy "--- mumamo-find-possible-chunk-new %s" (list start end exc-mode borders parseable-by fw-exc-fun)) + ;;(message "--- mumamo-find-possible-chunk-new %s" (list start end exc-mode borders parseable-by fw-exc-fun)) + (when fw-exc-mode + (unless (eq fw-exc-mode exc-mode) + ;;(message "fw-exc-mode=%s NEQ exc-mode=%s" fw-exc-mode exc-mode) + )) + ;;(msgtrc "find-poss-new returns %s" (list start end exc-mode borders parseable-by fw-exc-fun find-borders-fun)) + (when fw-exc-fun + (list start end exc-mode borders parseable-by fw-exc-fun find-borders-fun))))) + ;;(error (mumamo-display-error 'mumamo-chunk "%s" (error-message-string err))) + + ;;) + ) + +;; (defun temp-overlays-here () +;; (interactive) +;; (let* ((here (point)) +;; (ovl-at (overlays-at here)) +;; (ovl-in (overlays-in here (1+ here))) +;; (ovl-in0 (overlays-in here here)) +;; ) +;; (with-output-to-temp-buffer (help-buffer) +;; (help-setup-xref (list #'temp-overlays-at) (interactive-p)) +;; (with-current-buffer (help-buffer) +;; (insert (format "overlays-at %s:\n%S\n\n" here ovl-at)) +;; (insert (format "overlays-in %s-%s:\n%S\n\n" here (1+ here) ovl-in)) +;; (insert (format "overlays-in %s-%s:\n%S\n\n" here here ovl-in0)) +;; )))) +;; (defun temp-cursor-pos () +;; (interactive) +;; (what-cursor-position t)) +;; ;;(global-set-key [f9] 'temp-cursor-pos) +;; (defun temp-test-new-create-chunk () +;; (interactive) +;; (mumamo-delete-new-chunks) +;; ;;(setq x1 nil) +;; (let (x1 +;; (first t)) +;; (while (or first x1) +;; (setq first nil) +;; (setq x1 (mumamo-new-create-chunk (mumamo-find-next-chunk-values x1 nil nil nil))))) +;; ) + +;; (defun temp-create-last-chunk () +;; (interactive) +;; (mumamo-new-create-chunk (mumamo-find-next-chunk-values mumamo-last-chunk nil nil nil))) + +(defun mumamo-delete-new-chunks () + (setq mumamo-last-chunk nil) + (save-restriction + (widen) + (let ((ovls (overlays-in (point-min) (point-max)))) + (dolist (ovl ovls) + (when (overlay-get ovl 'mumamo-is-new) + ;;(msgtrc "delete-overlay %s delete-new-chunks" ovl) + (delete-overlay ovl)))))) + +(defun mumamo-new-create-chunk (new-chunk-values) + "Create and return a chunk from NEW-CHUNK-VALUES. +When doing this store the functions for creating the next chunk +after this in the properties below of the now created chunk: + +- 'mumamo-next-major: is nil or the next chunk's major mode. +- 'mumamo-next-end-fun: function that searches for end of AFTER-CHUNK +- 'mumamo-next-border-fun: functions that finds borders" + ;;((1 696 nxhtml-mode nil nil nil nil) (696 nil php-mode nil nil nil nil)) + ;;(current (list curr-min curr-max curr-major curr-border-min curr-border-max curr-parseable curr-fw-exc-fun)) + ;;(msgtrc "######new-create.chunk.new-chunk-values=%s" new-chunk-values) + (when new-chunk-values + (let* ((this-values (nth 0 new-chunk-values)) + (next-values (nth 1 new-chunk-values)) + (next-major (nth 0 next-values)) + (next-end-fun (nth 1 next-values)) + (next-border-fun (nth 2 next-values)) + (next-depth-diff (nth 3 next-values)) + (next-indent (nth 4 next-values)) + (this-beg (nth 0 this-values)) + (this-end (nth 1 this-values)) + (this-maj (nth 2 this-values)) + (this-bmin (nth 3 this-values)) + (this-bmax (nth 4 this-values)) + (this-pable (nth 5 this-values)) + (this-after-chunk (nth 7 this-values)) + ;;(this-is-closed (nth 8 this-values)) + (this-insertion-type-beg (nth 8 this-values)) + (this-insertion-type-end (nth 9 this-values)) + ;;(this-is-closed (and this-end (< 1 this-end))) + (this-after-chunk-depth (when this-after-chunk + (overlay-get this-after-chunk 'mumamo-depth))) + (depth-diff (if this-after-chunk + (overlay-get this-after-chunk 'mumamo-next-depth-diff) + 1)) + (depth (if this-after-chunk-depth + (+ this-after-chunk-depth depth-diff) + 0)) + ;;(fw-funs (nth 6 this-values)) + ;;(borders-fun (nth 7 this-values)) + ;;(this-is-closed (when (or this-end (mumamo-fun-eq this-maj (mumamo-main-major-mode))) t)) + (use-this-end (if this-end this-end (1+ (buffer-size)))) ;(save-restriction (widen) (point-max)))) + (this-chunk (when (and (<= this-beg use-this-end) + ;; Avoid creating two empty overlays + ;; at the this-end - but what if we are + ;; not creating, just changing the + ;; last overlay ... + ;; + ;; (not (and (= this-beg use-this-end) + ;; (= use-this-end (1+ (buffer-size))) + ;; this-after-chunk + ;; (= 0 (- (overlay-end this-after-chunk) (overlay-start this-after-chunk))) + ;; )) + ) + (when (= this-beg 1) + (if (= use-this-end 1) + (assert (mumamo-fun-eq (mumamo-main-major-mode) this-maj) t) + (if this-after-chunk ;; not first + (assert (not (mumamo-fun-eq (mumamo-main-major-mode) this-maj)) t) + (assert (mumamo-fun-eq (mumamo-main-major-mode) this-maj) t)))) + ;;(message "Create chunk %s - %s" this-beg use-this-end) + ;;(make-overlay this-beg use-this-end nil nil (not this-is-closed)) + (make-overlay this-beg use-this-end nil this-insertion-type-beg this-insertion-type-end) + )) + ;; Fix-me: move to mumamo-find-next-chunk-values + (this-border-fun (when (and this-chunk this-after-chunk) + ;;(overlay-get this-after-chunk 'mumamo-next-border-fun) + (mumamo-chunk-car this-after-chunk 'mumamo-next-border-fun) + )) + (this-borders (when this-border-fun + ;;(msgtrc "(funcall %s %s %s %s)" this-border-fun this-beg this-end this-maj) + (funcall this-border-fun this-beg this-end this-maj))) + ;; Fix-me, check: there is no first border when moving out. + (this-borders-min (when (= 1 depth-diff) + (nth 0 this-borders))) + ;; Fix-me, check: there is no bottom border when we move + ;; further "in" since borders are now always inside + ;; sub-chunks (if I remember correctly...). + ;;(this-borders-max (when (and this-is-closed + (this-borders-max (when (and (not this-insertion-type-end) + (/= 1 next-depth-diff)) + (nth 1 this-borders))) + ) + ;;(msgtrc "created %s, major=%s" this-chunk this-maj) + (when (> depth 4) (error "Chunk depth > 4")) + (setq this-bmin nil) + (setq this-bmax nil) + (when this-borders-min (setq this-bmin (- this-borders-min this-beg))) + (when this-borders-max (setq this-bmax (- this-end this-borders-max))) + ;;(when this-after-chunk (message "this-after-chunk.this-end=%s, this-beg=%s, this-end=%s" (overlay-end this-after-chunk) this-beg this-end)) + ;;(message "fw-funs=%s" fw-funs) + (when this-chunk + (overlay-put this-chunk 'mumamo-is-new t) + (overlay-put this-chunk 'face (mumamo-background-color depth)) + (overlay-put this-chunk 'mumamo-depth depth) + ;; Values for next chunk + (overlay-put this-chunk 'mumamo-next-depth-diff next-depth-diff) + (assert (symbolp next-major) t) + (overlay-put this-chunk 'mumamo-next-major next-major) + ;; Values for this chunk + ;;(overlay-put this-chunk 'mumamo-is-closed this-is-closed) + (overlay-put this-chunk 'mumamo-insertion-type-end this-insertion-type-end) + (overlay-put this-chunk 'mumamo-syntax-min-d this-bmin) + (overlay-put this-chunk 'mumamo-syntax-max-d this-bmax) + (overlay-put this-chunk 'mumamo-prev-chunk this-after-chunk) + (overlay-put this-chunk 'mumamo-next-indent next-indent) + (when this-after-chunk (overlay-put this-after-chunk 'mumamo-next-chunk this-chunk)) + + ;;(msgtrc "\n<<<<<<<<<<<<<<<<< next-depth-diff/depth-diff=%s/%s, this-maj=%s, this-after-chunk=%s" next-depth-diff depth-diff this-maj this-after-chunk) + ;;(overlay-put this-chunk 'mumamo-next-end-fun next-end-fun) + (cond + ((= 1 next-depth-diff) + (mumamo-chunk-push this-chunk 'mumamo-next-border-fun next-border-fun) + (mumamo-chunk-push this-chunk 'mumamo-next-end-fun next-end-fun)) + ((= -1 next-depth-diff) + (mumamo-chunk-pop this-chunk 'mumamo-next-border-fun) + (mumamo-chunk-pop this-chunk 'mumamo-next-end-fun)) + ((= 0 next-depth-diff) + nil) + (t (error "next-depth-diff=%s" next-depth-diff))) + ;;(msgtrc "mumamo-next-end-fun=%S" (overlay-get this-chunk 'mumamo-next-end-fun)) + + ;; Fix-me: replace 'mumamo-major-mode with multi major mode to make it more flexible. + (cond + ((= 1 depth-diff) + (mumamo-chunk-push this-chunk 'mumamo-major-mode this-maj)) + ((= -1 depth-diff) + (mumamo-chunk-pop this-chunk 'mumamo-major-mode) + ) + (t (error "depth-diff=%s" depth-diff))) + + (overlay-put this-chunk 'mumamo-parseable-by this-pable) + (overlay-put this-chunk 'created (current-time-string)) + (mumamo-update-chunk-margin-display this-chunk) + (setq mumamo-last-chunk this-chunk) ;; Use this chunk!!!! + ;; Get syntax-begin-function for syntax-ppss: + (let* ((syntax-begin-function + (mumamo-with-major-mode-fontification this-maj + ;; Do like in syntax.el: + '(if syntax-begin-function + (progn + syntax-begin-function) + (when (and (not syntax-begin-function) + ;; fix-me: How to handle boundp here? + (boundp 'font-lock-beginning-of-syntax-function) + font-lock-beginning-of-syntax-function) + font-lock-beginning-of-syntax-function))))) + (mumamo-msgfntfy "Got syntax-begin-function, modified=%s" (buffer-modified-p)) + (overlay-put this-chunk 'syntax-begin-function syntax-begin-function)) + ) + ;;(msgtrc "Created %s, this=%s, next=%s" this-chunk this-values next-values) + this-chunk + ) + )) + +(defun mumamo-update-chunk-margin-display (chunk) + "Set before-string of CHUNK as spec by `mumamo-margin-use'." + ;; Fix-me: This is not displayed. Emacs bug? + ;;(overlay-put this-chunk 'before-string `((margin left-margin) ,(format "%d %s" depth maj))) + (if (not mumamo-margin-info-mode) + (overlay-put chunk 'before-string nil) + (let* ((depth (overlay-get chunk 'mumamo-depth)) + (maj (mumamo-chunk-car chunk 'mumamo-major-mode)) + (strn (propertize (format "%d" depth) + 'face (list :inherit (or (mumamo-background-color depth) + 'default) + :foreground "#505050" + :underline t + :slant 'normal + :weight 'normal + ))) + (maj-name (substring (symbol-name maj) 0 -5)) + (strm (propertize maj-name 'face + (list :foreground "#a0a0a0" :underline nil + :background (frame-parameter nil 'background-color) + :weight 'normal + :slant 'normal))) + str + (margin (mumamo-margin-used))) + (when (> (length strm) 5) (setq strm (substring strm 0 5))) + (setq str (concat strn + strm + (propertize " " 'face 'default) + )) + (overlay-put chunk 'before-string + (propertize " " 'display + `((margin ,margin) ,str)))))) + +(defun mumamo-update-chunks-margin-display (buffer) + "Apply `update-chunk-margin-display' to all chunks in BUFFER." + (with-current-buffer buffer + (save-restriction + (widen) + (let ((chunk (mumamo-find-chunks 1 "margin-disp")) + (while-n0 0)) + (while (and (mumamo-while 1500 'while-n0 "chunk") + chunk) + (mumamo-update-chunk-margin-display chunk) + (setq chunk (overlay-get chunk 'mumamo-next-chunk))))))) + +(defvar mumamo-margin-used nil) +(make-variable-buffer-local 'mumamo-margin-used) +(put 'mumamo-margin-used 'permanent-local t) + +(defun mumamo-margin-used () + (setq mumamo-margin-used + (if (and (boundp 'linum-mode) linum-mode) 'right-margin (nth 0 mumamo-margin-use)))) + +;; (defun mumamo-set-window-margins-used (win) +;; "Set window margin according to `mumamo-margin-use'." +;; ;; Fix-me: old-margin does not work, break it up +;; (let* ((old-margin-used mumamo-margin-used) +;; (margin-used (mumamo-margin-used)) +;; (width (nth 1 mumamo-margin-use)) +;; (both-widths (window-margins win)) +;; (old-left (eq old-margin-used 'left-margin)) +;; (left (eq margin 'left-margin))) +;; ;; Change only the margin we used! +;; (if (not mumamo-margin-info-mode) +;; (progn +;; (set-window-margins win +;; (if left nil (car both-widths)) +;; (if (not left) nil (cdr both-widths))) +;; ) +;; ;;(msgtrc "set-window-margins-used margin-info-mode=t") +;; (case margin-used +;; ('left-margin (set-window-margins win width (when old-left (cdr both-widths)))) +;; ('right-margin (set-window-margins win (car both-widths) width)))))) + +(defun mumamo-update-buffer-margin-use (buffer) + ;;(msgtrc "update-buffer-margin-use %s" buffer) + (when (fboundp 'mumamo-update-chunks-margin-display) + (with-current-buffer buffer + (when mumamo-multi-major-mode + (let* ((old-margin-used mumamo-margin-used) + (margin-used (mumamo-margin-used)) + (old-is-left (eq old-margin-used 'left-margin)) + (is-left (eq margin-used 'left-margin)) + (width (nth 1 mumamo-margin-use)) + (need-update nil)) + (if (not mumamo-margin-info-mode) + (when old-margin-used + (setq need-update t) + (setq old-margin-used nil) + (if old-is-left + (setq left-margin-width 0) + (setq right-margin-width 0))) + (unless (and (eq old-margin-used margin-used) + (= width (if old-is-left left-margin-width right-margin-width))) + (setq need-update t) + (if is-left + (setq left-margin-width width) + (setq right-margin-width width)) + (unless (eq old-margin-used margin-used) + (if old-is-left + (setq left-margin-width 0) + (setq right-margin-width 0))))) + (when need-update + (mumamo-update-chunks-margin-display buffer) + (dolist (win (get-buffer-window-list buffer)) + (set-window-buffer win buffer))) + ) + ;; Note: window update must be before buffer update because it + ;; uses old-margin from the call to function margin-used. + ;; (dolist (win (get-buffer-window-list buffer)) + ;; (mumamo-set-window-margins-used win)) + ;; (mumamo-update-chunks-margin-display buffer) + )))) + +(defun mumamo-new-chunk-value-min (values) + (let ((this-values (nth 0 values))) + (nth 0 this-values))) + +(defun mumamo-new-chunk-value-max (values) + (let ((this-values (nth 0 values))) + (nth 1 this-values))) + +(defun mumamo-new-chunk-equal-chunk-values (chunk values) + ;;(msgtrc "eq? chunk=%S, values=%S" chunk values) + (let* (;; Chunk + (chunk-is-new (overlay-get chunk 'mumamo-is-new)) + ;;(chunk-is-closed (overlay-get chunk 'mumamo-is-closed)) + (chunk-insertion-type-end (overlay-get chunk 'mumamo-insertion-type-end)) + (chunk-next-major (overlay-get chunk 'mumamo-next-major)) + (chunk-next-end-fun (mumamo-chunk-car chunk 'mumamo-next-end-fun)) + (chunk-next-border-fun (mumamo-chunk-car chunk 'mumamo-next-border-fun)) + (chunk-next-chunk-diff (overlay-get chunk 'mumamo-next-depth-diff)) + (chunk-beg (overlay-start chunk)) + (chunk-end (overlay-end chunk)) + (chunk-bmin (overlay-get chunk 'mumamo-syntax-min-d)) + (chunk-bmax (overlay-get chunk 'mumamo-syntax-max-d)) + (chunk-prev-chunk (overlay-get chunk 'mumamo-prev-chunk)) + (chunk-major-mode (mumamo-chunk-car chunk 'mumamo-major-mode)) + (chunk-pable (overlay-get chunk 'mumamo-parseable-by)) + (chunk-depth-diff (if chunk-prev-chunk + (overlay-get chunk-prev-chunk 'mumamo-next-depth-diff) + 0)) + ;; Values + (this-values (nth 0 values)) + (next-values (nth 1 values)) + (values-next-major (nth 0 next-values)) + (values-next-end-fun (nth 1 next-values)) + (values-next-border-fun (nth 2 next-values)) + (values-next-depth-diff (nth 3 next-values)) + (values-beg (nth 0 this-values)) + (values-end (nth 1 this-values)) + (values-major-mode (nth 2 this-values)) + (values-bmin (nth 3 this-values)) + (values-bmax (nth 4 this-values)) + (values-pable (nth 5 this-values)) + (values-prev-chunk (nth 7 this-values)) + (values-insertion-type-beg (nth 8 this-values)) + (values-insertion-type-end (nth 9 this-values)) + ;;(values-is-closed (when values-end t)) + ) + ;;(msgtrc "values=%S" values) + (and t ;chunk-is-new + (eq chunk-next-major values-next-major) + + ;; Can't check chunk-next-end-fun or chunk-next-border-fun + ;; here since they are fetched from prev chunk: + ;;(progn (message "eq-c-v: here b: %s /= %s" chunk-next-end-fun values-next-end-fun) t) + ;;(eq chunk-next-end-fun values-next-end-fun) + ;;(progn (message "eq-c-v: here c, %s /= %s" chunk-next-border-fun values-next-border-fun) t) + ;;(eq chunk-next-border-fun values-next-border-fun) + + (= chunk-next-chunk-diff values-next-depth-diff) + (= chunk-beg values-beg) + ;;(progn (message "eq-c-v: here b") t) + ;; (and (equal chunk-is-closed values-is-closed) + ;; (or (not chunk-is-closed) + (and (equal chunk-insertion-type-end values-insertion-type-end) + (or ;;chunk-insertion-type-end + (= chunk-end values-end))) + ;;(progn (message "eq-c-v: here c, %s /= %s" chunk-major-mode values-major-mode) t) + (or (= -1 chunk-depth-diff) + (eq chunk-major-mode values-major-mode)) + ;;(progn (message "eq-c-v: here d") t) + (equal chunk-pable values-pable) + ;;(progn (message "eq-c-v: here e") t) + (eq chunk-prev-chunk values-prev-chunk) + ;;(progn (message "eq-c-v: here f") t) + ;;(eq chunk-is-closed values-is-closed) + (eq chunk-insertion-type-end values-insertion-type-end) + ;; fix-me: bmin bmax + ;;(and chunk-bmin values-bmin (= chunk-bmin values-bmin)) + ;;(and chunk-bmax values-bmax (= chunk-bmax values-bmax)) + ) + )) + +(defvar mumamo-sub-chunk-families nil + "Chunk dividing routines for sub chunks. +A major mode in a sub chunk can inherit chunk dividing routines +from multi major modes. This is the way chunks in chunks is +implemented. + +This variable is an association list with entries of the form + + \(CHUNK-MAJOR CHUNK-FAMILY) + +where CHUNK-MAJOR is the major mode in a chunk and CHUNK-FAMILY +is a chunk family \(ie the third argument to +`define-mumamo-multi-major-mode'. + +You can use the function `mumamo-inherit-sub-chunk-family' to add +to this list.") + +(defvar mumamo-multi-local-sub-chunk-families nil + "Multi major mode local chunk dividing rourines for sub chunks. +Like `mumamo-sub-chunk-families' specific additions for multi +major modes. The entries have the form + + \((CHUNK-MAJOR . MULTI-MAJOR) CHUNK-FAMILY) + +Use the function `mumamo-inherit-sub-chunk-family-locally' to add +to this list.") + +;;(mumamo-get-sub-chunk-funs 'html-mode) +(defun mumamo-get-sub-chunk-funs (major) + "Get chunk family sub chunk with major mode MAJOR." + (let ((rec (or + (assoc (cons major mumamo-multi-major-mode) mumamo-multi-local-sub-chunk-families) + (assoc major mumamo-sub-chunk-families)))) + (caddr (cadr rec)))) + +(defun mumamo-inherit-sub-chunk-family-locally (multi-major multi-using) + "Add chunk dividing routines from MULTI-MAJOR locally. +The dividing routines from multi major mode MULTI-MAJOR can then +be used in sub chunks in buffers using multi major mode +MULTI-USING." + (let* ((chunk-family (get multi-major 'mumamo-chunk-family)) + (major (nth 1 chunk-family))) + (let ((major-mode major)) + (when (derived-mode-p 'nxml-mode) + (error "Major mode %s major can't be used in sub chunks" major))) + (add-to-list 'mumamo-multi-local-sub-chunk-families + (list (cons major multi-using) chunk-family)))) + +(defun mumamo-inherit-sub-chunk-family (multi-major) + "Inherit chunk dividing routines from multi major modes. +Add chunk family from multi major mode MULTI-MAJOR to +`mumamo-sub-chunk-families'. + +Sub chunks with major mode the same as MULTI-MAJOR mode will use +this chunk familyu to find subchunks." + (let* ((chunk-family (get multi-major 'mumamo-chunk-family)) + (major (nth 1 chunk-family))) + (let ((major-mode major)) + (when (derived-mode-p 'nxml-mode) + (error "Major mode %s major can't be used in sub chunks" major))) + (add-to-list 'mumamo-sub-chunk-families (list major chunk-family)))) + +(defun mumamo-find-next-chunk-values (after-chunk from after-change-max chunk-at-after-change) + "Search forward for start of next chunk. +Return a list with chunk values for next chunk after AFTER-CHUNK +and some values for the chunk after it. + +For the first chunk AFTER-CHUNK is nil. Otherwise the values in stored in AFTER-CHUNK +is used to find the new chunk, its border etc. + + +See also `mumamo-new-create-chunk' for more information." + ;;(msgtrc "(find-next-chunk-values %s %s %s %s)" after-chunk from after-change-max chunk-at-after-change) + ;;(mumamo-backtrace "find-next") + (when after-chunk + (unless (eq (overlay-buffer after-chunk) + (current-buffer)) + (error "mumamo-find-next-chunk-values: after-chunk=%S, cb=%S" after-chunk (current-buffer)))) + (let* ((here (point)) + (max (point-max)) + ;;(after-chunk-is-closed (when after-chunk-valid (overlay-get after-chunk 'mumamo-is-closed))) + (after-chunk-insertion-type-end (when after-chunk (overlay-get after-chunk 'mumamo-insertion-type-end))) + ;; Note that "curr-*" values are fetched from "mumamo-next-*" values in after-chunk + (curr-min (if after-chunk (overlay-end after-chunk) 1)) + (curr-end-fun (when after-chunk + (mumamo-chunk-car after-chunk 'mumamo-next-end-fun))) + (curr-border-fun (when curr-end-fun (mumamo-chunk-car after-chunk 'mumamo-next-border-fun))) + (curr-syntax-min-max (when curr-border-fun (funcall curr-border-fun + (overlay-end after-chunk) + nil nil))) + (curr-syntax-min (or (car curr-syntax-min-max) + (when after-chunk (overlay-end after-chunk)) + 1)) + (search-from (or nil ;from + curr-syntax-min)) + ;;(dummy (msgtrc "search-from=%s" search-from)) + (main-chunk-funs (let ((chunk-info (cdr mumamo-current-chunk-family))) + (cadr chunk-info))) + (curr-major (if after-chunk + (or + ;; 'mumamo-next-major is used when we are going into a sub chunk. + (overlay-get after-chunk 'mumamo-next-major) + ;; We are going out of a sub chunk. + (mumamo-chunk-cadr after-chunk 'mumamo-major-mode)) + (mumamo-main-major-mode))) + ;;(dummy (msgtrc "curr-major=%s" curr-major)) + (curr-chunk-funs + (if (or (not after-chunk) + (= 0 (+ (overlay-get after-chunk 'mumamo-depth) + (overlay-get after-chunk 'mumamo-next-depth-diff)))) + main-chunk-funs + (mumamo-get-sub-chunk-funs curr-major))) + curr-max + next-max + curr-max-found + next-min + curr-border-min + curr-border-max + curr-parseable + next-fw-exc-fun + next-indent + next-major + curr-end-fun-end + next-border-fun + ;; The insertion types for the new chunk + (curr-insertion-type-beg (when after-chunk after-chunk-insertion-type-end)) + curr-insertion-type-end + next-depth-diff + r-point + ) + (unless (and after-chunk-insertion-type-end + (= (1+ (buffer-size)) ;; ie point-max + (overlay-end after-chunk))) + (when (>= max search-from) + (when curr-end-fun + ;; If after-change-max is non-nil here then this function has + ;; been called after changes that are all in one chunk. We + ;; need to check if the chunk right border have been changed, + ;; but we do not have to look much longer than the max point + ;; of the change. + ;;(message "set after-change-max nil") (setq after-change-max nil) + (let* ((use-max (if nil ;;after-change-max + (+ after-change-max 100) + max)) + (chunk-end (and chunk-at-after-change + (overlay-end chunk-at-after-change))) + ;;(use-min (max (- search-from 2) (point-min))) + (use-min curr-syntax-min) + (possible-end-fun-end t) + (end-search-pos use-min)) + ;; The code below takes care of the case when to subsequent + ;; chunks have the same ending delimiter. (Maybe a while + ;; loop is bit overkill here.) + (while (and possible-end-fun-end + (not curr-end-fun-end) + (< end-search-pos use-max)) + (setq curr-end-fun-end (funcall curr-end-fun end-search-pos use-max)) + (if (not curr-end-fun-end) + (setq possible-end-fun-end nil) + (cond ((and t ;after-chunk-is-closed + (< curr-end-fun-end (overlay-end after-chunk))) + (setq curr-end-fun-end nil) + (setq end-search-pos (1+ end-search-pos))) + ;; See if the end is in code + ((let* ((syn2-min-max (when curr-border-fun + (funcall curr-border-fun + (overlay-end after-chunk) + curr-end-fun-end + nil))) + (syn2-max (or (cadr syn2-min-max) + curr-end-fun-end))) + (not (mumamo-end-in-code use-min syn2-max curr-major))) + (setq end-search-pos (1+ curr-end-fun-end)) + (setq curr-end-fun-end nil) + )))) + (unless curr-end-fun-end + ;; Use old end if valid + (and after-change-max + chunk-end + (= -1 (overlay-get chunk-at-after-change 'mumamo-next-depth-diff)) + (< after-change-max chunk-end) + chunk-end)) + ;; Fix-me: Check if old chunk is valid. It is not valid if + ;; depth-diff = -1 and curr-end-fun-end is not the same as + ;; before. + + ;; Fix-me: this test should also be made for other chunks + ;; searches, but this catches most problems I think. + ;; (or (not curr-end-fun-end) + ;; ;; Fix-me: The bug in wiki-090804-js.html indicates that + ;; ;; we should not subtract 1 here. The subchunk there + ;; ;; ends with </script> and this can't be in column 1 + ;; ;; when the line before ends with a // style js comment + ;; ;; unless we don't subtract 1. + ;; ;; + ;; ;; However wiki-strange-hili-080629.html does not work + ;; ;; then because then the final " in style="..." is + ;; ;; included in the scan done in mumamo-end-in-code. + ;; ;; + ;; ;; The solution is to check for the syntax borders here. + ;; (let* ((syn2-min-max (when curr-border-fun + ;; (funcall curr-border-fun + ;; (overlay-end after-chunk) + ;; curr-end-fun-end + ;; nil))) + ;; (syntax-max (or (cadr syn2-min-max) + ;; curr-end-fun-end))) + ;; ;;(mumamo-end-in-code syntax-min (- curr-end-fun-end 1) curr-major) + ;; ;; + ;; ;; fix-me: This should be really in the individual + ;; ;; routines that finds possible chunks. Mabye this is + ;; ;; possible to fix now when just looking forward for + ;; ;; chunks? + ;; (mumamo-end-in-code curr-syntax-min syntax-max curr-major) + ;; ) + ;; (setq curr-end-fun-end nil)) + ;; Use old result if valid + ;; (and nil ;(not curr-end-fun-end) + ;; chunk-at-after-change + ;; (= -1 (overlay-get chunk-at-after-change 'mumamo-next-depth-diff)) + ;; (setq curr-end-fun-end (overlay-end chunk-at-after-change))) + ;;(msgtrc "find-next-chunk-values:curr-end-fun-end after end-in-code=%s" curr-end-fun-end) + )) + ;;(msgtrc "find-next-chunk-values:here d, curr-min=%s, after-chunk=%s" curr-min after-chunk) + (when (listp curr-chunk-funs) + ;;(msgtrc "find-next-chunk-values:curr-chunk-funs=%s" curr-chunk-funs) + (setq r-point (point)) + (dolist (fn curr-chunk-funs) + ;;(msgtrc "find-next-chunk-values:before (r (funcall fn search-from search-from max)), fn=%s search-from=%s, max=%s" fn search-from max) + (assert (= r-point (point)) t) + (let* ((r (funcall fn search-from search-from max)) + (rmin (nth 0 r)) + (rmax (nth 1 r)) + (rmajor-sub (nth 2 r)) + (rborder (nth 3 r)) + (rparseable (nth 4 r)) + (rfw-exc-fun (nth 5 r)) + (rborder-fun (nth 6 r)) + (rindent (nth 7 r)) + (rborder-min (when rborder (nth 0 rborder))) + (rborder-max (when rborder (nth 1 rborder))) + ;;(rmin-found rmin) + ) + ;;(msgtrc "find-next-chunk-values:fn=%s, r=%s" fn r) + (goto-char r-point) + (when r + (when rmax (message "mumamo warning: Bad r=%s, nth 1 should be nil" r)) + (unless (or rmin rmax) + (error "Bad r=%s, fn=%s" r fn)) + (unless rfw-exc-fun + (error "No fw-exc-fun returned from fn=%s, r=%s" fn r)) + (unless rmajor-sub + (error "No major mode for sub chunk, fn=%s, r=%s" fn r))) + (when r + (mumamo-msgfntfy " fn=%s, r=%s" fn r) + (unless rmin (setq rmin (point-max))) + ;;(unless rmax (setq rmax (point-min))) + ;; Do not allow zero length chunks + (unless rmax (setq rmax (point-max))) + (unless (and (> rmin 1) + rmax + (= rmin rmax)) + ;; comparision have to be done differently if we are in an + ;; exception part or not. since we are doing this from top to + ;; bottom the rules are: + ;; + ;; - exception parts always outrules non-exception part. when + ;; in exception part the min start point should be used. + ;; - when in non-exception part the max start point and the + ;; min end point should be used. + ;; + ;; check if first run: + + ;; Fix-me: there is some bug here when borders are not + ;; included and are not 0 width. + (if (not next-min) + (progn + (setq next-min rmin) + (setq curr-border-min rborder-min) + (setq next-max rmax) + (setq curr-border-max rborder-max) + ;;(setq curr-max-found rmin-found) + (setq curr-parseable rparseable) + (setq next-fw-exc-fun rfw-exc-fun) + (setq next-border-fun rborder-fun) + (setq next-indent rindent) + (setq next-major rmajor-sub)) + (if rmajor-sub + (if next-major + (when (or (not next-min) + (< rmin next-min)) + (setq next-min rmin) + (setq curr-border-min rborder-min) + (when rmax (setq max rmax)) + (setq curr-border-max rborder-max) + ;;(when rmin-found (setq curr-max-found t)) + (setq curr-parseable rparseable) + (setq next-fw-exc-fun rfw-exc-fun) + (setq next-border-fun rborder-fun) + (setq next-indent rindent) + (setq next-major rmajor-sub)) + (setq next-min rmin) + (setq curr-border-min rborder-min) + (when rmax (setq max rmax)) + (setq curr-border-max rborder-max) + ;;(when rmin-found (setq curr-max-found t)) + (setq curr-parseable rparseable) + (setq next-fw-exc-fun rfw-exc-fun) + (setq next-border-fun rborder-fun) + (setq next-indent rindent) + (setq next-major rmajor-sub)) + (unless next-major + (when (> next-min rmin) + (setq next-min rmin) + (setq curr-border-min rborder-min)) + (when (and rmax max + (> rmax max)) + ;;(setq max-found rmin-found) + ;;(when rmin-found (setq curr-max-found t)) + (when rmax (setq max rmax)) + (setq curr-border-max rborder-max)) + )))) + (mumamo-msgfntfy "next-min/max=%s/%s border=%s/%s search-from=%s" next-min max curr-border-min curr-border-max search-from) + ;; check! + (when (and next-min max) + ;;(assert (>= next-min search-from) t) + (assert (<= search-from max) t) + (when curr-border-min + (assert (<= next-min curr-border-min) t) + (assert (<= curr-border-min max) t)) + (when curr-border-max + (assert (<= next-min curr-border-max) t) + (assert (<= curr-border-max max) t)))) + ))) + (goto-char here) + (setq curr-max-found (or curr-max-found curr-end-fun-end)) + (when t ;curr-max-found + (setq curr-max (if max max (point-max))) + (setq curr-max (min (if next-min next-min curr-max) + (if curr-end-fun-end curr-end-fun-end curr-max)))) + ;;(setq curr-max nil) + (setq next-depth-diff (cond + ( (and curr-max curr-end-fun-end + (= curr-max curr-end-fun-end)) + -1) + ( (= curr-max (1+ (buffer-size))) + 0) + ( t 1))) + (when (= -1 next-depth-diff) ;; We will pop it from 'mumamo-major-mode + (setq next-major nil)) + (when curr-max + (unless (>= curr-max curr-min) + (error "curr-max is not >= curr-min"))) + ;;(setq curr-is-closed (and curr-max (< 1 curr-max))) + (when (and curr-max (= 1 curr-max)) + (assert (mumamo-fun-eq curr-major (mumamo-main-major-mode)) t) + ) + (assert (symbolp next-major) t) + ;; Fix-me: see for example rr-min8.php + (when (or ;;(not after-chunk) + (= curr-max (1+ (buffer-size))) + (cond + ((= next-depth-diff 1) + next-border-fun) + ((= next-depth-diff -1) + next-border-fun) + ((= next-depth-diff 0) + t) + (t (error "next-depth-diff=%s" next-depth-diff)))) + (setq curr-insertion-type-end t)) + (let ((current (list curr-min curr-max curr-major curr-border-min curr-border-max curr-parseable + curr-chunk-funs after-chunk + ;;curr-is-closed + curr-insertion-type-beg + curr-insertion-type-end + )) + (next (list next-major next-fw-exc-fun next-border-fun next-depth-diff next-indent))) + ;;(msgtrc "find-next-chunk-values=> current=%s, next=%s" current next) + (list current next)))))) + +;; Fix-me: This should check if the new chunk should be +;; parsed or not +;; (defsubst mumamo-chunk-nxml-parseable (chunk) +;; (mumamo-fun-eq (mumamo-main-major-mode) +;; (mumamo-chunk-major-mode xml-chunk))) + +(defun mumamo-valid-nxml-point (pos) + "Return non-nil if position POS is in an XML chunk." + (memq 'nxml-mode (get-text-property pos 'mumamo-parseable-by))) + +(defun mumamo-valid-nxml-chunk (chunk) + "Return t if chunk CHUNK should be valid XML." + (when chunk + (let ((major-mode (mumamo-chunk-major-mode chunk)) + (region (overlay-get chunk 'mumamo-region)) + (parseable-by (overlay-get chunk 'mumamo-parseable-by))) + ;;(message "mumamo-valid-nxml-chunk: major-mode=%s, parseble-by=%s" major-mode parseable-by) + (or region + (derived-mode-p 'nxml-mode) + (memq 'nxml-mode parseable-by))))) + +;; A good test case for the use of this is the troublesome code in the +;; first line of xml-as-string.php in nxml/nxhtml/bug-tests. Currently +;; this test code is however splitted and it looks like the code below +;; can't handle the line above if the line looks like below. The ?> is +;; still thought to be a border. Does this mean that ' is not treated +;; as a string separator? +;; +;; <?php header("Content-type:application/xml; charset=utf-8"); echo '<?xml version="1.0" encoding="utf-8"?>'; ?> +;; +;; However there are the reverse cases also, in lines like +;; +;; href="<?php $this->url($url); ?>" +;; <!-- <td><?php insert_a_lot_of_html(); ?> +;; +;; These are supposedly handled by using this test at the right +;; place... However it is not very clear in all cases whether chunk +;; dividers in comments and strings should be valid or not... +;; +;; For example in the first case above the php divider should be +;; valid. Probably it should be that in the second case too, but how +;; should mumamo know that? +;; +;; Fix-me: I think a per "chunk divider function + context" flag is +;; needed to handle this. Probably this will work the same for all web +;; dev things, ie the opening sub chunk divider is ALWAYS +;; valid. However that is not true for things like CSS, Javascript etc +;; in (X)HTML. + +(defun mumamo-end-in-code (syntax-start syntax-end major) + "Return t if possible syntax end is not in a string or comment. +Assume that the sexp syntax is nil at SYNTAX-START return t if +position SYNTAX-END is not in a string or comment according to +the sexp syntax using major mode MAJOR." + ;; Fix-me: This can't always detect html comments: <!-- + ;; ... -->. Could this be solved by RMS suggestion with a + ;; function/defmacro that binds variables to their global values? + (mumamo-msgfntfy "point-min,max=%s,%s syntax-start,end=%s,%s, major=%s" (point-min) (point-max) syntax-start syntax-end major) + ;;(msgtrc "end-in-code:here a after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + (assert (and syntax-start syntax-end) t) + (let ((doesnt-here (point)) + doesnt-ret) + (save-restriction + (widen) + ;;(msgtrc "end-in-code:here a2 after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + (mumamo-with-major-mode-fontification major + `(let (ppss) + ;; fix-me: Use main major mode, and `syntax-ppss'. Change the + ;; defadvice of this to make that possible. + ;;(msgtrc "end-in-code:here b after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + (setq ppss (parse-partial-sexp ,syntax-start (+ ,syntax-end 0))) + ;;(msgtrc "end-in-code %s %s %s:ppss=%S" ,syntax-start ,syntax-end ',major ppss) + ;;(msgtrc "end-in-code:here c after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + ;; If inside a string or comment then the end marker is + ;; invalid: + ;;(msgtrc "mumamo-end-in-code:ppss=%s" ppss) + (if (or (nth 3 ppss) + (nth 4 ppss)) + (progn + ;;(msgtrc "invalid end, syntax-end =%s" syntax-end) + (setq doesnt-ret nil) + (if (nth 4 ppss) ;; in comment, check if single line comment + (let ((here (point)) + eol-pos) + ;;(msgtrc "end-in-code, was in comment, ppss=%S" ppss) + (goto-char ,syntax-end) + (setq eol-pos (line-end-position)) + (goto-char here) + (setq ppss (parse-partial-sexp ,syntax-start (+ eol-pos 1))) + ;;(msgtrc "end-in-code, in comment, new ppss %s %s=%S" ,syntax-start (+ eol-pos 1) ppss) + (unless (nth 4 ppss) + (setq doesnt-ret t))))) + (setq doesnt-ret t) + ;;(msgtrc "valid end, syntax-end =%s" syntax-end) + )))) + (goto-char doesnt-here) + ;;(msgtrc "end-in-code:ret=%s" doesnt-ret) + doesnt-ret)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Easy chunk defining + +(defun mumamo-quick-chunk-forward (pos + min max + begin-mark end-mark inc mode + mark-is-border) + ;;(msgtrc "quick-chunk-forward %s %s %s" pos min max) + (let ((search-fw-exc-start + `(lambda (pos max) + (let ((exc-start + (if ,inc + (mumamo-chunk-start-fw-str-inc pos max ,begin-mark) + (mumamo-chunk-start-fw-str pos max ,begin-mark)))) + (when exc-start + (list exc-start mode nil))))) + (search-fw-exc-end + `(lambda (pos max) + ;;(msgtrc "search-fw-exc-end %s %s, inc=%s, end-mark=%s" pos max ,inc ,end-mark) + (save-match-data + (let ((ret (if ,inc + (mumamo-chunk-end-fw-str-inc pos max ,end-mark) + (mumamo-chunk-end-fw-str pos max ,end-mark)))) + ;;(msgtrc "search-fw-exc-end ret=%s" ret) + ret)))) + (find-borders + (when mark-is-border + `(lambda (start end exc-mode) + (let ((start-border) + (end-border)) + (if (and ,inc);; exc-mode) + (progn + (when start + (setq start-border + (+ start (length ,begin-mark)))) + (when end + (setq end-border + (- end (length ,end-mark))))) + (if (and (not ,inc) (not exc-mode)) + (progn + (when start + (setq start-border + (+ start (length ,end-mark)))) + (when end + (setq end-border + (- end (length ,begin-mark))))))) + (when (or start-border end-border) + (mumamo-msgfntfy "quick.start-border/end=%s/%s, start/end=%s/%s exc-mode=%s" start-border end-border start end exc-mode) + (list start-border end-border))))))) + (mumamo-possible-chunk-forward pos max + search-fw-exc-start + search-fw-exc-end + find-borders))) + +(defun mumamo-quick-static-chunk (pos + min max + begin-mark end-mark inc mode + mark-is-border) + (if t + (mumamo-quick-chunk-forward pos min max begin-mark end-mark inc mode mark-is-border) + ;; (let ((old (mumamo-quick-static-chunk-old pos min max begin-mark end-mark inc mode mark-is-border)) + ;; (new (mumamo-quick-chunk-forward pos min max begin-mark end-mark inc mode mark-is-border))) + ;; (unless (equal old new) (msgtrc "equal=%s\n\told=%S\n\tnew=%S" (equal old new) old new)) + ;; (if nil old new)) + )) + +;; (defun mumamo-quick-static-chunk-old (pos +;; min max +;; begin-mark end-mark inc mode +;; mark-is-border) +;; "Quick way to make a chunk function with static dividers. +;; Here is an example of how to use it: + +;; (defun mumamo-chunk-embperl-<- (pos min max) +;; \"Find [- ... -], return range and perl-mode.\" +;; (mumamo-quick-static-chunk pos min max \"[-\" \"-]\" nil 'perl-mode)) + +;; As you can see POS, MIN and MAX comes from argument of the +;; function you define. + +;; BEGIN-MARK should be a string that begins the chunk. +;; END-MARK should be a string that ends the chunk. + +;; If INC is non-nil then the dividers are included in the chunk. +;; Otherwise they are instead made parts of the surrounding chunks. + +;; MODE should be the major mode for the chunk. + +;; If MARK-IS-BORDER is non-nil then the marks are just borders and +;; not supposed to have the same syntax as the inner part of the + +;; Fix-me: This can only be useful if the marks are included in the +;; chunk, ie INC is non-nil. Should not these two arguments be +;; mixed then? +;; " +;; (mumamo-msgfntfy "quick.pos=%s min,max=%s,%s begin-mark/end=%s/%s mark-is-border=%s" pos min max begin-mark end-mark mark-is-border) +;; (let ((search-bw-exc-start +;; `(lambda (pos min) +;; (let ((exc-start +;; (if ,inc +;; (mumamo-chunk-start-bw-str-inc pos min begin-mark) +;; (mumamo-chunk-start-bw-str pos min begin-mark)))) +;; (when (and exc-start +;; (<= exc-start pos)) +;; (cons exc-start mode))))) +;; (search-bw-exc-end +;; `(lambda (pos min) +;; (if ,inc +;; (mumamo-chunk-end-bw-str-inc pos min ,end-mark) +;; (mumamo-chunk-end-bw-str pos min ,end-mark)))) +;; (search-fw-exc-start +;; `(lambda (pos max) +;; (if ,inc +;; (mumamo-chunk-start-fw-str-inc pos max ,begin-mark) +;; (mumamo-chunk-start-fw-str pos max ,begin-mark)))) +;; (search-fw-exc-end +;; `(lambda (pos max) +;; (save-match-data +;; (if ,inc +;; (mumamo-chunk-end-fw-str-inc pos max ,end-mark) +;; (mumamo-chunk-end-fw-str pos max ,end-mark))))) +;; (find-borders +;; (when mark-is-border +;; `(lambda (start end exc-mode) +;; (let ((start-border) +;; (end-border)) +;; (if (and ,inc exc-mode) +;; (progn +;; (when start +;; (setq start-border +;; (+ start (length ,begin-mark)))) +;; (when end +;; (setq end-border +;; (- end (length ,end-mark))))) +;; (if (and (not ,inc) (not exc-mode)) +;; (progn +;; (when start +;; (setq start-border +;; (+ start (length ,end-mark)))) +;; (when end +;; (setq end-border +;; (- end (length ,begin-mark))))))) +;; (when (or start-border end-border) +;; (mumamo-msgfntfy "quick.start-border/end=%s/%s, start/end=%s/%s exc-mode=%s" start-border end-border start end exc-mode) +;; (list start-border end-border))))))) +;; (mumamo-find-possible-chunk pos min max +;; search-bw-exc-start +;; search-bw-exc-end +;; search-fw-exc-start +;; search-fw-exc-end +;; find-borders))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Changing the major mode that the user sees + +(defvar mumamo-unread-command-events-timer nil) +(make-variable-buffer-local 'mumamo-unread-command-events-timer) + +(defun mumamo-unread-command-events (command-keys new-major old-last-command) + "Sync new keymaps after changing major mode in a timer. +Also tell new major mode. + +COMMAND-KEYS is the keys entered after last command and the call +to `mumamo-idle-set-major-mode' \(which is done in an idle +timer). Those keys are added to `unread-command-events' so they +can be used in the new keymaps. They should be in the format +returned by + + \(listify-key-sequence (this-command-keys-vector)) + +NEW-MAJOR mode is the new major mode. + +OLD-LAST-COMMAND is the value of `last-command' after switching +major mode. \(This is cleared by the function `top-level' so +this function will not see it since it is run in a timer.)" + (mumamo-condition-case err + (progn + ;; last-command seems to be cleared by top-level so set it + ;; back here. + (unless last-command + (setq last-command old-last-command)) + (when (< 0 (length command-keys)) + ;;(setq last-command-char nil) ;; For `viper-command-argument' + (setq unread-command-events (append command-keys nil))) + (message "Switched to %s" new-major)) + (error + (let ((mumamo-display-error-lwarn t)) + (mumamo-display-error 'mumamo-unread-command-events "err=%s" err))))) + +(defvar mumamo-idle-set-major-mode-timer nil) +(make-variable-buffer-local 'mumamo-idle-set-major-mode-timer) +(put 'mumamo-idle-set-major-mode-timer 'permanent-local t) + +(defun mumamotemp-pre-command () + "Temporary command for debugging." + (message "mumamotemp-pre 1: modified=%s %s" (buffer-modified-p) (current-buffer))) +(defun mumamotemp-post-command () + "Temporary command for debugging." + (message "mumamotemp-post 1: modified=%s %s" (buffer-modified-p) (current-buffer))) +(put 'mumamotemp-pre-command 'permanent-local-hook t) +(put 'mumamotemp-post-command 'permanent-local-hook t) +(defun mumamotemp-start () + "Temporary command for debugging." + (add-hook 'post-command-hook 'mumamotemp-post-command nil t) + (add-hook 'pre-command-hook 'mumamotemp-pre-command nil t)) + +(defsubst mumamo-cancel-idle-set-major-mode () + (when (timerp mumamo-idle-set-major-mode-timer) + (cancel-timer mumamo-idle-set-major-mode-timer)) + (setq mumamo-idle-set-major-mode-timer nil)) + +(defun mumamo-request-idle-set-major-mode () + "Setup to change major mode from chunk when Emacs is idle." + (mumamo-cancel-idle-set-major-mode) + (setq mumamo-idle-set-major-mode-timer + (run-with-idle-timer + mumamo-set-major-mode-delay + nil + 'mumamo-idle-set-major-mode (current-buffer) (selected-window)))) + +(defvar mumamo-done-first-set-major nil) +(make-variable-buffer-local 'mumamo-done-first-set-major) +(put 'mumamo-done-first-set-major 'permanent-local t) + +;; Fix-me: Add a property to the symbol instead (like in CUA). +(defvar mumamo-safe-commands-in-wrong-major + '(self-insert-command + fill-paragraph ;; It changes major mode + forward-char + viper-forward-char + backward-char + viper-backward-char + next-line + viper-next-line + previous-line + viper-previous-line + scroll-down + cua-scroll-down + scroll-up + cua-scroll-up + move-beginning-of-line + move-end-of-line + nonincremental-search-forward + nonincremental-search-backward + mumamo-backward-chunk + mumamo-forward-chunk + ;; Fix-me: add more + ) + ) + +(defun mumamo-fetch-local-map (major) + "Fetch local keymap for major mode MAJOR. +Do that by turning on the major mode in a new buffer. Add the +keymap to `mumamo-major-modes-local-maps'. + +Return the fetched local map." + (let (temp-buf-name + temp-buf + local-map) + (setq temp-buf-name (concat "mumamo-fetch-major-mode-local-" + (symbol-name major))) + (setq temp-buf (get-buffer temp-buf-name)) + (when temp-buf (kill-buffer temp-buf)) + (setq temp-buf (get-buffer-create temp-buf-name)) + (with-current-buffer temp-buf + (let ((mumamo-fetching-major t)) + (funcall major)) + (setq local-map (current-local-map)) + (when local-map (setq local-map (copy-keymap (current-local-map)))) + (add-to-list 'mumamo-major-modes-local-maps + (cons major-mode local-map))) + (kill-buffer temp-buf) + local-map)) + +(defvar mumamo-post-command-chunk nil) +(make-variable-buffer-local 'mumamo-post-command-chunk) + +(defun mumamo-post-command-get-chunk (pos) + "Get chunk at POS fast." + (let ((have-regions (and (boundp 'mumamo-regions) + mumamo-regions))) + (when have-regions (setq mumamo-post-command-chunk nil)) + (if (and mumamo-post-command-chunk + (overlayp mumamo-post-command-chunk) + ;;(progn (message "here a=%s" mumamo-post-command-chunk) t) + (overlay-buffer mumamo-post-command-chunk) + ;;(progn (message "here b=%s" mumamo-post-command-chunk) t) + (< pos (overlay-end mumamo-post-command-chunk)) + ;;(progn (message "here c=%s" mumamo-post-command-chunk) t) + (>= pos (overlay-start mumamo-post-command-chunk)) + ;;(progn (message "here d=%s" mumamo-post-command-chunk) t) + (mumamo-chunk-major-mode mumamo-post-command-chunk) + ;;(progn (msgtrc "here e=%s" mumamo-post-command-chunk) t) + ) + mumamo-post-command-chunk + ;;(msgtrc "--------------- new post-command-chunk") + (setq mumamo-post-command-chunk + (or (unless have-regions (mumamo-get-existing-new-chunk-at (point) nil)) + (mumamo-find-chunks (point) "post-command-get-chunk")))))) + +;; (setq mumamo-set-major-mode-delay 10) +(defun mumamo-set-major-post-command () + "Change major mode if necessary after a command. +If the major mode for chunk at `window-point' differ from current +major mode then change major mode to that for the chunk. If +however `mumamo-set-major-mode-delay' is greater than 0 just +request a change of major mode when Emacs is idle that long. + +See the variable above for an explanation why a delay might be +needed \(and is the default)." + ;;(msgtrc "set-major-post-command here") + (let* ((in-pre-hook (memq 'mumamo-set-major-pre-command pre-command-hook)) + (ovl (unless in-pre-hook (mumamo-post-command-get-chunk (point)))) + (major (when ovl (mumamo-chunk-major-mode ovl))) + (set-it-now (not (or in-pre-hook (mumamo-fun-eq major major-mode))))) + ;;(msgtrc "set-major-post-command ovl=%s, in-pre-hook=%s" ovl in-pre-hook) + (if (not set-it-now) + (unless (mumamo-fun-eq major major-mode) + (when mumamo-idle-set-major-mode-timer + (mumamo-request-idle-set-major-mode))) + (if mumamo-done-first-set-major + (if (<= 0 mumamo-set-major-mode-delay) + ;; Window point has been moved to a new chunk with a new + ;; major mode. Major mode will not be changed directly, + ;; but in an idle timer or in pre-command-hook. To avoid + ;; that the user get the wrong key bindings for the new + ;; chunk fetch the local map directly and apply that. + (let* ((map-rec (assoc major mumamo-major-modes-local-maps)) + (map (cdr map-rec))) + (unless map + (setq map (mumamo-fetch-local-map major))) + (unless (eq map 'no-local-map) + (use-local-map map)) + (add-hook 'pre-command-hook 'mumamo-set-major-pre-command nil t) + (mumamo-request-idle-set-major-mode)) + (mumamo-set-major major ovl) + (message "Switched to %s" major-mode)) + (mumamo-set-major major ovl))))) + +(defun mumamo-set-major-pre-command () + "Change major mode if necessary before a command. +When the key sequence that invoked the command is in current +local map and major mode is not the major mode for the current +mumamo chunk then set major mode to that for the chunk." + (mumamo-condition-case err + ;; First see if we can avoid changing major mode + (if (memq this-command mumamo-safe-commands-in-wrong-major) + (mumamo-request-idle-set-major-mode) + ;;(message "pre point=%s" (point)) + (let* ((ovl (mumamo-find-chunks (point) "mumamo-set-major-pre-command")) + (major (mumamo-chunk-major-mode ovl))) + ;;(message "pre point=%s" (point)) + (if (not major) + (lwarn '(mumamo-set-major-pre-command) :error "major=%s" major) + (when (or (not (mumamo-fun-eq major-mode major)) + (not (mumamo-set-major-check-keymap))) + (setq major-mode nil) + (mumamo-set-major major ovl) + ;; Unread the last command key sequence + (setq unread-command-events + (append (listify-key-sequence (this-command-keys-vector)) + unread-command-events)) + ;; Some commands, like `viper-command-argument' need to + ;; know the last command, so tell them. + (setq this-command (lambda () + (interactive) + (setq this-command last-command))))))) + (error + (mumamo-display-error 'mumamo-set-major-pre-command + "cb:%s, %s" (current-buffer) (error-message-string err))))) + +(defun mumamo-idle-set-major-mode (buffer window) + "Set major mode from mumamo chunk when Emacs is idle. +Do this only if current buffer is BUFFER and then do it in window +WINDOW. + +See the variable `mumamo-set-major-mode-delay' for an +explanation." + (save-match-data ;; runs in idle timer + (mumamo-msgfntfy "mumamo-idle-set-major-mode b=%s, window=%s" buffer window) + (with-selected-window window + ;; According to Stefan Monnier we need to set the buffer too. + (with-current-buffer (window-buffer window) + (when (eq buffer (current-buffer)) + (mumamo-condition-case err + ;;(let* ((ovl (mumamo-get-chunk-at (point))) + ;;(message "idle point=%s" (point)) + (let* ((ovl (mumamo-find-chunks (point) "mumamo-idle-set-major-mode")) + (major (mumamo-chunk-major-mode ovl)) + (modified (buffer-modified-p))) + ;;(message "idle point=%s" (point)) + (unless (mumamo-fun-eq major major-mode) + ;;(message "mumamo-set-major at A") + (mumamo-set-major major ovl) + ;; Fix-me: This is a bug workaround. Possibly in Emacs. + (when (and (buffer-modified-p) + (not modified)) + (set-buffer-modified-p nil)) + ;; sync keymap + (when (timerp mumamo-unread-command-events-timer) + (cancel-timer mumamo-unread-command-events-timer)) + (when unread-command-events + ;; Save unread keys before calling `top-level' which + ;; will clear them. + (setq mumamo-unread-command-events-timer + (run-with-idle-timer + 0 nil + 'mumamo-unread-command-events + unread-command-events + major last-command)) + (top-level) + ))) + (error + (mumamo-display-error 'mumamo-idle-set-major-mode + "cb=%s, err=%s" (current-buffer) err)))))))) + +(defun mumamo-post-command-1 (&optional no-debug) + "See `mumamo-post-command'. +Turn on `debug-on-error' unless NO-DEBUG is nil." + (unless no-debug (setq debug-on-error t)) + (setq mumamo-find-chunks-level 0) + (mumamo-msgfntfy "mumamo-post-command-1 ENTER: font-lock-mode=%s" font-lock-mode) + (if font-lock-mode + (mumamo-set-major-post-command) + ;;(mumamo-on-font-lock-off) + ) + ;;(msgtrc "mumamo-post-command-1 EXIT: font-lock-keywords-only =%s" (default-value 'font-lock-keywords-only)) + ) + + + + +(defvar mumamo-bug-3467-w14 41) +(defvar mumamo-bug-3467-w15 51) +;;(mumamo-check-has-bug3467 t) +;;(kill-local-variable 'mumamo-bug-3467-w14) +(defun mumamo-check-has-bug3467 (verbose) + (let ((has-bug nil)) + (with-temp-buffer + (let ((mumamo-bug-3467-w14 42) + (mumamo-bug-3467-w15 52)) + (when verbose (message "mumamo-bug-3467-w14 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when verbose (message "mumamo-bug-3467-w15 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15))) + (set (make-local-variable 'mumamo-bug-3467-w14) 43) + (set-default 'mumamo-bug-3467-w14 44) + (set-default 'mumamo-bug-3467-w15 54) + (when verbose (message "mumamo-bug-3467-w14 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when verbose (message "mumamo-bug-3467-w15 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15)))) + (when verbose (message "mumamo-bug-3467-w14 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when (/= mumamo-bug-3467-w14 43) (setq has-bug t)) + (when (/= (default-value 'mumamo-bug-3467-w14) 41) (setq has-bug t)) + (when verbose (message "mumamo-bug-3467-w15 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15))) + ) + (when verbose (message "mumamo-bug-3467-w14 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when verbose (message "mumamo-bug-3467-w15 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15))) + (or has-bug + (local-variable-p 'mumamo-bug-3467-w14) + (/= (default-value 'mumamo-bug-3467-w14) 41) + ) + )) + +(defvar mumamo-has-bug3467 (mumamo-check-has-bug3467 nil)) + +(defun mumamo-emacs-start-bug3467-timer-if-needed () + "Work around for Emacs bug 3467. The only one I have found." + (when mumamo-has-bug3467 + (run-with-idle-timer 0 nil 'mumamo-emacs-bug3467-workaround))) + +(defun mumamo-emacs-bug3467-workaround () + "Work around for Emacs bug 3467. The only one I have found." + (set-default 'font-lock-keywords-only nil)) + + + + +(defun mumamo-post-command () + "Run this in `post-command-hook'. +Change major mode if necessary." + ;;(msgtrc "mumamo-post-command") + (when mumamo-multi-major-mode + (mumamo-condition-case err + (mumamo-post-command-1 t) + (error + (mumamo-msgfntfy "mumamo-post-command %S" err) + ;; Warnings are to disturbing when run in post-command-hook, + ;; but this message is important so show it with an highlight. + (message + (propertize + "%s\n- Please try M-: (mumamo-post-command-1) to see what happened." + 'face 'highlight) + (error-message-string err)))))) + +(defun mumamo-change-major-function () + "Function added to `change-major-mode-hook'. +Remove mumamo when changing to a new major mode if the change is +not done because point was to a new chunk." + (unless mumamo-set-major-running + (mumamo-turn-off-actions))) + +(defun mumamo-derived-from-mode (major from-mode) + "Return t if major mode MAJOR is derived from FROM-MODE." + (let ((major-mode major)) + (derived-mode-p from-mode))) + +;; This is the new version of add-hook. For its origin see +;; http://lists.gnu.org/archive/html/emacs-devel/2007-12/msg00169.html +;; +;;(unless (> emacs-major-version 22) +(defvar mumamo-test-add-hook nil + "Internal use.") +(unless (and t + (let ((has-it nil)) + ;;(add-hook 'mumamo-test-add-hook 'mumamo-jit-lock-after-change nil t) + (add-hook 'mumamo-test-add-hook 'mumamo-after-change nil t) + (setq has-it (eq 'permanent-local-hook + (get 'mumamo-test-add-hook 'permanent-local))) + has-it)) + (defun add-hook (hook function &optional append local) + "Add to the value of HOOK the function FUNCTION. +FUNCTION is not added if already present. +FUNCTION is added (if necessary) at the beginning of the hook list +unless the optional argument APPEND is non-nil, in which case +FUNCTION is added at the end. + +The optional fourth argument, LOCAL, if non-nil, says to modify +the hook's buffer-local value rather than its default value. +This makes the hook buffer-local if needed, and it makes t a member +of the buffer-local value. That acts as a flag to run the hook +functions in the default value as well as in the local value. + +HOOK should be a symbol, and FUNCTION may be any valid function. If +HOOK is void, it is first set to nil. If HOOK's value is a single +function, it is changed to a list of functions." + (or (boundp hook) (set hook nil)) + (or (default-boundp hook) (set-default hook nil)) + (if local (unless (local-variable-if-set-p hook) + (set (make-local-variable hook) (list t))) + ;; Detect the case where make-local-variable was used on a hook + ;; and do what we used to do. + (unless (and (consp (symbol-value hook)) (memq t (symbol-value hook))) + (setq local t))) + (let ((hook-value (if local (symbol-value hook) (default-value hook)))) + ;; If the hook value is a single function, turn it into a list. + (when (or (not (listp hook-value)) (eq (car hook-value) 'lambda)) + (setq hook-value (list hook-value))) + ;; Do the actual addition if necessary + (unless (member function hook-value) + (setq hook-value + (if append + (append hook-value (list function)) + (cons function hook-value)))) + ;; Set the actual variable + (if local + (progn + ;; If HOOK isn't a permanent local, + ;; but FUNCTION wants to survive a change of modes, + ;; mark HOOK as partially permanent. + (and (symbolp function) + (get function 'permanent-local-hook) + (not (get hook 'permanent-local)) + (put hook 'permanent-local 'permanent-local-hook)) + (set hook hook-value)) + (set-default hook hook-value)))) + ) + + +(defvar mumamo-survive-hooks + '( + ;; activate-mark-hook after-change-functions after-save-hook + ;; before-save-functions auto-save-hook before-revert-hook + ;; buffer-access-fontify-functions calendar-load-hook + ;; command-line-functions compilation-finish-function + ;; deactivate-mark-hook find-file-hook + ;; find-file-not-found-functions first-change-hook + ;; kbd-macro-termination-hook kill-buffer-hook + ;; kill-buffer-query-functions menu-bar-update-hook + ;; post-command-hook pre-abbrev-expand-hook pre-command-hook + ;; write-contents-functions write-file-functions + ;; write-region-annotate-functions + ;; c-special-indent-hook + )) + +;; +;; Emulation modes +;; +;; These variables should have 'permanant-local t set in their +;; packages IMO, but now they do not have that. +(eval-after-load 'viper-cmd + (progn + (put 'viper-after-change-functions 'permanent-local t) + (put 'viper-before-change-functions 'permanent-local t) + )) +(eval-after-load 'viper + (progn + (put 'viper-post-command-hooks 'permanent-local t) + (put 'viper-pre-command-hooks 'permanent-local t) + ;;minor-mode-map-alist + ;; viper-mode-string -- is already buffer local, globally void + (put 'viper-mode-string 'permanent-local t) + )) +;;viper-tut--part +(eval-after-load 'viper-init + (progn + (put 'viper-d-com 'permanent-local t) + (put 'viper-last-insertion 'permanent-local t) + (put 'viper-command-ring 'permanent-local t) + (put 'viper-vi-intercept-minor-mode 'permanent-local t) + (put 'viper-vi-basic-minor-mode 'permanent-local t) + (put 'viper-vi-local-user-minor-mode 'permanent-local t) + (put 'viper-vi-global-user-minor-mode 'permanent-local t) + (put 'viper-vi-state-modifier-minor-mode 'permanent-local t) + (put 'viper-vi-diehard-minor-mode 'permanent-local t) + (put 'viper-vi-kbd-minor-mode 'permanent-local t) + (put 'viper-insert-intercept-minor-mode 'permanent-local t) + (put 'viper-insert-basic-minor-mode 'permanent-local t) + (put 'viper-insert-local-user-minor-mode 'permanent-local t) + (put 'viper-insert-global-user-minor-mode 'permanent-local t) + (put 'viper-insert-state-modifier-minor-mode 'permanent-local t) + (put 'viper-insert-diehard-minor-mode 'permanent-local t) + (put 'viper-insert-kbd-minor-mode 'permanent-local t) + (put 'viper-replace-minor-mode 'permanent-local t) + (put 'viper-emacs-intercept-minor-mode 'permanent-local t) + (put 'viper-emacs-local-user-minor-mode 'permanent-local t) + (put 'viper-emacs-global-user-minor-mode 'permanent-local t) + (put 'viper-emacs-kbd-minor-mode 'permanent-local t) + (put 'viper-emacs-state-modifier-minor-mode 'permanent-local t) + (put 'viper-vi-minibuffer-minor-mode 'permanent-local t) + (put 'viper-insert-minibuffer-minor-mode 'permanent-local t) + (put 'viper-automatic-iso-accents 'permanent-local t) + (put 'viper-special-input-method 'permanent-local t) + (put 'viper-intermediate-command 'permanent-local t) + ;; already local: viper-undo-needs-adjustment + (put 'viper-began-as-replace 'permanent-local t) + ;; already local: viper-replace-overlay + ;; already local: viper-last-posn-in-replace-region + ;; already local: viper-last-posn-while-in-insert-state + ;; already local: viper-sitting-in-replace + (put 'viper-replace-chars-to-delete 'permanent-local t) + (put 'viper-replace-region-chars-deleted 'permanent-local t) + (put 'viper-current-state 'permanent-local t) + (put 'viper-cted 'permanent-local t) + (put 'viper-current-indent 'permanent-local t) + (put 'viper-preserve-indent 'permanent-local t) + (put 'viper-auto-indent 'permanent-local t) + (put 'viper-electric-mode 'permanent-local t) + ;; already local: viper-insert-point + ;; already local: viper-pre-command-point + (put 'viper-com-point 'permanent-local t) + (put 'viper-ex-style-motion 'permanent-local t) + (put 'viper-ex-style-editing 'permanent-local t) + (put 'viper-ESC-moves-cursor-back 'permanent-local t) + (put 'viper-delete-backwards-in-replace 'permanent-local t) + ;; already local: viper-related-files-and-buffers-ring + (put 'viper-local-search-start-marker 'permanent-local t) + (put 'viper-search-overlay 'permanent-local t) + (put 'viper-last-jump 'permanent-local t) + (put 'viper-last-jump-ignore 'permanent-local t) + (put 'viper-minibuffer-current-face 'permanent-local t) + ;; already local: viper-minibuffer-overlay + (put 'viper-command-ring 'permanent-local t) + (put 'viper-last-insertion 'permanent-local t) + )) +(eval-after-load 'viper-keym + (progn + ;; already local: viper-vi-local-user-map + ;; already local: viper-insert-local-user-map + ;; already local: viper-emacs-local-user-map + (put 'viper--key-maps 'permanent-local t) + (put 'viper--intercept-key-maps 'permanent-local t) + ;; already local: viper-need-new-vi-local-map + ;; already local: viper-need-new-insert-local-map + ;; already local: viper-need-new-emacs-local-map + )) +(eval-after-load 'viper-mous + (progn + (put 'viper-mouse-click-search-noerror 'permanent-local t) + (put 'viper-mouse-click-search-limit 'permanent-local t) + )) +(eval-after-load 'viper-util + (progn + (put 'viper-syntax-preference 'permanent-local t) + (put 'viper-non-word-characters 'permanent-local t) + (put 'viper-ALPHA-char-class 'permanent-local t) + )) + +(eval-after-load 'cua-base + (progn + (put 'cua-inhibit-cua-keys 'permanent-local t) + (put 'cua--explicit-region-start 'permanent-local t) + (put 'cua--status-string 'permanent-local t) + )) +;; This is for the defvar in ido.el: +(eval-after-load 'ido + (progn + (put 'cua-inhibit-cua-keys 'permanent-local t) + )) +(eval-after-load 'cua-rect + (progn + (put 'cua--rectangle 'permanent-local t) + (put 'cua--rectangle-overlays 'permanent-local t) + )) +(eval-after-load 'edt + (progn + (put 'edt-select-mode 'permanent-local t) + )) +(eval-after-load 'tpu-edt + (progn + (put 'tpu-newline-and-indent-p 'permanent-local t) + (put 'tpu-newline-and-indent-string 'permanent-local t) + (put 'tpu-saved-delete-func 'permanent-local t) + (put 'tpu-buffer-local-map 'permanent-local t) + (put 'tpu-mark-flag 'permanent-local t) + )) +(eval-after-load 'vi + (progn + (put 'vi-add-to-mode-line 'permanent-local t) + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-scroll-amount + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-shift-width + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-point + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-length + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-repetition + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-overwrt-p + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-prefix-code + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-last-change-command + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-last-shell-command + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-last-find-char + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mark-alist + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-insert-state + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-local-map + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-mode-name + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-major-mode + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-case-fold + ;; + )) +(eval-after-load 'vi + (progn + (put 'vip-emacs-local-map 'permanent-local t) + (put 'vip-insert-local-map 'permanent-local t) + (put 'vip-insert-point 'permanent-local t) + (put 'vip-com-point 'permanent-local t) + (put 'vip-current-mode 'permanent-local t) + (put 'vip-emacs-mode-line-buffer-identification 'permanent-local t) + (put 'vip-current-major-mode 'permanent-local t) + )) + +(eval-after-load 'hi-lock + (progn + (put 'hi-lock-mode 'permanent-local t) + )) + +;; +;; Minor modes that are not major mode specific +;; + +(put 'visual-line-mode 'permanent-local t) + +(eval-after-load 'flymake + (progn + ;; hook functions: + (put 'flymake-after-change-function 'permanent-local-hook t) + (put 'flymake-after-save-hook 'permanent-local-hook t) + (put 'flymake-kill-buffer-hook 'permanent-local-hook t) + ;; hooks: +;;; (put 'after-change-functions 'permanent-local 'permanent-local-hook) +;;; (put 'after-save-hook 'permanent-local 'permanent-local-hook) +;;; (put 'kill-buffer-hook 'permanent-local 'permanent-local-hook) + ;; vars: + (put 'flymake-mode 'permanent-local t) + (put 'flymake-is-running 'permanent-local t) + (put 'flymake-timer 'permanent-local t) + (put 'flymake-last-change-time 'permanent-local t) + (put 'flymake-check-start-time 'permanent-local t) + (put 'flymake-check-was-interrupted 'permanent-local t) + (put 'flymake-err-info 'permanent-local t) + (put 'flymake-new-err-info 'permanent-local t) + (put 'flymake-output-residual 'permanent-local t) + (put 'flymake-mode-line 'permanent-local t) + (put 'flymake-mode-line-e-w 'permanent-local t) + (put 'flymake-mode-line-status 'permanent-local t) + (put 'flymake-temp-source-file-name 'permanent-local t) + (put 'flymake-master-file-name 'permanent-local t) + (put 'flymake-temp-master-file-name 'permanent-local t) + (put 'flymake-base-dir 'permanent-local t))) + +;; (eval-after-load 'imenu +;; (progn +;; ;; Fix-me: imenu is only useful for main major mode. The menu +;; ;; disappears in sub chunks because it is tighed to +;; ;; local-map. Don't know what to do about that. I do not +;; ;; understand the reason for binding it to local-map, but I +;; ;; suspect the intent is to have different menu items for +;; ;; different modes. Could not that be achieved by deleting the +;; ;; menu and creating it again when changing major mode? (That must +;; ;; be implemented in imenu.el of course.) +;; ;; +;; ;; hook functions: +;; ;;; (put 'imenu-update-menubar 'permanent-local-hook t) +;; ;; hooks: +;; (put 'menu-bar-update-hook 'permanent-local 'permanent-local-hook) +;; ;; vars: +;; (put 'imenu-generic-expression 'permanent-local t) +;; (put 'imenu-create-index-function 'permanent-local t) +;; (put 'imenu-prev-index-position-function 'permanent-local t) +;; (put 'imenu-extract-index-name-function 'permanent-local t) +;; (put 'imenu-name-lookup-function 'permanent-local t) +;; (put 'imenu-default-goto-function 'permanent-local t) +;; (put 'imenu--index-alist 'permanent-local t) +;; (put 'imenu--last-menubar-index-alist 'permanent-local t) +;; (put 'imenu-syntax-alist 'permanent-local t) +;; (put 'imenu-case-fold-search 'permanent-local t) +;; (put 'imenu-menubar-modified-tick 'permanent-local t) +;; )) + +(eval-after-load 'longlines + (progn + ;; Fix-me: take care of longlines-mode-off + (put 'longlines-mode 'permanent-local t) + (put 'longlines-wrap-beg 'permanent-local t) + (put 'longlines-wrap-end 'permanent-local t) + (put 'longlines-wrap-point 'permanent-local t) + (put 'longlines-showing 'permanent-local t) + (put 'longlines-decoded 'permanent-local t) + ;; + (put 'longlines-after-change-function 'permanent-local-hook t) + (put 'longlines-after-revert-hook 'permanent-local-hook t) + (put 'longlines-before-revert-hook 'permanent-local-hook t) + (put 'longlines-decode-buffer 'permanent-local-hook t) + (put 'longlines-decode-region 'permanent-local-hook t) + (put 'longlines-mode-off 'permanent-local-hook t) + (put 'longlines-post-command-function 'permanent-local-hook t) + (put 'longlines-window-change-function 'permanent-local-hook t) + ;;(put 'mail-indent-citation 'permanent-local-hook t) + )) + + +;; Fix-me: Rails, many problematic things: + +;;; Fix-me: No idea about these, where are they used?? Add them to +;;; mumamo-per-buffer-local-vars?: +;; predictive-main-dict +;; predictive-prog-mode-main-dict +;; predictive-use-auto-learn-cache +;; predictive-dict-autosave-on-kill-buffer +(eval-after-load 'inf-ruby + (progn + (put 'inferior-ruby-first-prompt-pattern 'permanent-local t) + (put 'inferior-ruby-prompt-pattern 'permanent-local t) + )) + +;;; These are for the output buffer (no problems): +;; font-lock-keywords-only +;; font-lock-defaults -- always buffer local +;; scroll-margin +;; scroll-preserve-screen-position + +(eval-after-load 'rails-script + (progn + (put 'rails-script:run-after-stop-hook 'permanent-local t) + (put 'rails-script:show-buffer-hook 'permanent-local t) + (put 'rails-script:output-mode-ret-value 'permanent-local t) + )) + +;;; No problems I believe (it is in output buffer): +;; compilation-error-regexp-alist-alist +;; compilation-error-regexp-alist + +;;; Fix-me: This is in the minor mode, what to do? Looks like it +;;; should have 'permanent-local t - in this case. I have added it to +;;; mumamo-per-buffer-local-vars for now. +;; tags-file-name + +(eval-after-load 'rails + (progn + (put 'rails-primary-switch-func 'permanent-local t) + (put 'rails-secondary-switch-func 'permanent-local t) + )) + +;; (defun test-js-perm () +;; (put 'js--quick-match-re 'permanent-local t) +;; (put 'js--quick-match-re-func 'permanent-local t) +;; (put 'js--cache-end 'permanent-local t) +;; (put 'js--last-parse-pos 'permanent-local t) +;; (put 'js--state-at-last-parse-pos 'permanent-local t) +;; (put 'js--tmp-location 'permanent-local t)) +;; (test-js-perm) + +(defvar mumamo-per-buffer-local-vars + '( + buffer-file-name + left-margin-width + right-margin-width + ;; Fix-me: This is to prevent font-lock-mode turning off/on, but + ;; is it necessary? + ;;font-lock-mode-major-mode + tags-file-name + nxhtml-menu-mode + ;; Fix-me: adding rng timers here stops Emacs from looping after + ;; indenting in ind-0-error.php, but I have no clue why. Hm. This + ;; problem is gone, but I forgot why. + rng-c-current-token ;;rng-cmpct.el:132:(make-variable-buffer-local 'rng-c-current-token) + rng-c-escape-positions ;;rng-cmpct.el:341:(make-variable-buffer-local 'rng-c-escape-positions) + rng-c-file-name ;;rng-cmpct.el:344:(make-variable-buffer-local 'rng-c-file-name) + rng-current-schema-file-name ;;rng-loc.el:37:(make-variable-buffer-local 'rng-current-schema-file-name) + rng-current-schema ;;rng-pttrn.el:71:(make-variable-buffer-local 'rng-current-schema) + ;;rng-validate-timer is permanent-local t + ;;rng-validate-timer ;;rng-valid.el:141:(make-variable-buffer-local 'rng-validate-timer) + ;;rng-validate-quick-timer is permanent-local t + ;;rng-validate-quick-timer ;;rng-valid.el:146:(make-variable-buffer-local 'rng-validate-quick-timer) + rng-error-count ;;rng-valid.el:153:(make-variable-buffer-local 'rng-error-count) + rng-message-overlay ;;rng-valid.el:158:(make-variable-buffer-local 'rng-message-overlay) + rng-message-overlay-inhibit-point ;;rng-valid.el:165:(make-variable-buffer-local 'rng-message-overlay-inhibit-point) + rng-message-overlay-current ;;rng-valid.el:169:(make-variable-buffer-local 'rng-message-overlay-current) + rng-validate-up-to-date-end ;;rng-valid.el:188:(make-variable-buffer-local 'rng-validate-up-to-date-end) + rng-conditional-up-to-date-start ;;rng-valid.el:199:(make-variable-buffer-local 'rng-conditional-up-to-date-start) + rng-conditional-up-to-date-end ;;rng-valid.el:205:(make-variable-buffer-local 'rng-conditional-up-to-date-end) + rng-validate-mode ;;rng-valid.el:212:(make-variable-buffer-local 'rng-validate-mode) + rng-dtd ;;rng-valid.el:215:(make-variable-buffer-local 'rng-dtd) + + nxml-syntax-highlight-flag ;; For pre-Emacs nxml + ;;nxml-ns-state - not buffer local currently + nxml-prolog-regions ;;snxml-mode.el:362:(make-variable-buffer-local 'nxml-prolog-regions) + nxml-last-fontify-end ;;dnxml-mode.el:367:(make-variable-buffer-local 'nxml-last-fontify-end) + nxml-degraded ;;dnxml-mode.el:373:(make-variable-buffer-local 'nxml-degraded) + nxml-char-ref-extra-display ;;ynxml-mode.el:397:(make-variable-buffer-local 'nxml-char-ref-extra-display) + nxml-prolog-end ;;dnxml-rap.el:92:(make-variable-buffer-local 'nxml-prolog-end) + nxml-scan-end ;;dnxml-rap.el:107:(make-variable-buffer-local 'nxml-scan-end) + + ;;buffer-invisibility-spec + ;;header-line-format + + ;; Fix-me: These must be handled with 'permanent-local since they may be changed: + line-move-visual ;;simple.el:4537: (kill-local-variable 'line-move-visual) + word-wrap ;;simple.el:4538: (kill-local-variable 'word-wrap) + truncate-lines ;;simple.el:4539: (kill-local-variable 'truncate-lines) + truncate-partial-width-windows ;;simple.el:4540: (kill-local-variable 'truncate-partial-width-windows) + fringe-indicator-alist ;;simple.el:4541: (kill-local-variable 'fringe-indicator-alist) + visual-line--saved-state ;;simple.el:4544: (kill-local-variable 'visual-line--saved-state))) + vis-mode-saved-buffer-invisibility-spec ;;simple.el:6237: (kill-local-variable 'vis-mode-saved-buffer-invisibility-spec)) + + ) + "Per buffer local variables. +See also `mumamo-per-main-major-local-vars'.") + +;; Fix-me: use this, but how exactly? I think the var values must be +;; picked up at every change from main major mode. And restored after +;; changing to the new major mode - but maybe a bit differently if +;; this is the main major mode. +(defvar mumamo-per-main-major-local-vars + '( + buffer-invisibility-spec + header-line-format + ) + "Per main major local variables. +Like `mumamo-per-buffer-local-vars', but this is fetched from the +main major mode.") + +;; (when nil +;; (make-variable-buffer-local 'mumamo-survive-minor-modes) +;; (put 'mumamo-survive-minor-modes 'permanent-local t) +;; (defvar mumamo-survive-minor-modes nil +;; "Hold local minor mode variables specific major modes. +;; Those values are saved when leaving a chunk with a certain +;; major mode and restored when entering a chunk with the same +;; major mode again. + +;; The value of this variable is an associative list where the key +;; is a list with + +;; \(MAJOR-MODE MINOR-MODE) + +;; and the value is a stored value for the minor mode.") +;; ) + +(defun mumamo-make-variable-buffer-permanent (var) + "Make buffer local value of VAR survive when moving point to a new chunk. +When point is moved between chunks in a multi major mode the +major mode will be changed. This will by default kill all local +variables unless they have a non-nil `permanent-local' property +\(see info node `(elisp)Creating Buffer-Local'). + +If you do not want to put a `permanent-local' property on a +variable you can instead use this function to make variable VAR +survive chunk switches in all mumamo multi major mode buffers." + ;; If you want it to survive chunk switches only in the current + ;; buffer then use `mumamo-make-local-permanent' instead." + (pushnew var (default-value 'mumamo-per-buffer-local-vars))) + +;; ;; Fix-me: use local value +;; ;; Fix-me: delelete local value when exiting mumamo +;; (defun mumamo-make-local-permanent (var) +;; "Make buffer local value of VAR survive when moving point to a new chunk. +;; This is for the current buffer only. +;; In most cases you almost certainly want to use +;; `mumamo-make-variable-buffer-permanent' instead." +;; (pushnew var mumamo-per-buffer-local-vars)) + +(defvar mumamo-per-buffer-local-vars-done-by-me nil + "Variables set by mumamo already. +Used to avoid unnecessary warnings if setting major mode fails.") + +;; (mumamo-hook-p 'viper-pre-command-hooks) +;; (mumamo-hook-p 'viper-before-change-functions) +;; (mumamo-hook-p 'c-special-indent-hook) +(defun mumamo-hook-p (sym) + "Try to detect if SYM is a hook variable. +Just check the name." + (let ((name (symbol-name sym))) + (or (string= "-hook" (substring name -5)) + (string= "-hooks" (substring name -6)) + (string= "-functions" (substring name -10))))) + +(defvar mumamo-major-mode nil) +(make-variable-buffer-local 'mumamo-major-mode) +(put 'mumamo-major-mode 'permanent-local t) + +(defvar mumamo-change-major-mode-no-nos + '((font-lock-change-mode t) + (longlines-mode-off t) + global-font-lock-mode-cmhh + (nxml-cleanup t) + (turn-off-hideshow t)) + "Avoid running these in `change-major-mode-hook'.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Remove things from hooks temporarily + +;; Fix-me: This is a bit disorganized, could not decide which level I +;; wanted this on. + +(defvar mumamo-after-change-major-mode-no-nos + '(;;nxhtml-global-minor-mode-enable-in-buffers + global-font-lock-mode-enable-in-buffers) + "Avoid running these in `after-change-major-mode-hook'.") + +(defvar mumamo-removed-from-hook nil) + +(defun mumamo-remove-from-hook (hook remove) + "From hook HOOK remove functions in list REMOVE. +Save HOOK and the list of functions removed to +`mumamo-removed-from-hook'." + (let (did-remove + removed) + (dolist (rem remove) + ;;(message "rem.rem=%s" rem) + (setq did-remove nil) + (if (listp rem) + (when (memq (car rem) (symbol-value hook)) + (setq did-remove t) + (remove-hook hook (car rem) t)) + (when (memq rem (symbol-value hook)) + (setq did-remove t) + (remove-hook hook rem))) + (when did-remove + (setq removed (cons rem removed)))) + (setq mumamo-removed-from-hook + (cons (cons hook removed) + mumamo-removed-from-hook)))) + +(defun mumamo-addback-to-hooks () + "Add back what was removed by `mumamo-remove-from-hook'." + ;;(message "mumamo-removed-from-hook=%s" mumamo-removed-from-hook) + (dolist (rem-rec mumamo-removed-from-hook) + (mumamo-addback-to-hook (car rem-rec) (cdr rem-rec)))) + +(defun mumamo-addback-to-hook (hook removed) + "Add to hook HOOK the list of functions in REMOVED." + ;;(message "addback: hook=%s, removed=%s" hook removed) + (dolist (rem removed) + ;;(message "add.rem=%s" rem) + (if (listp rem) + (add-hook hook (car rem) nil t) + (add-hook hook rem)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Compare mumamo-irrelevant-buffer-local-vars +(defvar mumamo-buffer-locals-dont-set + '( + adaptive-fill-mode + adaptive-fill-first-line-regexp + adaptive-fill-regexp + add-log-current-defun-header-regexp + auto-composition-function + auto-composition-mode + auto-composition-mode-major-mode + auto-fill-chars + + beginning-of-defun-function + buffer-auto-save-file-format + buffer-auto-save-file-name + buffer-backed-up + buffer-display-count + buffer-display-time + buffer-file-coding-system + buffer-file-format + buffer-file-name + buffer-file-truename + buffer-invisibility-spec + buffer-read-only + buffer-saved-size + buffer-undo-list + + c++-template-syntax-table + c-<-op-cont-regexp + c-<>-multichar-token-regexp + c->-op-cont-regexp + c-after-suffixed-type-decl-key + c-after-suffixed-type-maybe-decl-key + c-anchored-cpp-prefix + c-assignment-op-regexp + c-at-vsemi-p-fn + c-backslash-column + c-backslash-max-column + ;;c-basic-offset + c-before-font-lock-function + c-block-comment-prefix + c-block-comment-start-regexp + c-block-prefix-charset + c-block-stmt-1-key + c-block-stmt-2-key + c-brace-list-key + c-cast-parens + c-class-key + c-cleanup-list + c-colon-type-list-re + c-comment-only-line-offset + c-comment-prefix-regexp + c-comment-start-regexp + c-current-comment-prefix + c-decl-block-key + c-decl-hangon-key + c-decl-prefix-or-start-re + c-decl-prefix-re + c-decl-start-re + c-doc-comment-start-regexp + c-doc-comment-style + c-found-types + c-get-state-before-change-function + c-hanging-braces-alist + c-hanging-colons-alist + c-hanging-semi&comma-criteria + c-identifier-key + c-identifier-start + c-identifier-syntax-modifications + c-identifier-syntax-table + ;;c-indent-comment-alist + ;;c-indent-comments-syntactically-p + ;;c-indentation-style + c-keywords-obarray + c-keywords-regexp + c-known-type-key + c-label-kwds-regexp + c-label-minimum-indentation + c-label-prefix-re + c-line-comment-starter + c-literal-start-regexp + c-multiline-string-start-char + c-nonlabel-token-key + c-nonsymbol-chars + c-nonsymbol-token-regexp + c-not-decl-init-keywords + ;;c-offsets-alist + c-old-BOM + c-old-EOM + c-opt-<>-arglist-start + c-opt-<>-arglist-start-in-paren + c-opt-<>-sexp-key + c-opt-asm-stmt-key + c-opt-bitfield-key + c-opt-block-decls-with-vars-key + c-opt-block-stmt-key + c-opt-cpp-macro-define-id + c-opt-cpp-macro-define-start + c-opt-cpp-prefix + c-opt-cpp-start + c-opt-extra-label-key + c-opt-friend-key + c-opt-identifier-concat-key + c-opt-inexpr-brace-list-key + c-opt-method-key + c-opt-op-identifier-prefix + c-opt-postfix-decl-spec-key + c-opt-type-component-key + c-opt-type-concat-key + c-opt-type-modifier-key + c-opt-type-suffix-key + c-other-decl-block-key + c-other-decl-block-key-in-symbols-alist + c-overloadable-operators-regexp + c-paragraph-separate + c-paragraph-start + c-paren-stmt-key + c-prefix-spec-kwds-re + c-primary-expr-regexp + c-primitive-type-key + c-recognize-<>-arglists + c-recognize-colon-labels + c-recognize-knr-p + c-recognize-paren-inexpr-blocks + c-recognize-paren-inits + c-recognize-typeless-decls + c-regular-keywords-regexp + c-simple-stmt-key + c-special-brace-lists + c-special-indent-hook + c-specifier-key + c-stmt-delim-chars + c-stmt-delim-chars-with-comma + c-string-escaped-newlines + c-symbol-key + c-symbol-start + c-syntactic-eol + c-syntactic-ws-end + c-syntactic-ws-start + c-type-decl-end-used + c-type-decl-prefix-key + c-type-decl-suffix-key + c-type-prefix-key + c-vsemi-status-unknown-p-fn + + case-fold-search + comment-end + comment-end-skip + comment-indent-function + comment-line-break-function + comment-multi-line + comment-start + comment-start-skip + cursor-type + + default-directory + defun-prompt-regexp + delay-mode-hooks + + enable-multibyte-characters + end-of-defun-function + + fill-paragraph-function + font-lock-beginning-of-syntax-function + font-lock-defaults + font-lock-extend-after-change-region-function + font-lock-extend-region-functions + font-lock-fontified + font-lock-fontify-buffer-function + font-lock-fontify-region-function + font-lock-keywords + ;;font-lock-keywords-only + font-lock-keywords-case-fold-search + font-lock-mode + font-lock-mode-hook + font-lock-mode-major-mode + font-lock-multiline + font-lock-set-defaults + font-lock-syntactic-keywords + font-lock-syntactically-fontified + font-lock-syntax-table + font-lock-unfontify-buffer-function + font-lock-unfontify-region-function + fontification-functions + forward-sexp-function + + indent-line-function + indent-region-function + imenu--index-alist + imenu--last-menubar-index-alist + imenu-create-index-function + imenu-menubar-modified-tick + isearch-mode + + jit-lock-after-change-extend-region-functions + jit-lock-context-unfontify-pos + jit-lock-contextually + jit-lock-functions + jit-lock-mode + + line-move-ignore-invisible + local-abbrev-table + + major-mode + mark-active + ;;mark-ring + mode-line-process + mode-name + + normal-auto-fill-function + ;;nxhtml-menu-mode-major-mode + + open-paren-in-column-0-is-defun-start + outline-level + outline-regexp + + paragraph-ignore-fill-prefix + paragraph-separate + paragraph-start + parse-sexp-ignore-comments + parse-sexp-lookup-properties + php-mode-pear-hook + point-before-scroll + + ;; More symbols from visual inspection + ;;before-change-functions + ;;delayed-mode-hooks + ;;imenu-case-fold-search + ;;imenu-generic-expression + rngalt-completing-read-tag + rngalt-completing-read-attribute-name + rngalt-completing-read-attribute-value + rngalt-complete-first-try + rngalt-complete-last-try + rngalt-complete-tag-hooks + + syntax-begin-function + ) + "Buffer local variables that is not saved/set per chunk. +This is supposed to contain mostly buffer local variables +specific to major modes and that are not meant to be customized +by the user. +") + +(when (< emacs-major-version 23) + (defadvice c-after-change (around + mumamo-ad-c-after-change + activate + compile + ) + ;;(msgtrc "c-after-change: major-mode=%s c-nonsymbol-token-regexp=%s" major-mode c-nonsymbol-token-regexp) + (when (or (not mumamo-multi-major-mode) + (derived-mode-p 'c-mode)) + ad-do-it)) + ) + +(defun mumamo-save-per-major-local-vars (major) + "Save some per major local variables for major mode MAJOR. +This should be called before switching to a new chunks major +mode." + ;;(message "mumamo-save-per-major-local-vars %s %s" major (current-buffer)) + (let ((locals (buffer-local-variables))) + (setq locals (mapcar (lambda (local) + (unless + (or (memq (car local) mumamo-buffer-locals-dont-set) + (memq (car local) mumamo-per-buffer-local-vars) + (memq (car local) mumamo-per-main-major-local-vars) + (get (car local) 'permanent-local)) + local)) + locals)) + (setq locals (delq nil locals)) + (setq locals (sort locals (lambda (sym-a sym-b) + (string< (symbol-name (car sym-a)) + (symbol-name (car sym-b)))))) + (setq mumamo-buffer-locals-per-major + (assq-delete-all major mumamo-buffer-locals-per-major)) + (setq mumamo-buffer-locals-per-major + (cons (cons major-mode locals) + mumamo-buffer-locals-per-major)))) + +;; (benchmark 1000 '(mumamo-save-per-major-local-vars major-mode)) +;; (benchmark 1000 '(mumamo-restore-per-major-local-vars major-mode)) +(defvar mumamo-restore-per-major-local-vars-in-hook-major nil) +(defun mumamo-restore-per-major-local-vars-in-hook () + "Restore some per major mode local variables. +Call `mumamo-restore-per-major-local-vars'. +Use `mumamo-restore-per-major-local-vars-in-hook-major' as the +major mode. + +This should be called in the major mode setup hook." + (mumamo-restore-per-major-local-vars + mumamo-restore-per-major-local-vars-in-hook-major) + (setq mumamo-restore-per-major-local-vars-in-hook-major nil)) +(put 'mumamo-restore-per-major-local-vars-in-hook 'permanent-local-hook t) + +(defun mumamo-restore-per-major-local-vars (major) + "Restore some per major local variables for major mode MAJOR. +This should be called after switching to a new chunks major +mode." + (let ((locals (cdr (assq major mumamo-buffer-locals-per-major))) + var + perm) + (dolist (rec locals) + (setq var (car rec)) + (setq perm (get var 'permanent-local)) + (unless (or perm + (memq var mumamo-buffer-locals-dont-set)) + (set (make-local-variable var) (cdr rec)))))) + +;; (defun mumamo-testing-new () +;; (let ((locals (buffer-local-variables)) +;; var +;; perm +;; ) +;; (dolist (rec locals) +;; (setq var (car rec)) +;; (setq perm (get var 'permanent-local)) +;; (unless (or perm +;; (memq var mumamo-buffer-locals-dont-set)) +;; (setq var (cdr rec)))) +;; )) +;; ;;(benchmark 1000 '(mumamo-testing-new)) + +(defun mumamo-get-hook-value (hook remove) + "Return hook HOOK value with entries in REMOVE removed. +Remove also t. The value returned is a list of both local and +default values." + (let ((value (append (symbol-value hook) (default-value hook) nil))) + (dolist (rem remove) + (setq value (delq rem value))) + (delq t value))) + +;; FIX-ME: Clean up the different ways of surviving variables during +;; change of major mode. +(defvar mumamo-set-major-keymap-checked nil) +(make-variable-buffer-local 'mumamo-set-major-keymap-checked) + +(defvar mumamo-org-startup-done nil) +(make-variable-buffer-local 'mumamo-org-startup-done) +(put 'mumamo-org-startup-done 'permanent-local t) + + +(defun mumamo-font-lock-fontify-chunk () + "Like `font-lock-default-fontify-buffer' but for a chunk. +Buffer must be narrowed to inner part of chunk when this function +is called." + (let ((verbose (if (numberp font-lock-verbose) + (and (> font-lock-verbose 0) + (> (- (point-max) (point-min)) font-lock-verbose)) + font-lock-verbose)) + font-lock-extend-region-functions ;; accept narrowing + (font-lock-unfontify-region-function 'ignore)) + ;;(setq verbose t) + (with-temp-message + (when verbose + (format "Fontifying %s part %s-%s (%s)..." (buffer-name) (point-min) (point-max) font-lock-verbose)) + (condition-case err + (save-excursion + (save-match-data + (font-lock-fontify-region (point-min) (point-max) verbose) + (font-lock-after-fontify-buffer) + (setq font-lock-fontified t))) + (msgtrc "font-lock-fontify-chunk: %s" (error-message-string err)) + ;; We don't restore the old fontification, so it's best to unfontify. + (quit (mumamo-font-lock-unfontify-chunk)))))) + + +(defun mumamo-font-lock-unfontify-chunk () + "Like `font-lock-default-unfontify-buffer' for . +Buffer must be narrowed to chunk when this function is called." + ;; Make sure we unfontify etc. in the whole buffer. + (save-restriction + ;;(widen) + (font-lock-unfontify-region (point-min) (point-max)) + (font-lock-after-unfontify-buffer) + (setq font-lock-fontified nil))) + +(defun mumamo-set-major (major chunk) + "Set major mode to MAJOR for mumamo." + (mumamo-msgfntfy "mumamo-set-major %s, %s" major (current-buffer)) + (mumamo-cancel-idle-set-major-mode) + (remove-hook 'pre-command-hook 'mumamo-set-major-pre-command t) + ;;(mumamo-backtrace "mumamo-set-major") + (remove-hook 'text-mode-hook 'viper-mode) ;; Fix-me: maybe add it back... + (let ((start-time (get-internal-run-time)) + end-time + used-time + ;; Viper + viper-vi-state-mode-list + viper-emacs-state-mode-list + viper-insert-state-mode-list + ;; Org-Mode + (org-inhibit-startup mumamo-org-startup-done) + ;; Tell `mumamo-change-major-function': + (mumamo-set-major-running major) + ;; Fix-me: Take care of the new values added to these hooks! + ;; That looks difficult. We may after this have changes to + ;; both buffer local value and global value. The global + ;; changes are in this variable, but the buffer local values + ;; have been set once again. + (change-major-mode-hook (mumamo-get-hook-value + 'change-major-mode-hook + mumamo-change-major-mode-no-nos)) + (after-change-major-mode-hook (mumamo-get-hook-value + 'after-change-major-mode-hook + mumamo-after-change-major-mode-no-nos)) + ;; Some major modes deactivates the mark, we do not want that: + deactivate-mark + ;; Font lock + (font-lock-mode font-lock-mode) + ;; We have to save and reset the cursor type, at least when + ;; Viper is used + (old-cursor-type cursor-type) + ;; Protect last-command: fix-me: probably remove + (last-command last-command) + ;; Fix-me: remove this + (old-rng-schema-file (when (boundp 'rng-current-schema-file-name) rng-current-schema-file-name)) + ;; Local vars, per buffer and per major mode + per-buffer-local-vars-state + per-main-major-local-vars-state + ) + ;; We are not changing mode from font-lock's point of view, so do + ;; not tell font-lock (let binding these hooks is probably not a + ;; good choice since they may contain other stuff too): + (setq mumamo-removed-from-hook nil) + (mumamo-remove-from-hook 'change-major-mode-hook mumamo-change-major-mode-no-nos) + + ;;;;;;;;;;;;;;;; + ;; Save per buffer local variables + (dolist (sym (reverse mumamo-per-buffer-local-vars)) + (when (boundp sym) + (when (and (get sym 'permanent-local) + (not (memq sym mumamo-per-buffer-local-vars-done-by-me)) + (not (mumamo-hook-p sym))) + (delq sym mumamo-per-buffer-local-vars) + (lwarn 'mumamo-per-buffer-local-vars :warning + "Already 'permanent-local t: %s" sym)))) + (dolist (var mumamo-per-buffer-local-vars) + (if (local-variable-p var) + (push (cons var (symbol-value var)) + per-buffer-local-vars-state))) + + ;;;;;;;;;;;;;;;; + ;; Save per main major local variables + (when (mumamo-fun-eq major-mode (mumamo-main-major-mode)) + (dolist (var mumamo-per-main-major-local-vars) + (if (local-variable-p var) + (push (cons var (symbol-value var)) + per-main-major-local-vars-state)))) + + ;; For all hooks that probably can have buffer local values, go + ;; through the buffer local values and look for a permanent-local + ;; property on each function. Remove those functions that does not + ;; have it. Then make the buffer local value of the hook survive + ;; by putting a permanent-local property on it. + (unless (> emacs-major-version 22) + (dolist (hk mumamo-survive-hooks) + (put hk 'permanent-local t) + (when (local-variable-p hk) + (let ((hkv (copy-sequence (symbol-value hk)))) + (dolist (v hkv) + (unless (or (eq v t) + (get v 'permanent-local-hook)) + (remove-hook hk v t) + )))))) + + (run-hooks 'mumamo-change-major-mode-hook) + + (setq mumamo-major-mode major) + + ;;;;;;;;;;;;;;;; + ;; Save per major mode local variables before switching major + (mumamo-save-per-major-local-vars major-mode) + ;; Prepare to restore per major mode local variables after + ;; switching back to major-mode, but do it in the greatest + ;; ancestor's mode hook (see `run-mode-hooks'): + (let (ancestor-hook-sym + parent-hook-sym + (parent major)) + ;; We want the greatest ancestor's mode hook: + (setq parent-hook-sym (intern-soft (concat (symbol-name parent) "-hook"))) + (when parent-hook-sym (setq ancestor-hook-sym parent-hook-sym)) + (while (get parent 'derived-mode-parent) + (setq parent (get parent 'derived-mode-parent)) + (setq parent-hook-sym (intern-soft (concat (symbol-name parent) "-hook"))) + (when parent-hook-sym (setq ancestor-hook-sym parent-hook-sym))) + (when ancestor-hook-sym + ;; Put first in local hook to run it first: + (setq mumamo-restore-per-major-local-vars-in-hook-major major) + (add-hook ancestor-hook-sym + 'mumamo-restore-per-major-local-vars-in-hook + nil t)) + + ;;(msgtrc "set-major A: buffer-invisibility-spec=%S" buffer-invisibility-spec) + ;;(msgtrc "set-major A: word-wrap=%S, cb=%s" word-wrap (current-buffer)) + ;;(mumamo-backtrace "set-major") + (let ((here (point))) + (unwind-protect + (save-restriction + (let* ((minmax (mumamo-chunk-syntax-min-max chunk t)) + (min (car minmax)) + (max (cdr minmax)) + (here (point)) + ;; Fix-me: For some reason let binding did not help. Is this a bug or? + ;; + ;;(font-lock-fontify-buffer-function 'mumamo-font-lock-fontify-chunk) + (old-bf (buffer-local-value 'font-lock-fontify-buffer-function (current-buffer))) + (inhibit-redisplay t) ;; Fix-me: said to be for internal purposes only + ) + (narrow-to-region min max) + (set (make-local-variable 'font-lock-fontify-buffer-function) 'mumamo-font-lock-fontify-chunk) + ;;(message "funcall major=%s, %s" major font-lock-fontify-buffer-function) + ;;(message "before funcall: function=%s" font-lock-fontify-buffer-function) + (put 'font-lock-fontify-buffer-function 'permanent-local t) + (funcall major) ;; <----------------------------------------------- + (put 'font-lock-fontify-buffer-function 'permanent-local nil) + (when old-bf + (set (make-local-variable 'font-lock-fontify-buffer-function) old-bf)) + )) + (goto-char here))) + ;;(msgtrc "set-major B: buffer-invisibility-spec=%S" buffer-invisibility-spec) + ;;(msgtrc "set-major B: word-wrap=%S, cb=%s" word-wrap (current-buffer)) + + (setq font-lock-mode-major-mode major) ;; Tell font-lock it is ok + (set (make-local-variable 'font-lock-function) 'mumamo-font-lock-function) + (if (not ancestor-hook-sym) + (mumamo-restore-per-major-local-vars major) + (remove-hook ancestor-hook-sym + 'mumamo-restore-per-major-local-vars-in-hook + t))) + ;;(msgtrc "set-major c: buffer-invisibility-spec=%S" buffer-invisibility-spec) + + (when (mumamo-fun-eq major 'org-mode) (setq mumamo-org-startup-done t)) + + (setq mumamo-major-mode-indent-line-function (cons major-mode indent-line-function)) + (make-local-variable 'indent-line-function) + + (setq mode-name (concat (format-mode-line mode-name) + (save-match-data + (replace-regexp-in-string + "-mumamo-mode$" "" + (format "/%s" mumamo-multi-major-mode))))) + + (dolist (hk mumamo-survive-hooks) (put hk 'permanent-local nil)) + + ;; (when (and (featurep 'flymake) + ;; flymake-mode) + ;; (add-hook 'after-change-functions 'flymake-after-change-function nil t) + ;; (add-hook 'after-save-hook 'flymake-after-save-hook nil t) + ;; (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t)) + + ;;;;;;;;;;;;;;;; + ;; Restore per buffer local variables + + ;; (dolist (sym mumamo-per-buffer-local-vars) + ;; (when (boundp sym) + ;; (put sym 'permanent-local nil))) + ;;(msgtrc "per-buffer-local-vars-state=%S" per-buffer-local-vars-state) + (dolist (saved per-buffer-local-vars-state) + ;;(msgtrc "restore p buffer: %s, local=%s" (car saved) (local-variable-p (car saved))) + (unless (local-variable-p (car saved)) + (set (make-local-variable (car saved)) (cdr saved)))) + + ;;;;;;;;;;;;;;;; + ;; Restore per main major local variables + (unless (mumamo-fun-eq major-mode (mumamo-main-major-mode)) + (dolist (saved per-main-major-local-vars-state) + (set (make-local-variable (car saved)) (cdr saved)))) + + (mumamo-addback-to-hooks) + + (setq cursor-type old-cursor-type) + (run-hooks 'mumamo-after-change-major-mode-hook) + + (when (derived-mode-p 'nxml-mode) + (when (and old-rng-schema-file + (not (string= old-rng-schema-file rng-current-schema-file-name))) + (let ((rng-schema-change-hook nil)) ;(list 'rng-alidate-clear))) + (condition-case err + (progn + (rng-set-schema-file-1 old-rng-schema-file) + (rng-what-schema)) + (nxml-file-parse-error + (nxml-display-file-parse-error err))) + (when rng-validate-mode + ;; Fix-me: Change rng-validate variables so that this is + ;; not necessary any more. + (rng-validate-mode 0) + (rng-validate-mode 1)) + ))) + ;; The nxml-parser should not die: + (when (mumamo-derived-from-mode (mumamo-main-major-mode) 'nxml-mode) + (add-hook 'after-change-functions 'rng-after-change-function nil t) + (add-hook 'after-change-functions 'nxml-after-change nil t) + ;; Added these for Emacs 22: + (unless nxml-prolog-end (setq nxml-prolog-end 1)) + (unless nxml-scan-end (setq nxml-scan-end (copy-marker 1)))) + +;;; (when (and global-font-lock-mode +;;; font-lock-global-modes +;;; font-lock-mode) +;;; (when global-font-lock-mode +;;; (add-hook 'change-major-mode-hook 'global-font-lock-mode-cmhh)) +;;; (add-hook 'change-major-mode-hook 'font-lock-change-mode nil t) + + (mumamo-set-fontification-functions) + + ;; If user has used M-x flyspell-mode then we need to correct it: + ;; Fix-me: This is inflexible. Need flyspell to cooperate. + (when (featurep 'flyspell) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify)) + + (if mumamo-done-first-set-major + (setq mumamo-just-changed-major t) + (mumamo-msgfntfy "mumamo-set-major: ----- removing 'fontified") + ;; Set up to fontify buffer + (mumamo-save-buffer-state nil + (remove-list-of-text-properties (point-min) (point-max) '(fontified))) + (setq mumamo-done-first-set-major t)) + + ;; Timing, on a 3ghz cpu: + ;; + ;; used-time=(0 0 0), major-mode=css-mode + ;; used-time=(0 0 0), major-mode=ecmascript-mode + ;; used-time=(0 0 0), major-mode=html-mode + ;; used-time=(0 0 203000), major-mode=nxhtml-mode + ;; + ;; After some changes 2007-04-25: + ;; + ;; used-time=(0 0 15000), major-mode=nxhtml-mode + ;; + ;; which is 15 ms. That seems acceptable though I am not sure + ;; everything is correct when switching to nxhtml-mode yet. I + ;; will have to wait for bug reports ;-) + ;; + ;; The delay is clearly noticeable and disturbing IMO unless you + ;; change major mode in an idle timer. + ;; + ;;(setq end-time (get-internal-run-time)) + ;;(setq used-time (time-subtract end-time start-time)) + ) + (setq mumamo-set-major-keymap-checked nil) + ;; Fix-me: Seems like setting/checking the keymap in a timer is + ;; problematc. This is an Emacs bug. + ;;(run-with-idle-timer 1 nil 'mumamo-set-major-check-keymap) + ;;(force-mode-line-update) (message "force-mode-line-update called") + ) + +(defun mumamo-set-major-check-keymap () + "Helper to work around an Emacs bug when setting local map in a timer." + (or mumamo-set-major-keymap-checked + (setq mumamo-set-major-keymap-checked + (let ((map-sym (intern-soft (concat (symbol-name major-mode) "-map")))) + (if (not map-sym) + t ;; Don't know what to do + (equal (current-local-map) + (symbol-value map-sym))))))) + +(defvar mumamo-original-fill-paragraph-function nil) +(make-variable-buffer-local 'mumamo-original-fill-paragraph-function) + +(defun mumamo-setup-local-fontification-vars () + "Set up buffer local variables for mumamo style fontification." + (make-local-variable 'font-lock-fontify-region-function) + (setq font-lock-fontify-region-function 'mumamo-fontify-region) + + ;; Like font-lock-turn-on-thing-lock: + (make-local-variable 'font-lock-fontify-buffer-function) + (setq font-lock-fontify-buffer-function 'jit-lock-refontify) + (setq font-lock-fontify-buffer-function 'mumamo-fontify-buffer) + ;; Don't fontify eagerly (and don't abort if the buffer is large). + (set (make-local-variable 'font-lock-fontified) t) + + (make-local-variable 'font-lock-unfontify-buffer-function) + (setq font-lock-unfontify-buffer-function 'mumamo-unfontify-buffer) + + (set (make-local-variable 'indent-line-function) 'mumamo-indent-line-function) + + ;;(setq mumamo-original-fill-paragraph-function fill-paragraph-function) + ;;(set (make-local-variable 'fill-paragraph-function) 'mumamo-fill-paragraph-function) + ;;(set (make-local-variable 'fill-forward-paragraph-function 'forward-paragraph) + + (make-local-variable 'indent-region-function) + (setq indent-region-function 'mumamo-indent-region-function) + + ;;(set (make-local-variable 'syntax-begin-function) 'mumamo-beginning-of-syntax) + + ;;(put 'font-lock-function 'permanent-local t) + + ;; FIX-ME: Not sure about this one, but it looks like it must be + ;; set: + (make-local-variable 'jit-lock-contextually) + (setq jit-lock-contextually t) + ) + +(defun mumamo-font-lock-function (mode) + ;;(mumamo-backtrace "font-lock-function") + (font-lock-default-function mode)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Turning on/off multi major modes + +(defun mumamo-set-fontification-functions () + "Let mumamo take over fontification. +This is run after changing major mode so that jit-lock will get +the major mode specific values. \(There are currently no such +values.)" + ;; Give the jit machinery a starting point: + (mumamo-jit-lock-register 'font-lock-fontify-region t) + ;; Set the functions that font-lock should use: + (mumamo-setup-local-fontification-vars) + ;; Need some hook modifications to keep things together too: + (add-hook 'change-major-mode-hook 'mumamo-change-major-function nil t) + (add-hook 'post-command-hook 'mumamo-post-command nil t) + (remove-hook 'change-major-mode-hook 'nxml-change-mode t) + (remove-hook 'change-major-mode-hook 'nxhtml-change-mode t) + ) + +(defun mumamo-initialize-state () + "Initialize some mumamo state variables." + (setq mumamo-done-first-set-major nil) + (setq mumamo-just-changed-major nil)) + +(defun mumamo-turn-on-actions (old-major-mode) + "Do what is necessary to turn on mumamo. +Turn on minor mode function `font-lock-mode'. +Set up for mumamo style fontification. +Create a mumamo chunk at point. +Run `mumamo-turn-on-hook'. + +OLD-MAJOR-MODE is used for the main major mode if the main major +mode in the chunk family is nil." + ;;(unless font-lock-mode (font-lock-mode 1)) + (mumamo-msgfntfy "mumamo-turn-on-actions") + (unless mumamo-current-chunk-family (error "Internal error: Chunk family is not set")) + (if (not mumamo-current-chunk-family) + (progn + (lwarn '(mumamo) :warning + "Could not turn on mumamo because chunk family was not set\n\tin buffer %s." + (current-buffer)) + (with-current-buffer "*Warnings*" + (insert "\tFor more information see `") + (mumamo-insert-describe-button 'define-mumamo-multi-major-mode 'describe-function) + (insert "'.\n"))) + ;; Load major mode: + (setq mumamo-org-startup-done nil) + (let ((main-major-mode (mumamo-major-mode-from-modespec (mumamo-main-major-mode)))) + (unless main-major-mode + (setcar (cdr mumamo-current-chunk-family) old-major-mode) + (setq main-major-mode (mumamo-main-major-mode))) + ;;(with-temp-buffer (funcall main-major-mode)) + (setq mumamo-major-mode main-major-mode) + (when (boundp 'nxml-syntax-highlight-flag) + (when (mumamo-derived-from-mode main-major-mode 'nxml-mode) + (set (make-local-variable 'nxml-syntax-highlight-flag) nil))) + ;; Init fontification + (mumamo-initialize-state) + (mumamo-set-fontification-functions) + (mumamo-save-buffer-state nil + (remove-list-of-text-properties (point-min) (point-max) + (list 'fontified))) + ;; For validation header etc: + (when (mumamo-derived-from-mode main-major-mode 'nxhtml-mode) + (require 'rngalt nil t) + (when (featurep 'rngalt) + (setq rngalt-major-mode (mumamo-main-major-mode)) + (rngalt-update-validation-header-overlay)) + (when (featurep 'rng-valid) + (setq rng-get-major-mode-chunk-function 'mumamo-find-chunks) + (setq rng-valid-nxml-major-mode-chunk-function 'mumamo-valid-nxml-chunk) + (setq rng-end-major-mode-chunk-function 'overlay-end)))) + ;;(mumamo-set-major-post-command) + ;;(add-hook 'change-major-mode-hook 'mumamo-change-major-function nil t) + (when (boundp 'flyspell-generic-check-word-predicate) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify)) + (run-hooks 'mumamo-turn-on-hook) + ;;(mumamo-get-chunk-save-buffer-state (point)) + (let ((buffer-windows (get-buffer-window-list (current-buffer)))) + (if (not buffer-windows) + (let* ((ovl (mumamo-find-chunks (point) "mumamo-turn-on-actions")) + (major (when ovl (mumamo-chunk-major-mode ovl)))) + (when major + (mumamo-set-major major ovl))) + (dolist (win (get-buffer-window-list (current-buffer) nil t)) + (let ((wp (or (window-end win) + (window-point win) + (window-start win)))) + (mumamo-get-chunk-save-buffer-state wp) + (when (eq win (selected-window)) + (let* ((ovl (mumamo-find-chunks wp "mumamo-turn-on-actions")) + (major (when ovl (mumamo-chunk-major-mode ovl)))) + (when major + (mumamo-set-major major ovl)))))))) + ;;(msgtrc "mumamo-turn-on-action exit: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ;; This did not help for Emacs bug 3467: + ;;(set-default 'font-lock-keywords-only nil) + ;;(setq font-lock-keywords-only nil) + ) + (set (make-local-variable 'font-lock-function) 'mumamo-font-lock-function) + (mumamo-emacs-start-bug3467-timer-if-needed) + ) + +;; (defun mumamo-on-font-lock-off () +;; "The reverse of `mumamo-turn-on-actions'." +;; (let ((mumamo-main-major-mode (mumamo-main-major-mode))) +;; (mumamo-turn-off-actions) +;; ;; Turning off `font-lock-mode' also turns off `mumamo-mode'. It is +;; ;; quite tricky to not turn on `font-lock-mode' again in case we got +;; ;; here because it was turned off. We must first remove the cmhh +;; ;; function and then also run the internal font lock turn off. +;; (let* ((flm font-lock-mode) +;; (flgm global-font-lock-mode) +;; (remove-cmhh (and (not flm) flgm))) +;; ;; If remove-cmhh is non-nil then we got here because +;; ;; `font-lock-mode' was beeing turned off in the buffer, but +;; ;; `global-font-lock-mode' is still on. +;; (when remove-cmhh +;; (remove-hook 'change-major-mode-hook 'global-font-lock-mode-cmhh)) + +;; (if mumamo-main-major-mode +;; (funcall mumamo-main-major-mode) +;; (fundamental-mode)) + +;; (unless flm +;; (setq font-lock-mode nil) +;; (font-lock-mode-internal nil)) +;; (when remove-cmhh +;; (add-hook 'change-major-mode-hook 'global-font-lock-mode-cmhh))))) + +(defun mumamo-turn-off-actions () + "The reverse of `mumamo-turn-on-actions'." + (mumamo-msgfntfy "mumamo-turn-off-actions") + (when (fboundp 'nxhtml-validation-header-mode) + (nxhtml-validation-header-mode -1)) + (when (mumamo-derived-from-mode + (nth 1 mumamo-current-chunk-family) 'nxml-mode) + (when (fboundp 'nxml-change-mode) + (nxml-change-mode))) + (when (and (boundp 'rng-validate-mode) + rng-validate-mode) + (rng-validate-mode 0)) + (when (featurep 'rng-valid) + (setq rng-get-major-mode-chunk-function nil) + (setq rng-valid-nxml-major-mode-chunk-function nil) + (setq rng-end-major-mode-chunk-function nil) + ) + ;; Remove nxml for Emacs 22 + (remove-hook 'after-change-functions 'rng-after-change-function t) + (remove-hook 'after-change-functions 'nxml-after-change t) + (when (boundp 'rngalt-major-mode) + (setq rngalt-major-mode nil)) + (remove-hook 'change-major-mode-hook 'mumamo-change-major-function t) + ;;(mumamo-unfontify-chunks) + ;;(remove-hook 'after-change-functions 'mumamo-jit-lock-after-change t) + (remove-hook 'after-change-functions 'mumamo-after-change t) + (remove-hook 'post-command-hook 'mumamo-post-command t) + ;;(remove-hook 'c-special-indent-hook 'mumamo-c-special-indent t) + (mumamo-margin-info-mode -1) + (when (fboundp 'mumamo-clear-all-regions) (mumamo-clear-all-regions)) + (save-restriction + (widen) + (mumamo-save-buffer-state nil + (set-text-properties (point-min) (point-max) nil))) + (setq mumamo-current-chunk-family nil) + (setq mumamo-major-mode nil) + (setq mumamo-multi-major-mode nil) ;; for minor-mode-map-alist + (setq mumamo-multi-major-mode nil) + (mumamo-remove-all-chunk-overlays) + (when (fboundp 'rng-cancel-timers) (rng-cancel-timers)) + ) + +(defvar mumamo-turn-on-hook nil + "Normal hook run after turning on `mumamo-mode'.") +(put 'mumamo-turn-on-hook 'permanent-local t) + +(defvar mumamo-change-major-mode-hook nil + "Normal hook run before internal change of major mode.") +(put 'mumamo-change-major-mode-hook 'permanent-local t) + +(defvar mumamo-after-change-major-mode-hook nil + "Normal hook run after internal change of major mode.") +(put 'mumamo-after-change-major-mode-hook 'permanent-local t) + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Defining multi major modes + +(defvar mumamo-defined-multi-major-modes nil + "List of functions defined for turning on mumamo. +Those functions should be called instead of calling a major mode +function when you want to use multiple major modes in a buffer. +They may be added to for example `auto-mode-alist' to +automatically have the major mode support turned on when opening +a file. + +Each of these functions defines how to mix certain major modes in +a buffer. + +All functions defined by `define-mumamo-multi-major-mode' are +added to this list. See this function for a general description +of how the functions work. + +If you want to quickly define a new mix of major modes you can +use `mumamo-quick-static-chunk'.") + +;;;###autoload +(defun mumamo-list-defined-multi-major-modes (show-doc show-chunks match) + "List currently defined multi major modes. +If SHOW-DOC is non-nil show the doc strings added when defining +them. \(This is not the full doc string. To show the full doc +string you can click on the multi major mode in the list.) + +If SHOW-CHUNKS is non-nil show the names of the chunk dividing +functions each multi major mode uses. + +If MATCH then show only multi major modes whos names matches." + (interactive (list (y-or-n-p "Include short doc string? ") + (y-or-n-p "Include chunk function names? ") + (read-string "List only multi major mode matching regexp (emtpy for all): "))) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'mumamo-list-defined-multi-major-modes) (interactive-p)) + (with-current-buffer (help-buffer) + (insert "The currently defined multi major modes in your Emacs are:\n\n") + (let ((mmms (reverse mumamo-defined-multi-major-modes)) + (here (point))) + (setq mmms (sort mmms (lambda (a b) + (string< (symbol-name (cdr a)) + (symbol-name (cdr b)))))) + (when (string= match "") (setq match nil)) + (while mmms + (let* ((mmm (car mmms)) + (sym (cdr mmm)) + (desc (car mmm)) + (auto (get sym 'autoload)) + (auto-desc (when auto (nth 1 auto))) + (family (get sym 'mumamo-chunk-family)) + (chunks (nth 2 family))) + (when (or (not match) + (string-match-p match (symbol-name sym))) + (insert " `" (symbol-name sym) "'" + " (" desc ")\n" + (if (and show-doc auto-desc) + (concat " " auto-desc "\n") + "") + (if show-chunks + (format " Chunks:%s\n" + (let ((str "") + (nn 0)) + (mapc (lambda (c) + (if (< nn 2) + (setq str (concat str " ")) + (setq nn 0) + (setq str (concat str "\n "))) + (setq nn (1+ nn)) + (setq str (concat str (format "%-30s" (format "`%s'" c)))) + ) + chunks) + str)) + "") + (if (or show-doc show-chunks) "\n\n" "") + )) + (setq mmms (cdr mmms)))) + )))) + +(defun mumamo-describe-chunks (chunks) + "Return text describing CHUNKS." + (let* ((desc + (concat "* Main major mode: `" (symbol-name (nth 1 chunks)) "'\n" + "\n* Functions for dividing into submodes:\n"))) + (dolist (divider (nth 2 chunks)) + (setq desc + (concat + desc + "\n`" (symbol-name divider) + "'\n " + (let ((doc (if (functionp divider) + (documentation divider t) + "(Function not compiled when building doc)"))) + (if (not doc) + "(Not documented)" + (substring doc 0 (string-match "\n" doc))))))) + (setq desc + (concat + desc + "\n\n(Note that the functions for dividing into chunks returns\n" + "a major mode specifier which may be translated into a major mode\n" + "by `mumamo-main-major-mode'.)\n")) + desc)) + +(defun mumamo-add-multi-keymap (toggle keymap) + "Add TOGGLE and KEYMAP to `minor-mode-map-alist'. +This is used to add a keymap to multi major modes since the local +keymap is occupied by the major modes. + +It is also used to add the `mumamo-map' keymap to every buffer +with a multi major mode." + ;; Copied from add-minor-mode + ;; Add the map to the minor-mode-map-alist. + (when keymap + (let ((existing (assq toggle minor-mode-map-alist)) + (after t)) + (if existing + (setcdr existing keymap) + (let ((tail minor-mode-map-alist) found) + (while (and tail (not found)) + (if (eq after (caar tail)) + (setq found tail) + (setq tail (cdr tail)))) + (if found + (let ((rest (cdr found))) + (setcdr found nil) + (nconc found (list (cons toggle keymap)) rest)) + (setq minor-mode-map-alist (cons (cons toggle keymap) + minor-mode-map-alist)))))))) + +(defvar mumamo-map + (let ((map (make-sparse-keymap))) + (define-key map [(control meta prior)] 'mumamo-backward-chunk) + (define-key map [(control meta next)] 'mumamo-forward-chunk) + ;; Use mumamo-indent-line-function: + ;;(define-key map [tab] 'indent-for-tab-command) + (define-key map [(meta ?q)] 'fill-paragraph) + map) + "Keymap that is active in all mumamo buffers. +It has the some priority as minor mode maps.") +;;(make-variable-buffer-local 'mumamo-map) +(put 'mumamo-map 'permanent-local t) + +(mumamo-add-multi-keymap 'mumamo-multi-major-mode mumamo-map) + +;;;###autoload +(defun mumamo-multi-major-modep (value) + "Return t if VALUE is a multi major mode function." + (and (fboundp value) + (rassq value mumamo-defined-multi-major-modes))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Indenting, filling, moving etc + +;; FIX-ME: Indentation in perl here doc indents the ending mark which +;; corrupts the perl here doc. + +(defun mumamo-indent-line-function () + "Function to indent the current line. +This is the buffer local value of `indent-line-function' when +mumamo is used." + (let ((here (point-marker)) + fontification-functions + rng-nxml-auto-validate-flag + (before-text (<= (current-column) (current-indentation)))) + (mumamo-indent-line-function-1 nil nil nil) + ;; If the marker was in the indentation part strange things happen + ;; if we try to go back to the marker, at least in php-mode parts. + (if before-text + (back-to-indentation) + (goto-char here)))) + +(defun mumamo-indent-current-line-chunks (last-chunk-prev-line) + "Return a list of chunks to consider when indenting current line. +This list consists of four chunks at these positions: +- Beginning of line - 1 +- Beginning of line +- End of line +- End of line + 1" + ;; Fix-me: must take markers into account too when a submode + ;; includes the markers. + (setq last-chunk-prev-line nil) + ;;(msgtrc "indent-current-line-chunks: last-chunk-prev-line=%S" last-chunk-prev-line) + (save-restriction + (widen) + (let* ((lb-pos (line-beginning-position)) + (le-pos (line-end-position)) + (pos0 (if (> lb-pos (point-min)) + (1- lb-pos) + (point-min))) + (pos1 lb-pos) + (pos2 le-pos) + (pos3 (if (< le-pos (point-max)) + (+ 1 le-pos) + (point-max))) + ;; Create all chunks on this line first, then grab them + (ovl3 (mumamo-find-chunks pos3 "mumamo-indent-current-line-chunks")) + (ovl2 (if (>= pos2 (overlay-start ovl3)) + ovl3 + (mumamo-get-existing-new-chunk-at pos2))) + (ovl1 (if (>= pos1 (overlay-start ovl2)) + ovl2 + (mumamo-get-existing-new-chunk-at pos1))) + (ovl0 (if (> pos0 (overlay-start ovl1)) + ovl1 + (mumamo-get-existing-new-chunk-at pos0 t)))) + (list ovl0 ovl1 ovl2 ovl3)))) + +;; Fix-me: need to back up past comments in for example <style> /* comment */ +;; fix-me: clean up +(put 'mumamo-error-ind-0 'error-conditions '(error mumamo-error-ind-0)) +(put 'mumamo-error-ind-0 'error-message "indentation 0 in sub chunk") + + + +;;;;;;;;;;;;;;;;;;;;;;;; +;; Template indentation +;;; Contact Marc Bowes when I've finished this. + +(defvar mumamo-template-indent-buffer nil) +(make-variable-buffer-local 'mumamo-template-indent-buffer) +(put 'mumamo-template-indent-buffer 'permanent-local t) + +(defvar mumamo-template-indent-change-min nil) +(make-variable-buffer-local 'mumamo-template-indent-change-min) +(put 'mumamo-template-indent-hange-min 'permanent-local t) + +(defun mumamo-template-indent-after-change (beg end len) + (setq mumamo-template-indent-change-min + (if mumamo-template-indent-change-min + (min mumamo-template-indent-change-min beg) + beg))) + +;; (defun mumamo-get-indentor-create (indentor-chunk prev-indentor) +;; (let ((indentor (overlay-get indentor-chunk 'mumamo-indentor)) +;; (indentor-buffer (when indentor (overlay-buffer indentor))) +;; (chunk-str (with-current-buffer (overlay-buffer indentor-chunk) +;; (buffer-substring-no-properties (overlay-start indentor-chunk) +;; (overlay-end indentor-chunk)))) +;; ) +;; (unless (and indentor +;; (eq indentor-buffer mumamo-template-indent-buffer) +;; (string= chunk-str (overlay-get indentor 'indentor-chunk-string))) +;; (when indentor +;; (when (buffer-live-p +;; indentor +;; )) +(defun mumamo-indentor-valid (indentor chunk chunk-string) + (and indentor + chunk + (buffer-live-p (overlay-buffer chunk)) + (string= chunk-string (overlay-get indentor 'indentor-chunk-string)) + )) + +(defun mumamo-template-indent-get-chunk-shift (indentor-chunk) + "Return indentation shift for INDENTOR-CHUNK row and line after. +;; Fix-me: Handle changes better. + +Indentation shift has two parts: shift for current line and for next line. +This function returns a cons with these two parts. +" + (assert (overlayp indentor-chunk) t) + (assert (buffer-live-p (overlay-buffer indentor-chunk)) t) + (let ((indentor (overlay-get indentor-chunk 'mumamo-indentor)) + (prev-chunk (overlay-get indentor-chunk 'mumamo-prev-chunk)) + prev-indentor prev-indentor-chunk) + (when indentor (assert (eq indentor-chunk (overlay-get indentor 'indentor-chunk)) t)) + (unless (and mumamo-template-indent-buffer + (buffer-live-p mumamo-template-indent-buffer)) + (setq indentor nil) + (setq mumamo-template-indent-buffer + (get-buffer-create (concat (buffer-name) + "-template-indent-buffer"))) + (with-current-buffer mumamo-template-indent-buffer + (setq buffer-undo-list t) + (let ((major (car (overlay-get indentor-chunk 'mumamo-major-mode)))) + (funcall major)))) + (when indentor + (unless (eq (overlay-buffer indentor) mumamo-template-indent-buffer) + (setq indentor nil))) + ;; We need the prev indentor to indent relative to. + (while (and prev-chunk (not prev-indentor-chunk)) + (setq prev-chunk (overlay-get prev-chunk 'mumamo-prev-chunk)) + (when prev-chunk + (when (eq (overlay-get prev-chunk 'mumamo-next-indent) + 'mumamo-template-indentor) + (setq prev-indentor-chunk (overlay-get prev-chunk 'mumamo-next-chunk))))) + (when prev-indentor-chunk + (setq prev-indentor (overlay-get prev-indentor-chunk 'mumamo-indentor))) + (when prev-indentor + (unless (buffer-live-p (overlay-buffer prev-indentor)) + (setq prev-indentor nil))) + (when prev-indentor (assert (eq (overlay-buffer prev-indentor) mumamo-template-indent-buffer) t)) + (with-current-buffer mumamo-template-indent-buffer + (save-restriction + (widen) + ;; Insert a blank line to be able to go to start of first + ;; overlay -1. Do it here in case the user erases the buffer. + (when (= 0 (buffer-size)) (insert "\n")) + (let ((i-str (when indentor + (buffer-substring-no-properties (overlay-start indentor) (overlay-end indentor)))) + (i-beg (when indentor (overlay-start indentor))) + (c-str (with-current-buffer (overlay-buffer indentor-chunk) + (buffer-substring-no-properties (overlay-start indentor-chunk) + (overlay-end indentor-chunk)))) + (p-str (when prev-indentor-chunk + (with-current-buffer (overlay-buffer prev-indentor-chunk) + (buffer-substring-no-properties (overlay-start prev-indentor-chunk) + (overlay-end prev-indentor-chunk))))) + (c-beg (overlay-start indentor-chunk)) + (p-beg (when prev-indentor-chunk (overlay-start prev-indentor-chunk)))) + ;; Check if `indentor' and `prev-indentor' are valid + (when indentor + ;;(unless (string= c-str (overlay-get indentor 'indentor-chunk-string)) + (unless (mumamo-indentor-valid indentor indentor-chunk c-str) + (mumamo-remove-indentor indentor))) + (when prev-indentor + ;;(unless (string= p-str (overlay-get prev-indentor 'indentor-chunk-string)) + (unless (mumamo-indentor-valid prev-indentor prev-indentor-chunk p-str) + (mumamo-remove-indentor prev-indentor))) + (unless indentor + (setq i-beg + (or i-beg + (when prev-indentor + ;; We just put `indentor' after this, but we + ;; must also remove old stuff. + (goto-char (overlay-end prev-indentor)) + (forward-char 1) + (let* ((next-indentor (mumamo-indentor-at (point))) + (next-indentor-chunk (when next-indentor + (overlay-get next-indentor 'indentor-chunk))) + n-beg + (new-i-beg (unless next-indentor-chunk (point)))) + (while (not new-i-beg) + (setq n-beg (when (buffer-live-p (overlay-buffer next-indentor-chunk)) + (overlay-start next-indentor-chunk))) + (if (or (not n-beg) (< n-beg c-beg)) + (progn + (mumamo-remove-indentor next-indentor) + (goto-char (overlay-end prev-indentor)) + (forward-char 1) + (setq next-indentor (mumamo-indentor-at (point))) + (if next-indentor + (setq next-indentor-chunk (overlay-get next-indentor 'indentor-chunk)) + (setq new-i-beg (point)))) + (setq new-i-beg (point)))) + new-i-beg)) + ;; Fix-me: Find out where to insert indentor: + (let* ((ll 1) + (rr (point-max)) + mm new-i-beg m-ovl m-ovl-old m-chunk m-beg) + (while (< ll rr) + (setq mm (+ ll (/ (- rr ll) 2))) + (setq m-ovl-old m-ovl) + (setq m-ovl (mumamo-indentor-at mm)) + (if (or (not m-ovl) (eq m-ovl m-ovl-old)) + (setq rr ll) + (setq m-chunk (overlay-get m-ovl 'indentor-chunk)) + (setq m-beg (when (buffer-live-p (overlay-buffer m-chunk)) + (overlay-start m-chunk))) + (cond ((not m-beg) + (mumamo-remove-indentor m-ovl) + (setq rr (min rr (point-max)))) + ((> m-beg c-beg) + (setq ll (1+ mm))) + ((< m-beg c-beg) + (setq rr (1- mm))) + (t (error "Found old indentor at %s belonging to %S" mm m-chunk))))) + ;;(1+ (if m-ovl (overlay-end m-ovl) 0)) + (if m-ovl (1+ (overlay-end m-ovl)) 2) + ))) + (goto-char i-beg) + (setq indentor (mumamo-make-indentor indentor-chunk c-str))) + (unless prev-indentor + (when prev-indentor-chunk + (goto-char (overlay-start indentor)) + (goto-char (point-at-bol)) + (setq prev-indentor (mumamo-make-indentor prev-indentor-chunk p-str)))) + (when prev-indentor (mumamo-indent-indentor prev-indentor)) + (mumamo-indent-indentor indentor) + (let (prev-ind this-ind next-ind shift-in shift-out) + (when prev-indentor + (goto-char (overlay-end prev-indentor)) + (setq prev-ind (current-indentation))) + (goto-char (overlay-start indentor)) + (setq this-ind (current-indentation)) + (goto-char (overlay-end indentor)) + (setq next-ind (current-indentation)) + (when prev-ind (setq shift-in (- this-ind prev-ind))) + (setq shift-out (- next-ind this-ind)) + (msgtrc "template-indent-get-shunk-shift => (%s . %s)" shift-in shift-out) + (cons shift-in shift-out))))))) + + +(defun mumamo-ruby-beginning-of-indent () + "TODO: document" + ;; I don't understand this function. + ;; It seems like it should move to the line where indentation should deepen, + ;; but ruby-indent-beg-re only accounts for whitespace before class, module and def, + ;; so this will only match other block beginners at the beginning of the line. + (and + (prog1 + (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\b") nil 'move) + (skip-chars-forward " \t\n\r")) + (beginning-of-line))) + +(defadvice ruby-beginning-of-indent (around + mumamo-ad-ruby-beginning-of-indent + activate + compile + ) + (if t + (mumamo-ruby-beginning-of-indent) + ad-do-it) + ) + +(defun mumamo-indentor-at (pos) + "Return indentor overlay at POS." + (let ((here (point)) + eol-pos) + (goto-char pos) + (setq eol-pos (line-end-position)) + (goto-char here) + (catch 'ind + (dolist (ovl (or (overlays-at eol-pos) + (when (> eol-pos 1) + (overlays-at (1- eol-pos))))) + (when (overlay-get ovl 'indentor-chunk) + (throw 'ind ovl)))))) + +(defun mumamo-remove-indentor (indentor) + (let (beg end) + (goto-char (overlay-start indentor)) + (setq beg (point-at-bol)) + (goto-char (overlay-end indentor)) + (setq end (1+ (point-at-eol))) + (delete-region beg end) + (delete-overlay indentor) + (setq indentor nil))) + +(defun mumamo-indent-indentor (indentor) + (goto-char (overlay-start indentor)) + (if (= 2 (point-at-bol)) + (progn + (back-to-indentation) + (delete-region 2 (point)) + (insert " ")) + (indent-according-to-mode)) + (goto-char (overlay-end indentor)) + (indent-according-to-mode)) + +(defun mumamo-make-indentor (indentor-chunk chunk-string) + (let* ((beg (point)) + (syntax-min-max (mumamo-chunk-syntax-min-max indentor-chunk t)) + (inner (with-current-buffer (overlay-buffer indentor-chunk) + (buffer-substring-no-properties (cdr syntax-min-max) + (car syntax-min-max)))) + indentor) + (insert inner) + (insert "\n\n") + (setq indentor (make-overlay beg (1- (point)) nil t t)) + (overlay-put indentor 'indentor-chunk indentor-chunk) + (overlay-put indentor 'face 'secondary-selection) + (overlay-put indentor 'indentor-chunk-string chunk-string) + (overlay-put indentor-chunk 'mumamo-indentor indentor) + indentor)) + +;;(mumamo-fun-eq 'js-mode 'javascript-mode) +(defun mumamo-fun-eq (fun1 fun2) + "Return non-nil if same functions or aliases." + (or (eq fun1 fun2) + (progn + (while (and (fboundp fun1) + (symbolp (symbol-function fun1))) + (setq fun1 (symbol-function fun1))) + (while (and (fboundp fun2) + (symbolp (symbol-function fun2))) + (setq fun2 (symbol-function fun2))) + (eq fun1 fun2)))) + +(defun mumamo-indent-line-function-1 (prev-line-chunks + last-parent-major-indent + entering-submode-arg) + ;; Fix-me: error indenting in xml-as-string at <?\n?> + ;; Fix-me: clean up, use depth diff. go back to sibling not to main etc. + ;; Fix-me: Add indentation hints to chunks, for example heredocs and rhtml. + ;; Fix-me: maybe use special indentation functions for certain multi major modes? rhtml? + "Indent current line. +When doing that care must be taken if this line's major modes at +the start and end are different from previous line major modes. +The latter may be known through the parameter PREV-LINE-CHUNKS. + +Also the indentation of the last previous main major line may be +necessary to know. This may be known through the parameter +LAST-PARENT-MAJOR-INDENT. + +If the two parameters above are nil then this function will +search backwards in the buffer to try to determine their values. + +The following rules are used when indenting: + +- If the major modes are the same in this and the previous line + then indentation is done using that major mode. + +- Exception: If the chunks are not the same AND there is + precisely one chunk between them which have the property value + of 'mumamo-next-indent equal to 'mumamo-template-indentor then + a special indent using the content of the middle chunk is + done. An example of this is eRuby where a middle chunk could + look like: + + <% 3.times do %> + + This example will increase indentation for the next line the + same way as the chunk content would do in single major mode + ruby-mode. + + FIXE-ME: IMPLEMENT THE ABOVE! + +- Otherwise if going into a submode indentation is increased by + `mumamo-submode-indent-offset' (if this is nil then indentation + will instead be 0). + +- However first non-empty line indentation in a chunk when going + in is special if prev-prev chunk is on same mumamo-depth and + have the same major mode. Then indent relative last non-empty + line in prev-prev chunk. + +- When going out of a submode indentation is reset to + LAST-PARENT-MAJOR-INDENT. + +- At the border the 'dividers' should be indented as the parent + chunk. There are the following typical situations regarding + inner/outer major modes: + + 1) <style type='text/css'> + Going in next line; first char outer; line end inner; + + 2) </style> + Going out this line; First char inner or outer; line end outer; + + 3) <?php + Going in next line; first char outer or inner; line end inner; + + 4) ?> + Going out this line; first char inner; line end outer; + + From this we deduce the following way to compute if we are + going in or out: + + - Odd above (going in): Compare prev line end's mumamo-depth + with current line end's dito. Set flag for first line in + chunk. + + - Even above (going out): Same test as for going in, but going + out happens on current line. +" + ;;(msgtrc "indent-line-function-1 blp=%s" (line-beginning-position)) + (setq prev-line-chunks nil) + ;;(setq last-parent-major-indent nil) + ;;(setq entering-submode-arg nil) + (unless prev-line-chunks + (save-excursion + (goto-char (line-beginning-position 1)) + (unless (= (point) 1) + (skip-chars-backward "\n\t ") + (goto-char (line-beginning-position 1)) + (setq prev-line-chunks (mumamo-indent-current-line-chunks nil)) + ;;(msgtrc "%d:prev-line-chunks=%S" (save-restriction (widen) (line-number-at-pos)) prev-line-chunks ) + ))) + (let* ((prev-line-chunk0 (nth 0 prev-line-chunks)) + (prev-line-chunk2 (nth 2 prev-line-chunks)) + (prev-line-chunk3 (nth 3 prev-line-chunks)) + (prev-line-major0 (mumamo-chunk-major-mode (nth 0 prev-line-chunks))) + (prev-line-major1 (mumamo-chunk-major-mode (nth 1 prev-line-chunks))) + (prev-line-major2 (mumamo-chunk-major-mode (nth 2 prev-line-chunks))) + (prev-line-major3 (mumamo-chunk-major-mode (nth 3 prev-line-chunks))) + (prev-depth2 (if prev-line-chunk2 + (overlay-get prev-line-chunk2 'mumamo-depth) + 0)) + (prev-depth3 (if prev-line-chunk3 + (overlay-get prev-line-chunk3 'mumamo-depth) + 0)) + + (this-line-chunks (mumamo-indent-current-line-chunks (nth 3 prev-line-chunks))) + ;;(dummy (msgtrc "%d:this-line-chunks=%S" (save-restriction (widen) (line-number-at-pos)) this-line-chunks)) + (this-line-chunk0 (nth 0 this-line-chunks)) + (this-line-chunk2 (nth 2 this-line-chunks)) + (this-line-chunk3 (nth 3 this-line-chunks)) + (this-line-major0 (mumamo-chunk-major-mode (nth 0 this-line-chunks))) + (this-line-major1 (mumamo-chunk-major-mode (nth 1 this-line-chunks))) + (this-line-major2 (mumamo-chunk-major-mode (nth 2 this-line-chunks))) + (this-line-major3 (mumamo-chunk-major-mode (nth 3 this-line-chunks))) + (this-depth2 (overlay-get this-line-chunk2 'mumamo-depth)) + (this-depth3 (overlay-get this-line-chunk3 'mumamo-depth)) + + ;;(dummy (msgtrc "a\t this=%S" this-line-chunks)) + this-line-indent-major + major-indent-line-function + (main-major (mumamo-main-major-mode)) + (old-indent (current-indentation)) + (next-entering-submode (if (< prev-depth3 this-depth3) 'yes 'no)) + (entering-submode + ;; Fix-me + (progn + (unless nil ;entering-submode-arg + (let* ((prev-prev-line-chunks + (save-excursion + (goto-char (line-beginning-position 0)) + (unless (bobp) + (skip-chars-backward "\n\t ") + (goto-char (line-beginning-position 1)) + (let ((chunks (mumamo-indent-current-line-chunks nil))) + ;;(msgtrc "%d:prev-prev-line-chunks=%S" (save-restriction (widen) (line-number-at-pos)) chunks) + chunks)))) + (prev-prev-line-chunk2 (nth 2 prev-prev-line-chunks)) + (prev-prev-line-chunk3 (nth 3 prev-prev-line-chunks)) + (prev-prev-depth2 (when prev-prev-line-chunk2 + (overlay-get prev-prev-line-chunk2 'mumamo-depth))) + (prev-prev-depth3 (when prev-prev-line-chunk3 + (overlay-get prev-prev-line-chunk3 'mumamo-depth)))) + ;;(msgtrc "depths 2=%s/%s/%s 3=%s/%s/%s" prev-prev-depth2 prev-depth2 this-depth2 prev-prev-depth3 prev-depth3 this-depth3) + (setq entering-submode-arg + (if prev-prev-depth2 + (if (and (eq prev-prev-line-chunk2 + (overlay-get prev-line-chunk2 'mumamo-prev-chunk)) + (< prev-prev-depth2 prev-depth2)) + 'yes + 'no) + (if (> this-depth2 0) 'yes 'no) + )) + )) + (eq 'yes entering-submode-arg) + )) ;; fix-me + ;; Fix-me + (leaving-submode (> prev-depth2 this-depth2)) + want-indent ;; The indentation we desire + got-indent + (here-on-line (point-marker)) + this-pending-undo-list + (while-n1 0) + (while-n2 0) + (while-n3 0) + ;; Is there a possible indentor chunk on this line?: + (this-line-indentor-chunk (when (> (overlay-start this-line-chunk2) + (point-at-bol)) + (overlay-get this-line-chunk2 'mumamo-prev-chunk))) + ;;(dummy (msgtrc "this-line-indentor-chunk=%S" this-line-indentor-chunk)) + ;; Check if this really is an indentor chunk: + ;; Fix-me: 'mumamo-indentor is not put on the chunk yet since + ;; it is done in mumamo-template-indent-get-chunk-shift ... - + ;; and now it is calle too often ... + (this-line-indentor-prev (when this-line-indentor-chunk + (overlay-get this-line-indentor-chunk 'mumamo-prev-chunk))) + (this-line-is-indentor (and this-line-indentor-prev + (eq (overlay-get this-line-indentor-prev 'mumamo-next-indent) + 'mumamo-template-indentor) + (progn + (goto-char (overlay-start this-line-indentor-chunk)) + (back-to-indentation) + (= (point) (overlay-start this-line-indentor-chunk))))) + ;; Fix-me: rewrite and reorder. We do not need both shift-in and shift-out + (this-template-shift (when this-line-is-indentor + (mumamo-template-indent-get-chunk-shift this-line-indentor-chunk))) + ;;(dummy (msgtrc "this-line-indentor=%s, %S" this-template-shift this-line-is-indentor)) + ;; Fix-me: skip over blank lines backward here: + (prev-template-indentor (when prev-line-chunk0 + (unless (eq this-line-chunk0 prev-line-chunk0) + (let* ((prev (overlay-get this-line-chunk0 'mumamo-prev-chunk)) + (prev-prev (overlay-get prev 'mumamo-prev-chunk))) + (when (and (eq prev-prev prev-line-chunk0) + (eq (overlay-get prev-prev 'mumamo-next-indent) + 'mumamo-template-indentor)) + prev))))) + (prev-template-shift-rec (when prev-template-indentor + (mumamo-template-indent-get-chunk-shift prev-template-indentor) + )) + (template-shift (if (and (car this-template-shift) (/= 0 (car this-template-shift))) + (car this-template-shift) + (when prev-template-shift-rec + (cdr prev-template-shift-rec)))) + (template-indent-abs (when (and template-shift + (/= 0 template-shift)) + (+ template-shift + (let ((here (point))) + (if prev-template-indentor + (goto-char (overlay-start prev-template-indentor)) + (goto-char (overlay-start this-line-indentor-chunk)) + (skip-chars-backward " \t\r\n\f")) + (prog1 + (current-indentation) + (goto-char here)))))) + ) + (when (and leaving-submode entering-submode) + (message "Do not know how to indent here (both leaving and entering sub chunks)") + ) + ;; Fix-me: indentation + ;;(error "Leaving=%s, entering=%s this0,1,2,3=%s,%s,%s,%s" leaving-submode entering-submode this-line-major0 this-line-major1 this-line-major2 this-line-major3) + (when (or leaving-submode entering-submode) + (unless last-parent-major-indent + (save-excursion + ;;(while (and (> 500 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 500 'while-n1 "last-parent-major-indent") + (not last-parent-major-indent)) + (if (bobp) + (setq last-parent-major-indent 0) + (goto-char (line-beginning-position 0)) + (when (mumamo-fun-eq main-major + (mumamo-chunk-major-mode + (car + (mumamo-indent-current-line-chunks nil))) + ) + (skip-chars-forward " \t") + (if (eolp) + (setq last-parent-major-indent 0) + (setq last-parent-major-indent (current-column))))))))) + (mumamo-msgindent " leaving-submode=%s, entering-submode=%s" leaving-submode entering-submode) + ;;(msgtrc " leaving-submode=%s, entering-submode=%s, template-indentor=%s" leaving-submode entering-submode template-indentor) + + ;; Fix-me: use this. + ;; - clean up after chunk deletion + ;; - next line after a template-indentor, what happens? + ;;(setq template-indentor nil) ;; fix-me + (cond + ( template-indent-abs + (setq want-indent (max 0 template-indent-abs))) + ( leaving-submode + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; First line after submode + (mumamo-msgindent " leaving last-parent-major-indent=%s" last-parent-major-indent) + (if (eq (overlay-get (overlay-get this-line-chunk0 'mumamo-prev-chunk) + 'mumamo-next-indent) + 'heredoc) + (setq want-indent 0) + (setq want-indent last-parent-major-indent))) + + ( entering-submode + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; First line in submode + ;;(setq this-line-indent-major this-line-major0) + (setq this-line-indent-major (mumamo-indent-get-major-to-use this-line-major0 this-depth3)) + ;;(when (and prev-line-major0 (not (mumamo-fun-eq this-line-major0 prev-line-major0))) (setq this-line-indent-major prev-line-major0)) + (mumamo-msgindent " this-line-indent-major=%s, major-mode=%s this0=%s" this-line-indent-major major-mode this-line-major0) + (mumamo-msgindent " mumamo-submode-indent-offset=%s" mumamo-submode-indent-offset) + (unless (mumamo-fun-eq this-line-indent-major major-mode) + (mumamo-set-major this-line-indent-major this-line-chunk0)) + (setq want-indent (+ last-parent-major-indent + (if (= 0 last-parent-major-indent) + (if mumamo-submode-indent-offset-0 + mumamo-submode-indent-offset-0 + -1000) + (if mumamo-submode-indent-offset + mumamo-submode-indent-offset + -1000)))) + (unless (< 0 want-indent) (setq want-indent nil)) + (when (and want-indent (mumamo-indent-use-widen major-mode)) + ;; In this case only use want-indent if it is bigger than the + ;; indentation calling indent-line-function would give. + (condition-case nil + (atomic-change-group + (mumamo-call-indent-line (nth 0 this-line-chunks)) + (when (> want-indent (current-indentation)) + (signal 'mumamo-error-ind-0 nil)) + (setq want-indent nil)) + (mumamo-error-ind-0))) + (unless want-indent + (mumamo-call-indent-line (nth 0 this-line-chunks))) + (mumamo-msgindent " enter sub.want-indent=%s, curr=%s, last-main=%s" want-indent (current-indentation) + last-parent-major-indent) + ;;(unless (> want-indent (current-indentation)) (setq want-indent nil)) + ) + + ( t + ;; We have to change major mode, because we know nothing + ;; about the requirements of the indent-line-function: + ;; Fix-me: This may be cured by RMS suggestion to + ;; temporarily set all variables back to global values? + (setq this-line-indent-major (mumamo-indent-get-major-to-use this-line-major0 this-depth3)) + (mumamo-msgindent " this-line-indent-major=%s" this-line-indent-major) + (unless (mumamo-fun-eq this-line-indent-major major-mode) (mumamo-set-major this-line-indent-major this-line-chunk0)) + ;; Use the major mode at the beginning of since a sub chunk may + ;; start at start of line. + (if (mumamo-fun-eq this-line-major1 main-major) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; In main major mode + ;; + ;; Take care of the case when all the text is in a + ;; sub chunk. In that case use the same indentation as if + ;; the code all belongs to the surrounding major mode. + (let ((here (point)) + (use-widen (mumamo-indent-use-widen main-major))) + ;; If we can't indent indent using the main major mode + ;; because it is only blanks and we should not widen, + ;; then use the indentation on the line where it starts. + (mumamo-msgindent " In main major mode") + (forward-line 0) + (skip-chars-backward " \t\n\r\f") + (forward-line 0) + (if (or use-widen (>= (point) (overlay-start this-line-chunk0))) + (progn + (goto-char here) + (mumamo-call-indent-line this-line-chunk0)) + (setq want-indent (current-indentation)) + (goto-char here)) + (mumamo-msgindent " In main major mode B") + (setq last-parent-major-indent (current-indentation))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; In sub major mode + ;; + ;; Get the indentation the major mode alone would use: + ;;(setq got-indent (mumamo-get-major-mode-indent-column)) + ;; Since this line has another major mode than the + ;; previous line we instead want to indent relative to + ;; that line in a way decided in mumamo: + (mumamo-msgindent " In sub major mode") + (let ((chunk (mumamo-get-chunk-save-buffer-state (point))) + (font-lock-dont-widen t) + ind-zero + (here (point)) + ind-on-first-sub-line) + (save-restriction + (mumamo-update-obscure chunk here) + (let ((syn-min-max (mumamo-chunk-syntax-min-max chunk nil))) + (narrow-to-region (car syn-min-max) + (cdr syn-min-max))) + (condition-case nil + (atomic-change-group + (mumamo-call-indent-line (nth 0 this-line-chunks)) + (when (= 0 (current-indentation)) + (setq ind-zero t) + ;; It is maybe ok if indentation on first sub + ;; line is 0 so check that: + (goto-char (point-min)) + (widen) + (setq ind-on-first-sub-line (current-indentation)) + (goto-char here) + (signal 'mumamo-error-ind-0 nil))) + (mumamo-error-ind-0)) + ;; Unfortunately the indentation can sometimes get 0 + ;; here even though it is clear it should not be 0. This + ;; happens when there are only comments or empty lines + ;; above. + ;; + ;; See c:/test/erik-lilja-index.php for an example. + (when ind-zero ;(and t (= 0 (current-indentation))) + (save-excursion + (setq want-indent 0) + (unless (= 0 ind-on-first-sub-line) + ;;(while (and (> 500 (setq while-n2 (1+ while-n2))) + (while (and (mumamo-while 500 'while-n2 "want-indent") + (= 0 want-indent) + (/= (point) (point-min))) + (beginning-of-line 0) + (setq want-indent (current-indentation))) + ;; Now if want-indent is still 0 we need to look further above + (when (= 0 want-indent) + (widen) + ;;(while (and (> 500 (setq while-n3 (1+ while-n3))) + (while (and (mumamo-while 500 'while-n3 "want-indent 2") + (= 0 want-indent) + (/= (point) (point-min))) + (beginning-of-line 0) + (setq want-indent (current-indentation))) + ;; If we got to the main major mode we need to add + ;; the special submode offset: + (let* ((ovl (mumamo-get-chunk-save-buffer-state (point))) + (major (mumamo-chunk-major-mode ovl))) + (when (mumamo-fun-eq major main-major) + (setq want-indent (+ want-indent + (if (= 0 want-indent) + mumamo-submode-indent-offset-0 + mumamo-submode-indent-offset))))))))) + ))))) + (when want-indent + ;;(msgtrc "indent-line-to %s at line-beginning=%s" want-indent (line-beginning-position)) + (indent-line-to want-indent)) + ;; (when (and template-shift (/= 0 template-shift)) + ;; (let ((ind (+ (current-indentation) template-shift))) + ;; (indent-line-to ind))) + ;; (when template-indent-abs + ;; (indent-line-to template-indent-abs)) + (goto-char here-on-line) + ;;(msgtrc "exit: %s" (list this-line-chunks last-parent-major-indent)) + (list this-line-chunks last-parent-major-indent next-entering-submode))) + +;; Fix-me: use this for first line in a submode +;; Fix-me: check more carefully for widen since it may lead to bad results. +(defun mumamo-indent-use-widen (major-mode) + "Return non-nil if widen before indentation in MAJOR-MODE." + (let* ((specials (cadr (assoc major-mode mumamo-indent-widen-per-major))) + (use-widen (memq 'use-widen specials)) + (use-widen-maybe (assq 'use-widen specials))) + (or use-widen + (memq mumamo-multi-major-mode (cadr use-widen-maybe))))) +;;(mumamo-indent-use-widen 'php-mode) +;;(mumamo-indent-use-widen 'nxhtml-mode) +;;(mumamo-indent-use-widen 'html-mode) + +;; Fix-me: remove +;; (defun mumamo-indent-special-or-default (default-indent) +;; "Indent to DEFAULT-INDENT unless a special indent can be done." +;; (mumamo-with-major-mode-indentation major-mode +;; `(progn +;; (if (mumamo-indent-use-widen major-mode) +;; (save-restriction +;; (widen) +;; (mumamo-msgindent "=> special-or-default did widen, %s" major-mode) +;; (funcall indent-line-function)) +;; (indent-to-column default-indent))))) + +(defun mumamo-call-indent-line (chunk) + "Call the relevant `indent-line-function'." + ;;(msgtrc "call-indent-line %s, lbp=%s" chunk (line-beginning-position)) + (if nil + (mumamo-with-major-mode-indentation major-mode + `(save-restriction + (when (mumamo-indent-use-widen major-mode) + (mumamo-msgindent "=> indent-line did widen") + (widen)) + (funcall indent-line-function))) + (let ((maj (car mumamo-major-mode-indent-line-function)) + (fun (cdr mumamo-major-mode-indent-line-function))) + (assert (mumamo-fun-eq maj major-mode)) + (save-restriction + ;; (unless (mumamo-indent-use-widen major-mode) + ;; (let ((syn-min-max (mumamo-chunk-syntax-min-max chunk nil))) + ;; (narrow-to-region (car syn-min-max) (cdr syn-min-max)))) + (let ((mumamo-stop-widen (not (mumamo-indent-use-widen major-mode)))) + (if (not mumamo-stop-widen) + (widen) + (let ((syn-min-max (mumamo-chunk-syntax-min-max chunk nil))) + (narrow-to-region (car syn-min-max) (cdr syn-min-max)))) + ;;(msgtrc "call-indent-line fun=%s" fun) + ;;(funcall fun) + ;; Fix-me: Use mumamo-funcall-evaled to avoid (widen): + (mumamo-funcall-evaled fun) + ))))) + +(defvar mumamo-stop-widen nil) +(when nil + (let* ((fun 'describe-variable) + (lib (symbol-file fun 'defun))) + (find-function-search-for-symbol fun nil lib))) + +(defun mumamo-funcall-evaled (fun &rest args) + "Make sure FUN is evaled, then call it. +This make sure (currently) that defadvice for primitives are +called. They are not called in byte compiled code. + +See URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=5863' since +this may change." + (when mumamo-stop-widen + (unless (get fun 'mumamo-evaled) + (let* ((lib (symbol-file fun 'defun)) + (where (find-function-search-for-symbol fun nil lib)) + (buf (car where)) + (pos (cdr where))) + (with-current-buffer buf + (let ((close (and (not (buffer-modified-p)) + (= 1 (point))))) + ;;(goto-char pos) (eval-defun nil) + (msgtrc "mumamo-funcall-evaled %s" (current-buffer)) + (eval-buffer) + (when close (kill-buffer)))) + (put fun 'mumamo-evaled t)))) + (apply 'funcall fun args)) + +;;(require 'advice) +(defun mumamo-defadvice-widen () + (defadvice widen (around + mumamo-ad-widen + activate + compile + ) + (unless (and mumamo-multi-major-mode + mumamo-stop-widen) + ad-do-it))) +(eval-after-load 'mumamo + '(mumamo-defadvice-widen)) + +;; (defadvice font-lock-fontify-buffer (around +;; mumam-ad-font-lock-fontify-buffer +;; activate +;; compile +;; ) +;; (if mumamo-multi-major-mode +;; (save-restriction +;; (let* ((chunk (mumamo-find-chunks (point) "font-lock-fontify-buffer advice")) +;; (syn-min-max (mumamo-chunk-syntax-min-max chunk nil)) +;; (syn-min (car syn-min-max)) +;; (syn-max (cdr syn-min-max)) +;; (mumamo-stop-widen t)) +;; (narrow-to-region syn-min syn-max) +;; (font-lock-fontify-region syn-min syn-max))) +;; ad-do-it)) + +(defun mumamo-indent-region-function (start end) + "Indent the region between START and END." + (save-excursion + (setq end (copy-marker end)) + (goto-char start) + (let ((old-point -1) + prev-line-chunks + last-parent-major-indent + entering-submode-arg + ;; Turn off validation during indentation + (old-rng-validate-mode (when (boundp 'rng-validate-mode) rng-validate-mode)) + (rng-nxml-auto-validate-flag nil) + (nxhtml-use-imenu nil) + fontification-functions + rng-nxml-auto-validate-flag + (nxhtml-mode-hook (mumamo-get-hook-value + 'nxhtml-mode-hook + '(html-imenu-setup))) + ;; + (while-n1 0)) + (when old-rng-validate-mode (rng-validate-mode -1)) + ;;(while (and (> 3000 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 3000 'while-n1 "indent-region") + (< (point) end) + (/= old-point (point))) + ;;(message "mumamo-indent-region-function, point=%s" (point)) + (or (and (bolp) (eolp)) + (let ((ret (mumamo-indent-line-function-1 + prev-line-chunks + last-parent-major-indent + entering-submode-arg))) + (setq prev-line-chunks (nth 0 ret)) + (setq last-parent-major-indent (nth 1 ret)) + (setq entering-submode-arg (nth 2 ret)))) + (setq old-point (point)) + (forward-line 1)) + (when old-rng-validate-mode (rng-validate-mode 1))) + (message "Ready indenting region"))) + + +(defun mumamo-fill-forward-paragraph-function(&optional arg) + "Function to move over paragraphs used by filling code. +This is the buffer local value of +`fill-forward-paragraph-function' when mumamo is used." + ;; fix-me: Do this chunk by chunk + ;; Fix-me: use this (but only in v 23) + (let* ((ovl (mumamo-get-chunk-save-buffer-state (point))) + (major (mumamo-chunk-major-mode ovl))) + (mumamo-with-major-mode-fontification major + fill-forward-paragraph-function))) + +(defun mumamo-fill-chunk (&optional justify) + "Fill each of the paragraphs in the current chunk. +Narrow to chunk region trimmed white space at the ends. Then +call `fill-region'. + +The argument JUSTIFY is the same as in `fill-region' and a prefix +behaves the same way as there." + (interactive (progn + (barf-if-buffer-read-only) + (list (if current-prefix-arg 'full)))) + (let* ((ovl (mumamo-get-chunk-save-buffer-state (point))) + (major (mumamo-chunk-major-mode ovl))) + ;; Fix-me: There must be some bug that makes it necessary to + ;; always change mode when fill-paragraph-function is + ;; c-fill-paragraph. + + ;;(unless (mumamo-fun-eq major major-mode) (mumamo-set-major major ovl)) + (mumamo-set-major major ovl) + + (save-restriction + (mumamo-update-obscure ovl (point)) + (let* ((syn-min-max (mumamo-chunk-syntax-min-max ovl nil)) + (syn-min (car syn-min-max)) + (syn-max (cdr syn-min-max)) + use-min + (here (point-marker))) + (goto-char syn-min) + (skip-syntax-forward " ") + ;; Move back over chars that have whitespace syntax but have the p flag. + (backward-prefix-chars) + (setq use-min (point)) + (goto-char syn-max) + (skip-syntax-backward " ") + (fill-region use-min (point) justify))))) + +;; (defvar mumamo-dont-widen) +;; (defadvice widen (around +;; mumamo-ad-widen +;; activate +;; disable +;; compile +;; ) +;; "Make `widen' do nothing. +;; This is for `mumamo-fill-paragraph-function' and is necessary +;; when `c-fill-paragraph' is the real function used." +;; (unless (and (boundp 'mumamo-dont-widen) +;; mumamo-dont-widen) +;; ad-do-it)) + +(defadvice flymake-display-warning (around + mumamo-ad-flymake-display-warning + activate + compile) + "Display flymake warnings in the usual Emacs way." + (let ((msg (ad-get-arg 0))) + ;; Fix-me: Can't get backtrace here. Report it. + ;;(setq msg (format (concat msg "\n%S" (with-output-to-string (backtrace))))) + (lwarn '(flymake) :error msg))) +;;(lwarn '(flymake) :error "the warning") + +(defun mumamo-forward-chunk () + "Move forward to next chunk." + (interactive) + (let* ((chunk (mumamo-get-chunk-save-buffer-state (point))) + (end-pos (overlay-end chunk))) + (goto-char (min end-pos + (point-max))))) + +(defun mumamo-backward-chunk () + "Move backward to previous chunk." + (interactive) + (let* ((chunk (mumamo-get-chunk-save-buffer-state (point))) + (start-pos (overlay-start chunk))) + (goto-char (max (1- start-pos) + (point-min))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Spell checking + +(defun mumamo-flyspell-verify () + "Function used for `flyspell-generic-check-word-predicate'." + (let* ((chunk (when mumamo-multi-major-mode + (mumamo-find-chunks (point) "mumamo-lyspell-verify"))) + (chunk-major (when chunk (mumamo-chunk-major-mode chunk))) + (mode-predicate (when chunk-major + (let ((predicate (get chunk-major + 'flyspell-mode-predicate))) + (if predicate + predicate + (if (mumamo-derived-from-mode chunk-major + 'text-mode) + nil + 'flyspell-generic-progmode-verify))))) + ) + (if mode-predicate + ;; Fix-me: (run-hooks 'flyspell-prog-mode-hook) + (funcall mode-predicate) + t))) + +;; (featurep 'cc-engine) +(eval-after-load 'cc-engine + (progn + ;; From Alan's mail 2009-12-03: C Mode: acceleration in brace + ;; deserts. + ;; Fix-me: Should they be here, or...? + (put 'c-state-cache 'permanent-local t) + (put 'c-state-cache-good-pos 'permanent-local t) + (put 'c-state-nonlit-pos-cache 'permanent-local t) + (put 'c-state-nonlit-pos-cache-limit 'permanent-local t) + (put 'c-state-brace-pair-desert 'permanent-local t) + (put 'c-state-point-min 'permanent-local t) + (put 'c-state-point-min-lit-type 'permanent-local t) + (put 'c-state-point-min-lit-start 'permanent-local t) + (put 'c-state-min-scan-pos 'permanent-local t) + (put 'c-state-old-cpp-beg 'permanent-local t) + (put 'c-state-old-cpp-end 'permanent-local t) + + )) + +;; Fix-me: Seems perhaps like c-state-point-min-lit-start is reset in +;; c-state-mark-point-min-literal because c-state-literal-at returns +;; nil. (Or is (car lit) nil?) + +(defvar mumamo-c-state-cache-init nil) +(make-variable-buffer-local 'mumamo-c-state-cache-init) +(put 'mumamo-c-state-cache-init 'permanent-local t) + +(defun mumamo-c-state-cache-init () + (unless mumamo-c-state-cache-init + ;;(msgtrc "c-state-cache-init running") + (setq mumamo-c-state-cache-init t) + (setq c-state-cache (or c-state-cache nil)) + (put 'c-state-cache 'permanent-local t) + (setq c-state-cache-good-pos (or c-state-cache-good-pos 1)) + (put 'c-state-cache-good-pos 'permanent-local t) + (setq c-state-nonlit-pos-cache (or c-state-nonlit-pos-cache nil)) + (put 'c-state-nonlit-pos-cache 'permanent-local t) + (setq c-state-nonlit-pos-cache-limit (or c-state-nonlit-pos-cache-limit 1)) + (put 'c-state-nonlit-pos-cache-limit 'permanent-local t) + (setq c-state-brace-pair-desert (or c-state-brace-pair-desert nil)) + (put 'c-state-brace-pair-desert 'permanent-local t) + (setq c-state-point-min (or c-state-point-min 1)) + (put 'c-state-point-min 'permanent-local t) + (setq c-state-point-min-lit-type (or c-state-point-min-lit-type nil)) + (put 'c-state-point-min-lit-type 'permanent-local t) + (setq c-state-point-min-lit-start (or c-state-point-min-lit-start nil)) + (put 'c-state-point-min-lit-start 'permanent-local t) + (setq c-state-min-scan-pos (or c-state-min-scan-pos 1)) + (put 'c-state-min-scan-pos 'permanent-local t) + (setq c-state-old-cpp-beg (or c-state-old-cpp-beg nil)) + (put 'c-state-old-cpp-beg 'permanent-local t) + (setq c-state-old-cpp-end (or c-state-old-cpp-end nil)) + (put 'c-state-old-cpp-end 'permanent-local t) + (c-state-mark-point-min-literal))) + +(defadvice c-state-cache-init (around + mumamo-ad-c-state-cache-init + activate + compile + ) + (if (not mumamo-multi-major-mode) + ad-do-it + (mumamo-c-state-cache-init))) + +;; Fix-me: Have to add per chunk local majors for this one. +(defun mumamo-c-state-literal-at (here) + ;; If position HERE is inside a literal, return (START . END), the + ;; boundaries of the literal (which may be outside the accessible bit of the + ;; buffer). Otherwise, return nil. + ;; + ;; This function is almost the same as `c-literal-limits'. It differs in + ;; that it is a lower level function, and that it rigourously follows the + ;; syntax from BOB, whereas `c-literal-limits' uses a "local" safe position. + (let* ((is-here (point)) + (s (syntax-ppss here)) + (ret (when (or (nth 3 s) (nth 4 s)) ; in a string or comment + (parse-partial-sexp (point) (point-max) + nil ; TARGETDEPTH + nil ; STOPBEFORE + s ; OLDSTATE + 'syntax-table) ; stop at end of literal + (cons (nth 8 s) (point))))) + (goto-char is-here) + ret)) + +;; (save-restriction +;; (widen) +;; (let* ((chunk (mumamo-find-chunks (point) "mumamo-c-state-literal-at")) +;; (syntax-min-max (mumamo-chunk-syntax-min-max chunk t))) +;; (narrow-to-region (car syntax-min-max) (cdr syntax-min-max))) +;; (save-excursion +;; (let ((c c-state-nonlit-pos-cache) +;; pos npos lit) +;; ;; Trim the cache to take account of buffer changes. +;; (while (and c (> (car c) c-state-nonlit-pos-cache-limit)) +;; (setq c (cdr c))) +;; (setq c-state-nonlit-pos-cache c) + +;; (while (and c (> (car c) here)) +;; (setq c (cdr c))) +;; (setq pos (or (car c) (point-min))) + +;; (while (<= (setq npos (+ pos c-state-nonlit-pos-interval)) +;; here) +;; (setq lit (c-state-pp-to-literal pos npos)) +;; (setq pos (or (cdr lit) npos)) ; end of literal containing npos. +;; (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache))) + +;; (if (> pos c-state-nonlit-pos-cache-limit) +;; (setq c-state-nonlit-pos-cache-limit pos)) +;; (if (< pos here) +;; (setq lit (c-state-pp-to-literal pos here))) +;; lit)))) + + +(defadvice c-state-literal-at (around + mumamo-ad-c-state-state-literal-at + activate + compile + ) + (if (not mumamo-multi-major-mode) + ad-do-it + (mumamo-c-state-literal-at (ad-get-arg 0)))) + + +(defun mumamo-c-state-get-min-scan-pos () + ;; Return the lowest valid scanning pos. This will be the end of the + ;; literal enclosing point-min, or point-min itself. + (save-restriction + (save-excursion + (widen) + (mumamo-narrow-to-chunk-inner) + (or (and c-state-min-scan-pos + (>= c-state-min-scan-pos (point-min)) + c-state-min-scan-pos) + (if (not c-state-point-min-lit-start) + (goto-char (point-min)) + (goto-char c-state-point-min-lit-start) + (if (eq c-state-point-min-lit-type 'string) + (forward-sexp) + (forward-comment 1))) + (setq c-state-min-scan-pos (point)))))) + +(defadvice c-state-get-min-scan-pos (around + mumamo-ad-c-state-get-min-scan-pos-at + activate + compile + ) + (if (not mumamo-multi-major-mode) + ad-do-it + (setq ad-return-value (mumamo-c-state-get-min-scan-pos)))) + +(eval-after-load 'rng-match +;;; (defun rng-match-init-buffer () +;;; (make-local-variable 'rng-compile-table) +;;; (make-local-variable 'rng-ipattern-table) +;;; (make-local-variable 'rng-last-ipattern-index)) + (progn + (put 'rng-compile-table 'permanent-local t) + (put 'rng-ipattern-table 'permanent-local t) + (put 'rng-last-ipattern-index 'permanent-local t) + )) + +(eval-after-load 'flyspell + (progn + (put 'flyspell-mode 'permanent-local t) + + (put 'flyspell-generic-check-word-predicate 'permanent-local t) + + (put 'flyspell-casechars-cache 'permanent-local t) + (put 'flyspell-ispell-casechars-cache 'permanent-local t) + + (put 'flyspell-not-casechars-cache 'permanent-local t) + (put 'flyspell-ispell-not-casechars-cache 'permanent-local t) + + (put 'flyspell-auto-correct-pos 'permanent-local t) + (put 'flyspell-auto-correct-region 'permanent-local t) + (put 'flyspell-auto-correct-ring 'permanent-local t) + (put 'flyspell-auto-correct-word 'permanent-local t) + + (put 'flyspell-consider-dash-as-word-delimiter-flag 'permanent-local t) + + (put 'flyspell-dash-dictionary 'permanent-local t) + + (put 'flyspell-dash-local-dictionary 'permanent-local t) + + (put 'flyspell-word-cache-start 'permanent-local t) + (put 'flyspell-word-cache-end 'permanent-local t) + (put 'flyspell-word-cache-word 'permanent-local t) + (put 'flyspell-word-cache-result 'permanent-local t) + + (put 'flyspell-word-cache-start 'permanent-local t) + + + (put 'flyspell-kill-ispell-hook 'permanent-local-hook t) + (put 'flyspell-post-command-hook 'permanent-local-hook t) + (put 'flyspell-pre-command-hook 'permanent-local-hook t) + (put 'flyspell-after-change-function 'permanent-local-hook t) + (put 'flyspell-hack-local-variables-hook 'permanent-local-hook t) + (put 'flyspell-auto-correct-previous-hook 'permanent-local-hook t) + + (when mumamo-multi-major-mode + (when (featurep 'flyspell) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify))) + )) + +(defun flyspell-mumamo-mode () + "Turn on function `flyspell-mode' for multi major modes." + (interactive) + (require 'flyspell) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify) + (flyspell-mode 1) + ;;(run-hooks 'flyspell-prog-mode-hook) + ) + +(eval-after-load 'sgml-mode + (progn + (put 'sgml-tag-face-alist 'permanent-local t) + (put 'sgml-display-text 'permanent-local t) + (put 'sgml-tag-alist 'permanent-local t) + (put 'sgml-face-tag-alist 'permanent-local t) + (put 'sgml-tag-help 'permanent-local t) + )) + +(eval-after-load 'hl-line + (progn + (put 'hl-line-overlay 'permanent-local t) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; New versions of syntax-ppss functions, temporary written as defadvice. + +(defadvice syntax-ppss-flush-cache (around + mumamo-ad-syntax-ppss-flush-cache + activate + compile + ) + "Support for mumamo. +See the defadvice for `syntax-ppss' for an explanation." + (if (not mumamo-multi-major-mode) + ad-do-it + (let ((pos (ad-get-arg 0))) + (let* ((chunk-at-pos (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (mumamo-find-chunks-1 pos "syntax-ppss-flush-cache")))) + (if chunk-at-pos + (let* ((syntax-ppss-last (overlay-get chunk-at-pos 'syntax-ppss-last)) + (syntax-ppss-cache (overlay-get chunk-at-pos 'syntax-ppss-cache))) + ;;(setq ad-return-value ad-do-it) + ad-do-it + (overlay-put chunk-at-pos 'syntax-ppss-last syntax-ppss-last) + (overlay-put chunk-at-pos 'syntax-ppss-cache syntax-ppss-cache)) + ;;(setq ad-return-value ad-do-it) + ad-do-it + ))))) + +(defvar mumamo-syntax-chunk-at-pos nil + "Internal use.") +(make-variable-buffer-local 'mumamo-syntax-chunk-at-pos) + +;; Fix-me: Is this really needed? +;; See http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg00374.html +(defadvice syntax-ppss-stats (around + mumamo-ad-syntax-ppss-stats + activate + compile + ) + "Support for mumamo. +See the defadvice for `syntax-ppss' for an explanation." + (if mumamo-syntax-chunk-at-pos + (let* ((syntax-ppss-stats + (overlay-get mumamo-syntax-chunk-at-pos 'syntax-ppss-stats))) + ad-do-it + (overlay-put mumamo-syntax-chunk-at-pos 'syntax-ppss-stats syntax-ppss-stats)) + ad-do-it)) + +(defvar mumamo-syntax-ppss-major nil) + +;; FIX-ME: There is a problem with " in xhtml files, especially after +;; syntax="...". Looks like it is the " entry in +;; `sgml-font-lock-syntactic-keywords' that is jumping in! Dumping +;; things in `font-lock-apply-syntactic-highlight' seems to show that. +;; +;; (I have put in some dump code in my patched version of +;; Emacs+EmacsW32 there for that. This is commented out by default +;; and it will only work for the file nxhtml-changes.html which is big +;; enough for the problem to occur. It happens at point 1109.) +;; +;; It is this piece of code where the problem arise: +;; +;; (if (prog1 +;; (zerop (car (syntax-ppss (match-beginning 0)))) +;; (goto-char (match-end 0))) +;; .) +;; +;; +;; It comes from `sgml-font-lock-syntactic-keywords' in sgml-mode.el +;; and is supposed to protect from " that is not inside a tag. +;; However in this case for the second " in syntax="..." `syntax-ppss' +;; returns 0 as the first element in its return value. That happen +;; even though `major-mode' is correctly `html-mode'. It leads to +;; that the property 'syntax with the value (1) is added to the " +;; after the css-mode chunk in syntax="...". The problem persists +;; even if the chunk has `fundamental-mode' instead of `css-mode'. +;; +;; Bypassing the cache for `syntax-pss' by calling +;; `parse-partial-sexp' directly instead of doing ad-do-it (see +;; by-pass-chache in the code below) solves the problem for now. It +;; does not feel like the right solution however. +;; +;; One way of temporary solving the problem is perhaps to modify +;; `mumamo-chunk-attr=' to make "" borders, but I am not sure that it +;; works and it is the wrong solution. +(defadvice syntax-ppss (around + mumamo-ad-syntax-ppss + activate + compile + ) + "Support for mumamo chunks. +For each chunk store as properties of the chunk the parse state +that is normally hold in `syntax-ppss-last' and +`syntax-ppss-cache'. + +Compute the beginning parse state for a chunk this way: + +- If the chunk major mode is the same as the main major mode for + the multi major mode then parse from the beginning of the file + to the beginning of the chunk using the main major mode. While + doing that jump over chunks that do not belong to the main + major mode and cache the state at the end and beginning of the + the main major mode chunks. + +FIX-ME: implement above. Solution?: + (parse-partial-sexp syntax-min (1+ syntax-max) nil nil state-at-syntax-min) +Put this at next chunk's beginning. + +- Otherwise set the state at the beginning of the chunk to nil. + +Do here also other necessary adjustments for this." + (if (not mumamo-multi-major-mode) + ad-do-it + (let ((pos (ad-get-arg 0))) + (unless pos (setq pos (point))) + (let* ((chunk-at-pos (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + (mumamo-find-chunks-1 pos "syntax-ppss"))) + (dump2 (and (boundp 'dump-quote-hunt) + dump-quote-hunt + (boundp 'start) + ;;(= 1109 start) + ))) + ;;(setq dump2 t) + (setq mumamo-syntax-chunk-at-pos chunk-at-pos) + (when dump2 (msgtrc "\npos=%s point-min=%s mumamo-syntax-ppss.chunk-at-pos=%s" pos (point-min) chunk-at-pos)) + (if chunk-at-pos + (let* ((chunk-syntax-min-max (mumamo-chunk-syntax-min-max chunk-at-pos t)) + (chunk-syntax-min (car chunk-syntax-min-max)) + (chunk-major (mumamo-chunk-major-mode chunk-at-pos)) + (syntax-ppss-last (overlay-get chunk-at-pos 'syntax-ppss-last)) + (syntax-ppss-cache (overlay-get chunk-at-pos 'syntax-ppss-cache)) + (syntax-ppss-last-min (overlay-get chunk-at-pos 'syntax-ppss-last-min)) + (syntax-ppss-cache-min (list syntax-ppss-last-min)) + ;; This must be fetch the same way as in syntax-ppss: + (syntax-begin-function (overlay-get chunk-at-pos 'syntax-begin-function)) + (syntax-ppss-max-span (if chunk-syntax-min + (/ (- pos chunk-syntax-min -2) 2) + syntax-ppss-max-span)) + (syntax-ppss-stats (let ((stats (overlay-get chunk-at-pos 'syntax-ppss-stats))) + (if stats + stats + (default-value 'syntax-ppss-stats)))) + (last-min-pos (or (car syntax-ppss-last-min) + 1)) + ) + ;; If chunk has moved the cached values are invalid. + (unless (= chunk-syntax-min last-min-pos) + (setq syntax-ppss-last nil) + (setq syntax-ppss-last-min nil) + (setq syntax-ppss-cache nil) + (setq syntax-ppss-cache-min nil) + (setq syntax-ppss-stats (default-value 'syntax-ppss-stats))) + (when dump2 + (msgtrc " get syntax-ppss-last-min=%s len=%s chunk=%s" syntax-ppss-last-min (length syntax-ppss-last-min) chunk-at-pos) + (msgtrc " prop syntax-ppss-last-min=%s" (overlay-properties chunk-at-pos)) + (msgtrc " chunk-major=%s, %s, syntax-min=%s\n last-min=%s" chunk-major major-mode chunk-syntax-min syntax-ppss-last-min)) + ;;(setq dump2 nil) + (when syntax-ppss-last-min + (unless (car syntax-ppss-last-min) + ;;(msgtrc "fix-me: emacs bug workaround, setting car of syntax-ppss-last-min") + ;;(setcar syntax-ppss-last-min (1- chunk-syntax-min)) + ;;(msgtrc "fix-me: emacs bug workaround, need new syntax-ppss-last-min because car is nil") + (setq syntax-ppss-last-min nil) + )) + (unless syntax-ppss-last-min + (setq syntax-ppss-last nil) + (save-restriction + (widen) + (let* ((min-pos chunk-syntax-min) + (chunk-sub-major (mumamo-chunk-major-mode chunk-at-pos)) + (main-major (mumamo-main-major-mode)) + (is-main-mode-chunk (mumamo-fun-eq chunk-sub-major main-major))) + (when dump2 (msgtrc " min-pos=%s, is-main-mode-chunk=%s" min-pos is-main-mode-chunk)) + ;; Looks like assert can not be used here for some reason??? + ;;(assert (and min-pos) t) + (unless (and min-pos) (error "defadvice syntax-ppss: (and min-pos=%s)" min-pos)) + (setq syntax-ppss-last-min + (cons min-pos ;;(1- min-pos) + (if nil ;is-main-mode-chunk + ;; Fix-me: previous chunks as a + ;; cache? The problem is updating + ;; this. Perhaps it is possible to + ;; prune how far back to go by + ;; going to the first chunk + ;; backwards where + ;; (pars-partial-sexp min max) is + ;; "nil"? + (mumamo-with-major-mode-fontification main-major + `(parse-partial-sexp 1 ,min-pos nil nil nil nil)) + (parse-partial-sexp 1 1)))) + (setq syntax-ppss-cache-min (list syntax-ppss-last-min)) + (when dump2 (msgtrc " put syntax-ppss-last-min=%s len=%s chunk=%s" syntax-ppss-last-min (length syntax-ppss-last-min) chunk-at-pos)) + (when dump2 (msgtrc " prop syntax-ppss-last-min=%s" (overlay-properties chunk-at-pos))) + (overlay-put chunk-at-pos 'syntax-ppss-last-min syntax-ppss-last-min) + (let ((test-syntax-ppss-last-min + (overlay-get chunk-at-pos 'syntax-ppss-last-min))) + (when dump2 (msgtrc " test syntax-ppss-last-min=%s len=%s" test-syntax-ppss-last-min (length test-syntax-ppss-last-min))) + (when dump2 (msgtrc " propt syntax-ppss-last-min=%s" (overlay-properties chunk-at-pos))) + )))) + (when dump2 (msgtrc " here 0, syntax-ppss-last=%s" syntax-ppss-last)) + (unless syntax-ppss-last + (setq syntax-ppss-last syntax-ppss-last-min) + (setq syntax-ppss-cache syntax-ppss-cache-min)) + ;;(syntax-ppss pos) + (when dump2 (msgtrc " at 1, syntax-ppss-last=%s" syntax-ppss-last)) + (when dump2 (msgtrc " at 1, syntax-ppss-cache=%s" syntax-ppss-cache)) + (let (ret-val + (by-pass-cache t) + (dump2 dump2)) + (if (not by-pass-cache) + (progn + (when dump2 + (let ((old-ppss (cdr syntax-ppss-last)) + (old-pos (car syntax-ppss-last))) + ;;(assert (and old-pos pos) t) + (unless (and old-pos pos) (error "defadvice syntax-ppss: (and old-pos=%s pos=%s)" old-pos pos)) + (msgtrc "parse-partial-sexp=>%s" (parse-partial-sexp old-pos pos nil nil old-ppss)))) + (let (dump2) + (setq ret-val ad-do-it))) + (let ((old-ppss (cdr syntax-ppss-last)) + (old-pos (car syntax-ppss-last))) + (when dump2 + (msgtrc "Xparse-partial-sexp %s %s nil nil %s" old-pos pos old-ppss) + (let (dump2) + (msgtrc "ad-do-it=>%s" ad-do-it))) + (save-restriction + (widen) + ;;(assert (and old-pos pos) t) + (unless (and old-pos pos) (error "defadvice syntax-ppss 2 (and old-pos=%s pos=%s)" old-pos pos)) + (when dump2 + (msgtrc "parse-partial-sexp %s %s nil nil %s" old-pos pos old-ppss)) + (setq ret-val (parse-partial-sexp old-pos pos nil nil old-ppss))))) + (when dump2 (msgtrc " ==>ret-val=%s" ret-val)) + ;;(mumamo-backtrace "syntax-ppss") + (setq ad-return-value ret-val)) + (overlay-put chunk-at-pos 'syntax-ppss-last syntax-ppss-last) + (overlay-put chunk-at-pos 'syntax-ppss-cache syntax-ppss-cache) + (overlay-put chunk-at-pos 'syntax-ppss-stats syntax-ppss-stats) + ) + ad-do-it))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; rng-valid.el support + +;; Fix-me: The solution in this defadvice is temporary. The defadvice +;; for rng-do-some-validation should be fixed instead. +;; (ad-disable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) +;; (ad-ensable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) +(defadvice rng-mark-error (around + mumamo-ad-rng-mark-error + activate + compile) + "Adjust range for error to chunks." + (if (not mumamo-multi-major-mode) + ad-do-it + (let* ((beg (ad-get-arg 1)) + (end (ad-get-arg 2)) + (xml-parts nil) + (chunk (mumamo-find-chunks beg "rng-mark-error"))) + (if (not chunk) + ad-do-it + (when (and (not (overlay-get chunk 'mumamo-region)) + (mumamo-valid-nxml-chunk chunk)) + ;; rng-error + (let ((part-beg (max (overlay-start chunk) + beg)) + (part-end (min (overlay-end chunk) + end))) + (when (< part-beg part-end) + (ad-set-arg 1 part-beg) + (ad-set-arg 2 part-end) + ad-do-it))))))) + +(defadvice rng-do-some-validation-1 (around + mumamo-ad-rng-do-some-validation-1 + activate + compile) + "Adjust validation to chunks." + (if (not mumamo-multi-major-mode) + ad-do-it + (let (major-mode-chunk + (point-max (1+ (buffer-size))) ;(save-restriction (widen) (point-max))) + end-major-mode-chunk + (limit (+ rng-validate-up-to-date-end + rng-validate-chunk-size)) + (remove-start rng-validate-up-to-date-end) + (next-cache-point (+ (point) rng-state-cache-distance)) + (continue t) + (xmltok-dtd rng-dtd) + have-remaining-chars + xmltok-type + xmltok-start + xmltok-name-colon + xmltok-name-end + xmltok-replacement + xmltok-attributes + xmltok-namespace-attributes + xmltok-dependent-regions + xmltok-errors + (while-n1 0) + (while-n2 0) + (old-point -1) + ) + ;;(msgtrc "> > > > > enter rng-do-some-validation-1, continue-p-function=%s" continue-p-function) + (setq have-remaining-chars (< (point) point-max)) + (when (and continue (= (point) 1)) + (let ((regions (xmltok-forward-prolog))) + (rng-clear-overlays 1 (point)) + (while regions + (when (eq (aref (car regions) 0) 'encoding-name) + (rng-process-encoding-name (aref (car regions) 1) + (aref (car regions) 2))) + (setq regions (cdr regions)))) + (unless (equal rng-dtd xmltok-dtd) + (rng-clear-conditional-region)) + (setq rng-dtd xmltok-dtd)) + (setq while-n1 0) + (while (and (mumamo-while 2000 'while-n1 "continue") + (/= old-point (point)) + continue) + (setq old-point (point)) + ;; If mumamo (or something similar) is used then jump over parts + ;; that can not be parsed by nxml-mode. + (when (and rng-get-major-mode-chunk-function + rng-valid-nxml-major-mode-chunk-function + rng-end-major-mode-chunk-function) + (let ((here (point)) + next-non-space-pos) + (skip-chars-forward " \t\r\n") + (setq next-non-space-pos (point)) + (goto-char here) + (unless (and end-major-mode-chunk + ;; Remaining chars in this chunk? + (< next-non-space-pos end-major-mode-chunk)) + (setq end-major-mode-chunk nil) + (setq major-mode-chunk (funcall rng-get-major-mode-chunk-function next-non-space-pos "rng-do-some-validation-1 A")) + (setq while-n2 0) + (while (and (mumamo-while 500 'while-n2 "major-mode-chunk") + major-mode-chunk + (not (funcall rng-valid-nxml-major-mode-chunk-function major-mode-chunk)) + (< next-non-space-pos (point-max))) + ;;(msgtrc "next-non-space-pos=%s, cb=%s" next-non-space-pos (current-buffer)) + (let ((end-pos (funcall rng-end-major-mode-chunk-function major-mode-chunk))) + ;; fix-me: The problem here is that + ;; mumamo-find-chunks can return a 0-length chunk. + ;;(goto-char (+ end-pos 0)) + (goto-char (+ end-pos (if (= end-pos (point)) 1 0))) + (setq major-mode-chunk (funcall rng-get-major-mode-chunk-function (point) "rng-do-some-validation-1 B")) + ;;(message "---> here 3, point=%s, ep=%s, mm-chunk=%s" (point) end-pos major-mode-chunk) + ) + (setq next-non-space-pos (point)))) + ;; Stop parsing if we do not have a chunk here yet. + ;;(message "major-mode-chunk=%s" major-mode-chunk) + ;;(message "rng-valid-nxml-major-mode-chunk-function=%s" rng-valid-nxml-major-mode-chunk-function) + (setq continue (and major-mode-chunk + (funcall rng-valid-nxml-major-mode-chunk-function major-mode-chunk))) + ;;(unless continue (message "continue=nil, no major-mode-chunk")) + (when continue + ;;(message " continue=t") + (setq end-major-mode-chunk (funcall rng-end-major-mode-chunk-function major-mode-chunk))))) + + (when continue + ;; Narrow since rng-forward will continue into next chunk + ;; even if limit is at chunk end. + (if t + (progn + ;;(message "before rng-forward, point=%s" (point)) + (setq have-remaining-chars (rng-forward end-major-mode-chunk)) + ;;(message "after rng-forward, point=%s" (point)) + ) + ;; Fix-me: Validation does not work when narrowing because + ;; some state variables values seems to be lost. Probably + ;; looking at `rng-validate-prepare' will tell what to do. + (save-restriction + (when (and end-major-mode-chunk + (< (point-min) end-major-mode-chunk)) + (narrow-to-region (point-min) end-major-mode-chunk)) + (setq have-remaining-chars (rng-forward end-major-mode-chunk))) + (unless (> end-major-mode-chunk (point)) + ;;(setq have-remaining-chars t) + (goto-char end-major-mode-chunk)) + ) + ;;(message "end-major-mode-chunk=%s, rng-validate-up-to-date-end=%s" end-major-mode-chunk rng-validate-up-to-date-end) + (setq have-remaining-chars (< (point) point-max)) + ;;(unless have-remaining-chars (message "*** here have-remaining-chars=%s, p=%s/%s" have-remaining-chars (point) point-max)) + (let ((pos (point))) + (when end-major-mode-chunk + ;; Fix-me: Seems like we need a new initialization (or why + ;; do we otherwise hang without this?) + (and (> limit end-major-mode-chunk) (setq limit end-major-mode-chunk))) + (setq continue + (and have-remaining-chars + continue + (or (< pos limit) + (and continue-p-function + (funcall continue-p-function) + (setq limit (+ limit rng-validate-chunk-size)) + t)))) + ;;(unless continue (message "continue=nil, why?: %s<%s, %s" pos limit (when continue-p-function (funcall continue-p-function)))) + (cond ((and rng-conditional-up-to-date-start + ;; > because we are getting the state from (1- pos) + (> pos rng-conditional-up-to-date-start) + (< pos rng-conditional-up-to-date-end) + (rng-state-matches-current (get-text-property (1- pos) + 'rng-state))) + (when (< remove-start (1- pos)) + (rng-clear-cached-state remove-start (1- pos))) + ;; sync up with cached validation state + (setq continue nil) + ;; do this before settting rng-validate-up-to-date-end + ;; in case we get a quit + (rng-mark-xmltok-errors) + (rng-mark-xmltok-dependent-regions) + (setq rng-validate-up-to-date-end + (marker-position rng-conditional-up-to-date-end)) + (rng-clear-conditional-region) + (setq have-remaining-chars + (< rng-validate-up-to-date-end point-max)) + ;;(unless have-remaining-chars (message "have-remaining-chars=%s rng-validate-up-to-date-end=%s, point-max=%s" have-remaining-chars rng-validate-up-to-date-end point-max)) + ) + ((or (>= pos next-cache-point) + (not continue)) + (setq next-cache-point (+ pos rng-state-cache-distance)) + (rng-clear-cached-state remove-start pos) + (when have-remaining-chars + ;;(message "rng-cach-state (1- %s)" pos) + (rng-cache-state (1- pos))) + (setq remove-start pos) + (unless continue + ;; if we have just blank chars skip to the end + (when have-remaining-chars + (skip-chars-forward " \t\r\n") + (when (= (point) point-max) + (rng-clear-overlays pos (point)) + (rng-clear-cached-state pos (point)) + (setq have-remaining-chars nil) + ;;(message "have-remaining-chars => nil, cause (point) = point-max") + (setq pos (point)))) + (when (not have-remaining-chars) + (rng-process-end-document)) + (rng-mark-xmltok-errors) + (rng-mark-xmltok-dependent-regions) + (setq rng-validate-up-to-date-end pos) + (when rng-conditional-up-to-date-end + (cond ((<= rng-conditional-up-to-date-end pos) + (rng-clear-conditional-region)) + ((< rng-conditional-up-to-date-start pos) + (set-marker rng-conditional-up-to-date-start + pos)))))))))) + ;;(message "--- exit rng-do-some-validation-1, have-remaining-chars=%s" have-remaining-chars) + (setq have-remaining-chars (< (point) point-max)) + (setq ad-return-value have-remaining-chars)))) + +(defadvice rng-after-change-function (around + mumamo-ad-rng-after-change-function + activate + compile) + (when rng-validate-up-to-date-end + ad-do-it)) + +(defadvice rng-validate-while-idle (around + mumamo-ad-rng-validate-while-idle + activate + compile) + (if (not (buffer-live-p buffer)) + (rng-kill-timers) + ad-do-it)) + +(defadvice rng-validate-quick-while-idle (around + mumamo-ad-rng-validate-quick-while-idle + activate + compile) + (if (not (buffer-live-p buffer)) + (rng-kill-timers) + ad-do-it)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; xmltok.el + +;; (ad-disable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) +;; (ad-ensable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) +(defadvice xmltok-add-error (around + mumamo-ad-xmltok-add-error + activate + compile + ) + "Prevent rng validation errors in non-xml chunks. +This advice only prevents adding nxml/rng-valid errors in non-xml +chunks. Doing more seems like a very big job - unless Emacs gets +a narrow-to-multiple-regions function!" + (if (not mumamo-multi-major-mode) + ad-do-it + ;;(error "xmltok-add-error: %S" (with-output-to-string (backtrace))) + (when (let* ((start (or start xmltok-start)) + (end (or end (point))) + (chunk (mumamo-find-chunks (if start start end) "xmltok-add-error")) + ) + (or (not chunk) + (and (not (overlay-get chunk 'mumamo-region)) + (mumamo-valid-nxml-chunk chunk)))) + (setq xmltok-errors + (cons (xmltok-make-error message + (or start xmltok-start) + (or end (point))) + xmltok-errors))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Maybe activate advices + +;; Fix-me: This assumes there are no other advices on these functions. +(if t + (progn + ;; (ad-activate 'syntax-ppss) + ;; (ad-activate 'syntax-ppss-flush-cache) + ;; (ad-activate 'syntax-ppss-stats) + ;; (ad-activate 'rng-do-some-validation-1) + ;; (ad-activate 'rng-mark-error) + ;; (ad-activate 'xmltok-add-error) + (ad-enable-advice 'syntax-ppss 'around 'mumamo-ad-syntax-ppss) + (ad-enable-advice 'syntax-ppss-flush-cache 'around 'mumamo-ad-syntax-ppss-flush-cache) + (ad-enable-advice 'syntax-ppss-stats 'around 'mumamo-ad-syntax-ppss-stats) + (ad-enable-advice 'rng-do-some-validation-1 'around 'mumamo-ad-rng-do-some-validation-1) + (ad-enable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) + (ad-enable-advice 'rng-after-change-function 'around 'mumamo-ad-rng-after-change-function) + (ad-enable-advice 'rng-validate-while-idle 'around 'mumamo-ad-rng-validate-while-idle) + (ad-enable-advice 'rng-validate-quick-while-idle 'around 'mumamo-ad-rng-validate-quick-while-idle) + (ad-enable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) + ) + ;; (ad-deactivate 'syntax-ppss) + ;; (ad-deactivate 'syntax-ppss-flush-cache) + ;; (ad-deactivate 'syntax-ppss-stats) + ;; (ad-deactivate 'rng-do-some-validation-1) + ;; (ad-deactivate 'rng-mark-error) + ;; (ad-deactivate 'xmltok-add-error) + (ad-disable-advice 'syntax-ppss 'around 'mumamo-ad-syntax-ppss) + (ad-disable-advice 'syntax-ppss-flush-cache 'around 'mumamo-ad-syntax-ppss-flush-cache) + (ad-disable-advice 'syntax-ppss-stats 'around 'mumamo-ad-syntax-ppss-stats) + (ad-disable-advice 'rng-do-some-validation-1 'around 'mumamo-ad-rng-do-some-validation-1) + (ad-disable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) + (ad-disable-advice 'rng-after-change-function 'around 'mumamo-ad-rng-after-change-function) + (ad-disable-advice 'rng-validate-while-idle 'around 'mumamo-ad-rng-validate-while-idle) + (ad-disable-advice 'rng-validate-quick-while-idle 'around 'mumamo-ad-rng-validate-quick-while-idle) + (ad-disable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) + ) + +(font-lock-add-keywords + 'emacs-lisp-mode + '(("\\<define-mumamo-multi-major-mode\\>" . font-lock-keyword-face))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Simple defadvice to move into Emacs later + +(defun mumamo-ad-desktop-buffer-info (buffer) + (set-buffer buffer) + (list + ;; base name of the buffer; replaces the buffer name if managed by uniquify + (and (fboundp 'uniquify-buffer-base-name) (uniquify-buffer-base-name)) + ;; basic information + (desktop-file-name (buffer-file-name) desktop-dirname) + (buffer-name) + (if mumamo-multi-major-mode mumamo-multi-major-mode major-mode) + ;; minor modes + (let (ret) + (mapc + #'(lambda (minor-mode) + (and (boundp minor-mode) + (symbol-value minor-mode) + (let* ((special (assq minor-mode desktop-minor-mode-table)) + (value (cond (special (cadr special)) + ((functionp minor-mode) minor-mode)))) + (when value (add-to-list 'ret value))))) + (mapcar #'car minor-mode-alist)) + ret) + ;; point and mark, and read-only status + (point) + (list (mark t) mark-active) + buffer-read-only + ;; auxiliary information + (when (functionp desktop-save-buffer) + (funcall desktop-save-buffer desktop-dirname)) + ;; local variables + (let ((locals desktop-locals-to-save) + (loclist (buffer-local-variables)) + (ll)) + (while locals + (let ((here (assq (car locals) loclist))) + (if here + (setq ll (cons here ll)) + (when (member (car locals) loclist) + (setq ll (cons (car locals) ll))))) + (setq locals (cdr locals))) + ll))) + +(defadvice desktop-buffer-info (around + mumamo-ad-desktop-buffer-info + activate + compile) + (setq ad-return-value (mumamo-ad-desktop-buffer-info (ad-get-arg 0)))) + +(defun mumamo-ad-set-auto-mode-0 (mode &optional keep-mode-if-same) + "Apply MODE and return it. +If optional arg KEEP-MODE-IF-SAME is non-nil, MODE is chased of +any aliases and compared to current major mode. If they are the +same, do nothing and return nil." + (unless (and keep-mode-if-same + (eq (indirect-function mode) + (if mumamo-multi-major-mode + (indirect-function mumamo-multi-major-mode) + (indirect-function major-mode)))) + (when mode + (funcall mode) + mode))) + +(defadvice set-auto-mode-0 (around + mumamo-ad-set-auto-mode-0 + activate + compile) + (setq ad-return-value (mumamo-ad-set-auto-mode-0 (ad-get-arg 0) + (ad-get-arg 1) + ))) + + + +(defvar mumamo-sgml-get-context-last-close nil + "Last close tag start. +Only used for outermost level.") + +(defun mumamo-sgml-get-context (&optional until) + "Determine the context of the current position. +By default, parse until we find a start-tag as the first thing on a line. +If UNTIL is `empty', return even if the context is empty (i.e. +we just skipped over some element and got to a beginning of line). + +The context is a list of tag-info structures. The last one is the tag +immediately enclosing the current position. + +Point is assumed to be outside of any tag. If we discover that it's +not the case, the first tag returned is the one inside which we are." + (let ((here (point)) + (stack nil) + (ignore nil) + (context nil) + tag-info + last-close) + ;; CONTEXT keeps track of the tag-stack + ;; STACK keeps track of the end tags we've seen (and thus the start-tags + ;; we'll have to ignore) when skipping over matching open..close pairs. + ;; IGNORE is a list of tags that can be ignored because they have been + ;; closed implicitly. + ;; LAST-CLOSE is last close tag that can be useful for indentation + ;; when on outermost level. + (skip-chars-backward " \t\n") ; Make sure we're not at indentation. + (while + (and (not (eq until 'now)) + (or stack + (not (if until (eq until 'empty) context)) + (not (sgml-at-indentation-p)) + (and context + (/= (point) (sgml-tag-start (car context))) + (sgml-unclosed-tag-p (sgml-tag-name (car context))))) + (setq tag-info (ignore-errors (sgml-parse-tag-backward)))) + + ;; This tag may enclose things we thought were tags. If so, + ;; discard them. + (while (and context + (> (sgml-tag-end tag-info) + (sgml-tag-end (car context)))) + (setq context (cdr context))) + + (cond + ((> (sgml-tag-end tag-info) here) + ;; Oops!! Looks like we were not outside of any tag, after all. + (push tag-info context) + (setq until 'now)) + + ;; start-tag + ((eq (sgml-tag-type tag-info) 'open) + (when (and (null stack) + last-close) + (setq last-close 'no-use)) + (cond + ((null stack) + (if (assoc-string (sgml-tag-name tag-info) ignore t) + ;; There was an implicit end-tag. + nil + (push tag-info context) + ;; We're changing context so the tags implicitly closed inside + ;; the previous context aren't implicitly closed here any more. + ;; [ Well, actually it depends, but we don't have the info about + ;; when it doesn't and when it does. --Stef ] + (setq ignore nil))) + ((eq t (compare-strings (sgml-tag-name tag-info) nil nil + (car stack) nil nil t)) + (setq stack (cdr stack))) + (t + ;; The open and close tags don't match. + (if (not sgml-xml-mode) + (unless (sgml-unclosed-tag-p (sgml-tag-name tag-info)) + (message "Unclosed tag <%s>" (sgml-tag-name tag-info)) + (let ((tmp stack)) + ;; We could just assume that the tag is simply not closed + ;; but it's a bad assumption when tags *are* closed but + ;; not properly nested. + (while (and (cdr tmp) + (not (eq t (compare-strings + (sgml-tag-name tag-info) nil nil + (cadr tmp) nil nil t)))) + (setq tmp (cdr tmp))) + (if (cdr tmp) (setcdr tmp (cddr tmp))))) + (message "Unmatched tags <%s> and </%s>" + (sgml-tag-name tag-info) (pop stack))))) + + (if (and (null stack) (sgml-unclosed-tag-p (sgml-tag-name tag-info))) + ;; This is a top-level open of an implicitly closed tag, so any + ;; occurrence of such an open tag at the same level can be ignored + ;; because it's been implicitly closed. + (push (sgml-tag-name tag-info) ignore))) + + ;; end-tag + ((eq (sgml-tag-type tag-info) 'close) + (if (sgml-empty-tag-p (sgml-tag-name tag-info)) + (message "Spurious </%s>: empty tag" (sgml-tag-name tag-info)) + ;; Keep track of last close if context will return nil + (when (and (not last-close) + (null stack) + (> here (point-at-eol)) + (let ((here (point))) + (goto-char (sgml-tag-start tag-info)) + (skip-chars-backward " \t") + (prog1 + (bolp) + (goto-char here)))) + (setq last-close tag-info)) + + (push (sgml-tag-name tag-info) stack))) + )) + + ;; return context + (setq mumamo-sgml-get-context-last-close + (when (and last-close + (not (eq last-close 'no-use))) + (sgml-tag-start last-close))) + context)) + +(defadvice sgml-get-context (around + mumamo-ad-sgml-get-context + activate + compile) + (setq ad-return-value (mumamo-sgml-get-context (ad-get-arg 0)))) + +(defun mumamo-sgml-calculate-indent (&optional lcon) + "Calculate the column to which this line should be indented. +LCON is the lexical context, if any." + (unless lcon (setq lcon (sgml-lexical-context))) + + ;; Indent comment-start markers inside <!-- just like comment-end markers. + (if (and (eq (car lcon) 'tag) + (looking-at "--") + (save-excursion (goto-char (cdr lcon)) (looking-at "<!--"))) + (setq lcon (cons 'comment (+ (cdr lcon) 2)))) + + (case (car lcon) + + (string + ;; Go back to previous non-empty line. + (while (and (> (point) (cdr lcon)) + (zerop (forward-line -1)) + (looking-at "[ \t]*$"))) + (if (> (point) (cdr lcon)) + ;; Previous line is inside the string. + (current-indentation) + (goto-char (cdr lcon)) + (1+ (current-column)))) + + (comment + (let ((mark (looking-at "--"))) + ;; Go back to previous non-empty line. + (while (and (> (point) (cdr lcon)) + (zerop (forward-line -1)) + (or (looking-at "[ \t]*$") + (if mark (not (looking-at "[ \t]*--")))))) + (if (> (point) (cdr lcon)) + ;; Previous line is inside the comment. + (skip-chars-forward " \t") + (goto-char (cdr lcon)) + ;; Skip `<!' to get to the `--' with which we want to align. + (search-forward "--") + (goto-char (match-beginning 0))) + (when (and (not mark) (looking-at "--")) + (forward-char 2) (skip-chars-forward " \t")) + (current-column))) + + ;; We don't know how to indent it. Let's be honest about it. + (cdata nil) + ;; We don't know how to indent it. Let's be honest about it. + (pi nil) + + (tag + (goto-char (1+ (cdr lcon))) + (skip-chars-forward "^ \t\n") ;Skip tag name. + (skip-chars-forward " \t") + (if (not (eolp)) + (current-column) + ;; This is the first attribute: indent. + (goto-char (1+ (cdr lcon))) + (+ (current-column) sgml-basic-offset))) + + (text + (while (looking-at "</") + (forward-sexp 1) + (skip-chars-forward " \t")) + (let* ((here (point)) + (unclosed (and ;; (not sgml-xml-mode) + (looking-at sgml-tag-name-re) + (assoc-string (match-string 1) + sgml-unclosed-tags 'ignore-case) + (match-string 1))) + (context + ;; If possible, align on the previous non-empty text line. + ;; Otherwise, do a more serious parsing to find the + ;; tag(s) relative to which we should be indenting. + (if (and (not unclosed) (skip-chars-backward " \t") + (< (skip-chars-backward " \t\n") 0) + (back-to-indentation) + (> (point) (cdr lcon))) + nil + (goto-char here) + (nreverse (sgml-get-context (if unclosed nil 'empty))))) + (there (point))) + ;; Ignore previous unclosed start-tag in context. + (while (and context unclosed + (eq t (compare-strings + (sgml-tag-name (car context)) nil nil + unclosed nil nil t))) + (setq context (cdr context))) + ;; Indent to reflect nesting. + (cond + ;; If we were not in a text context after all, let's try again. + ((and context (> (sgml-tag-end (car context)) here)) + (goto-char here) + (sgml-calculate-indent + (cons (if (memq (sgml-tag-type (car context)) '(comment cdata)) + (sgml-tag-type (car context)) 'tag) + (sgml-tag-start (car context))))) + ;; Align on the first element after the nearest open-tag, if any. + ((and context + (goto-char (sgml-tag-end (car context))) + (skip-chars-forward " \t\n") + (< (point) here) (sgml-at-indentation-p)) + (current-column)) + (t + (goto-char (or (and (null context) + mumamo-sgml-get-context-last-close) + there)) + (+ (current-column) + (* sgml-basic-offset (length context))))))) + + (otherwise + (error "Unrecognized context %s" (car lcon))) + + )) + +(defadvice sgml-calculate-indent (around + mumamo-ad-sgml-calculate-indent + activate + compile) + (setq ad-return-value (mumamo-sgml-calculate-indent (ad-get-arg 0)))) + +(defadvice python-eldoc-function (around + mumamo-ad-python-eldoc-function + activate + compile) + (if (not mumamo-multi-major-mode) + ad-do-it + (let ((here (point))) + (unwind-protect + (save-restriction + (mumamo-narrow-to-chunk-inner) + ad-do-it) + (goto-char here))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; The END +;;(when buffer-file-name (message "Finished evaluating %s" buffer-file-name)) +;;(when load-file-name (message "Finished loading %s" load-file-name)) + +(provide 'mumamo) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo.el ends bere diff --git a/emacs/nxhtml/util/n-back.el b/emacs/nxhtml/util/n-back.el new file mode 100644 index 0000000..024b8e6 --- /dev/null +++ b/emacs/nxhtml/util/n-back.el @@ -0,0 +1,1296 @@ +;;; n-back.el --- n-back game +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-05-23 Sat +(defconst n-back:version "0.5");; Version: +;; Last-Updated: 2009-08-04 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `winsize'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; n-back game for brain training. See `n-back-game' for more +;; information. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +;;(eval-when-compile (require 'viper)) + +;; (setq n-back-trials 2) +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'nxhtml-base nil t)) +(eval-when-compile (require 'nxhtml-web-vcs nil t)) +(require 'winsize nil t) ;; Ehum... + +(defvar n-back-game-window nil) +(defvar n-back-game-buffer nil) + +(defvar n-back-ctrl-window nil) +(defvar n-back-ctrl-buffer nil) + +(defvar n-back-info-window nil) +(defvar n-back-info-buffer nil) + +(defvar n-back-trials-left nil) +(defvar n-back-timer nil) +(defvar n-back-clear-timer nil) + +(defvar n-back-result nil) +(defvar n-back-this-result nil) + +(defvar n-back-ring nil) + +(defvar n-back-num-active nil) + + +;;;###autoload +(defgroup n-back nil + "Customizations for `n-back-game' game." + :group 'games) + +(defgroup n-back-feel nil + "Customizations for `n-back-game' game keys, faces etc." + :group 'n-back) + +(defface n-back-ok + '((t (:foreground "black" :background "green"))) + "Face for OK answer." + :group 'n-back-feel) + +(defface n-back-bad + '((t (:foreground "black" :background "OrangeRed1"))) + "Face for bad answer." + :group 'n-back-feel) + +(defface n-back-hint + '((t (:foreground "black" :background "gold"))) + "Face for bad answer." + :group 'n-back-feel) + +(defface n-back-do-now + '((((background dark)) (:foreground "yellow")) + (t (:foreground "blue"))) + "Face for start and stop hints." + :group 'n-back-feel) + +(defface n-back-game-word + '((t (:foreground "black"))) + "Face for word displayed in game." + :group 'n-back-feel) + +(defface n-back-header + '((((background dark)) (:background "OrangeRed4")) + (t (:background "gold"))) + "Face for headers." + :group 'n-back-feel) + +(defface n-back-keybinding + '((((background dark)) (:background "purple4")) + (t (:background "OliveDrab1"))) + "Face for key bindings." + :group 'n-back-feel) + +(defface n-back-last-result + '((((background dark)) (:background "OliveDrab4")) + (t (:background "yellow"))) + "Face for last game result header." + :group 'n-back-feel) + +(defface n-back-welcome + '((((background dark)) (:foreground "OliveDrab3")) + (t (:foreground "OliveDrab4"))) + "Face for welcome string" + :group 'n-back-feel) + +(defface n-back-welcome-header + '((t (:height 2.0))) + "Face for welcome header." + :group 'n-back-feel) + +(defcustom n-back-level 1 + "The n-Back level." + :type '(radio (const 1) + (const 2) + (const 3) + (const 4)) + :set (lambda (sym val) + (set-default sym val) + (when (featurep 'n-back) + (n-back-update-control-buffer) + (n-back-update-info))) + :group 'n-back) + +(defcustom n-back-active-match-types '(position color sound) + "Active match types." + :type '(set (const position) + (const color) + (const sound) + (const word)) + :set (lambda (sym val) + (set-default sym val) + (setq n-back-num-active (length val)) + (when (featurep 'n-back) + (n-back-init-control-status) + (n-back-update-control-buffer) + (n-back-update-info))) + :group 'n-back) + +(defcustom n-back-allowed-match-types '(position color sound word) + "Match types allowed in auto challenging." + :type '(set (const position) + (const color) + (const sound) + (const word)) + :set (lambda (sym val) + (set-default sym val) + (when (featurep 'n-back) + (n-back-set-random-match-types (length n-back-active-match-types) nil) + (n-back-init-control-status) + (n-back-update-control-buffer) + (n-back-update-info))) + :group 'n-back) + +(defcustom n-back-auto-challenge t + "Automatic challenge decrease/increase." + :type 'boolean + :group 'n-back) + +(defun n-back-toggle-auto-challenge () + "Toggle `n-back-auto-challenge'." + (interactive) + (let ((val (not n-back-auto-challenge))) + (customize-set-variable 'n-back-auto-challenge val) + (customize-set-value 'n-back-auto-challenge val))) + +(defcustom n-back-colors + '("gold" "orange red" "lawn green" "peru" "pink" "gray" "light blue") + "Random colors to display." + :type '(repeat color) + :group 'n-back) + +(defcustom n-back-words "you cat going me forest crying brown" + "Random words to display." + :type 'string + :group 'n-back) + +(defcustom n-back-sound-volume 0.2 + "Sound volume 0-1." + :type 'float + :group 'n-back-feel) + +(defcustom n-back-sounds '("c:/program files/brain workshop/res" "piano-") + "Random sounds location." + :type '(list (directory :tag "Directory") + (regexp :tag "File name regexp")) + :group 'n-back) + +(defcustom n-back-keys + '( + [?p] + [?c] + [?s] + [?w] + ) + "Key bindings for answering." + :type '(list + (key-sequence :tag "position key") + (key-sequence :tag "color key") + (key-sequence :tag "sound key") + (key-sequence :tag "word key") + ) + ;; :set (lambda (sym val) + ;; (set-default sym val) + ;; (n-back-make-keymap)) + :group 'n-back-feel) + +(defvar n-back-control-mode-map nil) + +(defun n-back-key-binding (what) + "Return key binding used for WHAT match answers." + (nth + (case what + (position 0) + (color 1) + (sound 2) + (word 3)) + n-back-keys)) + +(defun n-back-make-keymap () + "Make keymap for the game." + (let ((map (make-sparse-keymap))) + (define-key map [?1] 'n-back-change-level) + (define-key map [?2] 'n-back-change-level) + (define-key map [?3] 'n-back-change-level) + (define-key map [?4] 'n-back-change-level) + (define-key map [?5] 'n-back-change-level) + (define-key map [?6] 'n-back-change-level) + (define-key map [??] 'n-back-help) + (define-key map [?\ ] 'n-back-play) + (define-key map [(control ?g)] 'n-back-stop) + (define-key map [?-] 'n-back-decrease-speed) + (define-key map [?+] 'n-back-increase-speed) + + (define-key map [(control ?r)] 'n-back-reset-game-to-saved) + (define-key map [(control ?s)] 'n-back-save-game-settings) + + (define-key map [?t ?p] 'n-back-toggle-position) + (define-key map [?t ?c] 'n-back-toggle-color) + (define-key map [?t ?s] 'n-back-toggle-sound) + (define-key map [?t ?w] 'n-back-toggle-word) + + (define-key map [?T ?a] 'n-back-toggle-auto-challenge) + (define-key map [up] 'n-back-challenge-up) + (define-key map [down] 'n-back-challenge-down) + + (define-key map [?T ?p] 'n-back-toggle-allowed-position) + (define-key map [?T ?c] 'n-back-toggle-allowed-color) + (define-key map [?T ?s] 'n-back-toggle-allowed-sound) + (define-key map [?T ?w] 'n-back-toggle-allowed-word) + + (define-key map (n-back-key-binding 'position) 'n-back-position-answer) + (define-key map (n-back-key-binding 'color) 'n-back-color-answer) + (define-key map (n-back-key-binding 'sound) 'n-back-sound-answer) + (define-key map (n-back-key-binding 'word) 'n-back-word-answer) + ;;(define-key map [t] 'ignore) + (setq n-back-control-mode-map map))) + +(defvar n-back-display-hint nil) +(defcustom n-back-hint t + "Display hints - learning mode." + :type 'boolean + :group 'n-back) + + + +(defvar n-back-sound-files nil) +;;(n-back-get-sound-files) +(defun n-back-get-sound-files () + "Get sound file names." + (let ((dir (nth 0 n-back-sounds)) + (regexp (nth 1 n-back-sounds))) + (when (file-directory-p dir) + (setq n-back-sound-files (directory-files dir nil regexp))))) + +(defun n-back-toggle-position () + "Toggle use of position in `n-back-active-match-types'." + (interactive) + (n-back-toggle 'position)) + +(defun n-back-toggle-color () + "Toggle use of color in `n-back-active-match-types'." + (interactive) + (n-back-toggle 'color)) + +(defun n-back-toggle-sound () + "Toggle use of sound in `n-back-active-match-types'." + (interactive) + (n-back-toggle 'sound)) + +(defun n-back-toggle-word () + "Toggle use of word in `n-back-active-match-types'." + (interactive) + (n-back-toggle 'word)) + +(defun n-back-toggle (match-type) + "Toggle use of MATCH-TYPE in `n-back-active-match-types'." + (n-back-toggle-1 match-type 'n-back-active-match-types)) + +(defun n-back-toggle-allowed-position () + "Toggle use of position in `n-back-allowed-match-types'." + (interactive) + (n-back-toggle-allowed 'position)) + +(defun n-back-toggle-allowed-color () + "Toggle use of color in `n-back-allowed-match-types'." + (interactive) + (n-back-toggle-allowed 'color)) + +(defun n-back-toggle-allowed-sound () + "Toggle use of sound in `n-back-allowed-match-types'." + (interactive) + (n-back-toggle-allowed 'sound)) + +(defun n-back-toggle-allowed-word () + "Toggle use of word in `n-back-allowed-match-types'." + (interactive) + (n-back-toggle-allowed 'word)) + +(defun n-back-toggle-allowed (match-type) + "Toggle use of MATCH-TYPE in `n-back-allowed-match-types'." + (n-back-toggle-1 match-type 'n-back-allowed-match-types)) + +(defun n-back-sort-types (types) + "Sort TYPES to order used in defcustoms here." + (sort types + (lambda (a b) + (let ((all '(position color sound word))) + (< (length (memq a all)) + (length (memq b all))))))) + +(defun n-back-toggle-1 (match-type active-list-sym) + "Toggle use of MATCH-TYPE in list ACTIVE-LIST-SYM." + (let (active-types) + (if (memq match-type (symbol-value active-list-sym)) + (setq active-types (delq match-type (symbol-value active-list-sym))) + (setq active-types (cons match-type (symbol-value active-list-sym)))) + (setq active-types (n-back-sort-types active-types)) + (customize-set-variable active-list-sym active-types) + (customize-set-value active-list-sym active-types))) + +(defcustom n-back-sec-per-trial 3.0 + "Seconds per trial." + :type 'float + :set (lambda (sym val) + (set-default sym val) + (when (featurep 'n-back) + (n-back-update-info))) + :group 'n-back) + +(defun n-back-decrease-speed () + "Decrease speed of trials." + (interactive) + (setq n-back-sec-per-trial (+ n-back-sec-per-trial 0.25)) + (when (> n-back-sec-per-trial 5.0) + (setq n-back-sec-per-trial 5.0)) + (n-back-update-info)) + +(defun n-back-increase-speed () + "Increase speed of trials." + (interactive) + (let ((sec (- n-back-sec-per-trial 0.25))) + (when (< sec 1.0) + (setq sec 1.0)) + (customize-set-variable 'n-back-sec-per-trial sec) + (customize-set-value 'n-back-sec-per-trial sec))) + +(defun n-back-help () + "Show help for `n-back-game' game." + (interactive) + (save-selected-window + (describe-function 'n-back-game))) + +(defun n-back-change-level (level) + "Change n-Back level to LEVEL." + (interactive (progn + (if (and (numberp last-input-event) + (>= last-input-event ?1) + (<= last-input-event ?9)) + (list (- last-input-event ?0)) + (list (string-to-number (read-string "n Back: ")))))) + (customize-set-variable 'n-back-level level) + (customize-set-value 'n-back-level level)) + +(defvar n-back-frame nil) + +;;;###autoload +(defun n-back-game () + "Emacs n-Back game. +This game is supposed to increase your working memory and fluid +intelligence. + +In this game something is shown for half a second on the screen +and maybe a sound is played. You should then answer if parts of +it is the same as you have seen or heard before. This is +repeated for about 20 trials. + +You answer with the keys shown in the bottom window. + +In the easiest version of the game you should answer if you have +just seen or heard what is shown now. By default the game gets +harder as you play it with success. Then first the number of +items presented in a trial grows. After that it gets harder by +that you have to somehow remember not the last item, but the item +before that \(or even earlier). That is what \"n-Back\" stands +for. + +Note that remember does not really mean remember clearly. The +game is for training your brain getting used to keep those things +in the working memory, maybe as a cross-modal unit. You are +supposed to just nearly be able to do what you do in the game. +And you are supposed to have fun, that is what your brain like. + +You should probably not overdue this. Half an hour a day playing +might be an optimal time according to some people. + +The game is shamelessly modeled after Brain Workshop, see URL +`http://brainworkshop.sourceforge.net/' just for the fun of +getting it into Emacs. The game resembles but it not the same as +that used in the report by Jaeggi mentioned at the above URL. + +Not all features in Brain Workshop are implemented here, but some +new are maybe ... - and you have it available here in Emacs." + ;; ----- + ;; Below is a short excerpt from the report by Jaeggi et al which + ;; gave the idea to the game: + + ;; Training task. For the training task, we used the same material + ;; as described by Jaeggi et al. (33), which was a dual n-Back task + ;; where squares at eight different locations were presented + ;; sequentially on a computer screen at a rate of 3 s (stimulus + ;; length, 500 ms; interstimulus interval, 2,500 ms). + ;; Simultaneously with the presentation of the squares, one of eight + ;; consonants was presented sequentially through headphones. A + ;; response was required whenever one of the presented stimuli + ;; matched the one presented n positions back in the sequence. The + ;; value of n was the same for both streams of stimuli. There were + ;; six auditory and six visual targets per block (four appearing in + ;; only one modality, and two appearing in both modalities + ;; simultaneously), and their positions were determined randomly. + ;; Participants made responses manually by pressing on the letter + ;; ââAââ of a standard keyboard with their left index finger for + ;; visual targets, and on the letter ââLââ with their right index + ;; finger for auditory targets. No responses were required for + ;; non-targets. + (interactive) + (n-back-make-keymap) + (when window-system + (unless (frame-live-p n-back-frame) + (setq n-back-frame (make-frame + (list '(name . "n-back game") + '(tool-bar-lines . 0) + '(menu-bar-lines . 0) + (case (frame-parameter nil 'background-mode) + (light '(background-color . "cornsilk")) + (dark '(background-color . "MidnightBlue")) + (otherwise nil)) + '(height . 45) + '(width . 150))))) + (select-frame n-back-frame) + (raise-frame n-back-frame)) + (n-back-cancel-timers) + (n-back-get-sound-files) + (unless n-back-sound-files + (when (memq 'sound n-back-allowed-match-types) + (n-back-toggle-allowed-sound)) + (when (memq 'sound n-back-active-match-types) + (n-back-toggle-sound))) + (n-back-init-control-status) + (n-back-setup-windows) + ) + +(defconst n-back-match-types + '((position ": position match" nil) + (color ": color match" nil) + (sound ": sound match" nil) + (word ": word match" nil) + )) + +(defvar n-back-control-status nil + "For showing status in control window.") +(setq n-back-control-status nil) + +;;(n-back-set-match-status 'position 'bad) +(defun n-back-set-match-status (match-type status) + "Set MATCH-TYPE status to STATUS for control window." + (unless (memq status '(ok bad miss nil)) (error "n-back: Bad status=%s" status)) + (let ((entry (assoc match-type n-back-control-status))) + (setcar (cddr entry) status) + )) + +;;(n-back-clear-match-status) +(defun n-back-clear-match-status () + "Clear match status for control window." + ;;(dolist (entry n-back-control-status) + (dolist (entry n-back-match-types) + (setcar (cddr entry) nil) + )) + +;; (n-back-init-control-status) +(defun n-back-init-control-status () + "Init match status for control window." + (setq n-back-control-status nil) + (dolist (what n-back-active-match-types) + (setq n-back-control-status + (cons (assoc what n-back-match-types) + n-back-control-status)))) + +(defsubst n-back-is-playing () + "Return non-nil when game is active." + (timerp n-back-timer)) + +;;(n-back-update-control-buffer) +(defun n-back-update-control-buffer () + "Update content of control buffer." + (save-match-data ;; runs in timer + (when (buffer-live-p n-back-ctrl-buffer) + (with-current-buffer n-back-ctrl-buffer + (setq buffer-read-only nil) + (erase-buffer) + (insert (propertize (format "%s %s-back" + (let ((n (length n-back-active-match-types))) + (cond + ((= 1 n) "Single") + ((= 2 n) "Dual") + ((= 3 n) "Triple") + )) + n-back-level + ) 'face 'n-back-header) + (propertize + (if (n-back-is-playing) " Press C-g to stop" " Press SPACE to play") + 'face 'n-back-do-now) + (if (n-back-is-playing) (format " Left %s" n-back-trials-left) "") + "\n") + ;;(unless n-back-control-status (n-back-init-control-status)) + (dolist (entry n-back-control-status) + (let* ((what (nth 0 entry)) + (msg (nth 1 entry)) + (sts (nth 2 entry)) + (key (key-description (n-back-key-binding what)))) + ;;(setq msg (concat (key-description (n-back-key-binding what)) msg)) + (cond + ((eq sts 'bad) + (setq msg (propertize (concat key msg) 'face 'n-back-bad))) + ((eq sts 'ok) + (setq msg (propertize (concat key msg) 'face 'n-back-ok))) + ((eq sts 'miss) + (setq msg (concat + (if n-back-display-hint + (propertize key 'face 'n-back-header) + key) + msg))) + ((not sts) + (setq msg (concat key msg))) + (t + (error "n-back:Unknown sts=%s" sts) + )) + (insert msg " ")) + ) + (when n-back-display-hint + (setq n-back-display-hint nil) + (run-with-timer 0.1 nil 'n-back-update-control-buffer)) + (setq buffer-read-only t) + (if (window-live-p n-back-ctrl-window) + (with-selected-window n-back-ctrl-window + (goto-char 1)) + (goto-char 1)))))) + +(defcustom n-back-trials 20 + "Number of trials per session." + :type 'integer + :group 'n-back) + +;;(n-back-compute-result-values n-back-result) +(defvar n-back-result-values nil) +(defun n-back-compute-single-result-value (entry) + "Compute result stored in ENTRY." + (let* ((what (nth 0 entry)) + (good (nth 1 entry)) + (bad (nth 2 entry)) + (miss (nth 3 entry)) + (err (+ bad miss)) + ;;(tot (+ good bad miss 0.0)) + ;;(gnum 6) + ;;(weighted-err (* err (/ gnum tot))) + ) + (cons what (if (= 0 good) + 0 + (/ (- n-back-trials err 0.0) + n-back-trials))))) + +(defun n-back-compute-result-values (result) + "Compute result values from game result RESULT." + (let ((results nil)) + (dolist (entry result) + (let ((res (n-back-compute-single-result-value entry))) + (setq results (cons res results)))) + (setq n-back-result-values (reverse results)))) + +;; Thresholds +(defun n-back-view-threshold-discussion-page () + "View some discussion of threshold." + (interactive) + (browse-url "http://groups.google.com/group/brain-training/browse_thread/thread/f4bfa452943c2a2d/ba31adfd0b97771c?lnk=gst&q=threshold#ba31adfd0b97771c")) + +;;(n-back-set-next-challenge) +(defvar n-back-worst nil) + +(defvar n-back-challenge-change nil) + +(defun n-back-set-next-challenge () + "Set next game difficulty level from last game result." + (let ((r 2.8)) ;; stay as default + (setq n-back-worst nil) + (dolist (res n-back-result-values) + (when (< (cdr res) r) + (setq r (cdr res)) + (setq n-back-worst res))) + (setq n-back-challenge-change (if (< r 0.74) + 'down + (if (> r 0.91) + 'up + 'stay))) + (n-back-change-challenge n-back-challenge-change))) + +(defun n-back-challenge-up () + "Make the game harder." + (interactive) + (n-back-change-challenge 'up)) + +(defun n-back-challenge-down () + "Make the game easier." + (interactive) + (n-back-change-challenge 'down)) + +(defun n-back-change-challenge (challenge-change) + "Change game difficulty level by CHALLENGE-CHANGE." + (let ((new-level n-back-level) + (new-num-active n-back-num-active) + (num-allowed (length n-back-allowed-match-types))) + (case challenge-change + (down + (if (= 1 n-back-num-active) + (unless (= 1 n-back-level) + (setq new-num-active (min 3 num-allowed)) + (setq new-level (1- n-back-level))) + (setq new-num-active (1- n-back-num-active)))) + (up + (if (or (<= 3 n-back-num-active) + (<= num-allowed n-back-num-active)) + (progn + (setq new-level (1+ n-back-level)) + (setq new-num-active 1)) + (setq new-num-active (min 3 (1+ n-back-num-active)))))) + ;;(when (= new-level 0) (setq new-level 1)) + ;;(when (= new-num-active 0) (setq new-num-active 1)) + (when (and (= new-level n-back-level) + (= new-num-active n-back-num-active)) + (setq n-back-challenge-change 'stay)) + (unless (= new-level n-back-level) + (customize-set-variable 'n-back-level new-level) + (customize-set-value 'n-back-level new-level)) + (n-back-set-random-match-types new-num-active (car n-back-worst)))) + +(defun n-back-set-random-match-types (num worst) + "Select NUM random match types. +If type WORST is non-nil try to include that." + (let ((alen (length n-back-allowed-match-types)) + (old-types n-back-active-match-types) + types) + (unless (<= num alen) + (error "n-back: Too many match types required = %s" num)) + (when (and worst + (< 1 num) + (memq worst n-back-allowed-match-types)) + (add-to-list 'types worst)) + (while (< (length types) num) + (add-to-list 'types (nth (random alen) n-back-allowed-match-types))) + (setq types (n-back-sort-types types)) + (unless (equal old-types types) + (customize-set-variable 'n-back-active-match-types types) + (customize-set-value 'n-back-active-match-types types)))) + +;; (defcustom n-back-keybinding-color "OliveDrab1" +;; "Background color for key binding hints." +;; :type 'color +;; :group 'n-back) + +(defun n-back-update-info () + "Update info buffer." + (when (buffer-live-p n-back-info-buffer) + (when (window-live-p n-back-info-window) + (set-window-buffer n-back-info-window n-back-info-buffer)) + (with-current-buffer n-back-info-buffer + (setq buffer-read-only nil) + (erase-buffer) + + (insert (propertize "n-back" 'face 'n-back-header) + " " + (propertize "Help: ?" 'face 'n-back-keybinding)) + + ;; Auto challenging + (insert "\n\nAuto challenging: " + (if n-back-auto-challenge "on " "off ") + (propertize "toggle: Ta" 'face 'n-back-keybinding)) + + (insert "\n Manually change challenging: " + (propertize "up-arrow/down-arrow" 'face 'n-back-keybinding)) + + (insert "\n Allowed match types: ") + (dolist (type n-back-allowed-match-types) + (insert (format "%s " type))) + (insert (propertize "toggle: T" 'face 'n-back-keybinding)) + + ;; Current game + (insert "\n\nCurrent game:") + + (insert (format "\n n Back: %s " n-back-level) + (propertize "change: number 1-9" 'face 'n-back-keybinding)) + (insert "\n Match types: ") + (dolist (type n-back-active-match-types) + (insert (format "%s " type))) + (insert (propertize "toggle: t" 'face 'n-back-keybinding)) + + (insert (format "\n %.2f seconds per trial " n-back-sec-per-trial) + (propertize "change: +/-" 'face 'n-back-keybinding)) + + ;; Save and restore + (insert "\n\n") + (insert "Game settings: " + (propertize "reset: C-r" 'face 'n-back-keybinding) + " " + (propertize "save: C-s" 'face 'n-back-keybinding)) + + (insert "\n\n") + (unless (or (n-back-is-playing) + (not n-back-result)) + (insert (propertize (format "Last result, %s" n-back-challenge-change) + 'face 'n-back-last-result) + "\n Good-Bad-Miss:") + (dolist (entry n-back-result) + (let* ((what (nth 0 entry)) + (good (nth 1 entry)) + (bad (nth 2 entry)) + (miss (nth 3 entry)) + (tot (+ good bad miss 0.0)) + (res (n-back-compute-single-result-value entry))) + (insert (format " %s: %s-%s-%s (%d%%)" + (key-description (n-back-key-binding what)) + good + bad + miss + (floor (* 100 (cdr res)))))))) + + (setq buffer-read-only t)))) + +(defun n-back-show-welcome (msg) + "Show welcome startup info and message MSG." + (when (and n-back-game-buffer + (buffer-live-p n-back-game-buffer)) + (with-current-buffer n-back-game-buffer + (let ((src (or (when (boundp 'nxhtml-install-dir) + (expand-file-name "nxhtml/doc/img/fun-brain-2.png" nxhtml-install-dir)) + "c:/program files/brain workshop/res/brain_graphic.png")) + img + buffer-read-only) + (erase-buffer) + ;;(insert (propertize "\nEmacs n-back game (after Brain Workshop)\n\n" 'face '(:height 2.0))) + (insert (propertize "\nEmacs n-back game (after Brain Workshop)\n\n" 'face 'n-back-welcome-header)) + (unless (file-exists-p src) + (n-back-maybe-download-files (file-name-directory src) (list (file-name-nondirectory src)))) + (if (file-exists-p src) + (condition-case err + (setq img (create-image src nil nil + :relief 0 + ;;:margin inlimg-margins + )) + (error (setq img (error-message-string err)))) + (setq img (concat "Image not found: " src))) + (if (stringp img) + (insert img) + (insert-image img)) + (insert (propertize "\n\nPlay for fun and maybe a somewhat happier brain" + 'face 'n-back-welcome)) + (when msg (insert "\n\n" msg)) + )))) + +(defun n-back-setup-windows () + "Setup game frame and windows." + (delete-other-windows) + ;; Info + (split-window-horizontally) + (setq n-back-info-window (next-window (frame-first-window))) + (setq n-back-info-buffer (get-buffer-create "* n-back info *")) + (when (< 75 (window-width n-back-info-window)) + (with-selected-window n-back-info-window + (enlarge-window (- 75 (window-width n-back-info-window)) t))) + (with-current-buffer n-back-info-buffer + (n-back-control-mode) + (setq wrap-prefix " ")) + (n-back-update-info) + ;; Control + (split-window-vertically) + (setq n-back-ctrl-window (next-window (frame-first-window))) + (setq n-back-ctrl-buffer (get-buffer-create "* n-back control *")) + (set-window-buffer n-back-ctrl-window n-back-ctrl-buffer) + (with-current-buffer n-back-ctrl-buffer (n-back-control-mode)) + (n-back-update-control-buffer) + (fit-window-to-buffer n-back-ctrl-window) + (set-window-dedicated-p n-back-ctrl-window t) + ;; Game + (setq n-back-game-window (frame-first-window)) + (setq n-back-game-buffer (get-buffer-create "*n-back game*")) + (set-window-buffer n-back-game-window n-back-game-buffer) + (set-window-dedicated-p n-back-game-window t) + (with-current-buffer n-back-game-buffer (n-back-control-mode)) + (n-back-show-welcome nil) + ;; Position in control window + (select-window n-back-ctrl-window) + ) + +;;(n-back-display "str" 1 0 3 3 6) +(defun n-back-display (str x y cols rows max-strlen color) + "Display a trial. +Display item with text STR at column X in row Y using COLS +columns and ROWS rows. Strings to display have max length +MAX-STRLEN. Display item with background color COLOR." + (unless (< x cols) (error "n-back: Not x=%s < cols=%s" x cols)) + (unless (< y rows) (error "Not y=%s < rows=%s" y rows)) + (unless str (setq str "")) + (with-current-buffer n-back-game-buffer + (let* (buffer-read-only + (tot-str "") + ;; Pad spaces left, two right, four between + (game-w (window-width n-back-game-window)) + (pad-x 0) + (scale (if (not window-system) + 1.0 + (/ (* 1.0 game-w) + (+ (* 2 pad-x) + (* (1- cols) 4) + (* cols max-strlen))))) + (str-diff (- max-strlen (length str))) + (str-l-len (/ str-diff 2)) + (str-r-len (- max-strlen (length str) str-l-len)) + (face-spec (if window-system + (list :inherit 'n-back-game-word :background color :height scale) + (list :inherit 'n-back-game-word :background color))) + (str-disp (propertize + (concat (make-string str-l-len 32) str (make-string str-r-len 32)) + 'face face-spec)) + (col-str (concat + (make-string pad-x ?p) + (make-string + (+ (* x (+ 4 max-strlen))) + 32 + ;;?x + ))) + ;; Pad lines above and below, two between + (pad-y 0) + (game-h (window-body-height n-back-game-window)) + (game-h-scaled (/ game-h scale)) + (lines-between (/ (- game-h-scaled rows (* 2 pad-y)) + (1- rows))) + (row-scaled (+ pad-y (* y (1+ lines-between)) (1- y))) + (row-num (if (= y 0) + pad-y + (round row-scaled))) + (row-str (make-string row-num ?\n))) + (setq show-trailing-whitespace nil) + ;;(setq cursor-type nil) + (erase-buffer) + (setq tot-str row-str) + (setq tot-str (concat tot-str col-str)) + (insert (propertize tot-str 'face (list :height scale))) + (insert str-disp) + ))) + +;; (setq timer-list nil) +;;(n-back-display-in-timer) +;; (setq n-back-trials-left 3) + +(defun n-back-clear-game-window () + "Erase game buffer." + (save-match-data ;; runs in timer + (with-current-buffer n-back-game-buffer + (let (buffer-read-only) + (erase-buffer))))) + +(defun n-back-play () + "Start playing." + (interactive) + (message " ") ;; For easier reading *Messages* + (n-back-update-info) + (if (not n-back-active-match-types) + (message (propertize "No active match types" + 'face 'secondary-selection)) + ;;(setq n-back-result nil) + (n-back-init-control-status) + (n-back-init-this-result) + (n-back-cancel-timers) + (winsize-set-mode-line-colors t) + (setq n-back-ring (make-ring (1+ n-back-level))) + (n-back-clear-game-window) + (setq n-back-trials-left (+ n-back-trials n-back-level)) + (random t) + (n-back-start-main-timer) + (n-back-update-control-buffer))) + +(defun n-back-start-main-timer () + "Start main game timer." + (setq n-back-timer + (run-with-timer + n-back-sec-per-trial + nil ;;n-back-sec-per-trial + 'n-back-display-in-timer))) + +(defun n-back-maybe-download-files (dir file-name-list) + (nxhtml-get-missing-files (file-relative-name dir nxhtml-install-dir) file-name-list)) + +(defun n-back-finish-game () + "Finish the game." + (n-back-cancel-timers) + (fit-window-to-buffer n-back-ctrl-window) + (setq n-back-result n-back-this-result) + (n-back-compute-result-values n-back-result) + (when n-back-auto-challenge (n-back-set-next-challenge)) + (n-back-update-info) + (n-back-init-control-status) + (n-back-clear-match-status) + (n-back-update-control-buffer) + (n-back-show-welcome "Game over") + (with-current-buffer n-back-game-buffer + ;;(setq n-back-challenge-change 'up) + (let (buffer-read-only) + (insert + "\n\n" + (case n-back-challenge-change + (up "Congratulations! I see you need more challenge, raising difficulty!") + (down "Making it a bit easier for now to make your playing more fun.") + (otherwise "This game challenges seems the right way for you now."))) + (let* ((dir (when (boundp 'nxhtml-install-dir) + (expand-file-name "nxhtml/doc/img/" nxhtml-install-dir))) + (up-imgs '("rembrandt-self-portrait.jpg" + "bacchante2.jpg" + "giraffe.jpg" + "Las_Medulas.jpg" + )) + (t-imgs '("continue-play.jpg" + "Toco_toucan.jpg" + "raindrops2.jpg" + "divine2.jpg" + ;;"butterflies.png" + "volga.jpg" + "healthy_feet2.jpg" + )) + ;; (setq n-back-trials 1) + (pic (when dir (case n-back-challenge-change + (up (nth (random (length up-imgs)) up-imgs)) + (otherwise (nth (random (length t-imgs)) t-imgs))))) + (src (when dir (expand-file-name pic dir))) + img) + (when (and src (not (file-exists-p src))) + ;; Time to download? + (n-back-maybe-download-files (file-name-directory src) (append up-imgs t-imgs nil))) + (when (and src (file-exists-p src)) + (condition-case err + (setq img (create-image src nil nil + :relief 0 + )) + (error (setq img (error-message-string err))))) + (if (stringp img) + img + (insert "\n\n") + (insert-image img))))) + (message "Game over")) + +(defun n-back-display-random () + "Display a random item." + (when (current-message) (message "")) + ;;(message "here start display") + (let* ((use-position (memq 'position n-back-active-match-types)) + (use-color (memq 'color n-back-active-match-types)) + (use-sound (memq 'sound n-back-active-match-types)) + (use-word (memq 'word n-back-active-match-types)) + (old-rec (when (n-back-match-possible) + (ring-ref n-back-ring (1- n-back-level)))) + (cols 3) + (rows 3) + (x (if use-position (random 3) 1)) + (y (if use-position (random 3) 1)) + (old-x (if use-position (nth 1 old-rec))) + (old-y (if use-position (nth 2 old-rec))) + (color (nth (if use-color (random (length n-back-colors)) 0) n-back-colors)) + (old-color (if use-color (nth 3 old-rec))) + (sound (when use-sound (expand-file-name (nth (random (length n-back-sound-files)) + n-back-sound-files) + (nth 0 n-back-sounds)))) + (old-sound (if use-sound (nth 4 old-rec))) + (words (when use-word (split-string n-back-words))) + (word (when use-word (nth (random (length words)) words))) + (old-word (when use-word (nth 5 old-rec))) + (str (if word word "")) ;(format "%s" n-back-trials-left)) + (max-strlen (if words + (+ 2 (apply 'max (mapcar (lambda (w) (length w)) words))) + 5)) + (compensate 24) + ) + ;; To get more targets make it more plausible that it is the same here. + ;; (/ (- 6 (/ 20.0 8)) 20) + (when old-rec + (when (and use-position + (not (and (= x old-x) + (= y old-y))) + (< (random 100) compensate)) + (setq x (nth 1 old-rec)) + (setq y (nth 2 old-rec))) + (when (and use-color + (not (equal color old-color)) + (< (random 100) compensate)) + (setq color (nth 3 old-rec))) + (when (and use-sound + (not (equal sound old-sound)) + (< (random 100) compensate)) + (setq sound (nth 4 old-rec))) + (when (and use-word + (not (equal word old-word)) + (< (random 100) compensate)) + (setq word (nth 5 old-rec)))) + (setq str word) ;; fix-me + (ring-insert n-back-ring (list str x y color sound word)) + ;;(message "here before display") + (n-back-display str x y cols rows max-strlen color) + ;;(when sound (play-sound (list 'sound :file sound))) + ;;(message "here before clear-m") + (n-back-clear-match-status) + ;;(message "here before position") + (when (and use-position (n-back-matches 'position)) (n-back-set-match-status 'position 'miss)) + ;;(message "here before color") + (when (and use-color (n-back-matches 'color)) (n-back-set-match-status 'color 'miss)) + ;;(message "here before sound") + (when (and use-sound (n-back-matches 'sound)) (n-back-set-match-status 'sound 'miss)) + ;;(message "here before word") + (when (and use-word (n-back-matches 'word)) (n-back-set-match-status 'word 'miss)) + (setq n-back-display-hint n-back-hint) + ;;(message "here before control") + (n-back-update-control-buffer) + ;;(message "here before clear timer") + (setq n-back-clear-timer (run-with-timer 0.5 nil 'n-back-clear-game-window)) + ;;(message "here before sound timer") + (when sound (run-with-timer 0.01 nil 'n-back-play-sound-in-timer sound)) + ;;(message "here exit display") + )) + +(defun n-back-display-in-timer () + "Display a trial in a timer." + (condition-case err + (save-match-data ;; runs in timer + (n-back-add-result) + (if (>= 0 (setq n-back-trials-left (1- n-back-trials-left))) + (n-back-finish-game) + (n-back-display-random) + (n-back-start-main-timer) + ;;(message "after start-main-timer") + )) + (error (message "n-back-display: %s" (error-message-string err)) + (n-back-cancel-timers)))) + +(defun n-back-play-sound-in-timer (sound-file) + "Play sound SOUND-FILE in a timer." + (condition-case err + (save-match-data ;; runs in timer + (play-sound (list 'sound :file sound-file :volume n-back-sound-volume))) + (error (message "n-back-sound: %s" (error-message-string err)) + (n-back-cancel-timers)))) + + +;;; Answers + +;;(defvar n-back-answers nil) + +(defun n-back-init-this-result () + "Init `n-back-this-result'." + (setq n-back-this-result nil) + (dolist (sts-entry n-back-control-status) + (let* ((what (nth 0 sts-entry)) + (res-entry (list what 0 0 0))) + (setq n-back-this-result (cons res-entry n-back-this-result))))) + +(defun n-back-match-possible () + "Return t if enouch entries have been shown to match." + (= (ring-length n-back-ring) (1+ n-back-level))) + +(defun n-back-add-result () + "Add result of last trial." + (when (n-back-match-possible) + (dolist (sts-entry n-back-control-status) + (let* ((what (nth 0 sts-entry)) + (sts (nth 2 sts-entry)) + (matches (n-back-matches what)) + (num (cond + ((eq sts 'ok) 1) + ((eq sts 'bad) 2) + ;;((eq sts nil) (when matches 3)) + ((eq sts 'miss) 3) + ((not sts) nil) + (t (error "n-back: Bad status=%s" sts)))) + (res-entry (when num (assoc what n-back-this-result))) + (lst (when num (nthcdr num res-entry)))) + (when num + (if res-entry + (setcar lst (1+ (car lst))) + (setq res-entry (list what 0 0 0)) + ;;(setq lst (nthcdr num res-entry)) + (setq n-back-this-result (cons res-entry n-back-this-result)))))))) + +(defun n-back-matches-position () + "Return non-nil iff last trial position match." + (when (n-back-match-possible) + (let* ((comp-item (ring-ref n-back-ring n-back-level)) + (curr-item (ring-ref n-back-ring 0)) + (comp-x (nth 1 comp-item)) + (curr-x (nth 1 curr-item)) + (comp-y (nth 2 comp-item)) + (curr-y (nth 2 curr-item))) + (and (= comp-y curr-y) + (= comp-x curr-x))))) + +(defun n-back-matches-color () + "Return non-nil iff last trial color match." + (when (n-back-match-possible) + (let* ((comp-item (ring-ref n-back-ring n-back-level)) + (curr-item (ring-ref n-back-ring 0)) + (comp-color (nth 3 comp-item)) + (curr-color (nth 3 curr-item))) + (equal comp-color curr-color)))) + +(defun n-back-matches-sound () + "Return non-nil iff last trial sound match." + (when (n-back-match-possible) + (let* ((comp-item (ring-ref n-back-ring n-back-level)) + (curr-item (ring-ref n-back-ring 0)) + (comp-sound (nth 4 comp-item)) + (curr-sound (nth 4 curr-item))) + (equal comp-sound curr-sound)))) + +(defun n-back-matches-word () + "Return non-nil iff last trial word match." + (when (n-back-match-possible) + (let* ((comp-item (ring-ref n-back-ring n-back-level)) + (curr-item (ring-ref n-back-ring 0)) + (comp-word (nth 5 comp-item)) + (curr-word (nth 5 curr-item))) + (equal comp-word curr-word)))) + +(defun n-back-matches (what) + "Return non-nil iff last trial part WHAT match." + (cond + ((eq what 'position) (n-back-matches-position)) + ((eq what 'color) (n-back-matches-color)) + ((eq what 'sound) (n-back-matches-sound)) + ((eq what 'word) (n-back-matches-word)) + (t (error "n-back: Unknown match type: %s" what)))) + +(defun n-back-answer (what) + "Tell that you think WHAT matched." + (when (n-back-is-playing) + (if (memq what n-back-active-match-types) + (if (n-back-match-possible) + (let ((sts (if (n-back-matches what) 'ok 'bad))) + (n-back-set-match-status what sts) + (n-back-update-control-buffer)) + (message "%s n-back items must be displayed before anything can match" + n-back-level)) + (message "%s match is not active" what) + (ding t)))) + +(defun n-back-position-answer () + "Tell that you think position matched." + (interactive) + (n-back-answer 'position)) + +(defun n-back-color-answer () + "Tell that you think color matched." + (interactive) + (n-back-answer 'color)) + +(defun n-back-sound-answer () + "Tell that you think sound matched." + (interactive) + (n-back-answer 'sound)) + +(defun n-back-word-answer () + "Tell that you think word matched." + (interactive) + (n-back-answer 'word)) + +(defun n-back-stop () + "Stop playing." + (interactive) + (n-back-cancel-timers) + (n-back-update-control-buffer) + (message "Stopped n-back game") + (n-back-show-welcome "Stopped")) + +(defvar viper-emacs-state-mode-list) ;; silence compiler +(defvar viper-emacs-state-hook) ;; silence compiler + +(define-derived-mode n-back-control-mode nil "N-back" + "Mode for controlling n-back game." + (setq cursor-type nil) + (setq buffer-read-only t) + (set (make-local-variable 'viper-emacs-state-mode-list) '(n-back-control-mode)) + (set (make-local-variable 'viper-emacs-state-hook) nil) ;; in vis cursor + (abbrev-mode -1) + (setq show-trailing-whitespace nil) + (when (fboundp 'visual-line-mode) (visual-line-mode 1)) + (n-back-make-keymap)) + +(defun n-back-cancel-timers () + "Cancel game timers." + (when (timerp n-back-timer) + (cancel-timer n-back-timer)) + (setq n-back-timer nil) + (when (timerp n-back-clear-timer) + (cancel-timer n-back-clear-timer)) + (setq n-back-clear-timer nil) + (winsize-set-mode-line-colors nil)) + +(defvar n-back-game-settings-symbols + '( + ;;n-back-keys + n-back-level + n-back-active-match-types + n-back-allowed-match-types + n-back-auto-challenge + ;;n-back-colors + ;;n-back-words + ;;n-back-sound-volume + ;;n-back-sounds + n-back-sec-per-trial + ;;n-back-keybinding-color + ;;n-back-trials + )) + +(defun n-back-save-game-settings () + "Save game settings." + (interactive) + (dolist (var n-back-game-settings-symbols) + ) + (custom-save-all)) + +(defun n-back-reset-game-to-saved () + "Reset game playing options to saved values." + (interactive) + (dolist (pass '(1 2)) + (dolist (var n-back-game-settings-symbols) + (if (= pass 1) + ;; pass 1 is for my lousy programming: + (condition-case err + (custom-reevaluate-setting var) + (error nil)) + (custom-reevaluate-setting var))))) + +(provide 'n-back) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; n-back.el ends here diff --git a/emacs/nxhtml/util/new-key-seq-widget.el b/emacs/nxhtml/util/new-key-seq-widget.el new file mode 100644 index 0000000..7ace679 --- /dev/null +++ b/emacs/nxhtml/util/new-key-seq-widget.el @@ -0,0 +1,312 @@ +;;; new-key-seq-widget.el --- New key-sequence widget for Emacs +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Tue Dec 25 23:00:43 2007 +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; New version of Kim's Emacs key-sequence widget. For inclusion in +;; Emacs I hope. +;; +;; Fix-me: check what was included. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; I do not know how much I have changed, but I keep it together here +;; for simplicity. +;; +;; Note: I have named made `widget-key-sequence-map' a constant for +;; the moment. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(require 'wid-edit) +(require 'edmacro) + +;;; I'm not sure about what this is good for? KFS. +;; +;;; This should probably be for customize-set-value etc, but it is not +;;; used. Or for the widget editing, but it is not used there +;;; either. /Lennart +(defvar widget-key-sequence-prompt-value-history nil + "History of input to `widget-key-sequence-prompt-value'.") + +(defvar widget-key-sequence-default-value [ignore] + "Default value for an empty key sequence.") + +(defconst widget-key-sequence-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map widget-field-keymap) + (define-key map [(control ?q)] 'widget-key-sequence-read-event) + (define-key map [(control ?t)] 'widget-key-sequence-toggle-input-format) + map)) + +(defvar widget-key-sequence-input-formats '(key-description vector)) + +(defcustom widget-key-sequence-default-input-format 'key-description + "Format used to edit key sequences. +This is the format shown and edited in a key-sequence widget." + :type '(choice (const :tag "Key description" 'key-description) + (const :tag "Vector" 'vector)) + :group 'widgets) + +(define-widget 'key-sequence 'restricted-sexp + "A key sequence." + :prompt-value 'widget-field-prompt-value + :prompt-internal 'widget-symbol-prompt-internal +; :prompt-match 'fboundp ;; What was this good for? KFS + :prompt-history 'widget-key-sequence-prompt-value-history + :action 'widget-field-action + :match-alternatives '(stringp vectorp) + :format "%{%t%}: %v" + :validate 'widget-key-sequence-validate + :value-to-internal 'widget-key-sequence-value-to-internal + :value-to-external 'widget-key-sequence-value-to-external + :value widget-key-sequence-default-value + :keymap widget-key-sequence-map + :help-echo "C-q: insert KEY, EVENT, or CODE; C-t: toggle format" + :tag "Key sequence") + + +;;; Leave these here for testing: +;; (edmacro-parse-keys "C-x h" t) => [24 104] +;; (key-description-to-vector "C-x h" ) => [(control 120) 104] +;; (key-description (key-description-to-vector "C-x h")) => "C-x h" +;; (key-description (edmacro-parse-keys "C-x h")) => "C-x h" +;; (key-description [M-mouse-1]) => <M-mouse-1> +;; (edmacro-parse-keys "<M-mouse-1>") => [M-mouse-1] + +;; (event-modifiers 'mouse-1) => (click mouse-1 mouse-1 mouse-1 mouse-1 mouse-1) +;; (event-modifiers 'M-mouse-1) => +;; (event-modifiers '(mouse-1)) => (click mouse-1 mouse-1 mouse-1 mouse-1 mouse-1) +;; (event-modifiers '(down-mouse-1)) => (click mouse-1 mouse-1 mouse-1 mouse-1 mouse-1) +;; (event-modifiers '(S-down-mouse-1)) => (shift down) +;; (event-modifiers 'S-down-mouse-1) => (shift down) +;; (event-modifiers 'down-mouse-1) => (click mouse-1 mouse-1 mouse-1 mouse-1 mouse-1) +;; (event-modifiers '(down-mouse-1)) => (click mouse-1 mouse-1 mouse-1 mouse-1 mouse-1) +;; (let ((m (make-sparse-keymap))) (define-key m [(down mouse-1)] 'hej)) +(defun key-description-to-vector (kd) + "Convert human readable key description KD to vector format. +KD should be in the format returned by `key-description'." + (let ((v + (vconcat + (mapcar (lambda (k) + ;; Fix-me: temporarily clean the event here: + (when (symbolp k) + (let ((esem (get k 'event-symbol-element-mask))) (when esem (lwarn t :warning "kd=%s, k=%s, esem=%s" kd k esem))) + (put k 'event-symbol-element-mask nil)) + (let ((m (event-modifiers k)) + (b (event-basic-type k))) + (setq m (delq 'click m)) + (if m + (nconc m (list b)) + b))) + ;; fix-me: does not always work for menu and tool + ;; bar event because they may contains spaces. + (edmacro-parse-keys kd t)))) + (m (make-sparse-keymap)) + ) + ;; Test before returning it: + (define-key m v 'test) + v)) + +(defun widget-key-sequence-current-input-format () + (let ((fmt (or (widget-get (widget-at (point)) :key-sequence-format) + widget-key-sequence-default-input-format))) + fmt)) + +(defun widget-key-sequence-toggle-input-format () + "Toggle key sequence input format." + (interactive) + (let* ((widget (widget-at (point))) + (value (widget-apply widget :value-get)) + (first (string-to-char value)) + (old-fmt + (let ((fmt (or (widget-get widget :key-sequence-format) + widget-key-sequence-default-input-format))) + fmt)) + (new-fmt + (let ((m (cdr (memq old-fmt widget-key-sequence-input-formats)))) + (if m (car m) (car widget-key-sequence-input-formats)))) + (new-value + (cond + ((eq new-fmt 'key-description) + (setq value (replace-regexp-in-string "\\` *\\(.*?\\) *\\'" "\\1" value)) + (if (string= value "") + "" + (key-description (read value)))) + ((eq new-fmt 'vector) + (format "%S" (key-description-to-vector value))) + (t + (error "Bad key seq format spec: %s" new-fmt)))) + (state (widget-get (widget-get widget :parent) :custom-state)) + ) + (widget-put widget :key-sequence-format new-fmt) + (setq new-value (propertize new-value 'face 'highlight)) + (widget-apply widget :value-set new-value) + (widget-setup) + (widget-put (widget-get widget :parent) :custom-state state) + (cond + ((eq new-fmt 'key-description) + (message "Switched to human readable format")) + ((eq new-fmt 'vector) + (message "Switched to vector format")) + (t + (error "Uh? format=%s" new-fmt))))) + + +(defun widget-key-sequence-read-event (ev) + "Read event or char code and put description in widget. +The events may come from keyboard, mouse, menu or tool bar. + +If the event is a mouse event then multiple entries will be +entered. It is not possible to know which one is wanted. Please +remove those not wanted! + +If 0-7 is pressed then code for an event is prompted for." + (interactive (list + (let ((inhibit-quit t) quit-flag) + (unless (eq 'key-description + (widget-key-sequence-current-input-format)) + (error "Wrong input format, please do C-t first")) + (read-event "Insert KEY, EVENT, or CODE: ")))) + (lwarn t :warning "=====> ev=%s" ev) + (let ((tr (and (keymapp function-key-map) + (lookup-key function-key-map (vector ev))))) + (insert (if (= (char-before) ?\s) "" " ")) + ;; Fix-me: change to check for ? instead of 0-7 to allow char + ;; literal input format + (when (and (integerp ev) + (or (and (<= ?0 ev) (< ev (+ ?0 (min 10 read-quoted-char-radix)))) + (and (<= ?a (downcase ev)) + (< (downcase ev) (+ ?a -10 (min 36 read-quoted-char-radix)))))) + (setq unread-command-events (cons ev unread-command-events) + ev (read-quoted-char (format "Enter code (radix %d)" read-quoted-char-radix)) + tr nil) + (if (and (integerp ev) (not (characterp ev))) + (insert (char-to-string ev)))) ;; throw invalid char error + (setq ev (key-description (list ev))) + (when (arrayp tr) + (setq tr (key-description (list (aref tr 0)))) + (when (y-or-n-p (format "Key %s is translated to %s -- use %s? " ev tr tr)) + (setq ev tr) + ;;(setq ev2 nil) + )) + (insert ev " ") + (when (or (string-match "mouse-" ev) + (string-match "menu-bar" ev) + (string-match "tool-bar" ev)) + (let ((ev2 (read-event nil nil (* 0.001 double-click-time)))) + (while ev2 + (lwarn t :warning "(stringp ev2)=%s, (sequencp ev2)=%s, (symbolp ev2)=%s, ev2=%S" (stringp ev2) (sequencep ev2) (symbolp ev2) ev2) + (if nil ;(memq 32 (append (symbol-name ev2) nil)) ;; Fix-me: contains space + (insert ?\" (symbol-name ev2) ?\") + (insert (key-description (list ev2)))) + (insert " ") + (setq ev2 (read-event nil nil (* 0.001 double-click-time)))))))) + +(defun widget-key-sequence-validate (widget) + "Validate the internal value of the widget. +Actually there is nothing to validate here. The internal value +is always valid, but it is however maybe not what the user +expects. Because of this the internal format is rewritten when +the user gives the value in a way that is not the normal +representation of it. A warning is also shown then." + (condition-case err + (let* ((int-val (widget-apply widget :value-get)) + (def-desc (key-description (edmacro-parse-keys int-val))) + (fmt (or (widget-get widget :key-sequence-format) + widget-key-sequence-default-input-format))) + ;; Normalize and compare with default description + (setq int-val + (replace-regexp-in-string " *" " " int-val t)) + (setq int-val + (replace-regexp-in-string "\\` *\\(.*?\\) *\\'" "\\1" int-val t)) + (unless (or + (eq fmt 'vector) + (string= int-val def-desc)) + ;; Replace with the default description if it is different + ;; so the user sees what the value actually means: + (widget-apply widget :value-set def-desc) + (lwarn t :warning + (concat "Key description %s means the same as %s\n" + "\tTip: You can type C-q to insert a key or event") + int-val def-desc) + ) + ;; Return nil if there a no problem validating + nil) + (error (widget-put widget :error (error-message-string err)) + (lwarn t :warning "invalid %S: %s" widget (error-message-string err)) + ;; Return widget if there was an error + widget))) + +(defun widget-key-sequence-value-to-internal (widget value) + (if (widget-apply widget :match value) + (if (equal value widget-key-sequence-default-value) + "" + (let ((fmt (or (widget-get widget :key-sequence-format) + widget-key-sequence-default-input-format))) + (if (eq fmt 'vector) + (format "%S" value) + (key-description value)))) + value)) + +(defun widget-key-sequence-value-to-external (widget value) + (if (stringp value) + (if (string-match "\\`[[:space:]]*\\'" value) + widget-key-sequence-default-value + ;; Give a better error message and a trace back on debug: + (condition-case err + (let* ((fmt (or (widget-get widget :key-sequence-format) + widget-key-sequence-default-input-format)) + (first (string-to-char value))) + (cond + ((eq fmt 'vector) + (read value) + ) + (t + (key-description-to-vector value)))) + (error (error "Bad value: %s" (error-message-string err))))) + value)) + +;; (customize-option 'new-key-seq-widget-test) +(defcustom new-key-seq-widget-test [] + "Testing only!" + :type 'key-sequence + :group 'widgets) + + (provide 'new-key-seq-widget) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; new-key-seq-widget.el ends here diff --git a/emacs/nxhtml/util/nxml-mode-os-additions.el b/emacs/nxhtml/util/nxml-mode-os-additions.el new file mode 100644 index 0000000..0765acf --- /dev/null +++ b/emacs/nxhtml/util/nxml-mode-os-additions.el @@ -0,0 +1,99 @@ +;;; nxml-mode-os-additions.el --- additional functions for nxml-mode + +;; Copyright (C) 2004 by Oliver Steele + +;; Author: Oliver Steele <steele@osteele.com> +;; Version: 1.0 (2004-08-08) +;; Homepage: http://osteele.com/sources/nxml-mode-os-additions.el +;; Keywords: XML + +;; 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., 59 Temple Place, Suite 330, Boston, +;; MA 02111-1307 USA + +;;; Description: + +;; nxml-mode-os-additions defines additional functions for using +;; James Clark's nxml-mode: +;; - reload the current buffer's schema +;; - edit the current buffer's schema + +;;; Installation: +;; +;; To use nxml-mode-os-additions.el, put it in your load-path and add +;; the following to your .emacs: +;; +;; (load-library "nxml-mode-os-additions") + +;; Configuration: +;; +;; To make it easier to use, assign the commands to some keys. +;; Once nxml-mode has been loaded, you can define keys on nxml-mode-map. +;; The function rng-mode-os-additions-set-key-bindings illustrates +;; this. +;; +;; Alternatively, you can place the following in your .emacs: +;; (add-hook 'nxml-mode-hook 'rng-mode-os-additions-set-key-bindings) + +;;; ChangeLog: +;; +;; 2004-08-08 (version 1.0): +;; * Initial public release + +;; Added require rng-valid (Lennart Borgman) + +;;; Code: + +(require 'nxml-mode) +(eval-and-compile (require 'rng-valid)) + +(defun rng-mode-os-additions-set-key-bindings () + (define-key nxml-mode-map "\C-c\C-s\C-r" 'rng-reload-schema-file) + ; move the rng-set-schema-file-and-validate to another key binding + ;(define-key nxml-mode-map "\C-c\C-s\C-s" 'rng-set-schema-file-and-validate) + (define-key nxml-mode-map "\C-c\C-sf" 'rng-find-schema-file) + ) + +(defun rng-reload-schema-file () + "Reloads the current schema file." + (interactive) + (let ((schema-filename rng-current-schema-file-name)) + (when schema-filename + (setq rng-current-schema (rng-load-schema schema-filename)) + (run-hooks 'rng-schema-change-hook) + (message "Reloaded schema %s" schema-filename)) + (unless schema-filename + (rng-set-schema-and-validate)))) + +;; Helper function for rng-find-schema-file* +(defun rng-apply-find-schema-file (fn) + (let ((schema-filename rng-current-schema-file-name)) + (unless schema-filename + (error "This file is not associated with a schema file.")) + (funcall fn schema-filename))) + +(defun rng-find-schema-file () + "Edit the current schema file." + (interactive) + (rng-apply-find-schema-file 'find-file)) + +(defun rng-find-schema-file-other-frame () + "Edit the current schema in another frame." + (interactive) + (rng-apply-find-schema-file 'find-file-other-frame)) + +(defun rng-find-schema-file-other-window () + "Edit the current schema in another window." + (interactive) + (rng-apply-find-schema-file 'find-file-other-window)) diff --git a/emacs/nxhtml/util/ocr-user.el b/emacs/nxhtml/util/ocr-user.el new file mode 100644 index 0000000..0bcd1d9 --- /dev/null +++ b/emacs/nxhtml/util/ocr-user.el @@ -0,0 +1,86 @@ +;;; ocr-user.el --- Input looong OCR number more safely +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-06-18T23:00:25+0200 Wed +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; I just get mad at entering OCR numbers more than twenty digits long +;; so I wrote this litte minor mode that colors up the digits three by +;; tree. +;; +;; To use it do +;; +;; M-x ocr-user-mode +;; +;; Crazy? Yeah, I get crazy by entering these digits. You would not +;; like to meet me when I have done that! +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(defconst ocr-keywords + `(( + ,(concat + ;;"\\<\\(?:" + "\\(?1:[0-9]\\{3\\}\\)" + "\\(?2:[0-9]\\{3\\}\\)?" + ;;"\\)+" + ) + (0 (progn + (put-text-property (match-beginning 1) (match-end 1) + 'face '(:background "LightBlue1")) + (when (match-beginning 2) + (put-text-property (match-beginning 2) (match-end 2) + 'face '(:background "PaleGreen1")))))))) + +;; 23456 +;; 1234567890 +;; 346789238 +;;;###autoload +(define-minor-mode ocr-user-mode + "Color up digits three by three." + :group 'convenience + (if ocr-user-mode + (font-lock-add-keywords nil ocr-keywords) + (font-lock-remove-keywords nil ocr-keywords)) + (font-lock-fontify-buffer)) + + +(provide 'ocr-user) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ocr-user.el ends here diff --git a/emacs/nxhtml/util/org-panel.el b/emacs/nxhtml/util/org-panel.el new file mode 100644 index 0000000..a8dfec0 --- /dev/null +++ b/emacs/nxhtml/util/org-panel.el @@ -0,0 +1,745 @@ +;;; org-panel.el --- Simple routines for us with bad memory +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Thu Nov 15 15:35:03 2007 +;; Version: 0.21 +;; Lxast-Updated: Wed Nov 21 03:06:03 2007 (3600 +0100) +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Fxeatures that might be required by this library: +;; +;; `easymenu', `font-lock', `noutline', `org', `outline', `syntax', +;; `time-date'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This defines a kind of control panel for `org-mode'. This control +;; panel should make it fast to move around and edit structure etc. +;; +;; To bring up the control panel type +;; +;; M-x orgpan-panel +;; +;; Type ? there for help. +;; +;; I suggest you add the following to your .emacs for quick access of +;; the panel: +;; +;; (eval-after-load 'org-mode +;; (define-key org-mode-map [(control ?c) ?p] 'orgpan-panel)) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(require 'org) +(require 'outline) + +;; Fix-me: this is for testing. A minor mode version interferes badly +;; with emulation minor modes. +(defconst orgpan-minor-mode-version nil) + +(defface orgpan-field + '((t (:inherit widget-field))) + "Face for fields." + :group 'orgpan) +(defvar orgpan-field-face 'orgpan-field) + +(defface orgpan-active-field + '((t (:inherit highlight))) + "Face for fields." + :group 'orgpan) +(defvar orgpan-active-field-face 'orgpan-active-field) + +(defface orgpan-spaceline + '((t (:height 0.2))) + "Face for spacing lines." + :group 'orgpan) + +(defcustom orgpan-panel-at-top nil + "Put org panel at top if non-nil." + :type 'boolean + :group 'orgpan) + +(defcustom orgpan-panel-buttons nil + "Panel style, if non-nil use buttons. +If there are buttons in the panel they are used to change the way +the arrow keys work. The panel looks something like this, with +the first button chosen: + + [Navigate] [Restructure] [TODO/Priority] + ---------- + up/down, left: Go to, right: Visibility + +The line below the buttons try to give a short hint about what +the arrow keys does. \(Personally I prefer the version without +buttons since I then do not have to remember which button is +active.)" + :type 'boolean + :group 'orgpan) + +;; Fix-me: add org-mode-map +;; (memq 'org-self-insert-command orgpan-org-mode-commands) +;; (memq 'org-self-insert-command orgpan-org-commands) +(defvar orgpan-org-mode-commands nil) +(setq orgpan-org-mode-commands nil) + +(defconst orgpan-org-commands + '( + orgpan-copy-subtree + orgpan-cut-subtree + orgpan-paste-subtree + undo + save-buffer + ;; + ;orgpan-occur + orgpan-find-org-file + ;; + org-cycle + org-global-cycle + outline-up-heading + outline-next-visible-heading + outline-previous-visible-heading + outline-forward-same-level + outline-backward-same-level + org-todo + org-show-todo-tree + org-priority-up + org-priority-down + org-move-subtree-up + org-move-subtree-down + org-do-promote + org-do-demote + org-promote-subtree + org-demote-subtree)) + + +(defvar orgpan-panel-window nil + "The window showing `orgpan-panel-buffer'.") + +(defvar orgpan-panel-buffer nil + "The panel buffer. +There can be only one such buffer at any time.") + +(defvar orgpan-org-window nil) +;;(make-variable-buffer-local 'orgpan-org-window) + +;; Fix-me: used? +(defvar orgpan-org-buffer nil) +;;(make-variable-buffer-local 'orgpan-org-buffer) + +(defvar orgpan-last-org-buffer nil) +;;(make-variable-buffer-local 'orgpan-last-org-buffer) + +(defvar orgpan-point nil) +;;(make-variable-buffer-local 'orgpan-point) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Hook functions etc + +(defun orgpan-delete-panel () + "Remove the panel." + (interactive) + (let ((was-in-panel (and (window-live-p orgpan-panel-window) + (eq (selected-window) orgpan-panel-window)))) + (when (buffer-live-p orgpan-panel-buffer) + (delete-windows-on orgpan-panel-buffer) + (kill-buffer orgpan-panel-buffer)) + (when was-in-panel + (select-window orgpan-org-window))) + (setq orgpan-panel-buffer nil) + (setq orgpan-panel-window nil) + (orgpan-panel-minor-mode 0) + (remove-hook 'post-command-hook 'orgpan-minor-post-command) + (remove-hook 'post-command-hook 'orgpan-mode-post-command) + ;;(remove-hook 'window-configuration-change-hook 'orgpan-window-config-change) + ) + +(defvar orgpan-from-panel 0) +(defun orgpan-mode-pre-command () + ;;(setq orgpan-from-panel nil) + (condition-case err + (if (not (and (windowp orgpan-org-window) + (window-live-p orgpan-org-window))) + (progn + (setq this-command 'ignore) + (orgpan-delete-panel) + (message "The window belonging to the panel had disappeared, removed panel.")) + (let ((buf (window-buffer orgpan-org-window))) + (when (with-current-buffer buf + (derived-mode-p 'org-mode)) + (setq orgpan-last-org-buffer buf)) + ;; Fix me: add a list of those commands that are not + ;; meaningful from the panel (for example org-time-stamp) + (when (or (memq this-command orgpan-org-commands) + (memq this-command orgpan-org-mode-commands) + ;; For some reason not all org commands are found above: + (unless (eq this-command 'org-self-insert-command) + (let ((this-name (format "%s" this-command))) + (when (< 4 (length this-name)) + (string= "org-" (substring this-name 0 4)))))) + (if (not (with-current-buffer buf + (derived-mode-p 'org-mode))) + (progn + (if (buffer-live-p orgpan-org-buffer) + (set-window-buffer orgpan-org-window orgpan-org-buffer) + (message "Please use `l' or `b' to choose an org-mode buffer")) + (setq this-command 'ignore)) + (setq orgpan-org-buffer (window-buffer orgpan-org-window)) + (setq orgpan-from-panel 1) + (select-window orgpan-org-window) + )))) + (error (lwarn 't :warning "orgpan-pre: %S" err)))) + +(defun orgpan-mode-post-command () + (condition-case err + (progn + ;;(message "post %s" (current-time-string))(sit-for 1) + (unless (and (windowp orgpan-panel-window) + (window-live-p orgpan-panel-window) + (bufferp orgpan-panel-buffer) + (buffer-live-p orgpan-panel-buffer)) + (orgpan-delete-panel)) + (unless (active-minibuffer-window) + (when (and (= 1 orgpan-from-panel) + (windowp orgpan-panel-window) + (window-live-p orgpan-panel-window)) + (select-window orgpan-panel-window) + (when (derived-mode-p 'orgpan-mode) + (setq deactivate-mark t) + (when orgpan-panel-buttons + (unless (and orgpan-point + (= (point) orgpan-point)) + ;; Go backward so it is possible to click on a "button": + (orgpan-backward-field))))) + (when (< 0 orgpan-from-panel) + (setq orgpan-from-panel (1- orgpan-from-panel))) + (unless (eq (selected-window) orgpan-panel-window) + (orgpan-delete-panel)))) + (error (lwarn 't :warning "orgpan-post: %S" err)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Commands + +(defun orgpan-last-buffer () + "Open last org-mode buffer in panels org window." + (interactive) + (let ((buf (window-buffer orgpan-org-window)) + (last-buf orgpan-last-org-buffer)) +;; (when (with-current-buffer buf +;; (derived-mode-p 'org-mode)) +;; (setq orgpan-last-org-buffer buf)) + (when (eq last-buf buf) + (setq last-buf nil)) + (if (not last-buf) + (orgpan-switch-buffer) + (set-window-buffer orgpan-org-window last-buf)))) + +(defun orgpan-switch-buffer () + "Switch to next org-mode buffer in panels org window." + (interactive) + (let ((buf (window-buffer orgpan-org-window)) + (org-buffers nil)) + (with-current-buffer buf + (when (derived-mode-p 'org-mode) + (bury-buffer buf) + ;;(setq orgpan-last-org-buffer buf) + )) + (setq org-buffers (delq nil (mapcar (lambda (buf) + (when (with-current-buffer buf + (derived-mode-p 'org-mode)) + buf)) + (buffer-list)))) + (setq org-buffers (delq buf org-buffers)) + (if (not org-buffers) + (message "No other org-mode buffers") + (set-window-buffer orgpan-org-window (car org-buffers)) + (setq orgpan-org-buffer (car org-buffers))))) + +(defcustom orgpan-cautious-cut-copy-paste nil + "Ask the user about panel cut, paste and copy before doing them. +This refers to the functions `orgpan-paste-subtree', +`orgpan-cut-subtree' and `orgpan-copy-subtree'." + :type 'boolean + :group 'orgpan) + +(defun orgpan-paste-subtree () + (interactive) + (if orgpan-cautious-cut-copy-paste + (if (y-or-n-p "Paste subtree here? ") + (org-paste-subtree) + (message "Nothing was pasted")) + (org-paste-subtree))) + +(defun orgpan-cut-subtree () + (interactive) + (let ((heading (progn + (org-back-to-heading) + (buffer-substring (point) (line-end-position)) + ))) + (if orgpan-cautious-cut-copy-paste + (if (y-or-n-p (format "Do you want to cut the subtree\n%s\n? " heading)) + (org-cut-subtree) + (message "Nothing was cut")) + (org-cut-subtree)))) + +(defun orgpan-copy-subtree () + (interactive) + (let ((heading (progn + (org-back-to-heading) + (buffer-substring (point) (line-end-position)) + ))) + (if orgpan-cautious-cut-copy-paste + (if (y-or-n-p (format "Do you want to copy the subtree\n%s\n? " heading)) + (org-copy-subtree) + (message "Nothing was copied")) + (org-copy-subtree)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Buttons + +(defvar orgpan-ovl-help nil) + +(defun orgpan-check-panel-mode () + (unless (derived-mode-p 'orgpan-mode) + (error "Not orgpan-mode in buffer: %s" major-mode))) + +(defun orgpan-display-bindings-help () + ;;(orgpan-check-panel-mode) + (setq orgpan-point (point-marker)) + (let* ((ovls (overlays-at orgpan-point)) + (ovl (car ovls)) + (help (when ovl (overlay-get ovl 'orgpan-explain)))) + (dolist (o (overlays-in (point-min) (point-max))) + (unless ovl (setq ovl o)) + (overlay-put o 'face orgpan-field-face)) + (overlay-put ovl 'face orgpan-active-field-face) + (unless orgpan-ovl-help + (setq orgpan-ovl-help (make-overlay orgpan-point orgpan-point))) + (overlay-put orgpan-ovl-help 'before-string help))) + +(defun orgpan-forward-field () + (interactive) + (orgpan-check-panel-mode) + (let ((pos (next-overlay-change (point)))) + (unless (overlays-at pos) + (setq pos (next-overlay-change pos))) + (when (= pos (point-max)) + (setq pos (point-min)) + (unless (overlays-at pos) + (setq pos (next-overlay-change pos)))) + (goto-char pos)) + (orgpan-display-bindings-help)) + +(defun orgpan-backward-field () + (interactive) + (orgpan-check-panel-mode) + (when (= (point) (point-min)) + (goto-char (point-max))) + (let ((pos (previous-overlay-change (point)))) + (unless (overlays-at pos) + (setq pos (previous-overlay-change pos))) + (goto-char pos)) + (orgpan-display-bindings-help)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mode +(defun orgpan-agenda () + "Start agenda" + (interactive) + (orgpan-delete-panel) + (call-interactively 'org-agenda)) + +(defun orgpan-outline-up-heading (arg &optional invisible-ok) + (interactive "p") + (outline-back-to-heading invisible-ok) + (let ((start-level (funcall outline-level))) + (if (<= start-level 1) + (message "Already at top level of the outline") + (outline-up-heading arg invisible-ok)))) + +(defvar orgpan-mode-map + ;; Fix-me: clean up here! + ;; Fix-me: viper support + (let ((map (make-sparse-keymap))) + (define-key map [?q] 'orgpan-delete-panel) + (define-key map [??] 'orgpan-help) + (define-key map [?a] 'orgpan-agenda) + ;; Copying etc + (define-key map [?c] 'orgpan-copy-subtree) + (define-key map [?x] 'orgpan-cut-subtree) + (define-key map [?v] 'orgpan-paste-subtree) + (define-key map [?z] 'undo) + (define-key map [(control ?c)] 'orgpan-copy-subtree) + (define-key map [(control ?x)] 'orgpan-cut-subtree) + (define-key map [(control ?v)] 'orgpan-paste-subtree) + (define-key map [(control ?z)] 'undo) + ;; Buffers: + (define-key map [?b] 'orgpan-switch-buffer) + (define-key map [?l] 'orgpan-last-buffer) + (define-key map [?o] 'orgpan-find-org-file) + (define-key map [?w] 'save-buffer) + ;; Some keys for moving between headings. Emacs keys for next/prev + ;; line seems ok: + (define-key map [(control ?p)] 'outline-previous-visible-heading) + (define-key map [(control ?n)] 'outline-next-visible-heading) + (define-key map [(shift control ?p)] 'outline-backward-same-level) + (define-key map [(shift control ?n)] 'outline-forward-same-level) + ;; A mnemunic for up: + (define-key map [(control ?u)] 'orgpan-outline-up-heading) + ;; Search sparse tree: + (define-key map [?s] 'org-sparse-tree) + ;;(define-key map [?s] 'orgpan-occur) + ;;(define-key map [?s] 'org-occur) + ;; Same as in org-mode: + ;;(define-key map [(control ?c)(control ?v)] 'org-show-todo-tree) + ;; Fix-me: This leads to strange problems: + ;;(define-key map [t] 'ignore) + map)) + +(defun orgpan-find-org-file () + "Prompt for an .org file and open it." + (interactive) + (let ((file-name + (read-file-name + "Find .org file: " nil nil t nil + (lambda (fn) + (unless (backup-file-name-p fn) + (let ((ext (file-name-extension fn))) + (when ext + (string= "org" ext)))))))) + (find-file file-name))) + +(defun orgpan-occur () + "Replacement for `org-occur'. +Technical reasons." + (interactive) + (let ((rgx (read-from-minibuffer "(panel) Regexp: "))) + (setq orgpan-from-panel 1) + (select-window orgpan-org-window) + (org-occur rgx))) + +(defun orgpan-sparse-tree (&optional arg) + "Create a sparse tree, prompt for the details. +This command can create sparse trees. You first need to select the type +of match used to create the tree: + +t Show entries with a specific TODO keyword. +T Show entries selected by a tags match. +p Enter a property name and its value (both with completion on existing + names/values) and show entries with that property. +r Show entries matching a regular expression" + (interactive "P") + (let (ans kwd value) + (message "Sparse tree: [r]egexp [t]odo-kwd [T]ag [p]roperty") + (setq ans (read-char-exclusive)) + (cond + ((equal ans ?t) + (org-show-todo-tree '(4))) + ((equal ans ?T) + (call-interactively 'org-tags-sparse-tree)) + ((member ans '(?p ?P)) + (setq kwd (completing-read "Property: " + (mapcar 'list (org-buffer-property-keys)))) + (setq value (completing-read "Value: " + (mapcar 'list (org-property-values kwd)))) + (unless (string-match "\\`{.*}\\'" value) + (setq value (concat "\"" value "\""))) + (org-tags-sparse-tree arg (concat kwd "=" value))) + ((member ans '(?r ?R)) + (call-interactively 'org-occur)) + (t (error "No such sparse tree command \"%c\"" ans))))) + +;; (defun orgpan-avoid-viper-in-buffer () +;; ;; Fix-me: This is ugly. However see `this-major-mode-requires-vi-state': +;; (set (make-local-variable 'viper-emacs-state-mode-list) '(orgpan-mode)) +;; (set (make-local-variable 'viper-new-major-mode-buffer-list) nil) +;; (local-set-key [?\ ] 'ignore)) + +(define-derived-mode orgpan-mode nil "Org-Panel" + "Mode for org-simple.el control panel." + (set (make-local-variable 'buffer-read-only) t) + (unless orgpan-minor-mode-version + (add-hook 'pre-command-hook 'orgpan-mode-pre-command nil t) + (add-hook 'post-command-hook 'orgpan-mode-post-command t)) + (set (make-local-variable 'cursor-type) nil) + (when (boundp 'yas/dont-activate) (setq yas/dont-activate t)) + ;; Avoid emulation modes here (cua, viper): + (set (make-local-variable 'emulation-mode-map-alists) nil)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Panel layout + +(defun orgpan-insert-field (text keymap explain) + (insert text) + (let* ((end (point)) + (len (length text)) + (beg (- end len)) + (ovl (make-overlay beg end))) + (overlay-put ovl 'face orgpan-field-face) + (overlay-put ovl 'keymap keymap) + (overlay-put ovl 'orgpan-explain explain))) + +(defconst orgpan-with-keymap + (let ((map (make-sparse-keymap))) + (set-keymap-parent map org-mode-map) + ;; Users are used to tabbing between fields: + (define-key map [(tab)] 'orgpan-forward-field) + (define-key map [(shift tab)] 'orgpan-backward-field) + (define-key map [backtab] 'orgpan-backward-field) + ;; Now we must use something else for visibility (first does not + ;; work if Viper): + (define-key map [(meta tab)] 'org-cycle) + (define-key map [(control meta tab)] 'org-global-cycle) + map)) + +(defconst orgpan-without-keymap + (let ((map (make-sparse-keymap))) + (set-keymap-parent map org-mode-map) + ;; Visibility (those are in org-mode-map): + ;;(define-key map [tab] 'org-cycle) + ;;(define-key map [(shift tab)] 'org-global-cycle) + ;; Navigate: + (define-key map [left] 'orgpan-outline-up-heading) + (define-key map [right] 'org-cycle) + (define-key map [up] 'outline-previous-visible-heading) + (define-key map [down] 'outline-next-visible-heading) + (define-key map [(shift down)] 'outline-forward-same-level) + (define-key map [(shift up)] 'outline-backward-same-level) + ;; Restructure: + (define-key map [(control up)] 'org-move-subtree-up) + (define-key map [(control down)] 'org-move-subtree-down) + (define-key map [(control left)] 'org-do-promote) + (define-key map [(control right)] 'org-do-demote) + (define-key map [(control shift left)] 'org-promote-subtree) + (define-key map [(control shift right)] 'org-demote-subtree) + ;; Todo etc + (define-key map [?+] 'org-priority-up) + (define-key map [?-] 'org-priority-down) + (define-key map [?t] 'org-todo) + map)) + +(defun orgpan-make-panel-without-buttons (buf) + (with-current-buffer buf + (insert (propertize "*Org Panel*" 'face 'orgpan-active-field)) + (let ((ovl (make-overlay (point-min) (point-max)))) + (overlay-put ovl 'priority 10) + (overlay-put ovl 'face 'orgpan-active-field)) + (insert " ? for help, q quit\n") + (insert (propertize "arrows" 'face 'font-lock-keyword-face) + ": Go to, " + (propertize "C-arrows" 'face 'font-lock-keyword-face) + ": Edit tree\n" + (propertize "C-cxvz" 'face 'font-lock-keyword-face) + ": copy cut paste undo, " + (propertize "tT+-" 'face 'font-lock-keyword-face) + ": todo priority, " + (propertize "s" 'face 'font-lock-keyword-face) + ": search, " + (propertize "o" 'face 'font-lock-keyword-face) + ": open file\n" + (propertize "w" 'face 'font-lock-keyword-face) + ": write, " + (propertize "a" 'face 'font-lock-keyword-face) + ": agenda" + "\n" + ) + (set-keymap-parent orgpan-mode-map orgpan-without-keymap) + (let ((ovl (make-overlay (point-min) (point-max)))) + (overlay-put ovl 'face 'secondary-selection)) + )) + +(defun orgpan-make-panel-with-buttons (buf) + (with-current-buffer buf + (let* ((base-map (make-sparse-keymap)) + (space-line (propertize "\n\n" 'face 'orgpan-spaceline)) + (arrow-face 'font-lock-keyword-face) + (L (propertize "left" 'face arrow-face)) + (R (propertize "right" 'face arrow-face)) + (U (propertize "up" 'face arrow-face)) + (D (propertize "down" 'face arrow-face))) + ;;(message D)(sit-for 2) + (define-key base-map [left] 'ignore) + (define-key base-map [right] 'ignore) + (define-key base-map [up] 'ignore) + (define-key base-map [down] 'ignore) + (define-key base-map [?q] 'delete-window) + (define-key base-map [??] 'orgpan-help) + ;; Navigating + (let ((map (copy-keymap base-map))) + (define-key map [left] 'outline-up-heading) + (define-key map [right] 'org-cycle) + (define-key map [up] 'outline-previous-visible-heading) + (define-key map [down] 'outline-next-visible-heading) + (define-key map [(shift down)] 'outline-forward-same-level) + (define-key map [(shift up)] 'outline-backward-same-level) + (orgpan-insert-field "Navigate" map (concat U "/" D ", " L ": Go to, " R ": Visibility"))) + (insert " ") + (let ((map (copy-keymap base-map))) + (define-key map [up] 'org-move-subtree-up) + (define-key map [down] 'org-move-subtree-down) + (define-key map [left] 'org-do-promote) + (define-key map [right] 'org-do-demote) + (define-key map [(shift left)] 'org-promote-subtree) + (define-key map [(shift right)] 'org-demote-subtree) + (orgpan-insert-field + "Restructure" map + (concat U "/" D ": " + (propertize "Move" 'face 'font-lock-warning-face) + ", " L "/" R ": " + (propertize "Level (w S: Subtree Level)" 'face 'font-lock-warning-face)))) + (insert " ") + (let ((map (copy-keymap base-map))) + (define-key map [up] 'org-priority-up) + (define-key map [down] 'org-priority-down) + (define-key map [right] 'org-todo) + (orgpan-insert-field "TODO/priority" map + (concat R ": TODO, " U "/" D ": Priority"))) + ) + (insert " ? for help, q quit\n") + (orgpan-display-bindings-help) + (set-keymap-parent orgpan-mode-map orgpan-with-keymap) + )) + +(defun orgpan-make-panel-buffer () + "Make the panel buffer." + (let* ((buf-name "*Org Panel*")) + (when orgpan-panel-buffer (kill-buffer orgpan-panel-buffer)) + ;;(with-current-buffer orgpan-panel-buffer (orgpan-mode)) + (setq orgpan-panel-buffer (get-buffer-create buf-name)) + (if orgpan-panel-buttons + (orgpan-make-panel-with-buttons orgpan-panel-buffer) + (orgpan-make-panel-without-buttons orgpan-panel-buffer)) + (with-current-buffer orgpan-panel-buffer + (orgpan-mode) + (goto-char (point-min))) + orgpan-panel-buffer)) + +(defun orgpan-help () + (interactive) + (set-keymap-parent orgpan-with-keymap nil) + (set-keymap-parent orgpan-without-keymap nil) + (describe-function 'orgpan-panel) + (set-keymap-parent orgpan-with-keymap org-mode-map) + (set-keymap-parent orgpan-without-keymap org-mode-map) + (message "Use 'l' to get back to last viewed org file")) + +(defcustom orgpan-panel-height 5 + "Panel height" + :type '(choice (integer :tag "One line" 2) + (integer :tag "All lines" 5)) + :group 'orgpan) + +(defun orgpan-panel () + "Create a control panel for current `org-mode' buffer. +The control panel may be used to quickly move around and change +the headings. The idea is that when you want to to a lot of this +kind of editing you should be able to do that with few +keystrokes (and without having to remember the complicated +keystrokes). A typical situation when this perhaps can be useful +is when you are looking at your notes file \(usually ~/.notes, +see `remember-data-file') where you have saved quick notes with +`remember'. + +The keys below are defined in the panel. Note that the commands +are carried out in the `org-mode' buffer that belongs to the +panel. + +\\{orgpan-mode-map} + +In addition to the keys above most of the keys in `org-mode' can +also be used from the panel. + +Note: There are two forms of the control panel, one with buttons +and one without. The default is without, see +`orgpan-panel-buttons'. If buttons are used choosing a different +button changes the binding of the arrow keys." + (interactive) + (unless (derived-mode-p 'org-mode) + (error "Buffer is not in org-mode")) + (orgpan-delete-panel) + (unless orgpan-org-mode-commands + (map-keymap (lambda (ev def) + (when (and def + (symbolp def) + (fboundp def)) + (setq orgpan-org-mode-commands + (cons def orgpan-org-mode-commands)))) + org-mode-map)) + (remq 'org-self-insert-command orgpan-org-mode-commands) + ;;(org-back-to-heading) + ;;(remove-hook 'window-configuration-change-hook 'orgpan-window-config-change) + (split-window) + (if orgpan-panel-at-top + (setq orgpan-org-window (next-window)) + (setq orgpan-org-window (selected-window)) + (select-window (next-window))) + (set-window-buffer (selected-window) (orgpan-make-panel-buffer)) + (setq orgpan-panel-window (selected-window)) + (set-window-dedicated-p orgpan-panel-window t) + (adjust-window-trailing-edge orgpan-org-window + (- (window-height) orgpan-panel-height) nil) + ;; The minor mode version starts here: + (when orgpan-minor-mode-version + (select-window orgpan-org-window) + (orgpan-panel-minor-mode 1) + (add-hook 'post-command-hook 'orgpan-minor-post-command t))) + +(define-minor-mode orgpan-panel-minor-mode + "Minor mode used in `org-mode' buffer when showing panel." + :keymap orgpan-mode-map + :lighter " PANEL" + :group 'orgpan + ) + +(defun orgpan-minor-post-command () + ;; Check org window and buffer + (if (and (windowp orgpan-org-window) + (window-live-p orgpan-org-window) + (eq orgpan-org-window (selected-window)) + (derived-mode-p 'org-mode) + ;; Check panel window and buffer + (windowp orgpan-panel-window) + (window-live-p orgpan-panel-window) + (bufferp orgpan-panel-buffer) + (buffer-live-p orgpan-panel-buffer) + (eq (window-buffer orgpan-panel-window) orgpan-panel-buffer) + ;; Check minor mode + orgpan-panel-minor-mode) + (setq cursor-type nil) + (orgpan-delete-panel))) + + +(provide 'org-panel) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; org-panel.el ends here diff --git a/emacs/nxhtml/util/ourcomments-util.el b/emacs/nxhtml/util/ourcomments-util.el new file mode 100644 index 0000000..5e9c2e6 --- /dev/null +++ b/emacs/nxhtml/util/ourcomments-util.el @@ -0,0 +1,2427 @@ +;;; ourcomments-util.el --- Utility routines +;; +;; Author: Lennart Borgman <lennart dot borgman at gmail dot com> +;; Created: Wed Feb 21 2007 +(defconst ourcomments-util:version "0.25") ;;Version: +;; Last-Updated: 2009-08-04 Tue +;; Keywords: +;; Compatibility: Emacs 22 +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; The functionality given by these small routines should in my +;; opinion be part of Emacs (but they are not that currently). +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'apropos)) +(eval-when-compile (require 'bookmark)) +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'grep)) +(eval-when-compile (require 'ido)) +(eval-when-compile (require 'org)) +(eval-when-compile (require 'recentf)) +(eval-when-compile (require 'uniquify)) + +(require 'cus-edit) + +;; (ourcomments-indirect-fun 'html-mumamo) +;; (ourcomments-indirect-fun 'html-mumamo-mode) +;;;###autoload +(defun ourcomments-indirect-fun (fun) + "Get the alias symbol for function FUN if any." + ;; This code is from `describe-function-1'. + (when (and (symbolp fun) + (functionp fun)) + (let ((def (symbol-function fun))) + (when (symbolp def) + (while (and (fboundp def) + (symbolp (symbol-function def))) + (setq def (symbol-function def))) + def)))) + +(defun ourcomments-goto-line (line) + "A version of `goto-line' for use in elisp code." + (save-restriction + (widen) + (goto-char (point-min)) + (forward-line (1- line)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Popups etc. + +(defun point-to-coord (point) + "Return coordinates of POINT in selected window. +The coordinates are in the form \(\(XOFFSET YOFFSET) WINDOW). +This form is suitable for `popup-menu'." + ;; Fix-me: showtip.el adds (window-inside-pixel-edges + ;; (selected-window)). Why? + (let* ((pn (posn-at-point point)) + (x-y (posn-x-y pn)) + (x (car x-y)) + (y (cdr x-y)) + (pos (list (list x (+ y 20)) (selected-window)))) + pos)) + +;;;###autoload +(defun popup-menu-at-point (menu &optional prefix) + "Popup the given menu at point. +This is similar to `popup-menu' and MENU and PREFIX has the same +meaning as there. The position for the popup is however where +the window point is." + (let ((where (point-to-coord (point)))) + (popup-menu menu where prefix))) + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Toggles in menus + +;;;###autoload +(defmacro define-toggle (symbol value doc &rest args) + "Declare SYMBOL as a customizable variable with a toggle function. +The purpose of this macro is to define a defcustom and a toggle +function suitable for use in a menu. + +The arguments have the same meaning as for `defcustom' with these +restrictions: + +- The :type keyword cannot be used. Type is always 'boolean. +- VALUE must be t or nil. + +DOC and ARGS are just passed to `defcustom'. + +A `defcustom' named SYMBOL with doc-string DOC and a function +named SYMBOL-toggle is defined. The function toggles the value +of SYMBOL. It takes no parameters. + +To create a menu item something similar to this can be used: + + \(define-key map [SYMBOL] + \(list 'menu-item \"Toggle nice SYMBOL\" + 'SYMBOL-toggle + :button '(:toggle . SYMBOL)))" + (declare + (doc-string 3) + (debug t)) + (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle"))) + (SYMBOL-name (symbol-name symbol)) + (var-doc doc) + (fun-doc (concat "Toggles the \(boolean) value of `" + SYMBOL-name + "'.\n" + "For how to set it permanently see this variable.\n" + ))) + (let ((var (append `(defcustom ,symbol ,value ,var-doc) + args + nil)) + (fun `(defun ,SYMBOL-toggle () + ,fun-doc + (interactive) + (customize-set-variable (quote ,symbol) (not ,symbol))))) + ;;(message "\nvar=%S\nfun=%S\n" var fun) + ;; Fix-me: I am having problems with this one, see + ;; http://lists.gnu.org/archive/html/help-gnu-emacs/2009-12/msg00608.html + `(progn ,var ,fun) + ))) + +;;(macroexpand '(define-toggle my-toggle t "doc" :tag "Short help" :group 'popcmp)) +;;(macroexpand-all (define-toggle my-toggle t "doc" :tag "Short help" :group 'popcmp)) + +;;;###autoload +(defmacro define-toggle-old (symbol value doc &rest args) + (declare (doc-string 3)) + (list + 'progn + (let ((var-decl (list 'custom-declare-variable + (list 'quote symbol) + (list 'quote value) + doc))) + (while args + (let ((arg (car args))) + (setq args (cdr args)) + (unless (symbolp arg) + (error "Junk in args %S" args)) + (let ((keyword arg) + (value (car args))) + (unless args + (error "Keyword %s is missing an argument" keyword)) + (setq args (cdr args)) + (cond + ((not (memq keyword '(:type))) + (setq var-decl (append var-decl (list keyword value)))) + (t + (lwarn '(define-toggle) :error "Keyword %s can't be used here" + keyword)))))) + (when (assoc :type var-decl) (error ":type is set. Should not happen!")) + (setq var-decl (append var-decl (list :type '(quote boolean)))) + var-decl) + (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle"))) + (SYMBOL-name (symbol-name symbol)) + (fun-doc (concat "Toggles the \(boolean) value of `" + SYMBOL-name + "'.\n" + "For how to set it permanently see this variable.\n" + ;;"\nDescription of `" SYMBOL-name "':\n" doc + ))) + `(defun ,SYMBOL-toggle () + ,fun-doc + (interactive) + (customize-set-variable (quote ,symbol) (not ,symbol))) + ))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Indentation of regions + +;; From an idea by weber <hugows@gmail.com> +;; (defun indent-line-or-region () +;; "Indent line or region. +;; Only do this if indentation seems bound to \\t. + +;; Call `indent-region' if region is active, otherwise +;; `indent-according-to-mode'." +;; (interactive) +;; ;; Do a wild guess if we should indent or not ... +;; (let* ((indent-region-mode) +;; ;; The above hides the `indent-line-or-region' binding +;; (t-bound (key-binding [?\t]))) +;; (if (not +;; (save-match-data +;; (string-match "indent" (symbol-name t-bound)))) +;; (call-interactively t-bound t) +;; (if (and mark-active ;; there is a visible region selected +;; transient-mark-mode) +;; (indent-region (region-beginning) (region-end)) +;; (indent-according-to-mode))))) ;; indent line + +;; (define-minor-mode indent-region-mode +;; "Use \\t to indent line or region. +;; The key \\t is bound to `indent-line-or-region' if this mode is +;; on." +;; :global t +;; :keymap '(([?\t] . indent-line-or-region))) +;; (when indent-region-mode (indent-region-mode 1)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Minor modes + +;; (defmacro define-globalized-minor-mode-with-on-off (global-mode mode +;; turn-on turn-off +;; &rest keys) +;; "Make a global mode GLOBAL-MODE corresponding to buffer-local minor MODE. +;; This is a special variant of `define-globalized-minor-mode' for +;; mumamo. It let bounds the variable GLOBAL-MODE-checking before +;; calling TURN-ON or TURN-OFF. + +;; TURN-ON is a function that will be called with no args in every buffer +;; and that should try to turn MODE on if applicable for that buffer. +;; TURN-OFF is a function that turns off MODE in a buffer. +;; KEYS is a list of CL-style keyword arguments. As the minor mode +;; defined by this function is always global, any :global keyword is +;; ignored. Other keywords have the same meaning as in `define-minor-mode', +;; which see. In particular, :group specifies the custom group. +;; The most useful keywords are those that are passed on to the +;; `defcustom'. It normally makes no sense to pass the :lighter +;; or :keymap keywords to `define-globalized-minor-mode', since these +;; are usually passed to the buffer-local version of the minor mode. + +;; If MODE's set-up depends on the major mode in effect when it was +;; enabled, then disabling and reenabling MODE should make MODE work +;; correctly with the current major mode. This is important to +;; prevent problems with derived modes, that is, major modes that +;; call another major mode in their body." + +;; (let* ((global-mode-name (symbol-name global-mode)) +;; (pretty-name (easy-mmode-pretty-mode-name mode)) +;; (pretty-global-name (easy-mmode-pretty-mode-name global-mode)) +;; (group nil) +;; (extra-keywords nil) +;; (MODE-buffers (intern (concat global-mode-name "-buffers"))) +;; (MODE-enable-in-buffers +;; (intern (concat global-mode-name "-enable-in-buffers"))) +;; (MODE-check-buffers +;; (intern (concat global-mode-name "-check-buffers"))) +;; (MODE-cmhh (intern (concat global-mode-name "-cmhh"))) +;; (MODE-major-mode (intern (concat (symbol-name mode) +;; "-major-mode"))) +;; (MODE-checking (intern (concat global-mode-name "-checking"))) +;; keyw) + +;; ;; Check keys. +;; (while (keywordp (setq keyw (car keys))) +;; (setq keys (cdr keys)) +;; (case keyw +;; (:group (setq group (nconc group (list :group (pop keys))))) +;; (:global (setq keys (cdr keys))) +;; (t (push keyw extra-keywords) (push (pop keys) extra-keywords)))) + +;; (unless group +;; ;; We might as well provide a best-guess default group. +;; (setq group +;; `(:group ',(intern (replace-regexp-in-string +;; "-mode\\'" "" (symbol-name mode)))))) + +;; `(progn + +;; ;; Define functions for the global mode first so that it can be +;; ;; turned on during load: + +;; ;; List of buffers left to process. +;; (defvar ,MODE-buffers nil) + +;; ;; The function that calls TURN-ON in each buffer. +;; (defun ,MODE-enable-in-buffers () +;; (let ((,MODE-checking nil)) +;; (dolist (buf ,MODE-buffers) +;; (when (buffer-live-p buf) +;; (with-current-buffer buf +;; (if ,mode +;; (unless (eq ,MODE-major-mode major-mode) +;; (setq ,MODE-checking t) +;; (,mode -1) +;; (,turn-on) +;; (setq ,MODE-checking nil) +;; (setq ,MODE-major-mode major-mode)) +;; (setq ,MODE-checking t) +;; (,turn-on) +;; (setq ,MODE-checking nil) +;; (setq ,MODE-major-mode major-mode))))))) +;; (put ',MODE-enable-in-buffers 'definition-name ',global-mode) + +;; (defun ,MODE-check-buffers () +;; (,MODE-enable-in-buffers) +;; (setq ,MODE-buffers nil) +;; (remove-hook 'post-command-hook ',MODE-check-buffers)) +;; (put ',MODE-check-buffers 'definition-name ',global-mode) + +;; ;; The function that catches kill-all-local-variables. +;; (defun ,MODE-cmhh () +;; (add-to-list ',MODE-buffers (current-buffer)) +;; (add-hook 'post-command-hook ',MODE-check-buffers)) +;; (put ',MODE-cmhh 'definition-name ',global-mode) + + +;; (defvar ,MODE-major-mode nil) +;; (make-variable-buffer-local ',MODE-major-mode) + +;; ;; The actual global minor-mode +;; (define-minor-mode ,global-mode +;; ,(format "Toggle %s in every possible buffer. +;; With prefix ARG, turn %s on if and only if ARG is positive. +;; %s is enabled in all buffers where `%s' would do it. +;; See `%s' for more information on %s." +;; pretty-name pretty-global-name pretty-name turn-on +;; mode pretty-name) +;; :global t ,@group ,@(nreverse extra-keywords) + +;; ;; Setup hook to handle future mode changes and new buffers. +;; (if ,global-mode +;; (progn +;; (add-hook 'after-change-major-mode-hook +;; ',MODE-enable-in-buffers) +;; ;;(add-hook 'find-file-hook ',MODE-check-buffers) +;; (add-hook 'find-file-hook ',MODE-cmhh) +;; (add-hook 'change-major-mode-hook ',MODE-cmhh)) +;; (remove-hook 'after-change-major-mode-hook ',MODE-enable-in-buffers) +;; ;;(remove-hook 'find-file-hook ',MODE-check-buffers) +;; (remove-hook 'find-file-hook ',MODE-cmhh) +;; (remove-hook 'change-major-mode-hook ',MODE-cmhh)) + +;; ;; Go through existing buffers. +;; (let ((,MODE-checking t)) +;; (dolist (buf (buffer-list)) +;; (with-current-buffer buf +;; ;;(if ,global-mode (,turn-on) (when ,mode (,mode -1))) +;; (if ,global-mode (,turn-on) (,turn-off)) +;; )))) + +;; ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Unfilling +;; +;; The idea is from +;; http://interglacial.com/~sburke/pub/emacs/sburke_dot_emacs.config + +;;;###autoload +(defun unfill-paragraph () + "Unfill the current paragraph." + (interactive) (with-unfilling 'fill-paragraph)) +;;(defalias 'unwrap-paragraph 'unfill-paragraph) + +;;;###autoload +(defun unfill-region () + "Unfill the current region." + (interactive) (with-unfilling 'fill-region)) +;;(defalias 'unwrap-region 'unfill-region) + +;;;###autoload +(defun unfill-individual-paragraphs () + "Unfill individual paragraphs in the current region." + (interactive) (with-unfilling 'fill-individual-paragraphs)) +;;(defalias 'unwrap-individual-paragraphs 'unfill-individual-paragraphs) + +(defun with-unfilling (fn) + "Unfill using the fill function FN." + (let ((fill-column (1+ (point-max)))) (call-interactively fn))) + +(defvar fill-dwim-state nil) +(defvar fill-dwim-mark nil) + +;;;###autoload +(defun fill-dwim (arg) + "Fill or unfill paragraph or region. +With prefix ARG fill only current line." + (interactive "P") + (or arg + (not fill-dwim-mark) + (equal (point-marker) fill-dwim-mark) + (setq fill-dwim-state nil)) + (if mark-active + ;; This avoids deactivating the mark + (progn + (if fill-dwim-state + (call-interactively 'unfill-region) + (call-interactively 'fill-region)) + (setq deactivate-mark nil)) + (if arg + (fill-region (line-beginning-position) (line-end-position)) + (if fill-dwim-state + (call-interactively 'unfill-paragraph) + (call-interactively 'fill-paragraph)))) + (setq fill-dwim-mark (copy-marker (point))) + (unless arg + (setq fill-dwim-state (not fill-dwim-state)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Widgets + +;;;###autoload +(defun ourcomments-mark-whole-buffer-or-field () + "Mark whole buffer or editable field at point." + (interactive) + (let* ((field (widget-field-at (point))) + (from (when field (widget-field-start field))) + (to (when field (widget-field-end field))) + (size (when field (widget-get field :size)))) + (if (not field) + (mark-whole-buffer) + (while (and size + (not (zerop size)) + (> to from) + (eq (char-after (1- to)) ?\s)) + (setq to (1- to))) + (push-mark (point)) + (push-mark from nil t) + (goto-char to)))) + +;; (rassq 'genshi-nxhtml-mumamo-mode mumamo-defined-turn-on-functions) +;; (major-modep 'nxhtml-mode) +;; (major-modep 'nxhtml-mumamo-mode) +;; (major-modep 'jsp-nxhtml-mumamo-mode) +;; (major-modep 'gsp-nxhtml-mumamo-mode) +;; (major-modep 'asp-nxhtml-mumamo-mode) +;; (major-modep 'django-nxhtml-mumamo-mode) +;; (major-modep 'eruby-nxhtml-mumamo-mode) +;; (major-modep 'eruby-nxhtml-mumamo-mode) +;; (major-modep 'smarty-nxhtml-mumamo-mode) +;; (major-modep 'embperl-nxhtml-mumamo-mode) +;; (major-modep 'laszlo-nxml-mumamo-mode) +;; (major-modep 'genshi-nxhtml-mumamo-mode) +;; (major-modep 'javascript-mode) +;; (major-modep 'espresso-mode) +;; (major-modep 'css-mode) +;; (major-modep 'js-mode) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Lines + +;; Changed from move-beginning-of-line to beginning-of-line to support +;; physical-line-mode. +;; Fix-me: use end-of-visual-line etc. +;;;###autoload +(defun ourcomments-move-beginning-of-line(arg) + "Move point to beginning of line or indentation. +See `beginning-of-line' for ARG. + +If `line-move-visual' is non-nil then the visual line beginning +is first tried. + +If in a widget field stay in that." + (interactive "p") + (let ((pos (point)) + vis-pos + (field (widget-field-at (point)))) + (when line-move-visual + (line-move-visual -1 t) + (beginning-of-line) + (setq vis-pos (point)) + (goto-char pos)) + (call-interactively 'beginning-of-line arg) + (when (and vis-pos + (= vis-pos (point))) + (while (and (> pos (point)) + (not (eobp))) + (let (last-command) + (line-move-visual 1 t))) + (line-move-visual -1 t)) + (when (= pos (point)) + (if (= 0 (current-column)) + (skip-chars-forward " \t") + (backward-char) + (beginning-of-line))) + (when (and field + (< (point) (widget-field-start field))) + (goto-char (widget-field-start field))))) +(put 'ourcomments-move-beginning-of-line 'CUA 'move) + +;;;###autoload +(defun ourcomments-move-end-of-line(arg) + "Move point to end of line or after last non blank char. +See `end-of-line' for ARG. + +Similar to `ourcomments-move-beginning-of-line' but for end of +line." + (interactive "p") + (or arg (setq arg 1)) + (let ((pos (point)) + vis-pos + eol-pos) + (when line-move-visual + (let (last-command) (line-move-visual 1 t)) + (end-of-line) + (setq vis-pos (point)) + (goto-char pos)) + (call-interactively 'end-of-line arg) + (when (and vis-pos + (= vis-pos (point))) + (setq eol-pos (point)) + (beginning-of-line) + (let (last-command) (line-move-visual 1 t)) + ;; move backwards if we moved to a new line + (unless (= (point) eol-pos) + (backward-char))) + (when (= pos (point)) + (if (= (line-end-position) (point)) + (skip-chars-backward " \t") + (forward-char) + (end-of-line))))) +(put 'ourcomments-move-end-of-line 'CUA 'move) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Keymaps + +(defun ourcomments-find-keymap-variables (key--- binding--- keymap---) + "Return a list of matching keymap variables. +They should have key KEY--- bound to BINDING--- and have value +KEYMAP---. + +Ignore `special-event-map', `global-map', `overriding-local-map' +and `overriding-terminal-local-map'." + (let ((vars--- nil) + (ancestors--- nil)) + (let ((parent (keymap-parent keymap---))) + (while parent + (setq ancestors--- (cons parent ancestors---)) + (setq parent (keymap-parent parent)))) + (mapatoms (lambda (symbol) + (unless (memq symbol '(keymap--- + ancestors--- + vars--- + special-event-map + global-map + overriding-local-map + overriding-terminal-local-map + )) + (let (val) + (if (boundp symbol) + (setq val (symbol-value symbol)) + (when (keymapp symbol) + (setq val (symbol-function symbol)))) + (when (and val + (keymapp val) + (eq binding--- (lookup-key val key--- t))) + (if (equal val keymap---) + (push symbol vars---) + (when ancestors--- + (catch 'found + (dolist (ancestor ancestors---) + (when (equal val ancestor) + (push symbol vars---) + (throw 'found nil))))))))))) +;;; (let ((childs nil)) +;;; (dolist (var vars---) +;;; (dolist (ancestor ancestors---) +;;; (when (equal (keymap-parent var) +;;; ( + vars---)) + +;; This is modelled after `current-active-maps'. +(defun key-bindings (key &optional olp position) + "Return list of bindings for key sequence KEY in current keymaps. +The first binding is the active binding and the others are +bindings shadowed by this in the order of their priority level +\(see Info node `(elisp) Searching Keymaps'). + +The entries in the list have the form + + \(BINDING (MAPS) MORE-INFO) + +where BINDING is the command bound to and MAPS are matching maps +\(according to `ourcomments-find-keymap-variables'). + +MORE-INFO is a list with more information + + \(PRIORITY-LEVEL \[ACTIVE-WHEN]) + +where PRIORITY-LEVEL is a symbol matching the level where the +keymap is found and ACTIVE-WHEN is a symbol which must be non-nil +for the keymap to be active \(minor mode levels only)." + ;;(message "\nkey-bindings %s %s %s" key olp position) + (let* ((bindings nil) + (maps (current-active-maps)) + map + map-sym + map-rec + binding + keymaps + minor-maps + where + map-where + where-map + (local-map (current-local-map)) + (pt (or position (point))) + (point-keymap (get-char-property pt 'keymap)) + (point-local-map (get-char-property pt 'local-map)) + ) + (setq keymaps + (cons (list global-map 'global-map) + keymaps)) + (when overriding-terminal-local-map + (setq keymaps + (cons (list overriding-terminal-local-map 'overriding-terminal-local-map) + keymaps))) + (when overriding-local-map + (setq keymaps + (cons (list overriding-local-map 'overriding-local-map) + keymaps))) + (unless (cdr keymaps) + (when point-local-map + (setq keymaps + (cons (list point-local-map 'point-local-map) + keymaps))) + ;; Fix-me: + ;;/* If on a mode line string with a local keymap, + + (when local-map + (setq keymaps + (cons (list local-map 'local-map) + keymaps))) + + ;; Minor-modes + ;;(message "================ Minor-modes") + (dolist (list '(emulation-mode-map-alists + minor-mode-overriding-map-alist + minor-mode-map-alist)) + ;;(message "------- %s" list) + (let ((alists (if (eq list 'emulation-mode-map-alists) + (symbol-value list) + (list (symbol-value list))))) + (dolist (alist alists) + ;;(message "\n(symbolp alist)=%s alist= %s (symbol-value alist)=%s" (symbolp alist) "dum" "dum2") ;alist "dummy");(when (symbolp alist) (symbol-value alist))) + (when (symbolp alist) + (setq alist (symbol-value alist))) + (dolist (assoc alist) + (let* (;(assoc (car alist-rec)) + (var (when (consp assoc) (car assoc))) + (val (when (and (symbolp var) + (boundp var)) + (symbol-value var)))) + ;;(message "var= %s, val= %s" var val) + (when (and + val + (or (not (eq list 'minor-mode-map-alist)) + (not (assq var minor-mode-overriding-map-alist)))) + ;;(message "** Adding this") + (setq minor-maps + (cons (list (cdr assoc) list var) + minor-maps))) + ))))) + (dolist (map minor-maps) + ;;(message "cdr map= %s" (cdr map)) + (setq keymaps + (cons map + keymaps))) + (when point-keymap + (setq keymaps + (cons (list point-keymap 'point-keymap) + keymaps)))) + + ;; Fix-me: compare with current-active-maps + (let ((ca-maps (current-active-maps)) + (wh-maps keymaps) + ca + wh) + (while (or ca-maps wh-maps) + (setq ca (car ca-maps)) + (setq wh (car wh-maps)) + (setq ca-maps (cdr ca-maps)) + (setq wh-maps (cdr wh-maps)) + ;;(message "\nca= %s" ca) + ;;(message "cdr wh= %s" (cdr wh)) + (unless (equal ca (car wh)) + (error "Did not match: %s" (cdr wh))))) + + (while keymaps + (setq map-rec (car keymaps)) + (setq map (car map-rec)) + (when (setq binding (lookup-key map key t)) + (setq map-sym (ourcomments-find-keymap-variables key binding map)) + (setq map-sym (delq 'map map-sym)) + (setq map-sym (delq 'local-map map-sym)) + (setq map-sym (delq 'point-keymap map-sym)) + (setq map-sym (delq 'point-local-map map-sym)) + (setq bindings (cons (list binding map-sym (cdr map-rec)) bindings))) + (setq keymaps (cdr keymaps))) + + (nreverse bindings))) + +(defun describe-keymap-placement (keymap-sym) + "Find minor mode keymap KEYMAP-SYM in the keymaps searched for key lookup. +See Info node `Searching Keymaps'." + ;;(info "(elisp) Searching Keymaps") + (interactive (list (ourcomments-read-symbol "Describe minor mode keymap symbol" + (lambda (sym) + (and (boundp sym) + (keymapp (symbol-value sym))))))) + (unless (symbolp keymap-sym) + (error "Argument KEYMAP-SYM must be a symbol")) + (unless (keymapp (symbol-value keymap-sym)) + (error "The value of argument KEYMAP-SYM must be a keymap")) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'describe-keymap-placement keymap-sym) (interactive-p)) + (with-current-buffer (help-buffer) + (insert "Placement of keymap `") + (insert-text-button (symbol-name keymap-sym) + 'action + (lambda (btn) + (describe-variable keymap-sym))) + (insert "'\nin minor modes activation maps:\n") + (let (found) + (dolist (map-root '(emulation-mode-map-alists + minor-mode-overriding-map-alist + minor-mode-map-alist + )) + (dolist (emul-alist (symbol-value map-root)) + ;;(message "emul-alist=%s" emul-alist) + (dolist (keymap-alist + (if (memq map-root '(emulation-mode-map-alists)) + (symbol-value emul-alist) + (list emul-alist))) + (let* ((map (cdr keymap-alist)) + (first (catch 'first + (map-keymap (lambda (key def) + (throw 'first (cons key def))) + map))) + (key (car first)) + (def (cdr first)) + (keymap-variables (when (and key def) + (ourcomments-find-keymap-variables + (vector key) def map))) + (active-var (car keymap-alist)) + ) + (assert (keymapp map)) + ;;(message "keymap-alist=%s, %s" keymap-alist first) + ;;(message "active-var=%s, %s" active-var keymap-variables) + (when (memq keymap-sym keymap-variables) + (setq found t) + (insert (format "\n`%s' " map-root)) + (insert (propertize "<= Minor mode keymap list holding this map" + 'face 'font-lock-doc-face)) + (insert "\n") + (when (symbolp emul-alist) + (insert (format " `%s' " emul-alist)) + (insert (propertize "<= Keymap alist variable" 'face 'font-lock-doc-face)) + (insert "\n")) + ;;(insert (format " `%s'\n" keymap-alist)) + (insert (format " `%s' " active-var)) + (insert (propertize "<= Activation variable" 'face 'font-lock-doc-face)) + (insert "\n") + ))))) + (unless found + (insert (propertize "Not found." 'face 'font-lock-warning-face))) + )))) + +;; This is a replacement for describe-key-briefly. +;;(global-set-key [f1 ?c] 'describe-key-and-map-briefly) +;;;###autoload +(defun describe-key-and-map-briefly (&optional key insert untranslated) + "Try to print names of keymap from which KEY fetch its definition. +Look in current active keymaps and find keymap variables with the +same value as the keymap where KEY is bound. Print a message +with those keymap variable names. Return a list with the keymap +variable symbols. + +When called interactively prompt for KEY. + +INSERT and UNTRANSLATED should normall be nil (and I am not sure +what they will do ;-)." + ;; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ;; From describe-key-briefly. Keep this as it is for easier update. + (interactive + (let ((enable-disabled-menus-and-buttons t) + (cursor-in-echo-area t) + saved-yank-menu) + (unwind-protect + (let (key) + ;; If yank-menu is empty, populate it temporarily, so that + ;; "Select and Paste" menu can generate a complete event. + (when (null (cdr yank-menu)) + (setq saved-yank-menu (copy-sequence yank-menu)) + (menu-bar-update-yank-menu "(any string)" nil)) + (setq key (read-key-sequence "Describe key (or click or menu item): ")) + ;; If KEY is a down-event, read and discard the + ;; corresponding up-event. Note that there are also + ;; down-events on scroll bars and mode lines: the actual + ;; event then is in the second element of the vector. + (and (vectorp key) + (let ((last-idx (1- (length key)))) + (and (eventp (aref key last-idx)) + (memq 'down (event-modifiers (aref key last-idx))))) + (read-event)) + (list + key + (if current-prefix-arg (prefix-numeric-value current-prefix-arg)) + 1 + )) + ;; Put yank-menu back as it was, if we changed it. + (when saved-yank-menu + (setq yank-menu (copy-sequence saved-yank-menu)) + (fset 'yank-menu (cons 'keymap yank-menu)))))) + (if (numberp untranslated) + (setq untranslated (this-single-command-raw-keys))) + (let* ((event (if (and (symbolp (aref key 0)) + (> (length key) 1) + (consp (aref key 1))) + (aref key 1) + (aref key 0))) + (modifiers (event-modifiers event)) + (standard-output (if insert (current-buffer) t)) + (mouse-msg (if (or (memq 'click modifiers) (memq 'down modifiers) + (memq 'drag modifiers)) " at that spot" "")) + (defn (key-binding key t)) + key-desc) + ;; Handle the case where we faked an entry in "Select and Paste" menu. + (if (and (eq defn nil) + (stringp (aref key (1- (length key)))) + (eq (key-binding (substring key 0 -1)) 'yank-menu)) + (setq defn 'menu-bar-select-yank)) + ;; Don't bother user with strings from (e.g.) the select-paste menu. + (if (stringp (aref key (1- (length key)))) + (aset key (1- (length key)) "(any string)")) + (if (and (> (length untranslated) 0) + (stringp (aref untranslated (1- (length untranslated))))) + (aset untranslated (1- (length untranslated)) "(any string)")) + ;; Now describe the key, perhaps as changed. + (setq key-desc (help-key-description key untranslated)) + ;; + ;; End of part from describe-key-briefly. + ;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + ;;(message "bindings=%s" (key-bindings key)) (sit-for 2) + ;; Find the keymap: + (let* ((maps (current-active-maps)) + ret + lk) + (if (or (null defn) (integerp defn) (equal defn 'undefined)) + (setq ret 'not-defined) + (catch 'mapped + (while (< 1 (length maps)) + (setq lk (lookup-key (car maps) key t)) + (when (and lk (not (numberp lk))) + (setq ret (ourcomments-find-keymap-variables key lk (car maps))) + (when ret + (throw 'mapped (car maps)))) + (setq maps (cdr maps)))) + (unless ret + (setq lk (lookup-key global-map key t)) + (when (and lk (not (numberp lk))) + (setq ret '(global-map))))) + (cond + ((eq ret 'not-defined) + (message "%s%s not defined in any keymap" key-desc mouse-msg)) + ((listp ret) + (if (not ret) + (message "%s%s is bound to `%s', but don't know where" + key-desc mouse-msg defn) + (if (= 1 (length ret)) + (message "%s%s is bound to `%s' in `%s'" + key-desc mouse-msg defn (car ret)) + (message "%s%s is bound to `%s' in keymap variables `%s'" + key-desc mouse-msg defn ret)))) + (t + (error "ret=%s" ret))) + ret))) + +;; (ourcomments-find-keymap-variables (current-local-map)) +;; (keymapp 'ctl-x-4-prefix) +;; (equal 'ctl-x-4-prefix (current-local-map)) +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Fringes. + +(defvar better-bottom-angles-defaults nil) +(defun better-fringes-bottom-angles (on) + ;;(bottom bottom-left-angle bottom-right-angle top-right-angle top-left-angle) + (if (not on) + (when better-bottom-angles-defaults + (set-default 'fringe-indicator-alist better-bottom-angles-defaults)) + (unless better-bottom-angles-defaults + (setq better-bottom-angles-defaults fringe-indicator-alist)) + (let ((better + '(bottom + bottom-right-angle bottom-right-angle + bottom-left-angle bottom-left-angle + )) + ;;(indicators (copy-list fringe-indicator-alist))) + (indicators (copy-sequence fringe-indicator-alist))) + (setq indicators (assq-delete-all 'bottom indicators)) + (set-default 'fringe-indicator-alist (cons better indicators))))) + +(defun better-fringes-faces (face face-important) + (dolist (bitmap '(bottom-left-angle + bottom-right-angle + top-left-angle + top-right-angle + + right-curly-arrow + left-arrow right-arrow + left-curly-arrow right-curly-arrow + up-arrow + down-arrow + left-bracket right-bracket + empty-line)) + (set-fringe-bitmap-face bitmap face)) + (dolist (bitmap '(right-triangle + question-mark)) + (set-fringe-bitmap-face bitmap face-important))) + +(defface better-fringes-bitmap + '((t (:foreground "dark khaki"))) + "Face for bitmap fringes." + :group 'better-fringes + :group 'nxhtml) + +(defface better-fringes-important-bitmap + '((t (:foreground "red"))) + "Face for bitmap fringes." + :group 'better-fringes + :group 'nxhtml) + +;;;###autoload +(define-minor-mode better-fringes-mode + "Choose another fringe bitmap color and bottom angle." + :global t + :group 'better-fringes + (if better-fringes-mode + (progn + (better-fringes-faces 'better-fringes-bitmap + 'better-fringes-important-bitmap) + (better-fringes-bottom-angles t)) + (better-fringes-faces nil nil) + (better-fringes-bottom-angles nil))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Copy+paste + +;; After an idea from andrea on help-gnu-emacs + +(defvar ourcomments-copy+paste-point nil) + +;;(global-set-key [(control ?c) ?y] 'ourcomments-copy+paste-set-point) +;;;###autoload +(defun ourcomments-copy+paste-set-point () + "Set point for copy+paste here. +Enable temporary minor mode `ourcomments-copy+paste-mode'. +However if point for copy+paste already is set then cancel it and +disable the minor mode. + +The purpose of this command is to make it easy to grab a piece of +text and paste it at current position. After this command you +should select a piece of text to copy and then call the command +`ourcomments-copy+paste'." + (interactive) + (if ourcomments-copy+paste-point + (ourcomments-copy+paste-mode -1) + (setq ourcomments-copy+paste-point (list (copy-marker (point)) + (selected-window) + (current-frame-configuration) + )) + (ourcomments-copy+paste-mode 1) + (let ((key (where-is-internal 'ourcomments-copy+paste)) + (ckeys (key-description (this-command-keys)))) + (setq key (if key (key-description (car key)) + "M-x ourcomments-copy+paste")) + (when (> (length ckeys) 12) + (setq ckeys "this command")) + (message "Paste point set; select region and do %s to copy+paste (or cancel with %s)" key ckeys)))) + +(defvar ourcomments-copy+paste-mode-map + (let ((map (make-sparse-keymap))) + ;; Bind the copy+paste command to C-S-v which reminds of cua-paste + ;; binding and is hopefully not bound. + (define-key map [(control shift ?v)] 'ourcomments-copy+paste) + map)) + +(define-minor-mode ourcomments-copy+paste-mode + "Temporary mode for copy+paste. +This minor mode is enabled by `ourcomments-copy+paste-set-point'. + +When this mode is active there is a key binding for +`ourcomments-copy+paste': +\\<ourcomments-copy+paste-mode-map> +\\[ourcomments-copy+paste] + +You should not turn on this minor mode yourself. It is turned on +by `ourcomments-copy+paste-set-point'. For more information see +that command." + :lighter " COPY+PASTE" + :global t + :group 'ourcomments-util + (if ourcomments-copy+paste-mode + (unless ourcomments-copy+paste-point + (message "Do not call this minor mode, use `ourcomments-copy+paste-set-point'.") + (setq ourcomments-copy+paste-mode nil)) + (when ourcomments-copy+paste-point + (setq ourcomments-copy+paste-point nil) + (message "Canceled copy+paste mode")))) + +(defvar ourcomments-copy+paste-ovl nil) + +(defun ourcomments-copy+paste-cancel-highlight () + (when (overlayp ourcomments-copy+paste-ovl) + (delete-overlay ourcomments-copy+paste-ovl)) + (setq ourcomments-copy+paste-ovl nil)) + +(defun ourcomments-copy+paste (restore-frames) + "Copy region to copy+paste point set by `ourcomments-copy+paste-set-point'. +Also if prefix argument is given then restore frame configuration +at the time that command was called. Otherwise look for the +buffer for copy+paste point in current frame. If found select +that window. If not then use `switch-to-buffer-other-window' to +display it." + (interactive "P") + (cond + ((not ourcomments-copy+paste-point) + (let ((key (where-is-internal 'ourcomments-copy+paste-set-point))) + (setq key (if key (key-description (car key)) + "M-x ourcomments-copy+paste-set-point")) + (message "Please select destination of copy+paste first with %s" key))) + ((not mark-active) + (message "Please select a region to copy+paste first")) + (t + ;;(copy-region-as-kill (region-beginning) (region-end)) + (clipboard-kill-ring-save (region-beginning) (region-end)) + (let* ((marker (nth 0 ourcomments-copy+paste-point)) + (orig-win (nth 1 ourcomments-copy+paste-point)) + (orig-fcfg (nth 2 ourcomments-copy+paste-point)) + (buf (marker-buffer marker)) + (win (or (when (window-live-p orig-win) orig-win) + (get-buffer-window buf)))) + (message "win=%s, buf=%s" win buf) + (cond (restore-frames + (set-frame-configuration orig-fcfg)) + ((and win (eq (window-buffer win) buf)) + (select-window win)) + (t + (switch-to-buffer-other-window buf))) + (goto-char marker)) + (let ((here (point)) + ovl) + (yank) + (setq ovl (make-overlay here (point))) + (overlay-put ovl 'face 'highlight) + (run-with-idle-timer 2 nil 'ourcomments-copy+paste-cancel-highlight) + (setq ourcomments-copy+paste-ovl ovl)) + (setq ourcomments-copy+paste-point nil) + (ourcomments-copy+paste-mode -1)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Misc. + +;;(describe-timers) +;;;###autoload +(defun describe-timers () + "Show timers with readable time format." + (interactive) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'ourcommenst-show-timers) (interactive-p)) + (with-current-buffer (help-buffer) + (insert (format-time-string "Timers at %Y-%m-%d %H:%M:%S\n\n" (current-time))) + (if (not timer-list) + (insert " None\n") + (insert (propertize + " When Rpt What\n" + 'face 'font-lock-doc-face)) + (dolist (tmr timer-list) + (let* ((hi-sec (timer--high-seconds tmr)) + (lo-sec (timer--low-seconds tmr)) + (mi-sec (timer--usecs tmr)) + (fun (timer--function tmr)) + (args (timer--args tmr)) + (idle-d (timer--idle-delay tmr)) + (rpt-d (timer--repeat-delay tmr)) + (time (concat (format-time-string " %Y-%m-%d %H:%M:%S" (list hi-sec lo-sec 0)) + (substring + (format "%.1f" (/ mi-sec 1000000.0)) + 1)))) + (assert (not idle-d) t) + (insert (format "%s %4s (`%-3s' %S)\n" time rpt-d fun args))))) + (insert "\nIdle timers:\n\n") + (if (not timer-idle-list) + (insert " None\n") + (insert (propertize + " After Rpt What\n" + 'face 'font-lock-doc-face)) + (dolist (tmr timer-idle-list) + (let* ((hi-sec (timer--high-seconds tmr)) + (lo-sec (timer--low-seconds tmr)) + (mi-sec (timer--usecs tmr)) + (fun (timer--function tmr)) + (args (timer--args tmr)) + (idle-d (timer--idle-delay tmr)) + (rpt-d (timer--repeat-delay tmr)) + (time (+ (* hi-sec 256 256) lo-sec (/ mi-sec 1000000.0))) + ) + (assert (not (not idle-d)) t) + (insert (format " %.2f sec %3s (`%s' %S)\n" time rpt-d fun args)))))))) + +(defcustom ourcomments-insert-date-and-time "%Y-%m-%d %R" + "Time format for command `ourcomments-insert-date-and-time'. +See `format-time-string'." + :type 'string + :group 'ourcomments-util) + +;;;###autoload +(defun ourcomments-insert-date-and-time () + "Insert date and time. +See option `ourcomments-insert-date-and-time' for how to +customize it." + (interactive) + (insert (format-time-string ourcomments-insert-date-and-time))) + +;;;###autoload +(defun find-emacs-other-file (display-file) + "Find corresponding file to source or installed elisp file. +If you have checked out and compiled Emacs yourself you may have +Emacs lisp files in two places, the checked out source tree and +the installed Emacs tree. If buffer contains an Emacs elisp file +in one of these places then find the corresponding elisp file in +the other place. Return the file name of this file. + +Rename current buffer using your `uniquify-buffer-name-style' if +it is set. + +When DISPLAY-FILE is non-nil display this file in other window +and go to the same line number as in the current buffer." + (interactive (list t)) + (unless (buffer-file-name) + (error "This buffer is not visiting a file")) + (unless source-directory + (error "Can't find the checked out Emacs sources")) + (let* ((installed-directory (file-name-as-directory + (expand-file-name ".." exec-directory))) + (relative-installed (file-relative-name + (buffer-file-name) installed-directory)) + (relative-source (file-relative-name + (buffer-file-name) source-directory)) + (name-nondir (file-name-nondirectory (buffer-file-name))) + source-file + installed-file + other-file + (line-num (save-restriction + (widen) + (line-number-at-pos)))) + (cond + ((and relative-installed + (not (string= name-nondir relative-installed)) + (not (file-name-absolute-p relative-installed)) + (not (string= ".." (substring relative-installed 0 2)))) + (setq source-file (expand-file-name relative-installed source-directory))) + ((and relative-source + (not (string= name-nondir relative-source)) + (not (file-name-absolute-p relative-source)) + (not (string= ".." (substring relative-source 0 2)))) + (setq installed-file (expand-file-name relative-source installed-directory)))) + (setq other-file (or source-file installed-file)) + (unless other-file + (error "This file is not in Emacs source or installed lisp tree")) + (unless (file-exists-p other-file) + (error "Can't find the corresponding file %s" other-file)) + (when display-file + (when uniquify-buffer-name-style + (rename-buffer (file-name-nondirectory buffer-file-name) t)) + (find-file-other-window other-file) + (ourcomments-goto-line line-num)) + other-file)) + +;;;###autoload +(defun ourcomments-ediff-files (def-dir file-a file-b) + "In directory DEF-DIR run `ediff-files' on files FILE-A and FILE-B. +The purpose of this function is to make it eaiser to start +`ediff-files' from a shell through Emacs Client. + +This is used in EmacsW32 in the file ediff.cmd where Emacs Client +is called like this: + + @%emacs_client% -e \"(setq default-directory \\\"%emacs_cd%\\\")\" + @%emacs_client% -n -e \"(ediff-files \\\"%f1%\\\" \\\"%f2%\\\")\" + +It can of course be done in a similar way with other shells." + (let ((default-directory def-dir)) + (ediff-files file-a file-b))) + + +(defun ourcomments-latest-changelog () + "not ready" + (let ((changelogs + '("ChangeLog" + "admin/ChangeLog" + "doc/emacs/ChangeLog" + "doc/lispintro/ChangeLog" + "doc/lispref/ChangeLog" + "doc/man/ChangeLog" + "doc/misc/ChangeLog" + "etc/ChangeLog" + "leim/ChangeLog" + "lib-src/ChangeLog" + "lisp/ChangeLog" + "lisp/erc/ChangeLog" + "lisp/gnus/ChangeLog" + "lisp/mh-e/ChangeLog" + "lisp/org/ChangeLog" + "lisp/url/ChangeLog" + "lwlib/ChangeLog" + "msdos/ChangeLog" + "nextstep/ChangeLog" + "nt/ChangeLog" + "oldXMenu/ChangeLog" + "src/ChangeLog" + "test/ChangeLog")) + (emacs-root (expand-file-name ".." exec-directory) + )))) + +(defun ourcomments-read-symbol (prompt predicate) + "Basic function for reading a symbol for describe-* functions. +Prompt with PROMPT and show only symbols satisfying function +PREDICATE. PREDICATE takes one argument, the symbol." + (let* ((symbol (symbol-at-point)) + (enable-recursive-minibuffers t) + val) + (when predicate + (unless (and symbol + (symbolp symbol) + (funcall predicate symbol)) + (setq symbol nil))) + (setq val (completing-read (if symbol + (format + "%s (default %s): " prompt symbol) + (format "%s: " prompt)) + obarray + predicate + t nil nil + (if symbol (symbol-name symbol)))) + (if (equal val "") symbol (intern val)))) + +(defun ourcomments-command-at-point () + (let ((fun (function-called-at-point))) + (when (commandp fun) + fun))) + +;;;###autoload +(defun describe-command (command) + "Like `describe-function', but prompts only for interactive commands." + (interactive + (let* ((fn (ourcomments-command-at-point)) + (prompt (if fn + (format "Describe command (default %s): " fn) + "Describe command: ")) + (enable-recursive-minibuffers t) + val) + (setq val (completing-read prompt + obarray 'commandp t nil nil + (and fn (symbol-name fn)))) + (list (if (equal val "") fn (intern val))))) + (describe-function command)) + + +;;;###autoload +(defun buffer-narrowed-p () + "Return non-nil if the current buffer is narrowed." + (/= (buffer-size) + (- (point-max) + (point-min)))) + +;;;###autoload +(defun narrow-to-comment () + (interactive) + (let* ((here (point-marker)) + (size 1000) + (beg (progn (forward-comment (- size)) + ;; It looks like the wrong syntax-table is used here: + ;;(message "skipped %s " (skip-chars-forward "[:space:]")) + ;; See Emacs bug 3823, http://debbugs.gnu.org/cgi/bugreport.cgi?bug=3823 + (message "skipped %s " (skip-chars-forward " \t\r\n")) + (point))) + (end (progn (forward-comment size) + ;;(message "skipped %s " (skip-chars-backward "[:space:]")) + (message "skipped %s " (skip-chars-backward " \t\r\n")) + (point)))) + (goto-char here) + (if (not (and (>= here beg) + (<= here end))) + (error "Not in a comment") + (narrow-to-region beg end)))) + +(defvar describe-symbol-alist nil) + +(defun describe-symbol-add-known(property description) + (when (assq property describe-symbol-alist) + (error "Already known property")) + (setq describe-symbol-alist + (cons (list property description) + describe-symbol-alist))) + +;;(describe-symbol-add-known 'variable-documentation "Doc for variable") +;;(describe-symbol-add-known 'cl-struct-slots "defstruct slots") + +(defun property-list-keys (plist) + "Return list of key names in property list PLIST." + (let ((keys)) + (while plist + (setq keys (cons (car plist) keys)) + (setq plist (cddr plist))) + keys)) + +(defun ourcomments-symbol-type (symbol) + "Return a list of types where symbol SYMBOL is used. +The can include 'variable, 'function and variaus 'cl-*." + (symbol-file symbol) + ) + +(defun ourcomments-defstruct-p (symbol) + "Return non-nil if symbol SYMBOL is a CL defstruct." + (let ((plist (symbol-plist symbol))) + (and (plist-member plist 'cl-struct-slots) + (plist-member plist 'cl-struct-type) + (plist-member plist 'cl-struct-include) + (plist-member plist 'cl-struct-print)))) + +(defun ourcomments-defstruct-slots (symbol) + (unless (ourcomments-defstruct-p symbol) + (error "Not a CL defstruct symbol: %s" symbol)) + (let ((cl-struct-slots (get symbol 'cl-struct-slots))) + (delq 'cl-tag-slot + (loop for rec in cl-struct-slots + collect (nth 0 rec))))) + +;; (ourcomments-defstruct-slots 'ert-test) + +(defun ourcomments-defstruct-file (symbol) + (unless (ourcomments-defstruct-p symbol) + (error "Not a CL defstruct symbol: %s" symbol)) + ) + +(defun ourcomments-member-defstruct (symbol) + "Return defstruct name if member." + (when (and (functionp symbol) + (plist-member (symbol-plist symbol) 'cl-compiler-macro)) + (let* (in-defstruct + (symbol-file (symbol-file symbol)) + buf + was-here) + (unless symbol-file + (error "Can't check if defstruct member since don't know symbol file")) + (setq buf (find-buffer-visiting symbol-file)) + (setq was-here (with-current-buffer buf (point))) + (unless buf + (setq buf (find-file-noselect symbol-file))) + (with-current-buffer buf + (save-restriction + (widen) + (let* ((buf-point (find-definition-noselect symbol nil))) + (goto-char (cdr buf-point)) + (save-match-data + (when (looking-at "(defstruct (?\\(\\(?:\\sw\\|\\s_\\)+\\)") + (setq in-defstruct (match-string-no-properties 1)))))) + (if was-here + (goto-char was-here) + (kill-buffer (current-buffer)))) + in-defstruct))) +;; (ourcomments-member-defstruct 'ert-test-name) +;; (ourcomments-member-defstruct 'ert-test-error-condition) + +(defun ourcomments-custom-group-p (symbol) + (and (intern-soft symbol) + (or (and (get symbol 'custom-loads) + (not (get symbol 'custom-autoload))) + (get symbol 'custom-group)))) + +;;;###autoload +(defun describe-custom-group (symbol) + "Describe customization group SYMBOL." + (interactive + (list + (ourcomments-read-symbol "Customization group" + 'ourcomments-custom-group-p))) + ;; Fix-me: + (message "g=%s" symbol)) +;; nxhtml + +;; Added this to current-load-list in cl-macs.el +;; (describe-defstruct 'ert-stats) +;;;###autoload +(defun describe-defstruct (symbol) + (interactive (list (ourcomments-read-symbol "Describe defstruct" + 'ourcomments-defstruct-p))) + (if (not (ourcomments-defstruct-p symbol)) + (message "%s is not a CL defstruct." symbol) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'describe-defstruct symbol) (interactive-p)) + (with-current-buffer (help-buffer) + (insert "This is a description of a CL thing.") + (insert "\n\n") + (insert (format "%s is a CL `defstruct'" symbol)) + (let ((file (symbol-file symbol))) + (if file + ;; Fix-me: .elc => .el + (let ((name (file-name-nondirectory file))) + (insert "defined in file %s.\n" (file-name-nondirectory file))) + (insert ".\n"))) + (insert "\n\nIt has the following slot functions:\n") + (let ((num-slot-funs 0) + (slots (ourcomments-defstruct-slots symbol))) + (dolist (slot slots) + (if (not (fboundp (intern-soft (format "%s-%s" symbol slot)))) + (insert (format " Do not know function for slot %s\n" slot)) + (setq num-slot-funs (1+ num-slot-funs)) + (insert (format " `%s-%s'\n" symbol slot)))) + (unless (= num-slot-funs (length slots)) + (insert " No information about some slots, maybe :conc-name was used\n"))))))) + +;;(defun describe-deftype (type) +;;;###autoload +(defun describe-symbol(symbol) + "Show information about SYMBOL. +Show SYMBOL plist and whether is is a variable or/and a +function." + (interactive (list (ourcomments-read-symbol "Describe symbol" nil))) +;;; (let* ((s (symbol-at-point)) +;;; (val (completing-read (if (and (symbolp s) +;;; (not (eq s nil))) +;;; (format +;;; "Describe symbol (default %s): " s) +;;; "Describe symbol: ") +;;; obarray +;;; nil +;;; t nil nil +;;; (if (symbolp s) (symbol-name s))))) +;;; (list (if (equal val "") s (intern val))))) + (require 'apropos) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'describe-symbol symbol) (interactive-p)) + (with-current-buffer (help-buffer) + (insert (format "Description of symbol %s\n\n" symbol)) + (when (plist-get (symbol-plist symbol) 'cl-compiler-macro) + (insert "(Looks like a CL thing.)\n")) + (if (boundp symbol) + (insert (format "- There is a variable `%s'.\n" symbol)) + (insert "- This symbol is not a variable.\n")) + (if (fboundp symbol) + (progn + (insert (format "- There is a function `%s'" symbol)) + (when (ourcomments-member-defstruct symbol) + (let ((ds-name (ourcomments-member-defstruct symbol))) + (insert "\n which is a member of defstruct ") + (insert-text-button (format "%s" ds-name) + 'symbol (intern-soft ds-name) + 'action (lambda (button) + (describe-symbol + (button-get button 'symbol)))))) + (insert ".\n")) + (insert "- This symbol is not a function.\n")) + (if (facep symbol) + (insert (format "- There is a face `%s'.\n" symbol)) + (insert "- This symbol is not a face.\n")) + (if (ourcomments-custom-group-p symbol) + (progn + (insert "- There is a customization group ") + (insert-text-button (format "%s" symbol) + 'symbol symbol + 'action (lambda (button) + (describe-custom-group + (button-get button 'symbol)))) + (insert ".\n")) + (insert "- This symbol is not a customization group.\n")) + (if (ourcomments-defstruct-p symbol) + (progn + (insert (format "- There is a CL defstruct %s with setf-able slots:\n" symbol)) + (let ((num-slot-funs 0) + (slots (ourcomments-defstruct-slots symbol))) + (dolist (slot slots) + (if (not (fboundp (intern-soft (format "%s-%s" symbol slot)))) + (insert (format " Do not know function for slot %s\n" slot)) + (setq num-slot-funs (1+ num-slot-funs)) + (insert (format " `%s-%s'\n" symbol slot)))) + (unless (= num-slot-funs (length slots)) + (insert " No information about some slots, maybe :conc-name was used\n")))) + (insert "- This symbol is not a CL defstruct.\n")) + (insert "\n") + (let* ((pl (symbol-plist symbol)) + (pl-not-known (property-list-keys pl)) + any-known) + (if (not pl) + (insert (format "Symbol %s has no property list\n\n" symbol)) + ;; Known properties + (dolist (rec describe-symbol-alist) + (let ((prop (nth 0 rec)) + (desc (nth 1 rec))) + (when (plist-member pl prop) + (setq any-known (cons prop any-known)) + (setq pl-not-known (delq prop pl-not-known)) + (insert + "The following keys in the property list are known:\n\n") + (insert (format "* %s: %s\n" prop desc)) + ))) + (unless any-known + (insert "The are no known keys in the property list.\n")) + (let ((pl (ourcomments-format-plist pl "\n "))) + ;;(insert (format "plist=%s\n" (symbol-plist symbol))) + ;;(insert (format "pl-not-known=%s\n" pl-not-known)) + (insert "\nFull property list:\n\n (") + (insert (propertize pl 'face 'default)) + (insert ")\n\n"))))))) + +(defun ourcomments-format-plist (pl sep &optional compare) + (when (symbolp pl) + (setq pl (symbol-plist pl))) + (let (p desc p-out) + (while pl + (setq p (format "%s" (car pl))) + (if (or (not compare) (string-match apropos-regexp p)) + (if apropos-property-face + (put-text-property 0 (length (symbol-name (car pl))) + 'face apropos-property-face p)) + (setq p nil)) + (if p + (progn + (and compare apropos-match-face + (put-text-property (match-beginning 0) (match-end 0) + 'face apropos-match-face + p)) + (setq desc (pp-to-string (nth 1 pl))) + (setq desc (split-string desc "\n")) + (if (= 1 (length desc)) + (setq desc (concat " " (car desc))) + (let* ((indent " ") + (ind-nl (concat "\n" indent))) + (setq desc + (concat + ind-nl + (mapconcat 'identity desc ind-nl))))) + (setq p-out (concat p-out (if p-out sep) p desc)))) + (setq pl (nthcdr 2 pl))) + p-out)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; ido + +(defvar ourcomments-ido-visit-method nil) + +;;;###autoload +(defun ourcomments-ido-buffer-other-window () + "Show buffer in other window." + (interactive) + (setq ourcomments-ido-visit-method 'other-window) + (call-interactively 'ido-exit-minibuffer)) + +;;;###autoload +(defun ourcomments-ido-buffer-other-frame () + "Show buffer in other frame." + (interactive) + (setq ourcomments-ido-visit-method 'other-frame) + (call-interactively 'ido-exit-minibuffer)) + +;;;###autoload +(defun ourcomments-ido-buffer-raise-frame () + "Raise frame showing buffer." + (interactive) + (setq ourcomments-ido-visit-method 'raise-frame) + (call-interactively 'ido-exit-minibuffer)) + +(defun ourcomments-ido-switch-buffer-or-next-entry () + (interactive) + (if (active-minibuffer-window) + (ido-next-match) + (ido-switch-buffer))) + +(defun ourcomments-ido-mode-advice() + (when (memq ido-mode '(both buffer)) + (let ((the-ido-minor-map (cdr ido-minor-mode-map-entry))) + ;;(define-key the-ido-minor-map [(control tab)] 'ido-switch-buffer)) + (define-key the-ido-minor-map [(control tab)] 'ourcomments-ido-switch-buffer-or-next-entry)) + (dolist (the-map (list ido-buffer-completion-map ido-completion-map ido-common-completion-map)) + (when the-map + (let ((map the-map)) + (define-key map [(control tab)] 'ido-next-match) + (define-key map [(control shift tab)] 'ido-prev-match) + (define-key map [(control backtab)] 'ido-prev-match) + (define-key map [(shift return)] 'ourcomments-ido-buffer-other-window) + (define-key map [(control return)] 'ourcomments-ido-buffer-other-frame) + (define-key map [(meta return)] 'ourcomments-ido-buffer-raise-frame)))))) + +;; (defun ourcomments-ido-setup-completion-map () +;; "Set up the keymap for `ido'." + +;; (ourcomments-ido-mode-advice) + +;; ;; generated every time so that it can inherit new functions. +;; (let ((map (make-sparse-keymap)) +;; (viper-p (if (boundp 'viper-mode) viper-mode))) + +;; (when viper-p +;; (define-key map [remap viper-intercept-ESC-key] 'ignore)) + +;; (cond +;; ((memq ido-cur-item '(file dir)) +;; (when ido-context-switch-command +;; (define-key map "\C-x\C-b" ido-context-switch-command) +;; (define-key map "\C-x\C-d" 'ignore)) +;; (when viper-p +;; (define-key map [remap viper-backward-char] 'ido-delete-backward-updir) +;; (define-key map [remap viper-del-backward-char-in-insert] 'ido-delete-backward-updir) +;; (define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir)) +;; (set-keymap-parent map +;; (if (eq ido-cur-item 'file) +;; ido-file-completion-map +;; ido-file-dir-completion-map))) + +;; ((eq ido-cur-item 'buffer) +;; (when ido-context-switch-command +;; (define-key map "\C-x\C-f" ido-context-switch-command)) +;; (set-keymap-parent map ido-buffer-completion-map)) + +;; (t +;; (set-keymap-parent map ido-common-completion-map))) + +;; ;; ctrl-tab etc +;; (define-key map [(control tab)] 'ido-next-match) +;; (define-key map [(control shift tab)] 'ido-prev-match) +;; (define-key map [(control backtab)] 'ido-prev-match) +;; (define-key map [(shift return)] 'ourcomments-ido-buffer-other-window) +;; (define-key map [(control return)] 'ourcomments-ido-buffer-other-frame) +;; (define-key map [(meta return)] 'ourcomments-ido-buffer-raise-frame) + +;; (setq ido-completion-map map))) + +;; (defadvice ido-setup-completion-map (around +;; ourcomments-advice-ido-setup-completion-map +;; disable) +;; (setq ad-return-value (ourcomments-ido-setup-completion-map)) +;; ) + +;;(add-hook 'ido-setup-hook 'ourcomments-ido-mode-advice) +;;(remove-hook 'ido-setup-hook 'ourcomments-ido-mode-advice) +(defvar ourcomments-ido-adviced nil) +(unless ourcomments-ido-adviced +(defadvice ido-mode (after + ourcomments-advice-ido-mode + ;;activate + ;;compile + disable) + "Add C-tab to ido buffer completion." + (ourcomments-ido-mode-advice) + ;;ad-return-value + ) +;; (ad-activate 'ido-mode) +;; (ad-deactivate 'ido-mode) + +(defadvice ido-visit-buffer (before + ourcomments-advice-ido-visit-buffer + ;;activate + ;;compile + disable) + "Advice to show buffers in other window, frame etc." + (when ourcomments-ido-visit-method + (ad-set-arg 1 ourcomments-ido-visit-method) + (setq ourcomments-ido-visit-method nil) + )) +(setq ourcomments-ido-adviced t) +) + +;;(message "after advising ido") +;;(ad-deactivate 'ido-visit-buffer) +;;(ad-activate 'ido-visit-buffer) + +(defvar ourcomments-ido-old-state ido-mode) + +(defun ourcomments-ido-ctrl-tab-activate () + ;;(message "ourcomments-ido-ctrl-tab-activate running") + ;;(ad-update 'ido-visit-buffer) + ;;(unless (ad-get-advice-info 'ido-visit-buffer) + ;; Fix-me: The advice must be enabled before activation. Send bug report. + (ad-enable-advice 'ido-visit-buffer 'before 'ourcomments-advice-ido-visit-buffer) + (unless (cdr (assoc 'active (ad-get-advice-info 'ido-visit-buffer))) + (ad-activate 'ido-visit-buffer)) + ;; (ad-enable-advice 'ido-setup-completion-map 'around 'ourcomments-advice-ido-setup-completion-map) + ;; (unless (cdr (assoc 'active (ad-get-advice-info 'ido-setup-completion-map))) + ;; (ad-activate 'ido-setup-completion-map)) + ;;(ad-update 'ido-mode) + (ad-enable-advice 'ido-mode 'after 'ourcomments-advice-ido-mode) + (unless (cdr (assoc 'active (ad-get-advice-info 'ido-mode))) + (ad-activate 'ido-mode)) + (setq ourcomments-ido-old-state ido-mode) + (ido-mode (or ido-mode 'buffer))) + +;;;###autoload +(define-minor-mode ourcomments-ido-ctrl-tab + "Enable buffer switching using C-Tab with function `ido-mode'. +This changes buffer switching with function `ido-mode' the +following way: + +- You can use C-Tab. + +- You can show the selected buffer in three ways independent of + how you entered function `ido-mode' buffer switching: + + * S-return: other window + * C-return: other frame + * M-return: raise frame + +Those keys are selected to at least be a little bit reminiscent +of those in for example common web browsers." + :global t + :group 'emacsw32 + :group 'convenience + (if ourcomments-ido-ctrl-tab + (ourcomments-ido-ctrl-tab-activate) + (ad-disable-advice 'ido-visit-buffer 'before + 'ourcomments-advice-ido-visit-buffer) + (ad-disable-advice 'ido-mode 'after + 'ourcomments-advice-ido-mode) + ;; For some reason this little complicated construct is + ;; needed. If they are not there the defadvice + ;; disappears. Huh. + ;;(if ourcomments-ido-old-state + ;; (ido-mode ourcomments-ido-old-state) + ;; (when ido-mode (ido-mode -1))) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; New Emacs instance + +(defun ourcomments-find-emacs () + (locate-file invocation-name + (list invocation-directory) + exec-suffixes + ;; 1 ;; Fix-me: This parameter is depreceated, but used + ;; in executable-find, why? + )) + +(defvar ourcomments-restart-server-mode nil) + +(defun emacs-restart-in-kill () + "Last step in restart Emacs and start `server-mode' if on before." + (let* ((restart-args (when ourcomments-restart-server-mode + ;; Delay 3+2 sec to be sure the old server has stopped. + (list "--eval=(run-with-idle-timer 5 nil 'server-mode 1)"))) + ;; Fix-me: There is an Emacs bug here, default-directory shows + ;; up in load-path in the new Eamcs if restart-args is like + ;; this, but not otherwise. And it has w32 file syntax. The + ;; work around below is the best I can find at the moment. + (first-path (catch 'first + (dolist (p load-path) + (when (file-directory-p p) + (throw 'first p))))) + (default-directory (file-name-as-directory (expand-file-name first-path)))) + ;; Fix-me: Adding -nw to restart in console does not work. Any way to fix it? + (unless window-system (setq restart-args (cons "-nw" restart-args))) + ;;(apply 'call-process (ourcomments-find-emacs) nil 0 nil restart-args) + (apply 'emacs restart-args) + ;; Wait to give focus to new Emacs instance: + (sleep-for 3))) + +;;;###autoload +(defun emacs-restart () + "Restart Emacs and start `server-mode' if on before." + (interactive) + (if (not window-system) + (message "Can't restart emacs if window-system is nil") + (let ((wait 4)) + (while (> (setq wait (1- wait)) 0) + (message (propertize (format "Will restart Emacs in %d seconds..." wait) + 'face 'secondary-selection)) + (sit-for 1))) + (setq ourcomments-restart-server-mode server-mode) + (add-hook 'kill-emacs-hook 'emacs-restart-in-kill t) + (save-buffers-kill-emacs))) + +(defvar ourcomments-started-emacs-use-output-buffer nil + "If non-nil then save output form `emacs'. +Set this to `t' to debug problems with starting a new Emacs. + +If non-nil save output to buffer 'call-process emacs output'. +Note that this will lock the Emacs calling `emacs' until the new +Emacs has finished.") +;;(setq ourcomments-started-emacs-use-output-buffer t) +;;(defun my-test () (interactive) (emacs-Q "-bad-arg")) + +;;;###autoload +(defun emacs (&rest args) + "Start a new Emacs with default parameters. +Additional ARGS are passed to the new Emacs. + +See also `ourcomments-started-emacs-use-output-buffer'." + (interactive) + (recentf-save-list) + (let* ((out-buf (when ourcomments-started-emacs-use-output-buffer + (get-buffer-create "call-process emacs output"))) + (buf-arg (or out-buf 0)) + (args-text (mapconcat 'identity (cons "" args) " ")) + ret + (fin-msg "")) + (when out-buf + (display-buffer out-buf) + (setq fin-msg ". Finished.") + (message "Started 'emacs%s' => %s. Locked until this is finished." args-text ret fin-msg) + (redisplay)) + (setq ret (apply 'call-process (ourcomments-find-emacs) nil buf-arg nil args)) + (message "Started 'emacs%s' => %s%s" args-text ret fin-msg) + ret)) + +;;;###autoload +(defun emacs-buffer-file() + "Start a new Emacs showing current buffer file. +Go to the current line and column in that file. +If there is no buffer file then instead start with `dired'. + +This calls the function `emacs' with argument --no-desktop and +the file or a call to dired." + (interactive) + (recentf-save-list) + (let ((file (buffer-file-name)) + (lin (line-number-at-pos)) + (col (current-column))) + (if file + (apply 'emacs "--no-desktop" (format "+%d:%d" lin col) file nil) + (applay 'emacs "--no-desktop" "--eval" (format "(dired \"%s\")" default-directory nil))))) + +;;;###autoload +(defun emacs--debug-init(&rest args) + "Start a new Emacs with --debug-init parameter. +This calls the function `emacs' with added arguments ARGS." + (interactive) + (apply 'emacs "--debug-init" args)) + +;;;###autoload +(defun emacs--no-desktop (&rest args) + "Start a new Emacs with --no-desktop parameter. +This calls the function `emacs' with added arguments ARGS." + (interactive) + (apply 'emacs "--no-desktop" args)) + +;;;###autoload +(defun emacs-Q (&rest args) + "Start a new Emacs with -Q parameter. +Start new Emacs without any customization whatsoever. +This calls the function `emacs' with added arguments ARGS." + (interactive) + (apply 'emacs "-Q" args)) + +;;;###autoload +(defun emacs-Q-nxhtml(&rest args) + "Start new Emacs with -Q and load nXhtml. +This calls the function `emacs' with added arguments ARGS." + (interactive) + (let ((autostart (if (boundp 'nxhtml-install-dir) + (expand-file-name "autostart.el" nxhtml-install-dir) + (expand-file-name "../../EmacsW32/nxhtml/autostart.el" + exec-directory)))) + (apply 'emacs-Q "--debug-init" "--load" autostart args))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Searching + +(defun grep-get-buffer-files () + "Return list of files in a `grep-mode' buffer." + (or (and (compilation-buffer-p (current-buffer)) + (derived-mode-p 'grep-mode)) + (error "Not in a grep buffer")) + (let ((here (point)) + files + loc) + (font-lock-fontify-buffer) + (goto-char (point-min)) + (while (setq loc + (condition-case err + (compilation-next-error 1) + (error + ;; This should be the end, but give a message for + ;; easier debugging. + (message "%s" err) + nil))) + ;;(message "here =%s, loc=%s" (point) loc) + (let ((file (caar (nth 2 (car loc))))) + (setq file (expand-file-name file)) + (add-to-list 'files file))) + (goto-char here) + ;;(message "files=%s" files) + files)) + +(defvar grep-query-replace-defaults nil + "Default values of FROM-STRING and TO-STRING for `grep-query-replace'. +This is a cons cell (FROM-STRING . TO-STRING), or nil if there is +no default value.") + +;; Mostly copied from `dired-do-query-replace-regexp'. Fix-me: finish, test +;;;###autoload +(defun grep-query-replace(from to &optional delimited) + "Do `query-replace-regexp' of FROM with TO, on all files in *grep*. +Third arg DELIMITED (prefix arg) means replace only word-delimited matches. +If you exit (\\[keyboard-quit], RET or q), you can resume the query replace +with the command \\[tags-loop-continue]." + (interactive + (let ((common + ;; Use the regexps that have been used in grep + (let ((query-replace-from-history-variable 'grep-regexp-history) + (query-replace-defaults (or grep-query-replace-defaults + query-replace-defaults))) + (query-replace-read-args + "Query replace regexp in files in *grep*" t t)))) + (setq grep-query-replace-defaults (cons (nth 0 common) + (nth 1 common))) + (list (nth 0 common) (nth 1 common) (nth 2 common)))) + (dolist (file (grep-get-buffer-files)) + (let ((buffer (get-file-buffer file))) + (if (and buffer (with-current-buffer buffer + buffer-read-only)) + (error "File `%s' is visited read-only" file)))) + (tags-query-replace from to delimited + '(grep-get-buffer-files))) + +;;;###autoload +(defun ldir-query-replace (from to files dir &optional delimited) + "Replace FROM with TO in FILES in directory DIR. +This runs `query-replace-regexp' in files matching FILES in +directory DIR. + +See `tags-query-replace' for DELIMETED and more information." + (interactive (dir-replace-read-parameters nil nil)) + (message "%s" (list from to files dir delimited)) + ;;(let ((files (directory-files root nil file-regexp))) (message "files=%s" files)) + (tags-query-replace from to delimited + `(directory-files ,dir t ,files))) + +;;;###autoload +(defun rdir-query-replace (from to file-regexp root &optional delimited) + "Replace FROM with TO in FILES in directory tree ROOT. +This runs `query-replace-regexp' in files matching FILES in +directory tree ROOT. + +See `tags-query-replace' for DELIMETED and more information." + (interactive (dir-replace-read-parameters nil t)) + (message "%s" (list from to file-regexp root delimited)) + ;;(let ((files (directory-files root nil file-regexp))) (message "files=%s" files)) + (tags-query-replace from to delimited + `(rdir-get-files ,root ,file-regexp))) + +;; (rdir-get-files ".." "^a.*\.el$") +(defun rdir-get-files (root file-regexp) + (let ((files (directory-files root t file-regexp)) + (subdirs (directory-files root t))) + (dolist (subdir subdirs) + (when (and (file-directory-p subdir) + (not (or (string= "/." (substring subdir -2)) + (string= "/.." (substring subdir -3))))) + (setq files (append files (rdir-get-files subdir file-regexp) nil)))) + files)) + +(defun dir-replace-read-parameters (has-dir recursive) + (let* ((common + (let (;;(query-replace-from-history-variable 'grep-regexp-history) + ;;(query-replace-defaults (or grep-query-replace-defaults + ;; query-replace-defaults)) + ) + (query-replace-read-args + "Query replace regexp in files" t t))) + (from (nth 0 common)) + (to (nth 1 common)) + (delimited (nth 2 common)) + (files (replace-read-files from to)) + (root (unless has-dir (read-directory-name (if recursive "Root directory: " + "In single directory: "))))) + (list from to files root delimited))) + +;; Mostly copied from `grep-read-files'. Could possible be merged with +;; that. +(defvar replace-read-files-history nil) +;;;###autoload +(defun replace-read-files (regexp &optional replace) + "Read files arg for replace." + (let* ((bn (or (buffer-file-name) (buffer-name))) + (fn (and bn + (stringp bn) + (file-name-nondirectory bn))) + (default + (let ((pre-default + (or (and fn + (let ((aliases grep-files-aliases) + alias) + (while aliases + (setq alias (car aliases) + aliases (cdr aliases)) + (if (string-match (wildcard-to-regexp + (cdr alias)) fn) + (setq aliases nil) + (setq alias nil))) + (cdr alias))) + (and fn + (let ((ext (file-name-extension fn))) + (and ext (concat "^.*\." ext)))) + (car replace-read-files-history) + (car (car grep-files-aliases))))) + (if (string-match-p "^\\*\\.[a-zA-Z0-9]*$" pre-default) + (concat "\\." (substring pre-default 2) "$") + pre-default))) + (files (read-string + (if replace + (concat "Replace \"" regexp + "\" with \"" replace "\" in files" + (if default (concat " (default " default + ", regexp or *.EXT)")) + ": ") + (concat "Search for \"" regexp + "\" in files" + (if default (concat " (default " default ")")) + ": ")) + nil 'replace-read-files-history default))) + (let ((pattern (and files + (or (cdr (assoc files grep-files-aliases)) + files)))) + (if (and pattern + (string-match-p "^\\*\\.[a-zA-Z0-9]*$" pattern)) + (concat "\\." (substring pattern 2) "$") + pattern)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Info + +;;;###autoload +(defun info-open-file (info-file) + "Open an info file in `Info-mode'." + (interactive + (let ((name (read-file-name "Info file: " + nil ;; dir + nil ;; default-filename + t ;; mustmatch + nil ;; initial + ;; predicate: + (lambda (file) + (or (file-directory-p file) + (string-match ".*\\.info\\'" file)))))) + (list name))) + (info info-file)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Exec path etc + +(defun ourcomments-which (prog) + "Look for first program PROG in `exec-path' using `exec-suffixes'. +Return full path if found." + (interactive "sProgram: ") + (let ((path (executable-find prog))) + (when (with-no-warnings (called-interactively-p)) + (message "%s found in %s" prog path)) + path)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Custom faces and keys + +;;;###autoload +(defun use-custom-style () + "Setup like in `Custom-mode', but without things specific to Custom." + (make-local-variable 'widget-documentation-face) + (setq widget-documentation-face 'custom-documentation) + (make-local-variable 'widget-button-face) + (setq widget-button-face custom-button) + (setq show-trailing-whitespace nil) + + ;; We need this because of the "More" button on docstrings. + ;; Otherwise clicking on "More" can push point offscreen, which + ;; causes the window to recenter on point, which pushes the + ;; newly-revealed docstring offscreen; which is annoying. -- cyd. + (set (make-local-variable 'widget-button-click-moves-point) t) + + (set (make-local-variable 'widget-button-pressed-face) custom-button-pressed) + (set (make-local-variable 'widget-mouse-face) custom-button-mouse) + + ;; When possible, use relief for buttons, not bracketing. This test + ;; may not be optimal. + (when custom-raised-buttons + (set (make-local-variable 'widget-push-button-prefix) "") + (set (make-local-variable 'widget-push-button-suffix) "") + (set (make-local-variable 'widget-link-prefix) "") + (set (make-local-variable 'widget-link-suffix) "")) + + ;; From widget-keymap + (local-set-key "\t" 'widget-forward) + (local-set-key "\e\t" 'widget-backward) + (local-set-key [(shift tab)] 'advertised-widget-backward) + (local-set-key [backtab] 'widget-backward) + (local-set-key [down-mouse-2] 'widget-button-click) + (local-set-key [down-mouse-1] 'widget-button-click) + (local-set-key [(control ?m)] 'widget-button-press) + ;; From custom-mode-map + (local-set-key " " 'scroll-up) + (local-set-key "\177" 'scroll-down) + (local-set-key "n" 'widget-forward) + (local-set-key "p" 'widget-backward)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Bookmarks + +(defun bookmark-next-marked () + (interactive) + (let ((bb (get-buffer "*Bookmark List*")) + pos) + (when bb + (with-current-buffer bb + (setq pos (re-search-forward "^>" nil t)) + (unless pos + (goto-char (point-min)) + (setq pos (re-search-forward "^>" nil t))))) + (if pos + (with-current-buffer bb + ;; Defined in bookmark.el, should be loaded now. + (bookmark-bmenu-this-window)) + (call-interactively 'bookmark-bmenu-list) + (message "Please select bookmark for bookmark next command, then press n")))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Org Mode + +(defun ourcomments-org-complete-and-replace-file-link () + "If on a org file link complete file name and replace it." + (interactive) + (require 'org) + (let* ((here (point-marker)) + (on-link (eq 'org-link (get-text-property (point) 'face))) + (link-beg (when on-link + (previous-single-property-change (1+ here) 'face))) + (link-end (when on-link + (next-single-property-change here 'face))) + (link (when on-link (buffer-substring-no-properties link-beg link-end))) + type+link + link-link + link-link-beg + link-link-end + new-link + dir + ovl) + (when (and on-link + (string-match (rx string-start "[[" + (group (0+ (not (any "]"))))) link)) + (setq type+link (match-string 1 link)) + (when (string-match "^file:\\(.*\\)" type+link) + (setq link-link (match-string 1 type+link)) + (setq link-link-beg (+ 2 link-beg (match-beginning 1))) + (setq link-link-end (+ 2 link-beg (match-end 1))) + (unwind-protect + (progn + (setq ovl (make-overlay link-link-beg link-link-end)) + (overlay-put ovl 'face 'highlight) + (when link-link + (setq link-link (org-link-unescape link-link)) + (setq dir (when (and link-link (> (length link-link) 0)) + (file-name-directory link-link))) + (setq new-link (read-file-name "Org file:" dir nil nil (file-name-nondirectory link-link))) + (delete-overlay ovl) + (setq new-link (expand-file-name new-link)) + (setq new-link (file-relative-name new-link)) + (delete-region link-link-beg link-link-end) + (goto-char link-link-beg) + (insert (org-link-escape new-link)) + t)) + (delete-overlay ovl) + (goto-char here)))))) + +;; (defun ourcomments-org-paste-html-link (html-link) +;; "If there is an html link on clipboard paste it as an org link. +;; If you have this on the clipboard +;; <a href=\"http://my.site.org/\">My Site</a> +;; It will paste this +;; [[http://my.site.org/][My Site]] +;; If the URL is to a local file it will create an org link to the +;; file. +;; Tip: You can use the Firefox plugin Copy as HTML Link, see URL +;; `https://addons.mozilla.org/en-US/firefox/addon/2617'. +;; " +;; (interactive (list (current-kill 0))) +;; (let ((conv-link (ourcomments-org-convert-html-link html-link))) +;; (if (not conv-link) +;; (message (propertize "No html link on clipboard" 'face 'font-lock-warning-face)) +;; (insert conv-link)))) + +;; (defun ourcomments-org-convert-html-link (html-link) +;; (let (converted url str) +;; (save-match-data +;; (while (string-match ourcomments-org-paste-html-link-regexp html-link) +;; (setq converted t) +;; (setq url (match-string 1 html-link)) +;; (setq str (match-string 2 html-link)) +;; ;;(setq str (concat str (format "%s" (setq temp-n (1+ temp-n))))) +;; (setq html-link (replace-match (concat "[[" url "][" str "]]") nil nil html-link 0)))) +;; (when converted +;; html-link))) + +(defconst ourcomments-org-paste-html-link-regexp + "\\`\\(?:<a [^>]*?href=\"\\(.*?\\)\"[^>]*?>\\([^<]*\\)</a>\\)\\'") + +;;(string-match-p ourcomments-org-paste-html-link-regexp "<a href=\"link\">text</a>") + +;;(defvar temp-n 0) +(defun ourcomments-org-convert-html-links-in-buffer (beg end) + "Convert html link between BEG and END to org mode links. +If there is an html link in the buffer + + <a href=\"http://my.site.org/\">My Site</a> + +that starts at BEG and ends at END then convert it to this + + [[http://my.site.org/][My Site]] + +If the URL is to a local file and the buffer is visiting a file +make the link relative. + +However, if the html link is inside an #+BEGIN - #+END block or a +variant of such blocks then leave the link as it is." + (when (derived-mode-p 'org-mode) + (save-match-data + (let ((here (copy-marker (point))) + url str converted + lit-beg lit-end) + (goto-char beg) + (save-restriction + (widen) + (setq lit-beg (search-backward "#+BEGIN" nil t)) + (when lit-beg + (goto-char lit-beg) + (setq lit-end (or (search-forward "#+END" nil t) + (point-max))))) + (when (or (not lit-beg) + (> beg lit-end)) + (goto-char beg) + (when (save-restriction + (narrow-to-region beg end) + (looking-at ourcomments-org-paste-html-link-regexp)) + (setq converted t) + (setq url (match-string-no-properties 1)) + (setq str (match-string-no-properties 2)) + ;; Check if the URL is to a local file and absolute. And we + ;; have a buffer. + (when (and (buffer-file-name) + (> (length url) 5) + (string= (substring url 0 6) "file:/")) + (let ((abs-file-url + (if (not (memq system-type '(windows-nt ms-dos))) + (substring url 8) + (if (string= (substring url 0 8) "file:///") + (substring url 8) + ;; file://c:/some/where.txt + (substring url 7))))) + (setq url (concat "file:" + (file-relative-name abs-file-url + (file-name-directory + (buffer-file-name))))))) + (replace-match (concat "[[" url "][" str "]]") nil nil nil 0))) + (goto-char here) + nil)))) + +(defvar ourcomments-paste-with-convert-hook nil + "Normal hook run after certain paste commands. +These paste commands are in the list +`ourcomments-paste-with-convert-commands'. + +Each function in this hook is called with two parameters, the +start and end of the pasted text, until a function returns +non-nil.") +(add-hook 'ourcomments-paste-with-convert-hook 'ourcomments-org-convert-html-links-in-buffer) + +(defvar ourcomments-paste-beg) ;; dyn var +(defvar ourcomments-paste-end) ;; dyn var +(defun ourcomments-grab-paste-bounds (beg end len) + (setq ourcomments-paste-beg (min beg ourcomments-paste-beg)) + (setq ourcomments-paste-end (max end ourcomments-paste-end))) + +(defmacro ourcomments-advice-paste-command (paste-command) + (let ((adv-name (make-symbol (concat "ourcomments-org-ad-" + (symbol-name paste-command))))) + `(defadvice ,paste-command (around + ,adv-name) + (let ((ourcomments-paste-beg (point-max)) ;; dyn var + (ourcomments-paste-end (point-min))) ;; dyn var + (add-hook 'after-change-functions `ourcomments-grab-paste-bounds nil t) + ad-do-it ;;;;;;;;;;;;;;;;;;;;;;;;;; + (remove-hook 'after-change-functions `ourcomments-grab-paste-bounds t) + (run-hook-with-args-until-success 'ourcomments-paste-with-convert-hook + ourcomments-paste-beg + ourcomments-paste-end))))) + +(defcustom ourcomments-paste-with-convert-commands '(yank cua-paste viper-put-back viper-Put-back) + "Commands for which past converting is done. +See `ourcomments-paste-with-convert-mode' for more information." + :type '(repeat function) + :group 'ourcomments-util) + +;;;###autoload +(define-minor-mode ourcomments-paste-with-convert-mode + "Pasted text may be automatically converted in this mode. +The functions in `ourcomments-paste-with-convert-hook' are run +after commands in `ourcomments-paste-with-convert-commands' if any +of the functions returns non-nil that text is inserted instead of +the original text. + +For exampel when this mode is on and you paste an html link in an +`org-mode' buffer it will be directly converted to an org style +link. \(This is the default behaviour.) + +Tip: The Firefox plugin Copy as HTML Link is handy, see URL + `https://addons.mozilla.org/en-US/firefox/addon/2617'. + +Note: This minor mode will defadvice the paste commands." + :global t + :group 'cua + :group 'viper + :group 'ourcomments-util + (if ourcomments-paste-with-convert-mode + (progn + (dolist (command ourcomments-paste-with-convert-commands) + (eval `(ourcomments-advice-paste-command ,command)) + (ad-activate command))) + (dolist (command ourcomments-paste-with-convert-commands) + (ad-unadvise command)))) + +;; (ourcomments-advice-paste-command cua-paste) +;; (ad-activate 'cua-paste) +;; (ad-deactivate 'cua-paste) +;; (ad-update 'cua-paste) +;; (ad-unadvise 'cua-paste) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Menu commands to M-x history + +;; (where-is-internal 'mumamo-mark-chunk nil nil) +;; (where-is-internal 'mark-whole-buffer nil nil) +;; (where-is-internal 'save-buffer nil nil) +;; (where-is-internal 'revert-buffer nil nil) +;; (setq extended-command-history nil) +(defun ourcomments-M-x-menu-pre () + "Add menu command to M-x history." + (let ((is-menu-command (equal '(menu-bar) + (when (< 0 (length (this-command-keys-vector))) + (elt (this-command-keys-vector) 0)))) + (pre-len (length extended-command-history))) + (when (and is-menu-command + (not (memq this-command '(ourcomments-M-x-menu-mode)))) + (pushnew (symbol-name this-command) extended-command-history) + (when (< pre-len (length extended-command-history)) + ;; This message is given pre-command and is therefore likely + ;; to be overwritten, but that is ok in this case. If the user + ;; has seen one of these messages s?he knows. + (message (propertize "(Added %s to M-x history so you can run it from there)" + 'face 'file-name-shadow) + this-command))))) + +;;;###autoload +(define-minor-mode ourcomments-M-x-menu-mode + "Add commands started from Emacs menus to M-x history. +The purpose of this is to make it easier to redo them and easier +to learn how to do them from the command line \(which is often +faster if you know how to do it). + +Only commands that are not already in M-x history are added." + :global t + (if ourcomments-M-x-menu-mode + (add-hook 'pre-command-hook 'ourcomments-M-x-menu-pre) + (remove-hook 'pre-command-hook 'ourcomments-M-x-menu-pre))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Warnings etc + +(defvar ourcomments-warnings nil) + +(defun ourcomments-display-warnings () + (condition-case err + (let ((msg (mapconcat 'identity (reverse ourcomments-warnings) "\n"))) + (setq ourcomments-warnings nil) + (message "%s" (propertize msg 'face 'secondary-selection))) + (error (message "ourcomments-display-warnings: %s" err)))) + +(defun ourcomments-warning-post () + (condition-case err + (run-with-idle-timer 0.5 nil 'ourcomments-display-warnings) + (error (message "ourcomments-warning-post: %s" err)))) + +;;;###autoload +(defun ourcomments-warning (format-string &rest args) + (setq ourcomments-warnings (cons (apply 'format format-string args) + ourcomments-warnings)) + (add-hook 'post-command-hook 'ourcomments-warning-post)) + + + +(provide 'ourcomments-util) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ourcomments-util.el ends here diff --git a/emacs/nxhtml/util/ourcomments-widgets.el b/emacs/nxhtml/util/ourcomments-widgets.el new file mode 100644 index 0000000..359a0b1 --- /dev/null +++ b/emacs/nxhtml/util/ourcomments-widgets.el @@ -0,0 +1,141 @@ +;;; ourcomments-widgets.el --- widgets for custom etc +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-10-13 Tue +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(eval-when-compile (require 'mumamo nil t)) + +;;;###autoload (autoload 'command "ourcomments-widgets") +(define-widget 'command 'restricted-sexp + "A command function." + :complete-function (lambda () + (interactive) + (lisp-complete-symbol 'commandp)) + :prompt-value 'widget-field-prompt-value + :prompt-internal 'widget-symbol-prompt-internal + :prompt-match 'commandp + :prompt-history 'widget-command-prompt-value-history + :action 'widget-field-action + :match-alternatives '(commandp) + :validate (lambda (widget) + (unless (commandp (widget-value widget)) + (widget-put widget :error (format "Invalid command: %S" + (widget-value widget))) + widget)) + :value 'ignore + :tag "Command") + + +;;;###autoload +(defun major-or-multi-majorp (value) + "Return t if VALUE is a major or multi major mode function." + (or (and (fboundp 'mumamo-multi-major-modep) + (fboundp (mumamo-multi-major-modep value))) + (major-modep value))) + +;; Fix-me: This might in the future be defined in Emacs. +;;;###autoload +(defun major-modep (value) + "Return t if VALUE is a major mode function." + (let ((sym-name (symbol-name value))) + ;; Do some reasonable test to find out if it is a major mode. + ;; Load autoloaded mode functions. + ;; + ;; Fix-me: Maybe test for minor modes? How was that done? + (when (and (fboundp value) + (commandp value) + (not (memq value '(flyspell-mode + isearch-mode + savehist-mode + ))) + (< 5 (length sym-name)) + (string= "-mode" (substring sym-name (- (length sym-name) 5))) + (if (and (listp (symbol-function value)) + (eq 'autoload (car (symbol-function value)))) + (progn + (message "loading ") + (load (cadr (symbol-function value)) t t)) + t) + (or (memq value + ;; Fix-me: Complement this table of known major modes: + '(fundamental-mode + xml-mode + nxml-mode + nxhtml-mode + css-mode + javascript-mode + espresso-mode + php-mode + )) + (and (intern-soft (concat sym-name "-hook")) + ;; This fits `define-derived-mode' + (get (intern-soft (concat sym-name "-hook")) 'variable-documentation)) + (progn (message "Not a major mode: %s" value) + ;;(sit-for 4) + nil) + )) + t))) + +;;;###autoload (autoload 'major-mode-function "ourcomments-widgets") +(define-widget 'major-mode-function 'function + "A major mode lisp function." + :complete-function (lambda () + (interactive) + (lisp-complete-symbol 'major-or-multi-majorp)) + :prompt-match 'major-or-multi-majorp + :prompt-history 'widget-function-prompt-value-history + :match-alternatives '(major-or-multi-majorp) + :validate (lambda (widget) + (unless (major-or-multi-majorp (widget-value widget)) + (widget-put widget :error (format "Invalid function: %S" + (widget-value widget))) + widget)) + :value 'fundamental-mode + :tag "Major mode function") + + + +(provide 'ourcomments-widgets) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ourcomments-widgets.el ends here diff --git a/emacs/nxhtml/util/pause.el b/emacs/nxhtml/util/pause.el new file mode 100644 index 0000000..2e98d36 --- /dev/null +++ b/emacs/nxhtml/util/pause.el @@ -0,0 +1,794 @@ +;;; pause.el --- Take a break! +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-01-19 Sat +(defconst pause:version "0.70");; Version: +;; Last-Updated: 2010-01-18 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; If you are using Emacs then don't you need a little reminder to +;; take a pause? This library makes Emacs remind you of that. And +;; gives you a link to a yoga exercise to try in the pause. +;; +;; There are essentially two different ways to use this library. +;; Either you run a separate Emacs process that just reminds you of +;; pauses. To use it that way see `pause-start-in-new-emacs'. +;; +;; Or run it in the current Emacs. To do that add to your .emacs +;; +;; (require 'pause) +;; +;; and do +;; +;; M-x customize-group RET pause RET +;; +;; and set `pause-mode' to t. +;; +;; +;; Note: I am unsure if it works on all systems to use a separate +;; Emacs process. It does work on w32 though. Please tell me +;; about other systems. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +;;;###autoload +(defgroup pause nil + "Customize your health personal Emacs health saver!" + :group 'convenience) + +(defcustom pause-after-minutes 15 + "Pause after this number of minutes." + :type 'number + :group 'pause) + +(defcustom pause-1-minute-delay 60 + "Number of seconds to wait in 1 minutes delay." + :type 'number + :group 'pause) + +(defcustom pause-idle-delay 5 + "Seconds to wait for user to be idle before pause." + :type 'number + :group 'pause) + +(defcustom pause-even-if-not-in-emacs t + "Jump up pause even if not in Emacs." + :type 'boolean + :group 'pause) + +(defcustom pause-restart-anyway-after 2 + "If user does not use Emacs restart timer after this minutes. +This is used when a user has clicked a link." + :type 'number + :group 'pause) + +(defcustom pause-tell-again-after 2 + "If user does not exit pause tell again after this minutes." + :type 'number + :group 'pause) + +(defcustom pause-extra-fun 'pause-start-get-yoga-poses + "Function to call for extra fun when pausing. +Default is to show a link to a yoga exercise (recommended!). + +Set this variable to nil if you do not want any extra fun. + +If this variable's value is a function it will be called when the +pause frame has just been shown." + :type '(choice (function :tag "Extra function") + (const :tag "No extra function" nil)) + :group 'pause) + +(defvar pause-exited-from-button nil) + +(defcustom pause-background-color "orange" + "Background color during pause." + :type 'color + :group 'pause) + +(defcustom pause-mode-line-color "sienna" + "Mode line color during pause." + :type 'color + :group 'pause) + +(defcustom pause-1-minute-mode-line-color "yellow" + "Mode line color during 1 minute phase of pause." + :type 'color + :group 'pause) + +(defface pause-text-face + '((t (:foreground "sienna" :height 1.5 :bold t))) + "Face main text in pause buffer." + :group 'pause) + +(defface pause-info-text-face + '((t (:foreground "yellow"))) + "Face info text in pause buffer." + :group 'pause) + +(defface pause-message-face + '((t (:inherit secondary-selection))) + "Face for pause messages." + :group 'pause) + +(defface pause-1-minute-message-face + '((t (:inherit mode-line-inactive))) + "Face for pause messages." + :group 'pause) + +(defcustom pause-break-text + (concat "\n\tHi there," + "\n\tYou are worth a PAUSE!" + "\n\nTry some mindfulness:" + "\n\t- Look around and observe." + "\n\t- Listen." + "\n\t- Feel your body.") + "Text to show during pause." + :type 'integer + :group 'pause) + +(defvar pause-el-file (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + +(defvar pause-default-img-dir + (let ((this-dir (file-name-directory pause-el-file))) + (expand-file-name "../etc/img/pause/" this-dir))) + +(defcustom pause-img-dir pause-default-img-dir + "Image directory for pause. +A random image is choosen from this directory for pauses." + :type 'directory + :group 'pause) + + + +(defvar pause-timer nil) + +;;(defvar pause-break-exit-calls nil) + +(defun pause-start-timer () + (pause-start-timer-1 (* 60 pause-after-minutes))) + +(defun pause-start-timer-1 (sec) + (pause-cancel-timer) + (setq pause-timer (run-with-timer sec nil 'pause-pre-break))) + +(defun pause-one-minute () + "Give you another minute ..." + (pause-start-timer-1 pause-1-minute-delay) + (message (propertize " OK, I will come back in a minute! -- greatings from pause" + 'face 'pause-message-face))) + +(defun pause-save-me () + (pause-start-timer) + (message (propertize " OK, I will save you again in %d minutes! -- greatings from pause " + 'face 'pause-message-face) + pause-after-minutes)) + +(defun pause-pre-break () + (condition-case err + (save-match-data ;; runs in timer + (pause-cancel-timer) + (setq pause-timer (run-with-idle-timer pause-idle-delay nil 'pause-break-in-timer))) + (error + (lwarn 'pause-pre-break + :error "%s" (error-message-string err))))) + +(defvar pause-break-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control meta shift ?p)] 'pause-break-exit) + (define-key map [tab] 'forward-button) + (define-key map [(meta tab)] 'backward-button) + (define-key map [(shift tab)] 'backward-button) + (define-key map [backtab] 'backward-button) + map)) + +(defvar pause-buffer nil) +(defvar pause-frame nil) + +(define-derived-mode pause-break-mode nil "Pause" + "Mode used during pause in pause buffer. + +It defines the following key bindings: + +\\{pause-break-mode-map}" + (set (make-local-variable 'buffer-read-only) t) + (setq show-trailing-whitespace nil) + ;;(set (make-local-variable 'cursor-type) nil) + ;; Fix-me: workaround for emacs bug + ;;(run-with-idle-timer 0 nil 'pause-hide-cursor) + ) + +;; Fix-me: make one state var +(defvar pause-break-exit-active nil) +(defvar pause-break-1-minute-state nil) + + +(defun pause-break () + (pause-cancel-timer) + (let ((wcfg (current-frame-configuration)) + (old-mode-line-bg (face-attribute 'mode-line :background)) + old-frame-bg-color + old-frame-left-fringe + old-frame-right-fringe + old-frame-tool-bar-lines + old-frame-menu-bar-lines + old-frame-vertical-scroll-bars) + (dolist (f (frame-list)) + (add-to-list 'old-frame-bg-color (cons f (frame-parameter f 'background-color))) + (add-to-list 'old-frame-left-fringe (cons f (frame-parameter f 'left-fringe))) + (add-to-list 'old-frame-right-fringe (cons f (frame-parameter f 'right-fringe))) + (add-to-list 'old-frame-tool-bar-lines (cons f (frame-parameter f 'tool-bar-lines))) + (add-to-list 'old-frame-menu-bar-lines (cons f (frame-parameter f 'menu-bar-lines))) + (add-to-list 'old-frame-vertical-scroll-bars (cons f (frame-parameter f 'vertical-scroll-bars)))) + + ;; Fix-me: Something goes wrong with the window configuration, try a short pause + (remove-hook 'window-configuration-change-hook 'pause-break-exit) + (run-with-idle-timer 0.2 nil 'pause-break-show) + (setq pause-break-exit-active nil) + (setq pause-break-1-minute-state nil) ;; set in `pause-break-show' + (setq pause-exited-from-button nil) + (unwind-protect + (let ((n 0) + (debug-on-error nil)) + (while (and (> 3 (setq n (1+ n))) + (not pause-break-exit-active) + (not pause-break-1-minute-state)) + (condition-case err + (recursive-edit) + (error (message "%s" (error-message-string err)))) + (unless (or pause-break-exit-active + pause-break-1-minute-state) + (when (> 2 n) (message "Too early to pause (%s < 2)" n)) + (add-hook 'window-configuration-change-hook 'pause-break-exit)))) + + (remove-hook 'window-configuration-change-hook 'pause-break-exit) + (pause-tell-again-cancel-timer) + ;;(set-frame-parameter nil 'background-color "white") + (dolist (f (frame-list)) + (set-frame-parameter f 'background-color (cdr (assq f old-frame-bg-color))) + (set-frame-parameter f 'left-fringe (cdr (assq f old-frame-left-fringe))) + (set-frame-parameter f 'right-fringe (cdr (assq f old-frame-right-fringe))) + (set-frame-parameter f 'tool-bar-lines (cdr (assq f old-frame-tool-bar-lines))) + (set-frame-parameter f 'menu-bar-lines (cdr (assq f old-frame-menu-bar-lines))) + (set-frame-parameter f 'vertical-scroll-bars (cdr (assq f old-frame-vertical-scroll-bars)))) + ;; Fix-me: The frame grows unless we do redisplay here: + (redisplay t) + (set-frame-configuration wcfg t) + (when pause-frame(lower-frame pause-frame)) + (set-face-attribute 'mode-line nil :background old-mode-line-bg) + (run-with-idle-timer 2.0 nil 'run-hooks 'pause-break-exit-hook) + (kill-buffer pause-buffer) + (cond (pause-exited-from-button + ;; Do not start timer until we start working again. + (run-with-idle-timer 1 nil 'add-hook 'post-command-hook 'pause-save-me-post-command) + ;; But if we do not do that within some minutes then start timer anyway. + (run-with-idle-timer (* 60 pause-restart-anyway-after) nil 'pause-save-me)) + (pause-break-1-minute-state + (run-with-idle-timer 0 nil 'pause-one-minute)) + (t + (run-with-idle-timer 0 nil 'pause-save-me)))))) + +(defun pause-save-me-post-command () + (pause-start-timer)) + +(defvar pause-break-exit-hook nil + "Hook run after break exit. +Frame configuration has been restored when this is run. +Please note that it is run in a timer.") + +(defun pause-break-show () + ;; In timer + (save-match-data + (condition-case err + (pause-break-show-1) + (error + ;;(remove-hook 'window-configuration-change-hook 'pause-break-exit) + (pause-break-exit) + (message "pause-break-show error: %s" (error-message-string err)))))) + +(defvar pause-break-last-wcfg-change (float-time)) + +(defun pause-break-show-1 () + ;; Do these first if something goes wrong. + (setq pause-break-last-wcfg-change (float-time)) + ;;(run-with-idle-timer (* 1.5 (length (frame-list))) nil 'add-hook 'window-configuration-change-hook 'pause-break-exit) + + ;; fix-me: temporary: + ;;(add-hook 'window-configuration-change-hook 'pause-break-exit) + (unless pause-extra-fun (run-with-idle-timer 1 nil 'pause-break-message)) + (run-with-idle-timer 10 nil 'pause-break-exit-activate) + (setq pause-break-1-minute-state t) + (set-face-attribute 'mode-line nil :background pause-1-minute-mode-line-color) + (with-current-buffer (setq pause-buffer + (get-buffer-create "* P A U S E *")) + (let ((inhibit-read-only t)) + (erase-buffer) + (pause-break-mode) + (setq left-margin-width 25) + (pause-insert-img) + (insert (propertize pause-break-text 'face 'pause-text-face)) + (goto-char (point-min)) + (when (search-forward "mindfulness" nil t) + (make-text-button (- (point) 11) (point) + 'face '(:inherit pause-text-face :underline t) + 'action (lambda (btn) + (browse-url "http://www.jimhopper.com/mindfulness/")))) + (goto-char (point-max)) + (insert (propertize "\n\nClick on a link below to exit pause\n" 'face 'pause-info-text-face)) + ;;(add-text-properties (point-min) (point-max) (list 'keymap (make-sparse-keymap))) + (insert-text-button "Exit pause" + 'action `(lambda (button) + (condition-case err + (pause-break-exit-from-button) + (error (message "%s" (error-message-string err)))))) + (insert "\n") + (dolist (m '(hl-needed-mode)) + (when (and (boundp m) (symbol-value m)) + (funcall m -1))))) + (dolist (f (frame-list)) + (pause-max-frame f)) + (pause-tell-again) + (when pause-extra-fun (funcall pause-extra-fun)) + ;;(setq pause-break-exit-calls 0) + (setq pause-break-last-wcfg-change (float-time)) + (pause-tell-again-start-timer)) + +(defun pause-max-frame (f) + (let* ((avail-width (- (display-pixel-width) + (* 2 (frame-parameter f 'border-width)) + (* 2 (frame-parameter f 'internal-border-width)))) + (avail-height (- (display-pixel-height) + (* 2 (frame-parameter f 'border-width)) + (* 2 (frame-parameter f 'internal-border-width)))) + (cols (/ avail-width (frame-char-width))) + (rows (- (/ avail-height (frame-char-height)) 2))) + ;;(set-frame-parameter (selected-frame) 'fullscreen 'fullboth) + ;;(set-frame-parameter (selected-frame) 'fullscreen 'maximized) + (setq pause-break-last-wcfg-change (float-time)) + (with-selected-frame f + (delete-other-windows (frame-first-window f)) + (with-selected-window (frame-first-window) + (switch-to-buffer pause-buffer) + (goto-char (point-max)))) + (modify-frame-parameters f + `((background-color . ,pause-background-color) + (left-fringe . 0) + (right-fringe . 0) + (tool-bar-lines . 0) + (menu-bar-lines . 0) + (vertical-scroll-bars . nil) + (left . 0) + (top . 0) + (width . ,cols) + (height . ,rows) + )))) + +(defvar pause-tell-again-timer nil) + +(defun pause-tell-again-start-timer () + (pause-tell-again-cancel-timer) + (setq pause-tell-again-timer + (run-with-idle-timer (* 60 pause-tell-again-after) t 'pause-tell-again))) + +(defun pause-tell-again-cancel-timer () + (when (timerp pause-tell-again-timer) + (cancel-timer pause-tell-again-timer)) + (setq pause-tell-again-timer nil)) + +(defun pause-tell-again () + (when (and window-system pause-even-if-not-in-emacs) + (pause-max-frame pause-frame) + (raise-frame pause-frame))) + + +(defun pause-break-message () + (when (/= 0 (recursion-depth)) + (message "%s" (propertize "Please take a pause! (Or exit now to take it in 1 minute.)" + 'face 'pause-1-minute-message-face)))) + +(defun pause-break-exit-activate () + (when (/= 0 (recursion-depth)) + (setq pause-break-exit-active t) + (setq pause-break-1-minute-state nil) + (set-face-attribute 'mode-line nil :background pause-mode-line-color) + (message nil) + (with-current-buffer pause-buffer + (let ((inhibit-read-only t)) + ;; Fix-me: This interfere with text buttons. + ;;(add-text-properties (point-min) (point-max) (list 'keymap nil)) + )))) + +(defun pause-break-exit () + (interactive) + (let ((elapsed (- (float-time) pause-break-last-wcfg-change))) + ;;(message "elapsed=%s pause-break-last-wcfg-change=%s" elapsed pause-break-last-wcfg-change) + (setq pause-break-last-wcfg-change (float-time)) + (when (> elapsed 1.0) + (setq pause-break-exit-active t) + (remove-hook 'window-configuration-change-hook 'pause-break-exit) + ;;(pause-tell-again-cancel-timer) + (when (/= 0 (recursion-depth)) + (exit-recursive-edit))))) + +(defun pause-break-exit-from-button () + (setq pause-break-1-minute-state nil) + (setq pause-exited-from-button t) + (pause-break-exit)) + +(defun pause-insert-img () + (let* ((inhibit-read-only t) + img + src + (slice '(0 0 200 300)) + (imgs (directory-files pause-img-dir nil nil t)) + skip + ) + (setq imgs (delete nil + (mapcar (lambda (d) + (unless (file-directory-p d) d)) + imgs))) + (if (not imgs) + (setq img "No images found") + (setq skip (random (length imgs))) + (while (> skip 0) + (setq skip (1- skip)) + (setq imgs (cdr imgs))) + (setq src (expand-file-name (car imgs) pause-img-dir)) + (if (file-exists-p src) + (condition-case err + (setq img (create-image src nil nil + :relief 1 + ;;:margin inlimg-margins + )) + (error (setq img (error-message-string err)))) + (setq img (concat "Image not found: " src)))) + (if (stringp img) + (insert img) + (insert-image img nil 'left-margin slice) + ) + )) + +(defun pause-hide-cursor () + ;; runs in timer, save-match-data + (with-current-buffer pause-buffer + (set (make-local-variable 'cursor-type) nil))) + +(defun pause-cancel-timer () + (remove-hook 'post-command-hook 'pause-save-me-post-command) + (when (timerp pause-timer) (cancel-timer pause-timer)) + (setq pause-timer nil)) + +(defun pause-break-in-timer () + (save-match-data ;; runs in timer + (pause-cancel-timer) + (if (or (active-minibuffer-window) + (and (boundp 'edebug-active) + edebug-active)) + (let ((pause-idle-delay 5)) + (pause-pre-break)) + (let ((there-was-an-error nil)) + (condition-case err + (pause-break) + (error + (setq there-was-an-error t))) + (when there-was-an-error + (condition-case err + (progn + (select-frame last-event-frame) + (let ((pause-idle-delay nil)) + (pause-pre-break))) + (error + (lwarn 'pause-break-in-timer2 :error "%s" (error-message-string err)) + ))))))) + +(defcustom pause-only-when-server-mode t + "Allow `pause-mode' inly in the Emacs that has server-mode enabled. +This is to prevent multiple Emacs with `pause-mode'." + :type 'boolean + :group 'pause) + +;;;###autoload +(define-minor-mode pause-mode + "This minor mode tries to make you take a break. +It will jump up and temporary stop your work - even if you are +not in Emacs. If you are in Emacs it will however try to be +gentle and wait until you have been idle with the keyboard for a +short while. \(If you are not in Emacs it can't be gentle. How +could it?) + +Then it will show you a special screen with a link to a yoga +exercise you can do when you pause. + +After the pause you continue your work where you were +interrupted." + :global t + :group 'pause + :set-after '(server-mode) + (if pause-mode + (if (and pause-only-when-server-mode + (not server-mode) + (not (with-no-warnings (called-interactively-p)))) + (progn + (setq pause-mode nil) + (message "Pause mode canceled because not server-mode")) + (pause-start-timer)) + (pause-cancel-timer))) + +;; (emacs-Q "-l" buffer-file-name "--eval" "(pause-temp-err)") +;; (emacs-Q "-l" buffer-file-name "--eval" "(run-with-timer 1 nil 'pause-temp-err)") +;; (pause-temp-err) +(defun pause-temp-err () + (switch-to-buffer (get-buffer-create "pause-temp-err buffer")) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (add-text-properties (point-min) (point-max) (list 'keymap nil)) + (insert-text-button "click to test" + 'action (lambda (btn) + (message "Click worked"))) + ;;(add-text-properties (point-min) (point-max) (list 'keymap nil)) + )) + +;; (customize-group-other-window 'pause) +;; (apply 'custom-set-variables (pause-get-group-saved-customizations 'pause custom-file)) +;; (pause-get-group-saved-customizations 'w32shell custom-file) +(defun pause-get-group-saved-customizations (group cus-file) + "Return customizations saved for GROUP in CUS-FILE." + (let* ((cus-buf (find-buffer-visiting cus-file)) + (cus-old cus-buf) + (cus-point (when cus-old (with-current-buffer cus-old (point)))) + (cusg-all (get group 'custom-group)) + (cusg-vars (delq nil (mapcar (lambda (elt) + (when (eq (nth 1 elt) 'custom-variable) + (car elt))) + cusg-all))) + cus-vars-form + cus-face-form + cus-saved-vars + cus-saved-face) + (unless cus-buf (setq cus-buf (find-file-noselect cus-file))) + (with-current-buffer cus-buf + (save-restriction + (widen) + (goto-char (point-min)) + (while (progn + (while (progn (skip-chars-forward " \t\n\^l") + (looking-at ";")) + (forward-line 1)) + (not (eobp))) + (let ((form (read (current-buffer)))) + (cond + ((eq (car form) 'custom-set-variables) + (setq cus-vars-form form)) + ((eq (car form) 'custom-set-faces) + (setq cus-face-form form)) + ))))) + (dolist (vl (cdr cus-vars-form)) + (when (memq (car (cadr vl)) cusg-vars) + (setq cus-saved-vars (cons (cadr vl) cus-saved-vars)))) + cus-saved-vars)) + +;; (emacs-Q "-l" buffer-file-name "--eval" "(pause-start 0.1 nil)") +(defun pause-start (after-minutes cus-file) + "Start `pause-mode' with interval AFTER-MINUTES. +This bypasses `pause-only-when-server-mode'. + +You can use this funciton to start a separate Emacs process that +handles pause, for example like this if you want a pause every 15 +minutes: + + emacs -Q -l pause --eval \"(pause-start 15 nil)\" + +Note: Another easier alternative might be to use + `pause-start-in-new-emacs'." + (interactive "nPause after how many minutes: ") + (pause-start-1 after-minutes cus-file)) + +(defun pause-start-1 (after-minutes cus-file) + (setq debug-on-error t) + (pause-cancel-timer) + (when (and cus-file (file-exists-p cus-file)) + (let ((args (pause-get-group-saved-customizations 'pause cus-file))) + ;;(message "cus-file=%S" cus-file) + ;;(message "args=%S" args) + (apply 'custom-set-variables args))) + (setq pause-after-minutes after-minutes) + (let ((pause-only-when-server-mode nil)) + (pause-mode 1)) + (switch-to-buffer (get-buffer-create "Pause information")) + (insert (propertize "Emacs pause\n" + 'face '(:inherit variable-pitch :height 1.5))) + (insert (format "Pausing every %d minute.\n" after-minutes)) + (insert "Or, ") + (insert-text-button "pause now" + 'action `(lambda (button) + (condition-case err + (pause-break) + (error (message "%s" (error-message-string err)))))) + (insert "!\n") + ;;(setq buffer-read-only t) + (pause-break-mode) + (delete-other-windows) + (setq mode-line-format nil) + (setq pause-frame (selected-frame)) + (message nil) + (set-frame-parameter nil 'background-color pause-background-color)) + +;; (pause-start-in-new-emacs 0.3) +;; (pause-start-in-new-emacs 15) +;;;###autoload +(defun pause-start-in-new-emacs (after-minutes) + "Start pause with interval AFTER-MINUTES in a new Emacs instance. +The new Emacs instance will be started with -Q. However if +`custom-file' is non-nil it will be loaded so you can still +customize pause. + +One way of using this function may be to put in your .emacs +something like + + ;; for just one Emacs running pause + (when server-mode (pause-start-in-new-emacs 15)) + +See `pause-start' for more info. + +" + (interactive (list pause-after-minutes)) + (let* ((this-emacs (locate-file invocation-name + (list invocation-directory) + exec-suffixes)) + (cus-file (if custom-file custom-file "~/.emacs")) + (args `("-l" ,pause-el-file + "--geometry=40x3" + "-D" + "--eval" ,(format "(pause-start %s %S)" after-minutes cus-file)))) + (setq args (cons "-Q" args)) + (apply 'call-process this-emacs nil 0 nil args))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Link to yoga poses + +;; (defun w3-download-callback (fname) +;; (let ((coding-system-for-write 'binary)) +;; (goto-char (point-min)) +;; (search-forward "\n\n" nil t) +;; (write-region (point) (point-max) fname)) +;; (url-mark-buffer-as-dead (current-buffer)) +;; (message "Download of %s complete." (url-view-url t)) +;; (sit-for 3)) + +;;(run-with-idle-timer 0 nil 'pause-get-yoga-poses) +(defvar pause-yoga-poses-host-url "http://www.abc-of-yoga.com/") + +;;(pause-start-get-yoga-poses) +(defun pause-start-get-yoga-poses () + (require 'url-vars) + (let ((url-show-status nil)) ;; do not show download messages + (url-retrieve (concat pause-yoga-poses-host-url "yogapractice/mountain.asp") + 'pause-callback-get-yoga-poses))) + +(defun pause-callback-get-yoga-poses (status) + (let ((pose (pause-random-yoga-pose (pause-get-yoga-poses-1 (current-buffer))))) + (message nil) + (when (and pose (buffer-live-p pause-buffer)) + (pause-insert-yoga-link pose)))) + +(defun pause-insert-yoga-link (pose) + (with-current-buffer pause-buffer + (let ((here (point)) + (inhibit-read-only t) + (pose-url (concat pause-yoga-poses-host-url (car pose)))) + (goto-char (point-max)) + (insert "Link to yoga posture for you: ") + (insert-text-button (cdr pose) + 'action `(lambda (button) + (condition-case err + (progn + (browse-url ,pose-url) + (run-with-idle-timer 1 nil 'pause-break-exit-from-button)) + (error (message "%s" (error-message-string err)))))) + (insert "\n") + (pause-break-message)))) + +(defun pause-get-yoga-poses () + (let* ((url-show-status nil) ;; do not show download messages + (buf (url-retrieve-synchronously "http://www.abc-of-yoga.com/yogapractice/mountain.asp"))) + (pause-get-yoga-poses-1 buf))) + +;; (setq x (url-retrieve-synchronously "http://www.abc-of-yoga.com/yogapractice/mountain.asp")) +;; (setq x (url-retrieve-synchronously "http://www.emacswiki.org/emacs/EmacsFromBazaar")) + +;; (defun temp-y () +;; (message "before y") +;; ;;(setq y (url-retrieve-synchronously "http://www.emacswiki.org/emacs/EmacsFromBazaar")) +;; (setq x (url-retrieve-synchronously "http://www.abc-of-yoga.com/yogapractice/mountain.asp")) +;; (message "after x") +;; ) +;; (run-with-idle-timer 0 nil 'temp-y) + +(defun pause-get-yoga-poses-1 (buf) + (require 'url) + (setq url-debug t) + ;; url-insert-file-contents + (let* ((first-marker "<p>These are all the Yoga Poses covered in this section:</p>") + (table-patt "<table\\(?:.\\|\n\\)*?</table>") + table-beg + table-end + (pose-patt "<A HREF=\"\\([^\"]*?\\)\" class=\"LinkBold\">\\([^<]*?\\)</A>") + poses + (trouble-msg + (catch 'trouble + ;;(switch-to-buffer-other-window buf) + (with-current-buffer buf + (goto-char 1) + (rename-buffer "YOGA" t) + (unless (search-forward first-marker nil t) + (throw 'trouble "Can't find marker for the poses on the page")) + (backward-char 10) + (unless (re-search-forward table-patt nil t) + (throw 'trouble "Can't find table with poses on the page")) + (setq table-beg (match-beginning 0)) + (setq table-end (match-end 0)) + (goto-char table-beg) + (while (re-search-forward pose-patt table-end t) + (setq poses (cons (cons (match-string 1) (match-string 2)) + poses))) + (unless poses + (throw 'trouble "Can't find poses in table on the page")) + (kill-buffer) + nil)))) + (if trouble-msg + (progn + (message "%s" trouble-msg) + nil) + (message "Number of yoga poses found=%s" (length poses)) + poses))) + +(defun pause-random-yoga-pose (poses) + (when poses + (random t) + (let* ((n-poses (length poses)) + (pose-num (random (1- n-poses))) + (the-pose (nth pose-num poses))) + the-pose))) + +;;(pause-random-yoga-pose (pause-get-yoga-poses)) + +(provide 'pause) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; pause.el ends here diff --git a/emacs/nxhtml/util/pointback.el b/emacs/nxhtml/util/pointback.el new file mode 100644 index 0000000..7a17943 --- /dev/null +++ b/emacs/nxhtml/util/pointback.el @@ -0,0 +1,93 @@ +;;; pointback.el --- Restore window points when returning to buffers + +;; Copyright (C) 2009 Markus Triska + +;; Author: Markus Triska <markus.triska@gmx.at> +;; Keywords: convenience + +;; 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 3 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, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; When you have two windows X and Y showing different sections of the +;; same buffer B, then switch to a different buffer in X, and then +;; show B in X again, the new point in X will be the same as in Y. +;; With pointback-mode, window points are preserved instead, and point +;; will be where it originally was in X for B when you return to B. + +;; Use M-x pointback-mode RET to enable pointback-mode for a buffer. +;; Use M-x global-pointback-mode RET to enable it for all buffers. + +;;; Code: + +(require 'assoc) + +(defconst pointback-version "0.2") + +(defvar pointback-windows nil + "Association list of windows to buffers and window points.") + +(defun pointback-store-point () + "Save window point and start for the current buffer of the +selected window." + (sit-for 0) ; redisplay to update window-start + (let* ((buffers (cdr (assq (selected-window) pointback-windows))) + (b (assq (current-buffer) buffers)) + (p (cons (point) (window-start)))) + (if b + (setcdr b p) + (let ((current (cons (current-buffer) p))) + (aput 'pointback-windows (selected-window) (cons current buffers)))))) + +(defun pointback-restore () + "Restore previously stored window point for the selected window." + (let* ((buffers (cdr (assq (selected-window) pointback-windows))) + (b (assq (current-buffer) buffers)) + (p (cdr b))) + (when b + (goto-char (car p)) + (set-window-start (selected-window) (cdr p) t))) + ;; delete dead windows from pointback-windows + (dolist (w pointback-windows) + (unless (window-live-p (car w)) + (adelete 'pointback-windows (car w)))) + ;; delete window points of dead buffers + (dolist (w pointback-windows) + (let (buffers) + (dolist (b (cdr w)) + (when (buffer-live-p (car b)) + (push b buffers))) + (aput 'pointback-windows (car w) buffers)))) + +;;;###autoload +(define-minor-mode pointback-mode + "Restore previous window point when switching back to a buffer." + :lighter "" + (if pointback-mode + (progn + (add-hook 'post-command-hook 'pointback-store-point nil t) + (add-hook 'window-configuration-change-hook + 'pointback-restore nil t)) + (remove-hook 'post-command-hook 'pointback-store-point t) + (remove-hook 'window-configuration-change-hook 'pointback-restore t) + (setq pointback-windows nil))) + +;;;###autoload +(define-globalized-minor-mode global-pointback-mode pointback-mode pointback-on) + +(defun pointback-on () + (pointback-mode 1)) + +(provide 'pointback) +;;; pointback.el ends here diff --git a/emacs/nxhtml/util/popcmp.el b/emacs/nxhtml/util/popcmp.el new file mode 100644 index 0000000..319145d --- /dev/null +++ b/emacs/nxhtml/util/popcmp.el @@ -0,0 +1,472 @@ +;;; popcmp.el --- Completion enhancements, popup etc +;; +;; Author: Lennart Borgman +;; Created: Tue Jan 09 12:00:29 2007 +;; Version: 1.00 +;; Last-Updated: 2008-03-08T03:30:15+0100 Sat +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `ourcomments-util'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'ourcomments-util nil t)) + +;;;###autoload +(defgroup popcmp nil + "Customization group for popup completion." + :tag "Completion Style \(popup etc)" + :group 'nxhtml + :group 'convenience) + +;; (define-toggle popcmp-popup-completion t +;; "Use a popup menu for some completions if non-nil. + +;; ***** Obsolete: Use `popcmp-completion-style' instead. + +;; When completion is used for alternatives tighed to text at the +;; point in buffer it may make sense to use a popup menu for +;; completion. This variable let you decide whether normal style +;; completion or popup style completion should be used then. + +;; This style of completion is not implemented for all completions. +;; It is implemented for specific cases but the choice of completion +;; style is managed generally by this variable for all these cases. + +;; See also the options `popcmp-short-help-beside-alts' and +;; `popcmp-group-alternatives' which are also availabe when popup +;; completion is available." +;; :tag "Popup style completion" +;; :group 'popcmp) + +(defun popcmp-cant-use-style (style) + (save-match-data ;; runs in timer + (describe-variable 'popcmp-completion-style) + (message (propertize "popcmp-completion-style: style `%s' is not available" + 'face 'secondary-selection) + style))) + + + +(defun popcmp-set-completion-style (val) + "Internal use, set `popcmp-completion-style' to VAL." + (assert (memq val '(popcmp-popup emacs-default company-mode anything)) t) + (case val + ('company-mode (unless (fboundp 'company-mode) + (require 'company-mode nil t)) + (unless (fboundp 'company-mode) + (run-with-idle-timer 1 nil 'popcmp-cant-use-style val) + (setq val 'popcmp-popup))) + ('anything (unless (fboundp 'anything) + (require 'anything nil t)) + (unless (fboundp 'anything) + (run-with-idle-timer 1 nil 'popcmp-cant-use-style val) + (setq val 'popcmp-popup)))) + (set-default 'popcmp-completion-style val) + (unless (eq val 'company-mode) + (when (and (boundp 'global-company-mode) + global-company-mode) + (global-company-mode -1)) + (remove-hook 'after-change-major-mode-hook 'company-set-major-mode-backend) + (remove-hook 'mumamo-after-change-major-mode-hook 'mumamo-turn-on-company-mode)) + (when (eq val 'company-mode) + (unless (and (boundp 'global-company-mode) + global-company-mode) + (global-company-mode 1)) + (add-hook 'after-change-major-mode-hook 'company-set-major-mode-backend) + (add-hook 'mumamo-after-change-major-mode-hook 'mumamo-turn-on-company-mode))) + +;; fix-me: move to mumamo.el +(defun mumamo-turn-on-company-mode () + (when (and (boundp 'company-mode) + company-mode) + (company-mode 1) + (company-set-major-mode-backend))) + +;;;###autoload +(defcustom popcmp-completion-style (cond + ;;((and (fboundp 'global-company-mode) 'company-mode) 'company-mode) + (t 'popcmp-popup)) + "Completion style. +The currently available completion styles are: + +- popcmp-popup: Use OS popup menus (default). +- emacs-default: Emacs default completion. +- Company Mode completion. +- anything: The Anything elisp lib completion style. + +The style of completion set here is not implemented for all +completions. The scope varies however with which completion +style you have choosen. + +For information about Company Mode and how to use it see URL +`http://www.emacswiki.org/emacs/CompanyMode'. + +For information about Anything and how to use it see URL +`http://www.emacswiki.org/emacs/Anything'. + +See also the options `popcmp-short-help-beside-alts' and +`popcmp-group-alternatives' which are also availabe when popup +completion is available." + :type '(choice (const company-mode) + (const popcmp-popup) + (const emacs-default) + (const anything)) + :set (lambda (sym val) + (popcmp-set-completion-style val)) + :group 'popcmp) + +;;(define-toggle popcmp-short-help-beside-alts t +(define-minor-mode popcmp-short-help-beside-alts + "Show a short help text beside each alternative. +If this is non-nil a short help text is shown beside each +alternative for which such a help text is available. + +This works in the same circumstances as +`popcmp-completion-style'." + :tag "Short help beside alternatives" + :global t + :init-value t + :group 'popcmp) + +(defun popcmp-short-help-beside-alts-toggle () + "Toggle `popcmp-short-help-beside-alts'." + (popcmp-short-help-beside-alts (if popcmp-short-help-beside-alts -1 1))) + +;;(define-toggle popcmp-group-alternatives t +(define-minor-mode popcmp-group-alternatives + "Do completion in two steps. +For some completions the alternatives may have been grouped in +sets. If this option is non-nil then you will first choose a set +and then an alternative within this set. + +This works in the same circumstances as +`popcmp-completion-style'." + :tag "Group alternatives" + :global t + :init-value t + :group 'popcmp) + +(defun popcmp-group-alternatives-toggle () + "Toggle `popcmp-group-alternatives-toggle'." + (interactive) + (popcmp-group-alternatives (if popcmp-group-alternatives -1 1))) + +(defun popcmp-getsets (alts available-sets) + (let ((sets nil)) + (dolist (tg alts) + (let (found) + (dolist (s available-sets) + (when (member tg (cdr s)) + (setq found t) + (let ((sets-entry (assq (car s) sets))) + (unless sets-entry + (setq sets (cons (list (car s)) sets)) + (setq sets-entry (assq (car s) sets))) + (setcdr sets-entry (cons tg (cdr sets-entry)))))) + (unless found + (let ((sets-entry (assq 'unsorted sets))) + (unless sets-entry + (setq sets (cons (list 'unsorted) sets)) + (setq sets-entry (assq 'unsorted sets))) + (setcdr sets-entry (cons tg (cdr sets-entry))))))) + (setq sets (sort sets (lambda (a b) + (string< (format "%s" b) + (format "%s" a))))) + ;;(dolist (s sets) (setcdr s (reverse (cdr s)))) + sets)) + +(defun popcmp-getset-alts (set-name sets) + ;; Allow both strings and symbols as keys: + (let ((set (or (assoc (downcase set-name) sets) + (assoc (read (downcase set-name)) sets)))) + (cdr set))) + +(defvar popcmp-completing-with-help nil) + +(defun popcmp-add-help (alt alt-help-hash) + (if alt-help-hash + (let ((h (if (hash-table-p alt-help-hash) + (gethash alt alt-help-hash) + (let ((hh (assoc alt alt-help-hash))) + (cadr hh))) + )) + (if h + (concat alt " -- " h) + alt)) + alt)) + +(defun popcmp-remove-help (alt-with-help) + (when alt-with-help + (replace-regexp-in-string " -- .*" "" alt-with-help))) + +(defun popcmp-anything (prompt collection + predicate require-match + initial-input hist def inherit-input-method + alt-help alt-sets) + (let* ((table collection) + (alt-sets2 (apply 'append (mapcar 'cdr alt-sets))) + (cands (cond ((not (listp table)) alt-sets2) + (t table))) + ret-val + (source `((name . "Completion candidates") + (candidates . ,cands) + (action . (("Select current alternative (press TAB to see it again)" . (lambda (candidate) + (setq ret-val candidate)))))))) + (anything (list source) initial-input prompt) + ret-val)) + +(defun popcmp-completing-read-1 (prompt collection + predicate require-match + initial-input hist2 def inherit-input-method alt-help alt-sets) + ;; Fix-me: must rename hist to hist2 in par list. Emacs bug? + (cond + ((eq popcmp-completion-style 'emacs-default) + (completing-read prompt collection predicate require-match initial-input hist2 def inherit-input-method)) + ((eq popcmp-completion-style 'anything) + (popcmp-anything prompt collection predicate require-match initial-input hist2 def inherit-input-method + alt-help alt-sets)) + ((eq popcmp-completion-style 'company-mode) + ;; No way to read this from company-mode, use emacs-default + (completing-read prompt collection predicate require-match initial-input hist2 def inherit-input-method)) + (t (error "Do not know popcmp-completion-style %S" popcmp-completion-style)))) + +(defun popcmp-completing-read-other (prompt + table + &optional predicate require-match + initial-input pop-hist def inherit-input-method + alt-help + alt-sets) + (let ((alts + (if (and popcmp-group-alternatives alt-sets) + (all-completions initial-input table predicate) + (if popcmp-short-help-beside-alts + (all-completions "" table predicate) + table)))) + (when (and popcmp-group-alternatives alt-sets) + (let* ((sets (popcmp-getsets alts alt-sets)) + (set-names (mapcar (lambda (elt) + (capitalize (format "%s" (car elt)))) + sets)) + set) + (setq set + (popcmp-completing-read-1 (concat + (substring prompt 0 (- (length prompt) 2)) + ", select group: ") + set-names + nil t + nil nil nil inherit-input-method nil nil)) + (if (or (not set) (= 0 (length set))) + (setq alts nil) + (setq set (downcase set)) + (setq alts (popcmp-getset-alts set sets))))) + (if (not alts) + "" + (if (= 1 (length alts)) + (car alts) + (when popcmp-short-help-beside-alts + (setq alts (mapcar (lambda (a) + (popcmp-add-help a alt-help)) + alts))) + (popcmp-remove-help + ;;(completing-read prompt + (popcmp-completing-read-1 prompt + alts ;table + predicate require-match + initial-input pop-hist def inherit-input-method + ;;alt-help alt-sets + nil nil + )))))) + +(defun popcmp-completing-read-pop (prompt + table + &optional predicate require-match + initial-input hist def inherit-input-method + alt-help + alt-sets) + (unless initial-input + (setq initial-input "")) + (let ((matching-alts (all-completions initial-input table predicate)) + completion) + (if (not matching-alts) + (progn + (message "No alternative found") + nil) + (let ((pop-map (make-sparse-keymap prompt)) + (sets (when (and popcmp-group-alternatives alt-sets) + (popcmp-getsets matching-alts alt-sets))) + (add-alt (lambda (k tg) + (define-key k + (read (format "[popcmp-%s]" (replace-regexp-in-string " " "-" tg))) + (list 'menu-item + (popcmp-add-help tg alt-help) + `(lambda () + (interactive) + (setq completion ,tg))))))) + (if sets + (dolist (s sets) + (let ((k (make-sparse-keymap))) + (dolist (tg (cdr s)) + (funcall add-alt k tg)) + (define-key pop-map + (read (format "[popcmps-%s]" (car s))) + (list 'menu-item + (capitalize (format "%s" (car s))) + k)))) + (dolist (tg matching-alts) + (funcall add-alt pop-map tg))) + (popup-menu-at-point pop-map) + completion)))) + +(defvar popcmp-in-buffer-allowed nil) + +;;;###autoload +(defun popcmp-completing-read (prompt + table + &optional predicate require-match + initial-input pop-hist def inherit-input-method + alt-help + alt-sets) + "Read a string in the minubuffer with completion, or popup a menu. +This function can be used instead `completing-read'. The main +purpose is to provide a popup style menu for completion when +completion is tighed to text at point in a buffer. If a popup +menu is used it will be shown at window point. Whether a popup +menu or minibuffer completion is used is governed by +`popcmp-completion-style'. + +The variables PROMPT, TABLE, PREDICATE, REQUIRE-MATCH, +INITIAL-INPUT, POP-HIST, DEF and INHERIT-INPUT-METHOD all have the +same meaning is for `completing-read'. + +ALT-HELP should be nil or a hash variable or an association list +with the completion alternative as key and a short help text as +value. You do not need to supply help text for all alternatives. +The use of ALT-HELP is set by `popcmp-short-help-beside-alts'. + +ALT-SETS should be nil or an association list that has as keys +groups and as second element an alternative that should go into +this group. +" + (if (and popcmp-in-buffer-allowed + (eq popcmp-completion-style 'company-mode) + (boundp 'company-mode) + company-mode) + (progn + (add-hook 'company-completion-finished-hook 'nxhtml-complete-tag-do-also-for-state-completion t) + ;;(remove-hook 'company-completion-finished-hook 'nxhtml-complete-tag-do-also-for-state-completion) + (call-interactively 'company-nxml) + initial-input) + + (popcmp-mark-completing initial-input) + (let ((err-sym 'quit) + (err-val nil) + ret) + (unwind-protect + (if (eq popcmp-completion-style 'popcmp-popup) + (progn + (setq err-sym nil) + (popcmp-completing-read-pop + prompt + table + predicate require-match + initial-input pop-hist def inherit-input-method + alt-help + alt-sets)) + ;;(condition-case err + (prog1 + (setq ret (popcmp-completing-read-other + prompt + table + predicate require-match + initial-input pop-hist def inherit-input-method + alt-help + alt-sets)) + ;; Unless quit or error in Anything we come here: + ;;(message "ret=(%S)" ret) + (when (and ret (not (string= ret ""))) + (setq err-sym nil))) + ;; (error + ;; ;;(message "err=%S" err) + ;; (setq err-sym (car err)) + ;; (setq err-val (cdr err)))) + ) + (popcmp-unmark-completing) + (when err-sym (signal err-sym err-val)))))) + +(defvar popcmp-mark-completing-ovl nil) + +(defun popcmp-mark-completing (initial-input) + (let ((start (- (point) (length initial-input))) + (end (point))) + (if (overlayp popcmp-mark-completing-ovl) + (move-overlay popcmp-mark-completing-ovl start end) + (setq popcmp-mark-completing-ovl (make-overlay start end)) + (overlay-put popcmp-mark-completing-ovl 'face 'match))) + (sit-for 0)) + +(defun popcmp-unmark-completing () + (when popcmp-mark-completing-ovl + (delete-overlay popcmp-mark-completing-ovl))) + + +;; (defun popcmp-temp () +;; (interactive) +;; (let* ((coord (point-to-coord (point))) +;; (x (nth 0 (car coord))) +;; (y (nth 1 (car coord))) +;; (emacsw32-max-frames nil) +;; (f (make-frame +;; (list '(minibuffer . only) +;; '(title . "Input") +;; '(name . "Input frame") +;; (cons 'left x) +;; (cons 'top y) +;; '(height . 1) +;; '(width . 40) +;; '(border-width . 1) +;; '(internal-border-width . 2) +;; '(tool-bar-lines . nil) +;; '(menu-bar-lines . nil) +;; )))) +;; f)) + + +(provide 'popcmp) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; popcmp.el ends here diff --git a/emacs/nxhtml/util/readme.txt b/emacs/nxhtml/util/readme.txt new file mode 100644 index 0000000..b9db030 --- /dev/null +++ b/emacs/nxhtml/util/readme.txt @@ -0,0 +1,3 @@ +This subdirectory contains files used by nXhtml that I have +written. The files are placed here because they may be of use also +outside of nXhtml. diff --git a/emacs/nxhtml/util/rebind.el b/emacs/nxhtml/util/rebind.el new file mode 100644 index 0000000..cf4700c --- /dev/null +++ b/emacs/nxhtml/util/rebind.el @@ -0,0 +1,240 @@ +;;; rebind.el --- Rebind keys +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-01-20T12:04:37+0100 Sun +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; See `rebind-keys-mode' for information. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'new-key-seq-widget nil t)) +(eval-when-compile (require 'ourcomments-widgets nil t)) + + +(defun rebind-toggle-first-modifier (orig-key-seq mod) + (let* ((first (elt orig-key-seq 0)) + (new-key-seq (copy-sequence orig-key-seq))) + (setq first (if (memq mod first) + (delq mod first) + (cons mod first))) + (aset new-key-seq 0 first) + new-key-seq)) +;; (rebind-toggle-first-modifier (key-description-to-vector "C-c a") 'shift) +;; (rebind-toggle-first-modifier (key-description-to-vector "C-S-c a") 'shift) + +(defvar widget-commandp-prompt-value-history nil) + +;;;###autoload +(defgroup rebind nil + "Customizaton group for `rebind-keys-mode'." + :group 'convenience + :group 'emulations + :group 'editing-basics + :group 'emacsw32) + +;; (customize-option-other-window 'rebind-keys) +;; (Fetched key bindings from http://www.davidco.com/tips_tools/tip45.html) +(defcustom rebind-keys + '( + ("MS Windows - often used key bindings" t + ( + ( + [(control ?a)] + "C-a on w32 normally means 'select all'. In Emacs it is `beginning-of-line'." + t + shift + ourcomments-mark-whole-buffer-or-field) + ( + [(control ?o)] + "C-o on w32 normally means 'open file'. In Emacs it is `open-line'." + nil + shift + find-file) + ( + [(control ?f)] + "C-f is commonly search on w32. In Emacs it is `forward-char'." + nil + shift + isearch-forward) + ( + [(control ?s)] + "C-s is normally 'save file' on w32. In Emacs it is `isearch-forward'." + nil + nil + save-buffer) + ( + [(control ?w)] + "C-w is often something like kill-buffer on w32. In Emacs it is `kill-region'." + t + shift + kill-buffer) + ( + [(control ?p)] + "C-p is nearly always print on w32. In Emacs it is `previous-line'." + t + shift + hfyview-buffer) + ( + [(home)] + "HOME normally stays in a field. By default it does not do that in Emacs." + t + nil + ourcomments-move-beginning-of-line) + ( + [(control ?+)] + "C-+ often increases font size (in web browsers for example)." + t + shift + text-scale-adjust) + ( + [(control ?-)] + "C-- often decreases font size (in web browsers for example)." + t + shift + text-scale-adjust) + ( + [(control ?0)] + "C-0 often resets font size (in web browsers for example)." + t + shift + text-scale-adjust) + ))) + "Normal Emacs keys that are remapped to follow some other standard. +The purpose of this variable is to make it easy to switch between +Emacs key bindings and other standards. + +The new bindings are made in the global minor mode +`rebind-keys-mode' and will only have effect when this mode is +on. + +*Note:* You can only move functions bound in the global key map + this way. +*Note:* To get CUA keys you should turn on option `cua-mode'. +*Note:* To get vi key bindings call function `viper-mode'. +*Note:* `text-scale-adjust' already have default key bindings." + :type '(repeat + (list + (string :tag "For what") + (boolean :tag "Group on/off") + (repeat + (list + (key-sequence :tag "Emacs key binding") + (string :tag "Why rebind") + (boolean :tag "Rebinding on/off") + (choice :tag "Move original by" + (const :tag "Don't put it on any new binding" nil) + (choice :tag "Add key binding modifier" + (const meta) + (const control) + (const shift)) + (key-sequence :tag "New binding for original function")) + (command :tag "New command on above key")) + ))) + :set (lambda (sym val) + (set-default sym val) + (when (featurep 'rebind) + (rebind-update-keymap))) + :group 'rebind) + +(defvar rebind-keys-mode-map nil) + +(defvar rebind--emul-keymap-alist nil) + +;;(rebind-update-keymap) +(defun rebind-update-keymap () + (let ((m (make-sparse-keymap))) + (dolist (group rebind-keys) + (when (nth 1 group) + (dolist (v (nth 2 group)) + (let* ((orig-key (nth 0 v)) + (comment (nth 1 v)) + (enabled (nth 2 v)) + (new-choice (nth 3 v)) + (new-fun (nth 4 v)) + (orig-fun (lookup-key global-map orig-key)) + new-key) + (when enabled + (when new-choice + (if (memq new-choice '(meta control shift)) + (setq new-key (rebind-toggle-first-modifier orig-key new-choice)) + (setq new-key new-choice)) + (define-key m new-key orig-fun)) + (define-key m orig-key new-fun)))) + (setq rebind-keys-mode-map m)))) + (setq rebind--emul-keymap-alist (list (cons 'rebind-keys-mode rebind-keys-mode-map)))) + +;;;###autoload +(define-minor-mode rebind-keys-mode + "Rebind keys as defined in `rebind-keys'. +The key bindings will override almost all other key bindings +since it is put on emulation level, like for example ``cua-mode' +and `viper-mode'. + +This is for using for example C-a to mark the whole buffer \(or a +field). There are some predifined keybindings for this." + :keymap rebind-keys-mode-map + :global t + :group 'rebind + (if rebind-keys-mode + (progn + (rebind-update-keymap) + ;;(rebind-keys-post-command) + (add-hook 'post-command-hook 'rebind-keys-post-command t)) + (remove-hook 'post-command-hook 'rebind-keys-post-command) + (setq emulation-mode-map-alists (delq 'rebind--emul-keymap-alist emulation-mode-map-alists)))) + +(defun rebind-keys-post-command () + "Make sure we are first in the list when turned on. +This is reasonable since we are using this mode to really get the +key bindings we want!" + (unless (eq 'rebind--emul-keymap-alist (car emulation-mode-map-alists)) + (setq emulation-mode-map-alists (delq 'rebind--emul-keymap-alist emulation-mode-map-alists)) + (when rebind-keys-mode + (add-to-list 'emulation-mode-map-alists 'rebind--emul-keymap-alist)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Interactive functions for the keymap + + + +(provide 'rebind) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; rebind.el ends here diff --git a/emacs/nxhtml/util/rnc-mode.el b/emacs/nxhtml/util/rnc-mode.el new file mode 100644 index 0000000..5829a50 --- /dev/null +++ b/emacs/nxhtml/util/rnc-mode.el @@ -0,0 +1,265 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; A major mode for editing RELAX NG Compact syntax. +;; Version: 1.0b3 +;; Date: 2002-12-05 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Copyright (c) 2002, Pantor Engineering AB +;; All rights reserved. +;; +;; Redistribution and use in source and binary forms, with or +;; without modification, are permitted provided that the following +;; conditions are met: +;; +;; * Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; +;; * Redistributions in binary form must reproduce the above +;; copyright notice, this list of conditions and the following +;; disclaimer in the documentation and/or other materials provided +;; with the distribution. +;; +;; * Neither the name of Pantor Engineering AB nor the names of its +;; contributors may be used to endorse or promote products derived +;; from this software without specific prior written permission. +;; +;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +;; CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +;; INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +;; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +;; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +;; ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +;; POSSIBILITY OF SUCH DAMAGE. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Created by David.Rosenborg@pantor.com +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Example setup for your ~/.emacs file: +;; +;; (autoload 'rnc-mode "rnc-mode") +;; (setq auto-mode-alist +;; (cons '("\\.rnc\\'" . rnc-mode) auto-mode-alist)) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Changes since 1.0b: +;; Added a couple of defvars for faces to handle differences +;; between GNU Emacs and XEmacs. +;; +;; 2008-12-28: Changed forward-char-command => forward-char +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'font-lock) + +(defvar rnc-indent-level 3 "The RNC indentation level.") + +(defvar rnc-keywords + (mapcar (lambda (kw) (concat "\\b" kw "\\b")) + '("attribute" "div" "element" + "empty" "external" "grammar" "include" "inherit" "list" + "mixed" "notAllowed" "parent" "start" "string" + "text" "token")) + "RNC keywords") + +(defvar rnc-atoms + (mapcar (lambda (kw) (concat "\\b" kw "\\b")) + '("empty" "notAllowed" "string" "text" "token")) + "RNC atomic pattern keywords") + +(defun rnc-make-regexp-choice (operands) + "(op1 op2 ...) -> \"\\(op1\\|op2\\|...\\)\"" + (let ((result "\\(")) + (mapc (lambda (op) (setq result (concat result op "\\|"))) operands) + (concat (substring result 0 -2) "\\)"))) + +;; Font lock treats face names differently in GNU Emacs and XEmacs +;; The following defvars is a workaround + +(defvar italic 'italic) +(defvar default 'default) +(defvar font-lock-preprocessor-face 'font-lock-preprocessor-face) + +(defvar rnc-font-lock-keywords + (list + '("\\b\\(attribute\\|element\\)\\b\\([^{]+\\){" 2 + font-lock-variable-name-face) + '("[a-zA-Z][-a-zA-Z0-9._]*:[a-zA-Z][-a-zA-Z0-9._]*" . italic) + '("\\b\\(default\\(\\s +namespace\\)?\\|namespace\\|datatypes\\)\\(\\s +[a-zA-Z][-a-zA-Z0-9._]*\\)?\\s *=" 1 font-lock-preprocessor-face) + '("\\([a-zA-Z][-a-zA-Z0-9._]*\\)\\(\\s \\|\n\\)*[|&]?=" 1 + font-lock-function-name-face) + '("[a-zA-Z][a-zA-Z0-9._]*\\(-[a-zA-Z][a-zA-Z0-9._]*\\)+" . default) + (cons (rnc-make-regexp-choice rnc-atoms) 'italic) + (cons (rnc-make-regexp-choice rnc-keywords) font-lock-keyword-face) + ) + "RNC Highlighting") + + +(defun rnc-find-column (first start) + "Find which column to indent to." + + ;; FIXME: backward-sexp doesn't work with unbalanced braces in comments + + (let* (column + pos + ;; Find start of enclosing block or assignment + (token + (if (member first '("]" "}" ")")) + (progn + (goto-char (+ start 1)) + (backward-sexp) + (beginning-of-line) + (re-search-forward "\\S ") + (setq pos (point)) + (setq column (- (current-column) 1)) + 'lpar) + (catch 'done + (while (setq pos (re-search-backward "[{}()=]\\|\\[\\|\\]" + (point-min) t)) + (let ((c (match-string 0))) + (beginning-of-line) + (re-search-forward "\\S ") + (setq column (- (current-column) 1)) + (beginning-of-line) + (cond + ;; Don't match inside comments + ;; FIXME: Should exclude matches inside string literals too + ((re-search-forward "#" pos t) (beginning-of-line)) + ;; Skip block + ((member c '("]" "}" ")")) + (goto-char (+ pos 1)) + (backward-sexp)) + + ((string= c "=") (throw 'done 'eq)) + (t (throw 'done 'lpar))))))))) + + (cond + ((not pos) 0) + ((member first '("]" "}" ")")) column) + ((member first '("{" "(")) (+ column rnc-indent-level)) + + ;; Give lines starting with an operator a small negative indent. + ;; This allows for the following indentation style: + ;; foo = + ;; bar + ;; | baz + ;; | oof + ((member first '("," "&" "|")) (+ column (- rnc-indent-level 2))) + + ;; Check if first preceding non-whitespace character was an operator + ;; If not, this is most likely a new assignment. + ;; FIXME: This doesn't play well with name classes starting on a new + ;; line + ((eq token 'eq) + (goto-char start) + (if (and (re-search-backward "[^ \t\n]" (point-min) t) + (member (match-string 0) '("&" "|" "," "=" "~"))) + (+ column rnc-indent-level) + column)) + + (t (+ column rnc-indent-level))))) + +(defun rnc-indent-line () + "Indents the current line." + (interactive) + (let ((orig-point (point))) + (beginning-of-line) + (let* ((beg-of-line (point)) + (pos (re-search-forward "\\(\\S \\|\n\\)" (point-max) t)) + (first (match-string 0)) + (start (match-beginning 0)) + (col (- (current-column) 1))) + + (goto-char beg-of-line) + + (let ((indent-column (rnc-find-column first start))) + (goto-char beg-of-line) + + (cond + ;; Only modify buffer if the line must be reindented + ((not (= col indent-column)) + (if (not (or (null pos) + (= beg-of-line start))) + (kill-region beg-of-line start)) + + (goto-char beg-of-line) + + (while (< 0 indent-column) + (insert " ") + (setq indent-column (- indent-column 1)))) + + ((< orig-point start) (goto-char start)) + (t (goto-char orig-point))))))) + + +(defun rnc-electric-brace (arg) + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (rnc-indent-line) + (let ((p (point))) + (when (save-excursion + (beginning-of-line) + (let ((pos (re-search-forward "\\S " (point-max) t))) + (and pos (= (- pos 1) p)))) + (forward-char)))) + +(defvar rnc-mode-map () "Keymap used in RNC mode.") +(when (not rnc-mode-map) + (setq rnc-mode-map (make-sparse-keymap)) + (define-key rnc-mode-map "\C-c\C-c" 'comment-region) + (define-key rnc-mode-map "}" 'rnc-electric-brace) + (define-key rnc-mode-map "{" 'rnc-electric-brace) + (define-key rnc-mode-map "]" 'rnc-electric-brace) + (define-key rnc-mode-map "[" 'rnc-electric-brace)) + +;;;###autoload +(defun rnc-mode () + "Major mode for editing RELAX NG Compact Syntax schemas. +\\{rnc-mode-map}" + (interactive) + + (kill-all-local-variables) + + (make-local-variable 'indent-line-function) + (setq indent-line-function 'rnc-indent-line) + + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(rnc-font-lock-keywords nil t nil nil)) + + (use-local-map rnc-mode-map) + + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'comment-start-skip) + + (setq comment-start "#" + comment-end "" + comment-start-skip "\\([ \n\t]+\\)##?[ \n\t]+") + + (let ((rnc-syntax-table (copy-syntax-table))) + (modify-syntax-entry ?# "< " rnc-syntax-table) + (modify-syntax-entry ?\n "> " rnc-syntax-table) + (modify-syntax-entry ?\^m "> " rnc-syntax-table) + (modify-syntax-entry ?\\ "w " rnc-syntax-table) + (modify-syntax-entry ?' "\" " rnc-syntax-table) + (modify-syntax-entry ?. "w " rnc-syntax-table) + (modify-syntax-entry ?- "w " rnc-syntax-table) + (modify-syntax-entry ?_ "w " rnc-syntax-table) + (set-syntax-table rnc-syntax-table)) + + (setq mode-name "RNC" + major-mode 'rnc-mode) + (run-hooks 'rnc-mode-hook)) + +(provide 'rnc-mode) diff --git a/emacs/nxhtml/util/rxi.el b/emacs/nxhtml/util/rxi.el new file mode 100644 index 0000000..505d0b4 --- /dev/null +++ b/emacs/nxhtml/util/rxi.el @@ -0,0 +1,148 @@ +;;; rxi.el --- Interactive regexp reading using rx format +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-04-07T18:18:39+0200 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Read regexp as `rx' forms from minibuffer. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(defvar rxi-read-hist nil) + +(defun rxi-find-definition (rx-sym) + (let* ((rec (assoc rx-sym rx-constituents)) + ) + (while (symbolp (cdr rec)) + (setq rec (assoc (cdr rec) rx-constituents))) + (cdr rec))) + +(defun rxi-list-type-p (rx-sym) + (listp (rxi-find-definition rx-sym))) + +(defun rxi-complete () + "Complete `rx' constituents." + (interactive) + ;; Don't care about state for now, there will be an error instead + (let* ((partial (when (looking-back (rx (1+ (any "a-z01:|=>*?+\\-"))) nil t) + (match-string-no-properties 0))) + (candidates (let ((want-list + (= ?\( (char-before (match-beginning 0))))) + (delq nil + (mapcar (lambda (rec) + (let* ((sym (car rec)) + (lst (rxi-list-type-p sym))) + (when (or (and want-list lst) + (and (not want-list) + (not lst))) + (symbol-name sym)))) + rx-constituents)))) + (match-set (when partial + (all-completions + partial + candidates)))) + (cond + ((not match-set) + (message "No completions")) + ((= 1 (length match-set)) + (insert (substring (car match-set) (length partial)))) + (t + (with-output-to-temp-buffer "*Completions*" + (display-completion-list match-set partial)))))) + +(defvar rxi-read-keymap + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-completion-map) + (define-key map [tab] 'rxi-complete) + (define-key map [(meta tab)] 'rxi-complete) + (define-key map [?\ ] 'self-insert-command) + map)) + +(defvar rxi-trailing-overlay nil) + +(defun rxi-minibuf-setup () + (when rxi-trailing-overlay (delete-overlay rxi-trailing-overlay)) + (setq rxi-trailing-overlay + (make-overlay (point-max) (point-max) + (current-buffer) + t t)) + (overlay-put rxi-trailing-overlay 'after-string + (propertize ")" + 'face + (if (and + (fboundp 'noticeable-minibuffer-prompts-mode) + noticeable-minibuffer-prompts-mode) + 'minibuffer-noticeable-prompt + 'minibuffer-prompt))) + (remove-hook 'minibuffer-setup-hook 'rxi-minibuf-setup)) + +(defun rxi-minibuf-exit () + (when rxi-trailing-overlay + (delete-overlay rxi-trailing-overlay) + (setq rxi-trailing-overlay nil)) + (remove-hook 'minibuffer-exit-hook 'rxi-minibuf-exit)) + +(defun rxi-read (prompt) + "Read a `rx' regexp form from minibuffer. +Return cons of rx and regexp, both as strings." + (interactive (list "Test (rx ")) + (let (rx-str rx-full-str res-regexp) + (while (not res-regexp) + (condition-case err + (progn + (add-hook 'minibuffer-setup-hook 'rxi-minibuf-setup) + (add-hook 'minibuffer-exit-hook 'rxi-minibuf-exit) + (setq rx-str (read-from-minibuffer prompt + rx-str ;; initial-contents + rxi-read-keymap + nil ;; read + 'rxi-read-hist + nil ;; inherit-input-method - no idea... + )) + (setq rx-full-str (concat "(rx " rx-str ")")) + (setq res-regexp (eval (read rx-full-str)))) + (error (message "%s" (error-message-string err)) + (sit-for 2)))) + (when (with-no-warnings (called-interactively-p)) (message "%s => \"%s\"" rx-full-str res-regexp)) + (cons rx-full-str res-regexp))) + + +(provide 'rxi) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; rxi.el ends here diff --git a/emacs/nxhtml/util/search-form.el b/emacs/nxhtml/util/search-form.el new file mode 100644 index 0000000..b7b6dd2 --- /dev/null +++ b/emacs/nxhtml/util/search-form.el @@ -0,0 +1,473 @@ +;;; search-form.el --- Search form +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-05-05T01:50:20+0200 Sun +;; Version: 0.11 +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `cus-edit', `cus-face', `cus-load', `cus-start', `wid-edit'. +;; +;;;;;;;;;;seasfireplstring ;; +;; +;;; Commentary: +;; +;; After an idea by Eric Ludlam on Emacs Devel: +;; +;; http://lists.gnu.org/archive/html/emacs-devel/2008-05/msg00152.html +;; +;; NOT QUITE READY! Tagged files have not been tested. +;; +;; Fix-me: work on other windows buffer by default, not buffer from +;; where search form was created. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'ourcomments-util)) +(require 'cus-edit) +(require 'grep) + +(defvar search-form-sfield nil) +(make-variable-buffer-local 'search-form-sfield) +(defvar search-form-rfield nil) +(make-variable-buffer-local 'search-form-rfield) + +(defvar search-form-win-config nil) +(make-variable-buffer-local 'search-form-win-config) +(put 'search-form-win-config 'permanent-local t) + +(defvar search-form-current-buffer nil) + +(defun search-form-multi-occur-get-buffers () + (let* ((bufs (list (read-buffer "First buffer to search: " + (current-buffer) t))) + (buf nil) + (ido-ignore-item-temp-list bufs)) + (while (not (string-equal + (setq buf (read-buffer + (if (eq read-buffer-function 'ido-read-buffer) + "Next buffer to search (C-j to end): " + "Next buffer to search (RET to end): ") + nil t)) + "")) + (add-to-list 'bufs buf) + (setq ido-ignore-item-temp-list bufs)) + (nreverse (mapcar #'get-buffer bufs)))) + +(defvar search-form-buffer) ;; dyn var, silence compiler +(defvar search-form-search-string) ;; dyn var, silence compiler +(defvar search-form-replace-string) ;; dyn var, silence compiler + +(defun search-form-notify-1 (use-search-field + use-replace-field + w + hide-form + display-orig-buf) + (let ((search-form-search-string (when use-search-field (widget-value search-form-sfield))) + (search-form-replace-string (when use-replace-field (widget-value search-form-rfield))) + (search-form-buffer (current-buffer)) + (this-search (widget-get w :do-search)) + (do-it t)) + (if (and use-search-field + (= 0 (length search-form-search-string))) + (progn + (setq do-it nil) + (message "Please specify a search string")) + (when (and use-replace-field + (= 0 (length search-form-replace-string))) + (setq do-it nil) + (message "Please specify a replace string"))) + (when do-it + (if hide-form + (progn + (set-window-configuration search-form-win-config) + (funcall this-search search-form-search-string) + ;;(kill-buffer search-form-buffer) + ) + (when display-orig-buf + (let ((win (display-buffer search-form-current-buffer t))) + (select-window win t))) + ;;(funcall this-search search-form-search-string)) + (funcall this-search w) + )))) + +(defun search-form-notify-no-field (w &rest ignore) + (search-form-notify-1 nil nil w nil t)) + +(defun search-form-notify-sfield (w &rest ignore) + (search-form-notify-1 t nil w nil t)) + +(defun search-form-notify-sfield-nobuf (w &rest ignore) + (search-form-notify-1 t nil w nil nil)) + +(defun search-form-notify-both-fields (w &rest ignore) + (search-form-notify-1 t t w nil t)) + +(defun search-form-insert-button (title function descr do-search-fun) + (widget-insert " ") + (let ((button-title (format " %-15s " title))) + (widget-create 'push-button + :do-search do-search-fun + :notify 'search-form-notify-no-field + :current-buffer search-form-current-buffer + button-title)) + (widget-insert " " descr) + (widget-insert "\n")) + +(defun search-form-insert-search (title search-fun descr do-search-fun no-buf) + (widget-insert " ") + (let ((button-title (format " %-15s " title))) + (if no-buf + (widget-create 'push-button + :do-search do-search-fun + :notify 'search-form-notify-sfield-nobuf + :current-buffer search-form-current-buffer + button-title) + (widget-create 'push-button + :do-search do-search-fun + :notify 'search-form-notify-sfield + :current-buffer search-form-current-buffer + button-title) + )) + (widget-insert " " descr " ") + (search-form-insert-help search-fun) + (widget-insert "\n")) + +(defun search-form-insert-fb (descr + use-sfield + forward-fun + do-forward-fun + backward-fun + do-backward-fun) + (widget-insert (format " %s: " descr)) + (widget-create 'push-button + :do-search do-forward-fun + :use-sfield use-sfield + :notify '(lambda (widget &rest event) + (if (widget-get widget :use-sfield) + (search-form-notify-sfield widget) + (search-form-notify-no-field widget))) + :current-buffer search-form-current-buffer + " Forward ") + (widget-insert " ") + (search-form-insert-help forward-fun) + (widget-insert " ") + (widget-create 'push-button + :do-search do-backward-fun + :use-sfield use-sfield + :notify '(lambda (widget &rest event) + (if (widget-get widget :use-sfield) + (search-form-notify-sfield widget) + (search-form-notify-no-field widget))) + :current-buffer search-form-current-buffer + " Backward ") + (widget-insert " ") + (search-form-insert-help backward-fun) + (widget-insert "\n")) + +(defun search-form-insert-replace (title replace-fun descr do-replace-fun) + (widget-insert " ") + (let ((button-title (format " %-15s " title))) + (widget-create 'push-button + :do-search do-replace-fun + :notify 'search-form-notify-both-fields + :current-buffer search-form-current-buffer + button-title)) + (widget-insert " " descr " ") + (search-form-insert-help replace-fun) + (widget-insert "\n")) + +(defun search-form-insert-help (fun) + (widget-insert "(") + (widget-create 'function-link + :value fun + :tag "help" + :button-face 'link) + (widget-insert ")")) + +(defun sf-widget-field-value-set (widget value) + "Set current text in editing field." + (let ((from (widget-field-start widget)) + (to (widget-field-end widget)) + (buffer (widget-field-buffer widget)) + (size (widget-get widget :size)) + (secret (widget-get widget :secret)) + (old (current-buffer))) + (if (and from to) + (progn + (set-buffer buffer) + (while (and size + (not (zerop size)) + (> to from) + (eq (char-after (1- to)) ?\s)) + (setq to (1- to))) + (goto-char to) + (delete-region from to) + (insert value) + (let ((result (buffer-substring-no-properties from to))) + (when secret + (let ((index 0)) + (while (< (+ from index) to) + (aset result index + (get-char-property (+ from index) 'secret)) + (setq index (1+ index))))) + (set-buffer old) + result)) + (widget-get widget :value)))) + +(defvar search-form-form nil) + +(defun search-form-isearch-end () + (condition-case err + (progn + (message "sfie: search-form-form=%s" (widget-value (cdr search-form-form))) + (remove-hook 'isearch-mode-end-hook 'search-form-isearch-end) + ;; enter isearch-string in field + (with-current-buffer (car search-form-form) + ;; Fix-me: trashes the widget, it disappears... - there seem + ;; to be know default set function. + ;;(widget-value-set (cdr search-form-form) isearch-string) + )) + (error (message "search-form-isearch-end: %S" err)))) + +(defun search-form-isearch-forward (w) + (interactive) + (add-hook 'isearch-mode-end-hook 'search-form-isearch-end) + (with-current-buffer search-form-buffer + (setq search-form-form (cons search-form-buffer search-form-sfield)) + (message "sfif: cb=%s field=%S" (current-buffer) (widget-value (cdr search-form-form))) + ) + (call-interactively 'isearch-forward)) + +(defun search-form-isearch-backward (w) + (interactive) + (add-hook 'isearch-mode-end-hook 'search-form-isearch-end) + (setq search-form-form search-form-sfield) + (call-interactively 'isearch-backward)) + +;;;###autoload +(defun search-form () + "Display a form for search and replace." + (interactive) + (let* ((buf-name "*Search Form*") + (cur-buf (current-buffer)) + (buffer (get-buffer-create buf-name)) + (win-config (current-window-configuration))) + (setq search-form-current-buffer (current-buffer)) + (with-current-buffer buffer + (set (make-local-variable 'search-form-win-config) win-config)) + (switch-to-buffer-other-window buffer) + + (kill-all-local-variables) ;; why??? + (let ((inhibit-read-only t)) + (erase-buffer)) + ;;(Custom-mode) + (remove-overlays) + + (make-local-variable 'widget-button-face) + (setq widget-button-face custom-button) + (setq show-trailing-whitespace nil) + (when custom-raised-buttons + (set (make-local-variable 'widget-push-button-prefix) "") + (set (make-local-variable 'widget-push-button-suffix) "") + (set (make-local-variable 'widget-link-prefix) "") + (set (make-local-variable 'widget-link-suffix) "")) + + (widget-insert (propertize "Search/Replace, buffer: " 'face 'font-lock-comment-face)) + (widget-insert (format "%s" (buffer-name search-form-current-buffer))) + (let ((file (buffer-file-name search-form-current-buffer))) + (when file + (insert " (" file ")"))) + (widget-insert "\n\n") + (search-form-insert-fb + "Incremental String Search" nil + 'isearch-forward + 'search-form-isearch-forward + 'isearch-backward + 'search-form-isearch-backward) + + (search-form-insert-fb + "Incremental Regexp Search" nil + 'isearch-forward-regexp + (lambda (w) (call-interactively 'isearch-forward-regexp)) + 'isearch-backward-regexp + (lambda (w) (call-interactively 'isearch-backward-regexp))) + + ;; Fix-me: in multiple buffers, from buffer-list + + (widget-insert (make-string (window-width) ?-) "\n") + + (widget-insert "Search: ") + (setq search-form-sfield + (widget-create 'editable-field + :size 58)) + (widget-insert "\n\n") + (widget-insert (propertize "* Buffers:" 'face 'font-lock-comment-face) "\n") + (search-form-insert-fb "String Search" t + 'search-forward + (lambda (w) (search-forward search-form-search-string)) + 'search-backward + (lambda (w) (search-backward search-form-search-string))) + + (search-form-insert-fb "Regexp Search" t + 're-search-forward + (lambda (w) (re-search-forward search-form-search-string)) + 're-search-backward + (lambda (w) (re-search-backward search-form-search-string))) + + ;; occur + (search-form-insert-search "Occur" 'occur + "Lines in buffer" + (lambda (w) + (with-current-buffer (widget-get w :current-buffer) + (occur search-form-search-string))) + t) + + ;; multi-occur + ;; Fix-me: This should be done from buffer-list. Have juri finished that? + (search-form-insert-search "Multi-Occur" 'multi-occur + "Lines in specified buffers" + (lambda (w) + (let ((bufs (search-form-multi-occur-get-buffers))) + (multi-occur bufs search-form-search-string))) + t) + ;; + (widget-insert "\n") + (widget-insert (propertize "* Files:" 'face 'font-lock-comment-face) + "\n") + + (search-form-insert-search "Search in Dir" 'lgrep + "Grep in directory" + 'search-form-lgrep + t) + (search-form-insert-search "Search in Tree" 'rgrep + "Grep in directory tree" + 'search-form-rgrep + t) + + (widget-insert "\n") + + (search-form-insert-search "Tagged Files" 'tags-search + "Search files in tags table" + (lambda (w) + (with-current-buffer (widget-get w :current-buffer) + (tags-search search-form-search-string))) + t) + + (widget-insert (make-string (window-width) ?-) "\n") + + (widget-insert "Replace: ") + (setq search-form-rfield + (widget-create 'editable-field + :size 58)) + (widget-insert "\n\n") + + (widget-insert (propertize "* Buffers:" 'face 'font-lock-comment-face) "\n") + (search-form-insert-replace "Replace String" + 'query-replace + "In buffer from point" + (lambda (w) + (query-replace search-form-search-string search-form-replace-string))) + + (search-form-insert-replace "Replace Regexp" + 'query-replace-regexp + "In buffer from point" + (lambda (w) + (query-replace-regexp search-form-search-string search-form-replace-string))) + + (widget-insert "\n" (propertize "* Files:" 'face 'font-lock-comment-face) "\n") + + ;; fix-me: rdir-query-replace (from to file-regexp root &optional delimited) + (search-form-insert-replace "Replace in Dir" + 'ldir-query-replace + "Replace in files in directory" + 'search-form-ldir-replace) + (search-form-insert-replace "Replace in Tree" + 'rdir-query-replace + "Replace in files in directory tree" + 'search-form-rdir-replace) + + (widget-insert "\n") + + (search-form-insert-replace "Tagged Files" + 'tags-query-replace + "Replace in files in tags tables" + (lambda (w) + (tags-query-replace search-form-search-string search-form-replace-string))) + + (buffer-disable-undo) + (widget-setup) + (buffer-enable-undo) + (use-local-map widget-keymap) + (fit-window-to-buffer) + (widget-forward 1) + )) + +(defun search-form-lgrep (w) + (search-form-r-or-lgrep w t)) + +(defun search-form-rgrep (w) + (search-form-r-or-lgrep w nil)) + +(defun search-form-r-or-lgrep (w l) + (with-current-buffer (widget-get w :current-buffer) + (let* ((regexp search-form-search-string) + (files (grep-read-files regexp)) + (dir (read-directory-name (if l "In directory: " + "Base directory: ") + nil default-directory t))) + (if l + (lgrep regexp files dir) + (rgrep regexp files dir) + )))) + +(defun search-form-ldir-replace (w) + (search-form-l-or-r-dir-replace w t)) + +(defun search-form-rdir-replace (w) + (search-form-l-or-r-dir-replace w nil)) + +(defun search-form-l-or-r-dir-replace (w l) + (let ((files (replace-read-files search-form-search-string search-form-replace-string)) + (dir (read-directory-name (if l + "In directory: " + "In directory tree: ") + nil + (file-name-directory + (buffer-file-name search-form-current-buffer)) + t))) + (if l + (ldir-query-replace search-form-search-string search-form-replace-string files dir) + (rdir-query-replace search-form-search-string search-form-replace-string files dir)))) + +(provide 'search-form) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; search-form.el ends here diff --git a/emacs/nxhtml/util/sex-mode.el b/emacs/nxhtml/util/sex-mode.el new file mode 100644 index 0000000..290a1a0 --- /dev/null +++ b/emacs/nxhtml/util/sex-mode.el @@ -0,0 +1,463 @@ +;;; sex-mode.el --- Shell EXecute mode / Send to EXternal program +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-06-01T18:41:50+0200 Sun +(defconst sex-mode:version "0.71") +;; Last-Updated: 2009-01-06 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Open urls belonging to other programs with those programs. To +;; enable this turn on the global minor mode `sex-mode'. +;; +;; If you for example open a .pdf file with C-x C-f it can be opened +;; by the .pdf application you have set your computer to use. (Or, if +;; that such settings are not possible on your OS, with the +;; application you have choosen here.) +;; +;; There is also a defmacro `sex-with-temporary-apps' that you can use +;; for example with `find-file' to open files in external +;; applications. +;; +;; The functions used to open files in external applications are +;; borrowed from `org-mode'. There is some small differences: +;; +;; - There is an extra variable here `sex-file-apps' that is checked +;; before the corresponding lists in `org-mode'. +;; +;; - In `org-mode' any file that is not found in the lists (and is not +;; remote or a directory) is sent to an external application. This +;; would create trouble when used here in a file handler so the +;; logic is the reverse here: Any file that is not found in the +;; lists is opened inside Emacs. (Actually I think that might be a +;; good default in `org-mode' too, but I am not sure.) +;; +;; - Because of the above I have to guess which function is the one +;; that sends a file to an external application. +;; +;; (Currently the integration with org.el is not the best code wise. +;; We hope to improve that soon.) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +;;(org-open-file "c:/EmacsW32/nxhtml/nxhtml/doc/nxhtml-changes.html") +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'org)) +(eval-when-compile (require 'mailcap)) + +(defcustom sex-file-apps + '( + ("html" . emacs) + ("pdf" . default) + ("wnk" . default) + ) + "Application for opening a file. +See `sex-get-file-open-cmd'." + :group 'sex + :type '(repeat + (cons (choice :value "" + (string :tag "Extension") + (const :tag "Default for unrecognized files" t) + (const :tag "Remote file" remote) + (const :tag "Links to a directory" directory)) + (choice :value "" + (const :tag "Visit with Emacs" emacs) + (const :tag "Use system default" default) + (string :tag "Command") + (sexp :tag "Lisp form"))))) + +;;(sex-get-apps) + +(defvar sex-with-temporary-file-apps nil) + +(defun sex-get-apps () + (or sex-with-temporary-file-apps + (append sex-file-apps org-file-apps (org-default-apps)))) + +;; (sex-get-file-open-cmd "temp.el") +;; (sex-get-file-open-cmd "http://some.where/temp.el") +;; (sex-get-file-open-cmd "temp.c") +;; (sex-get-file-open-cmd "temp.pdf") +;; (sex-get-file-open-cmd "temp.doc") +;; (sex-get-file-open-cmd "/ftp:temp.doc") +;; (sex-get-file-open-cmd "http://some.host/temp.doc") +;; (sex-get-file-open-cmd "http://some.host/temp.html") + +(defun sex-get-file-open-cmd (path) + "Get action for opening file. +Construct a key from PATH: +- If PATH specifies a location on a remote system then set key to + 'remote. +- If PATH is a directory set key to 'directory. +- Otherwise use the file extension of PATH as key. + +Search with this key against the combined association list of +`sex-file-apps', `org-file-apps' and `org-default-apps'. The +first matching entry is used. + +If cdr of this entry is 'default then search again with key equal +to t for the default action for the operating system you are on +\(or your own default action if you have defined one in the +variables above). + +Return the cdr of the found entry. + +If no entry was found return `emacs' for opening inside Emacs." + (let* ((apps (sex-get-apps)) + (key (if (org-file-remote-p path) + 'remote + (if (file-directory-p path) + 'directory + (let ((ext (file-name-extension path))) + (if (and t ext) + ;; t should be a check for case insensitive + ;; file names ... - how do you do that? + (downcase ext) + ext))))) + (cmd (or (cdr (assoc key apps)) + 'emacs))) + (when (eq cmd 'default) + (setq cmd (or (cdr (assoc t apps)) + 'emacs))) + (when (eq cmd 'mailcap) + (require 'mailcap) + (mailcap-parse-mailcaps) + (let* ((mime-type (mailcap-extension-to-mime (or key ""))) + (command (mailcap-mime-info mime-type))) + (if (stringp command) + (setq cmd command) + (setq cmd 'emacs)))) + ;;(message "cmd=%s" cmd) + cmd)) + +;;;###autoload +(defgroup sex nil + "Customization group for `sex-mode'." + :group 'external) + +;;(setq sex-handle-urls t) +(defcustom sex-handle-urls nil + "When non-nil `sex-mode' also handles urls. +Turn on `url-handler-mode' when turning on `sex-mode' if this is +non-nil. Open urls in a web browser." + :type 'boolean + :group 'sex) + +;; (setq sex-keep-dummy-buffer nil) +;; (setq sex-keep-dummy-buffer 'visible) +;; (setq sex-keep-dummy-buffer 'burried) +(defcustom sex-keep-dummy-buffer 'visible + "Keep dummy buffer after opening file. +When opening a file with the shell a dummy buffer is created in +Emacs in `sex-file-mode' and an external program is called to +handle the file. How this dummy buffer is handled is governed by +this variable." + :type '(choice (const :tag "Visible" visible) + (const :tag "Burried" burried) + (const :tag "Do not keep it" nil)) + :group 'sex) + +(defcustom sex-reopen-on-buffer-entry nil + "If non-nil send file to shell again on buffer entry." + :type 'boolean + :group 'sex) + +(defun sex-post-command () + "Run post command in `sex-file-mode' buffers. +If `sex-reopen-on-buffer-entry' is non-nil then send the buffer +file to system again." + (when sex-reopen-on-buffer-entry + (if (and (boundp 'url-handler-regexp) + (string-match url-handler-regexp buffer-file-name)) + (sex-browse-url buffer-file-name) + (sex-handle-by-external buffer-file-name)) + (bury-buffer))) + +(defun sex-browse-url (url) + "Ask a web browser to open URL." + (condition-case err + (list (browse-url url) "Opened URL in web browser") + (error (list nil (error-message-string err))))) + +(defun sex-url-insert-file-contents (url &optional visit beg end replace) + (sex-generic-insert-file-contents + 'sex-browse-url + (concat "This dummy buffer is used just for opening a URL.\n" + "To open the URL again click here:\n\n ") + (concat "Tried to open URL in web browser, " + "but it failed with message\n\n ") + url visit beg end replace)) + +(defun sex-file-insert-file-contents (url &optional visit beg end replace) + ;;(message "sex-file-insert-file-contents %s %s %s %s %s" url visit beg end replace) + (sex-generic-insert-file-contents + 'sex-handle-by-external + (concat "This dummy buffer is used just for opening a file.\n" + "The file itself was sent to system for opening.\n\n" + "To open the file again click here:\n\n ") + (concat "Tried to send file" + " to system but it failed with message\n\n ") + url visit beg end replace)) + +(defun sex-write-file-function () + (set-buffer-modified-p nil) + (error "Can't write this to file, it is just a dummy buffer")) + +(defun sex-generic-insert-file-contents (insert-fun + success-header + fail-header + url &optional visit beg end replace) + (let ((window-config (current-window-configuration))) + (unless (= 0 (buffer-size)) + (error "Buffer must be empty")) + (set (make-local-variable 'write-file-functions) + '(sex-write-file-function)) + (let* ((name url) + ;;(result (sex-browse-url name)) + (result (funcall insert-fun name)) + (success (nth 0 result)) + (msg (nth 1 result))) + (setq buffer-file-name name) + (if success + (progn + (insert success-header) + (sex-setup-restore-window-config window-config) + (message "%s" msg)) + (insert (propertize "Error: " 'face 'font-lock-warning-face) + fail-header msg + "\n\nTo try again click here:\n\n ")) + (save-excursion + (insert-text-button + buffer-file-name + 'insert-fun insert-fun + 'action (lambda (button) + ;;(sex-browse-url buffer-file-name) + (funcall (button-get button 'insert-fun) buffer-file-name) + )))))) + +(defun sex-file-handler (operation &rest args) + "Handler for `insert-file-contents'." + ;;(message "\noperation=%s, args=%s" operation args) + (let ((done nil) + (ftype 'emacs)) + ;; Always open files inside Emacs if the file opening request came + ;; through Emacs client. Here is a primitive test if we are called + ;; from outside, client-record is bound in `server-visit-files' + ;; ... + (when (not (boundp 'client-record)) + (let* ((filename (car args)) + (insert-handling (sex-get-file-open-cmd filename))) + ;;(message "insert-handling=%s" insert-handling) + (when insert-handling + (setq ftype insert-handling)) + ;;(message "ftype=%s, filename=%s" ftype filename) + )) + (unless (eq ftype 'emacs) + ;;(message "using sex-file-insert-file-contents for %s" args) + (apply 'sex-file-insert-file-contents args) + (setq done t)) + ;; Handle any operation we don't know about. + (unless done + ;;(message "fallback for operation=%s, args=%s" operation args) + (let ((inhibit-file-name-handlers + (cons 'sex-file-handler + (and (eq inhibit-file-name-operation operation) + inhibit-file-name-handlers))) + (inhibit-file-name-operation operation)) + (apply operation args))))) +;; Note: Because of a bug in Emacs we must restrict the use of this +;; file handler to only 'insert-file-contents. (We should of course +;; anyway do that.) +(put 'sex-file-handler 'operations '(insert-file-contents)) + +(defun sex-setup-restore-window-config (window-config) + (when (not (eq sex-keep-dummy-buffer 'visible)) + (run-with-idle-timer 0 nil + 'sex-restore-window-config + (selected-frame) + window-config + (unless sex-keep-dummy-buffer + (current-buffer))))) + +(defun sex-restore-window-config (frame win-config buffer) + (save-match-data ;; runs in timer + (with-selected-frame frame + (set-window-configuration win-config)) + (when buffer (kill-buffer buffer)))) + +(defun sex-handle-by-external (&optional file) + "Give file FILE to external program. +Return a list: + + (SUCCESS MESSAGE) + +where SUCCESS is non-nil if operation succeeded and MESSAGE is an +informational message." + (unless file (setq file buffer-file-name)) + (let ((cmd (sex-get-file-open-cmd file))) + (assert (not (eq cmd 'emacs))) + (cond + ((and (stringp cmd) (not (string-match "^\\s-*$" cmd))) + ;; Remove quotes around the file name - we'll use shell-quote-argument. + (while (string-match "['\"]%s['\"]" cmd) + (setq cmd (replace-match "%s" t t cmd))) + (while (string-match "%s" cmd) + (setq cmd (replace-match + (save-match-data + (shell-quote-argument + (convert-standard-filename file))) + t t cmd))) + (save-window-excursion + (start-process-shell-command cmd nil cmd) + ;;(and (boundp 'org-wait) (numberp org-wait) (sit-for org-wait)) + ) + (list t (format "Opened %s in external application" file))) + ((consp cmd) + (let ((file (convert-standard-filename file))) + (eval cmd)) + (list t (format "Opened %s in external application" file))) + (t (list nil (format "Don't know how to handle %s" file)))) + )) + + +(define-derived-mode sex-file-mode nil + "External" + "Mode for files opened in external programs." + (add-hook 'post-command-hook 'sex-post-command nil t) + (set-keymap-parent (current-local-map) button-buffer-map) + (set-buffer-modified-p nil) + (setq buffer-read-only t)) + + +(defvar sex-old-url-insert-file-contents nil) +(defvar sex-old-url-handler-mode nil) + +;;;###autoload +(define-minor-mode sex-mode + "Open certain files in external programs. +See `sex-get-file-open-cmd' for how to determine which files to +open by external applications. Note that this selection is +nearly the same as in `org-mode'. The main difference is that +the fallback always is to open a file in Emacs. \(This is +necessary to avoid to disturb many of Emacs operations.) + +This affects all functions that opens files, like `find-file', +`find-file-noselect' etc. + +However it does not affect files opened through Emacs client. + +Urls can also be handled, see `sex-handle-urls'. + +When opening a file with the shell a \(temporary) dummy buffer is +created in Emacs with major mode `sex-file-mode' and an external +program is called to handle the file. How this dummy buffer is +handled is governed by `sex-keep-dummy-buffer'." + + ;; On MS Windows `w32-shell-execute' is called to open files in an + ;; external application. Be aware that this may run scripts if the + ;; script file extension is not blocked in `sex-open-alist'. + nil + :group 'sex + :global t + ;; fix-me: better list handling + (if sex-mode + (progn + (require 'org) + (dolist (rec (sex-get-apps)) + (let* ((ext (car rec)) + (app (cdr rec)) + (patt (when (and (stringp ext) + (not (eq app 'emacs))) + (concat "\\." ext "\\'")))) + (unless patt + (when (eq ext t) + (setq patt (concat ".*\\'")))) + (when patt + (unless (eq ext t) + (add-to-list 'auto-mode-alist (cons patt 'sex-file-mode))) + (add-to-list 'file-name-handler-alist + (cons patt 'sex-file-handler) t)))) + (setq sex-old-url-insert-file-contents + (get 'insert-file-contents 'url-file-handlers)) + (setq sex-old-url-handler-mode url-handler-mode) + (when sex-handle-urls + ;;(message "req url, before") + (require 'url-handlers) + ;;(message "req url, after") + (put 'insert-file-contents 'url-file-handlers + 'sex-url-insert-file-contents) + (unless url-handler-mode + (url-handler-mode 1) + ;;(message "after url-handler-mode 1") + ))) + ;; Remove from the lists: + ;;(let ((handler-list (copy-list file-name-handler-alist))) + (let ((handler-list (copy-sequence file-name-handler-alist))) + (dolist (handler handler-list) + (when (eq 'sex-file-handler (cdr handler)) + (setq file-name-handler-alist + (delete handler file-name-handler-alist))))) + ;;(let ((mode-alist (copy-list auto-mode-alist))) + (let ((mode-alist (copy-sequence auto-mode-alist))) + (dolist (auto-mode mode-alist) + (when (eq 'sex-file-mode (cdr auto-mode)) + (setq auto-mode-alist + (delete auto-mode auto-mode-alist))))) + (put 'insert-file-contents 'url-file-handlers + sex-old-url-insert-file-contents) + (unless sex-old-url-handler-mode (url-handler-mode 0)))) + +(defmacro sex-with-temporary-apps (open-alist &rest body) + "Run BODY with `sex-mode' on. +If OPEN-ALIST is not t it replaces the list normally used by +`sex-get-file-open-cmd'." + (declare (indent 1) (debug t)) + `(let ((old-sex-mode sex-mode) + (sex-with-temporary-file-apps + (if (eq ,open-alist t) + nil + ,open-alist))) + (when sex-mode (sex-mode -1)) + (sex-mode 1) + ,@body + (setq sex-with-temporary-file-apps nil) + (unless old-sex-mode (sex-mode -1)))) + +;; (with-sex t (find-file "c:/emacs-lisp/gimp-mode-v1.40/gimpmode.pdf")) +;; (with-sex nil (find-file "c:/emacs-lisp/gimp-mode-v1.40/gimpmode.pdf")) + +(provide 'sex-mode) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; sex-mode.el ends here diff --git a/emacs/nxhtml/util/sml-modeline.el b/emacs/nxhtml/util/sml-modeline.el new file mode 100644 index 0000000..882d184 --- /dev/null +++ b/emacs/nxhtml/util/sml-modeline.el @@ -0,0 +1,192 @@ +;;; sml-modeline.el --- Show position in a scrollbar like way in mode-line +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2010-03-16 Tue +;; Version: 0.5 +;; Last-Updated: 2010-03-18 Thu +;; URL: http://bazaar.launchpad.net/~nxhtml/nxhtml/main/annotate/head%3A/util/sml-modeline.el +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Show scrollbar like position indicator in mode line. +;; See the global minor mode `sml-modeline-mode' for more information. +;; +;; Idea and part of this code is adapted from David Engster's and Drew +;; Adam's code in these mail messages: +;; +;; http://lists.gnu.org/archive/html/emacs-devel/2010-03/msg00523.html +;; http://permalink.gmane.org/gmane.emacs.devel/122038 +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +;;;###autoload +(defgroup sml-modeline nil + "Customization group for `sml-modeline-mode'." + :group 'frames) + +(defun sml-modeline-refresh () + "Refresh after option changes if loaded." + (when (featurep 'sml-modeline) + (when (and (boundp 'sml-modeline-mode) + sml-modeline-mode) + (sml-modeline-mode -1) + (sml-modeline-mode 1)))) + +(defcustom sml-modeline-len 12 + "Mode line indicator total length." + :type 'integer + :set (lambda (sym val) + (set-default sym val) + (sml-modeline-refresh)) + :group 'sml-modeline) + +(defcustom sml-modeline-borders nil + "Indicator borders. +This is a pair of indicators, like [] or nil." + :type '(choice (const :tag "None" nil) + (cons (string :tag "Left border") + (string :tag "Right border"))) + :set (lambda (sym val) + (set-default sym val) + (sml-modeline-refresh)) + :group 'sml-modeline) + +(defcustom sml-modeline-numbers 'percentage + "Position number style. +This can be 'percentage or 'line-number." + :type '(choice (const :tag "Line numbers" line-numbers) + (const :tag "Percentage" percentage)) + :set (lambda (sym val) + (set-default sym val) + (sml-modeline-refresh)) + :group 'sml-modeline) + +(defface sml-modeline-end-face + '((t (:inherit match))) + "Face for invisible buffer parts." + :group 'sml-modeline) +;; 'face `(:background ,(face-foreground 'mode-line-inactive) +;; :foreground ,(face-background 'mode-line)) + +(defface sml-modeline-vis-face + '((t (:inherit region))) + "Face for invisible buffer parts." + :group 'sml-modeline) +;; 'face `(:background ,(face-foreground 'mode-line) +;; :foreground ,(face-background 'mode-line)) + +;;(sml-modeline-create) +(defun sml-modeline-create () + (let* ((wstart (window-start)) + (wend (window-end)) + number-max number-beg number-end + (sml-begin (or (car sml-modeline-borders) "")) + (sml-end (or (cdr sml-modeline-borders) "")) + (inner-len (- sml-modeline-len (length sml-begin) (length sml-end))) + bpad-len epad-len + pos-% + start end + string) + (if (not (or (< wend (save-restriction (widen) (point-max))) + (> wstart 1))) + "" + (cond + ((eq sml-modeline-numbers 'percentage) + (setq number-max (save-restriction (widen) (point-max))) + (setq number-beg (/ (float wstart) (float number-max))) + (setq number-end (/ (float wend) (float number-max))) + (setq start (floor (* number-beg inner-len))) + (setq end (floor (* number-end inner-len))) + (setq string + (concat (format "%02d" (round (* number-beg 100))) + "-" + (format "%02d" (round (* number-end 100))) "%%"))) + ((eq sml-modeline-numbers 'line-numbers) + (save-restriction + (widen) + (setq number-max (line-number-at-pos (point-max))) + (setq number-beg (line-number-at-pos wstart)) + (setq number-end (line-number-at-pos wend))) + (setq start (floor (* (/ number-beg (float number-max)) inner-len))) + (setq end (floor (* (/ number-end (float number-max)) inner-len))) + (setq string + (concat "L" + (format "%02d" number-beg) + "-" + (format "%02d" number-end)))) + (t (error "Unknown sml-modeline-numbers=%S" sml-modeline-numbers))) + (setq inner-len (max inner-len (length string))) + (setq bpad-len (floor (/ (- inner-len (length string)) 2.0))) + (setq epad-len (- inner-len (length string) bpad-len)) + (setq pos-% (+ bpad-len (length string) -1)) + (setq string (concat sml-begin + (make-string bpad-len 32) + string + (make-string epad-len 32) + sml-end)) + ;;(assert (= (length string) sml-modeline-len) t) + (when (= start sml-modeline-len) (setq start (1- start))) + (setq start (+ start (length sml-begin))) + (when (= start end) (setq end (1+ end))) + (when (= end pos-%) (setq end (1+ end))) ;; If on % add 1 + (put-text-property start end 'face 'sml-modeline-vis-face string) + (when (and (= 0 (length sml-begin)) + (= 0 (length sml-end))) + (put-text-property 0 start 'face 'sml-modeline-end-face string) + (put-text-property end sml-modeline-len 'face 'sml-modeline-end-face string)) + string))) + +(defvar sml-modeline-old-car-mode-line-position nil) + +;;;###autoload +(define-minor-mode sml-modeline-mode + "Show buffer size and position like scrollbar in mode line. +You can customize this minor mode, see option `sml-modeline-mode'. + +Note: If you turn this mode on then you probably want to turn off +option `scroll-bar-mode'." + :global t + :group 'sml-modeline + (if sml-modeline-mode + (progn + (unless sml-modeline-old-car-mode-line-position + (setq sml-modeline-old-car-mode-line-position (car mode-line-position))) + (setcar mode-line-position '(:eval (list (sml-modeline-create))))) + (setcar mode-line-position sml-modeline-old-car-mode-line-position))) + + +(provide 'sml-modeline) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; sml-modeline.el ends here diff --git a/emacs/nxhtml/util/tabkey2.el b/emacs/nxhtml/util/tabkey2.el new file mode 100644 index 0000000..d35e651 --- /dev/null +++ b/emacs/nxhtml/util/tabkey2.el @@ -0,0 +1,1701 @@ +;;; tabkey2.el --- Use second tab key pressed for what you want +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-03-15 +(defconst tabkey2:version "1.40") +;; Last-Updated: 2009-07-15 Wed +;; URL: http://www.emacswiki.org/cgi-bin/wiki/tabkey2.el +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `appmenu', `cl'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; The tab key is in Emacs often used for indentation. However if you +;; press the tab key a second time and Emacs tries to do indentation +;; again, then usually nothing exciting will happen. Then why not use +;; second tab key in a row for something else? +;; +;; Commonly used completion functions in Emacs is often bound to +;; something corresponding to Alt-Tab. Unfortunately this is unusable +;; if you have a window manager that have an apetite for it (like that +;; on MS Windows for example, and several on GNU/Linux). +;; +;; Then using the second tab key press for completion might be a good +;; choice and perhaps also easy to remember. +;; +;; This little library tries to make it easy to do use the second tab +;; press for completion. Or you can see this library as a swizz army +;; knife for the tab key ;-) +;; +;; See `tabkey2-mode' for more information. +;; +;; +;; This is a generalized of an idea Sebastien Rocca Serra once +;; presented on Emacs Wiki and called "Smart Tab". (It seems like +;; many others have also been using Tab for completion in one way or +;; another for years.) +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; Version 1.04: +;; - Add overlay to display state after first tab. +;; +;; Version 1.05: +;; - Fix remove overlay problem. +;; +;; Version 1.06: +;; - Add completion function choice. +;; - Add support for popcmp popup completion. +;; +;; Version 1.07: +;; - Add informational message after first tab. +;; +;; Version 1.08: +;; - Give better informational message after first tab. +;; +;; Version 1.09: +;; - Put flyspell first. +;; +;; Version 1.09: +;; - Give the overlay higher priority. +;; +;; Version 1.10: +;; - Correct tabkey2-completion-functions. +;; - Add double-tab for modes where tab can not be typed again. +;; - Use better condition for when completion can be done, so that it +;; can be done later while still on the same line. +;; - Add a better message handling for the "Tab completion state". +;; - Add C-g break out of the "Tab completion state". +;; - Add faces for highlight. +;; - Make it work in custom mode buffers. +;; - Fix documentation for `tabkey2-first' +;; +;; Version 1.11: +;; - Don't call chosen completion function directly. Instead make it +;; default for current buffer. +;; +;; Version 1.12: +;; - Simplify code. +;; - Add help to C-f1 during "Tab completion state". +;; - Fix documentation basics. +;; - Add customization of state message and line marking. +;; - Fix handling of double-Tab modes. +;; - Make user interaction better. +;; - Handle read-only in custom buffers better. +;; - Add more flexible check for if completion function is active. +;; - Support predictive mode. +;; - Reorder and simplify. +;; +;; Version 1.13: +;; - Add org-mode to the double-tab gang. +;; - Make it possible to use double-tab in normal buffers. +;; - Add cycling through completion functions to S-tab. +;; +;; Version 1.14: +;; - Fix bug in handling of read-only. +;; - Show completion binding in help message. +;; - Add binding to make current choice buffer local when cycling. +;; +;; Version 1.15: +;; - Fix problem at buffer end. +;; - Add S-tab to enter completion state without indentation. +;; - Add backtab bindings too for this. +;; - Remove double-tab, S-tab is better. +;; - Add list of modes that uses more tabs. +;; - Add list of modes that uses tab only for completion. +;; - Move first overlay when indentation changes. +;; - Make mark at line beginning 1 char long. +;; +;; Version 1.16: +;; - Don't call tab function when alternate key is pressed. +;; +;; Version 1.17: +;; - Let alternate key cycle completion functions instead of complete. +;; - Bind backtab. +;; - Fix bug when only one completion funciton was available. +;; - Fix bug when alt key and major without fix indent. +;; +;; Version 1.18: +;; - Add popup style messages. +;; - Add delay to first message. +;; - Use different face for indicator on line and message. +;; - Use different face for echo area and popup messages. +;; - Add anything to completion functions. +;; - Put help funciton on f1. +;; - Always bind alternate key to cycle. +;; - Change defcustoms to simplify (excuse me). +;; - Work around end of buffer problems. +;; - Work around start of buffer problems. +;; - Assure popup messages are visible. +;; - Reorder code in more logical order. +;; +;; Version 1.19: +;; - Make overlay keymap end advance. +;; - Remove overlay keymap parent. +;; +;; Version 1.20: +;; - Fix bug on emtpy line. +;; - Fix some text problems. +;; - Make f1 c/k work in tab completion state. +;; +;; Version 1.20: +;; - Fixed bug in overlay removal. +;; +;; Version 1.21: +;; - Fixed bug in minibuffer setup. +;; +;; Version 1.22: +;; - Honour widget-forward, button-forward. +;; +;; Version 1.23: +;; - Remove binding of shift tab. +;; - Check if use-region-p is defined. +;; +;; Version 1.24: +;; - Add option for completion state mode line marker. +;; - Fix bug in tabkey2-show-completion-functions. +;; - Move off completion point cancels completion state. +;; - Fix bugs in help. +;; - Try to fix some problems with invisible text, at least in +;; org-mode. +;; - Restore window config, completions often leaves without. +;; +;; Version 1.25: +;; - Fix bug in tabkey2-completion-state-p. +;; +;; Version 1.26: +;; - Make tabkey2-mode a buffer local mode. +;; - Add tabkey2-global-mode. +;; - Fix some bugs. +;; +;; Version 1.27: +;; - Fix some bugs in customization. +;; +;; Version 1.28: +;; - Use invisible-p. +;; +;; Version 1.29: +;; - Remove tabkey2-global-mode because of problem with minibuffers. +;; +;; Version 1.30: +;; - Add Semantic's smart completion to completion functions. +;; (Thanks Eric.) +;; +;; Version 1.31: +;; - Add yasnippet and pabbrev completion functions. (Thanks Eric.) +;; - Reorder completion functions. +;; +;; Version 1.32: +;; - Add support for pcomplete. +;; - Inform about other key bindings in completion functions list. +;; - Remove no longer used "preferred" from completion functions list. +;; +;; Version 1.33: +;; -- Automatically select next function on completion failure. +;; -- Add completion functions reset functions. +;; +;; Version 1.34: +;; - Set this-command on call-interactively. +;; - Avoid setting last-command. +;; +;; Version 1.35: +;; - Do not complete in or nearby mumamo chunk borders. +;; - Finish completion mode unless last command was a tabkey2 command. +;; - Finish when there are no more active completion functions. +;; +;; Version 1.36: +;; - Actually check if completion function is a defined command. +;; - Integrate better with YASnippet. +;; - Give YASnippet higher priority since that seems what is wanted. +;; +;; Version 1.37: +;; - Fix bug revealed by 1.36 changes. +;; +;; Version 1.38: +;; - Fix typo in completion function list. +;; - Fix corresponding part of check if function is active. +;; +;; Version 1.39: +;; - Try first [tab] and then [?\t] when looking for command. +;; +;; Version 1.40: +;; - Added Company Mode completion. +;; +;; Fix-me: maybe add \\_>> option to behave like smart-tab. But this +;; will only works for modes that does not do completion of empty +;; words (like in smart-tab). +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Known bugs +;; +;; - Maybe problems with comint shell. +;; - Does not check visibility very carefully. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'appmenu nil t)) +(eval-when-compile (require 'mumamo nil t)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Custom + +;;;###autoload +(defgroup tabkey2 nil + "Customization of second tab key press." + :group 'nxhtml + :group 'convenience) + +(defface tabkey2-highlight-line + '((t :inherit highlight)) + "Face for marker on line when default function is active." + :group 'tabkey2) + +(defface tabkey2-highlight-line2 + '((t :inherit isearch-fail)) + "Face for marker on line when non-default function is active." + :group 'tabkey2) + +(defface tabkey2-highlight-message + '((t :inherit tabkey2-highlight-line)) + "Face for messages in echo area." + :group 'tabkey2) + +(defface tabkey2-highlight-popup + '((default :box t :inherit tabkey2-highlight-message) + (((class color) (background light)) :foreground "black") + (((class color) (background dark)) :foreground "yellow")) + "Face for popup messages." + :group 'tabkey2) + +(defcustom tabkey2-show-mark-on-active-line t + "Show mark on active line if non-nil. +This mark is shown during 'Tab completion state'." + :type 'boolean + :group 'tabkey2) + +(defvar tabkey2-completion-lighter nil) +(defcustom tabkey2-completion-lighter-on nil + "Mode line lighter for function `tabkey2-completion-state-mode'." + :type 'boolean + :set (lambda (symbol value) + (set-default symbol value) + (setq tabkey2-completion-lighter (if value " Tab2" nil)) + (setq minor-mode-alist + (assq-delete-all 'tabkey2-completion-state-mode + minor-mode-alist))) + :group 'tabkey2) + +(defcustom tabkey2-show-message-on-enter 2.0 + "If non-nil show message when entering 'Tab completion state'. +If value is a number then delay message that number of seconds." + :type '(choice (const :tag "Don't show" nil) + (const :tag "Show at once" t) + (float :tag "Show, but delayed (seconds)")) + :group 'tabkey2) + + +;; (setq tabkey2-message-style 'popup) +;; (setq tabkey2-message-style 'echo-area) +(defcustom tabkey2-message-style 'popup + "How to show messages." + :type '(choice (const :tag "Popup" popup) + (const :tag "Echo area" echo-area)) + :group 'tabkey2) + +(defcustom tabkey2-in-minibuffer nil + "If non-nil use command `tabkey2-mode' also in minibuffer." + :type 'boolean + :group 'tabkey2) + +(defcustom tabkey2-in-appmenu t + "Show a completion menu in command `appmenu-mode' if t." + :type 'boolean + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'appmenu-add) + (if val + (appmenu-add 'tabkey2 nil t "Completion" 'tabkey2-appmenu) + (appmenu-remove 'tabkey2)))) + :group 'tabkey2) + +(defun yas/expandable-at-point () + "Return non-nil if a snippet can be expanded here." + (when (and (fboundp 'yas/template-condition-predicate) + (boundp 'yas/buffer-local-condition)) + (yas/template-condition-predicate + yas/buffer-local-condition))) + +(defvar tabkey2-company-backends + "List of frontends and their backends." + '((company-mode (NONE company-abbrev . "Abbrev") + (NONE company-css . "CSS") + (dabbrev-expan company-dabbrev . "dabbrev for plain text") + (NONE company-dabbrev-code . "dabbrev for code") + (NONE company-eclim . "eclim (an Eclipse interace)") + (lisp-symbol-complete company-elisp . "Emacs Lisp") + (complete-tag company-etags . "etags") + (NONE company-files . "Files") + (NONE company-gtags . "GNU Global") + (ispell-complete-word company-ispell . "ispell") + (flyspell-correct-word-before-point company-ispell . "ispell") + (NONE company-keywords . "Programming language keywords") + (nxml-complete company-nxml . "nxml") + (NONE company-oddmuse . "Oddmuse") + (NONE company-pysmell . "PySmell") + (NONE company-ropemacs . "ropemacs") + (senator-complete-symbol company-semantic . "CEDET Semantic") + (NONE company-tempo . "Tempo templates") + (NONE company-xcode . "Xcode")))) + +(defun tabkey2-find-front-end (fun) + (let (( + )))) + +(defcustom tabkey2-completion-functions + '( + ;; Front ends (should take care of the rest, ie temporary things, + ;; snippets etc...) + ("Company Mode completion" company-complete company-mode) + ;; Temporary things + ("Spell check word" flyspell-correct-word-before-point) + ;; Snippets + ("Yasnippet" yas/expand (yas/expandable-at-point)) + ;; Main mode related, often used + ("Semantic Smart Completion" senator-complete-symbol senator-minor-mode) + ("Programmable completion" pcomplete) + ("nXML completion" nxml-complete) + ("Complete Emacs symbol" lisp-complete-symbol) + ("Widget complete" widget-complete) + ("Comint Dynamic Complete" comint-dynamic-complete) + ("PHP completion" php-complete-function) + ("Tags completion" complete-tag) + ;; General word completion + ("Predictive word" complete-word-at-point predictive-mode) + ("Predictive abbreviations" pabbrev-expand-maybe) + ("Dynamic word expansion" dabbrev-expand nil (setq dabbrev--last-abbrev-location nil)) + ("Ispell complete word" ispell-complete-word) + ;; The catch all + ("Anything" anything (commandp 'anything)) + ) + "List of completion functions. +The first 'active' entry in this list is normally used during the +'Tab completion state' by `tabkey2-complete'. An entry in the +list should have either of this forms + + \(TITLE COMPLETION-FUNCTION ACTIVE-FORM RESET-FORM) + +TITLE to show in menus etc. + +COMPLETION-FUNCTION is the completion function symbol. + +The entry is considered active if the symbol COMPLETION-FUNCTION +is bound to a command and + + - This function has a key binding at point. + +or + + - The elisp expression ACTIVE-FORM evaluates to non-nil. If it + is a single symbol then its variable value is used, otherwise + the elisp form is evaled. + +RESET-FORM is used to reset the completion function before +calling it. + +When choosing with `tabkey2-cycle-completion-functions' +only the currently active entry in this list are shown." + :type '(repeat (list string (choice (command :tag "Currently known command") + (symbol :tag "Command not known yet")) + (choice (const :tag "Active only if it has a key binding at point" nil) + (sexp :tag "Elisp, if evals to non-nil then active")) + (sexp :tag "Elisp, reset completion function"))) + :group 'tabkey2) + +;; Use emulation mode map for first Tab key +(defconst tabkey2-mode-emul-map (make-sparse-keymap) + "This keymap just binds tab and alternate key all the time. +By default this binds Tab to `tabkey2-first'. The actual keys +bound are in `tabkey2-first-key' and `tabkey2-alternate-key'.") + +(defvar tabkey2--emul-keymap-alist nil) + +;; (setq tabkey2-keymap-overlay nil) +(defconst tabkey2-completion-state-emul-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) tab] 'tabkey2-make-current-default) + + ;;(define-key map tabkey2-alternate-key 'tabkey2-cycle-completion-functions) + (define-key map [backtab] 'tabkey2-cycle-completion-functions) + + (define-key map [(control f1)] 'tabkey2-completion-function-help) + (define-key map [(meta f1)] 'tabkey2-show-completion-functions) + (define-key map [f1] 'tabkey2-completion-state-help) + + (define-key map [(control ?g)] 'tabkey2-completion-state-off) + (define-key map [tab] 'tabkey2-complete) + map) + "This keymap is for `tabkey2-keymap-overlay'.") + +(defun tabkey2-bind-keys (first-key alternate-key) + (let ((mode-map tabkey2-mode-emul-map) + (comp-map tabkey2-completion-state-emul-map)) + ;; First key + (when (and (boundp 'tabkey2-first-key) + tabkey2-first-key) + (define-key mode-map tabkey2-first-key nil)) + (when first-key + (define-key mode-map first-key 'tabkey2-first)) + ;; Alternate key + (when (and (boundp 'tabkey2-alternate-key) + tabkey2-alternate-key) + (define-key mode-map tabkey2-alternate-key nil) + (define-key comp-map tabkey2-alternate-key nil)) + (when alternate-key + (define-key mode-map alternate-key 'tabkey2-cycle-completion-functions) + (define-key comp-map alternate-key 'tabkey2-cycle-completion-functions)) + (when (and (boundp 'tabkey2-completion-state-mode) + tabkey2-completion-state-mode) + (tabkey2-completion-state-mode -1) + (tabkey2-completion-state-mode 1)))) + +(defcustom tabkey2-first-key [tab] + "First key, first time indents, more invocations completes. +This key is always bound to `tabkey2-first'." + :set (lambda (sym val) + (set-default sym val) + (tabkey2-bind-keys + val + (when (boundp 'tabkey2-alternate-key) + tabkey2-alternate-key))) + :type 'key-sequence + :group 'tabkey2) + +(defcustom tabkey2-alternate-key [f8] + "Alternate key, bound to cycle and show completion functions. +This key is always bound to `tabkey2-cycle-completion-functions'." + :set (lambda (sym val) + (set-default sym val) + (tabkey2-bind-keys (when (boundp 'tabkey2-first-key) tabkey2-first-key) val)) + :type 'key-sequence + :group 'tabkey2) + +(tabkey2-bind-keys tabkey2-first-key tabkey2-alternate-key) + +;;;###autoload +(define-minor-mode tabkey2-mode + "More fun with Tab key number two (completion etc). +This global minor mode by default binds Tab in a way that let you +do completion with Tab in all buffers \(where it is possible). + +The Tab key is easy to type on your keyboard. Then why not use +it for completion, something that is very useful? Shells usually +use Tab for completion so many are used to it. This was the idea +of Smart Tabs and this is a generalization of that idea. + +However in Emacs the Tab key is usually used for indentation. +The idea here is that if Tab has been pressed once for +indentation, then as long as point stays further Tab keys might +as well do completion. + +So you kind of do Tab-Tab for first completion \(and then just +Tab for further completions as long as point is not moved). + +And there is even kind of Tab-Tab-Tab completion: If completion +fails the next completion function will be the one you try with +next Tab. \(You get some notification of this, of course.) + +See `tabkey2-first' for more information about usage. + +Note: If you do not want the Tab-Tab behaviour above, but still +want an easy way to reach the available completion functions, +then you can instead of turning on tabkey2-mode enter this in +your .emacs: + + \(global-set-key [f8] 'tabkey2-cycle-completion-functions) + +After hitting f8 you will then be in the same state as after the +first in tabkey2-mode." + :keymap nil + :global t + :group 'tabkey2 + (if tabkey2-mode + (progn + (add-hook 'minibuffer-setup-hook 'tabkey2-minibuffer-setup) + (add-hook 'post-command-hook 'tabkey2-post-command) + ;; Update emul here if keymap have changed + (setq tabkey2--emul-keymap-alist + (list (cons 'tabkey2-mode + tabkey2-mode-emul-map))) + (add-to-list 'emulation-mode-map-alists 'tabkey2--emul-keymap-alist)) + (tabkey2-completion-state-mode -1) + (remove-hook 'post-command-hook 'tabkey2-post-command) + (remove-hook 'minibuffer-setup-hook 'tabkey2-minibuffer-setup) + (setq emulation-mode-map-alists (delq 'tabkey2--emul-keymap-alist + emulation-mode-map-alists)))) + +(defcustom tabkey2-modes-that-use-more-tabs + '(python-mode + haskell-mode + makefile-mode + org-mode + Custom-mode + custom-mode ;; For Emacs 22 + ;; other + cmd-mode + ) + "In those modes use must use S-Tab to start completion state. +In those modes pressing Tab several types may make sense so you +can not go into 'Tab completion state' just because one Tab has +been pressed. Instead you use S-Tab to go into that state. +After that Tab does completion. + +You can do use S-Tab in other modes too if you want too." + :type '(repeat (choice (command :tag "Currently known command") + (symbol :tag "Command not known yet"))) + :group 'tabkey2) + +(defcustom tabkey2-modes-that-just-complete + '(shell-mode + fundamental-mode + text-mode) + "Tab is only used for completion in these modes. +Therefore `tabkey2-first' just calls the function on Tab." + :type '(repeat (choice (command :tag "Currently known command") + (symbol :tag "Command not known yet"))) + :group 'tabkey2) + +;;(setq tabkey2-use-popup-menus nil) +;; (defcustom tabkey2-use-popup-menus (when (featurep 'popcmp) t) +;; "Use pop menus if available." +;; :type 'boolean +;; :group 'tabkey2) + +;; (defvar tabkey2-preferred nil +;; "Preferred function for second tab key press.") +;; (make-variable-buffer-local 'tabkey2-preferred) +;; (put 'tabkey2-preferred 'permanent-local t) + +(defvar tabkey2-fallback nil + "Fallback function for second tab key press.") +(make-variable-buffer-local 'tabkey2-fallback) +(put 'tabkey2-fallback 'permanent-local t) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; State + +(defvar tabkey2-overlay nil + "Show when tab key 2 action is to be done.") +(defvar tabkey2-keymap-overlay nil + "Hold the keymap for tab key 2.") + +(defvar tabkey2-current-tab-info nil + "Saved information message for Tab completion state.") +(defvar tabkey2-current-tab-function nil + "Tab completion state current completion function.") +(make-variable-buffer-local 'tabkey2-current-tab-function) + +(defun tabkey2-completion-state-p () + "Return t if Tab completion state should continue. +Otherwise return nil." + (when (and (eq (current-buffer) (overlay-buffer tabkey2-keymap-overlay)) + (eq (overlay-get tabkey2-keymap-overlay 'window) (selected-window))) + (let* ((start (overlay-start tabkey2-keymap-overlay)) + (end (overlay-end tabkey2-keymap-overlay)) + (chars (append (buffer-substring-no-properties start end) nil))) + (and (not (memq ?\n chars)) + (not (eq ?\ (car (last chars)))) + (not (eq ?\ last-input-event)) + (<= start (point)) + (<= (point) end) + tabkey2-current-tab-function + (or (memq this-original-command '(tabkey2-first tabkey2-complete)) + (let* ((last-name (symbol-name this-original-command)) + (name-prefix "tabkey2-") + (prefix-len (length name-prefix))) + (and (> (length last-name) prefix-len) + (string= name-prefix (substring last-name 0 prefix-len))))) + )))) + +(defun tabkey2-read-only-p () + "Return non-nil if buffer seems to be read-only at point." + (or buffer-read-only + (get-char-property (min (+ 0 (point)) (point-max)) 'read-only) + (let ((remap (command-remapping 'self-insert-command (point)))) + (memq remap '(Custom-no-edit))))) + +;;;; Minor mode active after first tab + +(defun tabkey2-get-highlight-face () + (if (eq tabkey2-current-tab-function + (tabkey2-first-active-from-completion-functions)) + 'tabkey2-highlight-line + 'tabkey2-highlight-line2)) + +(defun tabkey2-move-overlays () + "Move overlays that mark the state and carries the state keymap." + (let* ((beg (let ((inhibit-field-text-motion t)) + (line-beginning-position))) + (ind (current-indentation)) + (end (+ beg 1)) ;(if (> ind 0) ind 1))) + (inhibit-read-only t)) + (unless tabkey2-overlay + (setq tabkey2-overlay (make-overlay beg end))) + ;; Fix-me: gets some strange errors, try avoid moving: + (unless (and (eq (current-buffer) (overlay-buffer tabkey2-overlay)) + (= beg (overlay-start tabkey2-overlay)) + (= end (overlay-end tabkey2-overlay))) + (move-overlay tabkey2-overlay beg end (current-buffer))) + ;; Give it a high priority, it is very temporary + (overlay-put tabkey2-overlay 'priority 1000) + (if tabkey2-show-mark-on-active-line + (progn + (overlay-put tabkey2-overlay 'face + ;;'tabkey2-highlight-line + (tabkey2-get-highlight-face) + ) + (overlay-put tabkey2-overlay 'help-echo + "This highlight shows that Tab completion state is on")) + (overlay-put tabkey2-overlay 'face nil) + (overlay-put tabkey2-overlay 'help-echo nil))) + ;; The keymap overlay + (let ((beg (line-beginning-position)) + (end (line-end-position))) + ;;(when (= end (point-max)) (setq end (1+ end))) + (setq beg (point)) + (setq end (point)) + + (unless tabkey2-keymap-overlay + ;; Make the rear of the overlay advance so that the keymap works + ;; at the end of a line and the end of the buffer. + (setq tabkey2-keymap-overlay (make-overlay 0 0 nil nil t))) + (overlay-put tabkey2-keymap-overlay 'priority 1000) + ;;(overlay-put tabkey2-keymap-overlay 'face 'secondary-selection) + (overlay-put tabkey2-keymap-overlay 'keymap + tabkey2-completion-state-emul-map) + (overlay-put tabkey2-keymap-overlay 'window (selected-window)) + (move-overlay tabkey2-keymap-overlay beg end (current-buffer)))) + +(defun tabkey2-is-active (fun chk) + "Return t FUN is active. +Return t if CHK is a symbol with non-nil value or a form that +evals to non-nil. + +Otherwise return t if FUN has a key binding at point." + (when (and (fboundp fun) + (commandp fun)) + (or (if (symbolp chk) + (when (boundp chk) (symbol-value chk)) + (eval chk)) + (let* ((emulation-mode-map-alists + ;; Remove keymaps from tabkey2 in this copy: + (delq 'tabkey2--emul-keymap-alist + (copy-sequence emulation-mode-map-alists))) + (keys (tabkey2-symbol-keys fun)) + kb-bound) + (dolist (key keys) + (unless (memq (car (append key nil)) + '(menu-bar)) + (setq kb-bound t))) + kb-bound)))) + +(defun tabkey2-is-active-p (fun) + "Return FUN is active. +Look it up in `tabkey2-completion-functions' to find out what to +check and return the value from `tabkey2-is-active'." + (let ((chk (catch 'chk + (dolist (rec tabkey2-completion-functions) + (when (eq fun (nth 1 rec)) + (throw 'chk (nth 2 rec))))))) + (tabkey2-is-active fun chk))) + +(defvar tabkey2-chosen-completion-function nil) +(make-variable-buffer-local 'tabkey2-chosen-completion-function) +(put 'tabkey2-chosen-completion-function 'permanent-local t) + +(defun tabkey2-first-active-from-completion-functions () + "Return first active completion function. +Look in `tabkey2-completion-functions' for the first function +that has an active key binding." + (catch 'active-fun + (dolist (rec tabkey2-completion-functions) + (let ((fun (nth 1 rec)) + (chk (nth 2 rec))) + (when (tabkey2-is-active fun chk) + (throw 'active-fun fun)))))) + +(defun tabkey2-get-default-completion-fun () + "Return the default completion function. +See `tabkey2-first' for the list considered." + (or (when (and tabkey2-chosen-completion-function + (tabkey2-is-active-p + tabkey2-chosen-completion-function)) + tabkey2-chosen-completion-function) + ;;tabkey2-preferred + (tabkey2-first-active-from-completion-functions) + tabkey2-fallback)) + +(defvar tabkey2-overlay-message nil) + +(defvar tabkey2-completion-state-mode nil) +;;(make-variable-buffer-local 'tabkey2-completion-state-mode) +(defun tabkey2-completion-state-mode (arg) + "Tab completion state minor mode. +This pseudo-minor mode holds the 'Tab completion state'. When this +minor mode is on completion key bindings are available. + +With ARG a positive number turn on, otherwise turn off this minor +mode. + +See `tabkey2-first' for more information." + ;;(assq-delete-all 'tabkey2-completion-state-mode minor-mode-alist) + (unless (assoc 'tabkey2-completion-state-mode minor-mode-alist) + ;;(setq minor-mode-alist (cons '(tabkey2-completion-state-mode " Tab2") + (setq minor-mode-alist (cons (list 'tabkey2-completion-state-mode + tabkey2-completion-lighter) + minor-mode-alist))) + (let ((emul-map (cdr (car tabkey2--emul-keymap-alist))) + (old-wincfg tabkey2-completion-state-mode)) + (setq tabkey2-completion-state-mode (when (and (numberp arg) + (> arg 0)) + ;;t + (current-window-configuration) + )) + (if tabkey2-completion-state-mode + (progn + ;; Set default completion function + (tabkey2-make-message-and-set-fun + (tabkey2-get-default-completion-fun)) + ;; Message + ;;(setq tabkey2-message-is-shown nil) + (when tabkey2-show-message-on-enter + (tabkey2-show-current-message + (when (numberp tabkey2-show-message-on-enter) + tabkey2-show-message-on-enter))) + ;; Move overlays + (tabkey2-move-overlays) + ;; Work around eob keymap problem ... + ;;(set-keymap-parent emul-map (overlay-get tabkey2-keymap-overlay + ;; 'keymap)) + ;; Set up for pre/post-command-hook + (add-hook 'pre-command-hook 'tabkey2-completion-state-pre-command) + (add-hook 'post-command-hook 'tabkey2-completion-state-post-command)) + ;;(set-keymap-parent emul-map nil) + (setq tabkey2-current-tab-function nil) + (when (and old-wincfg + tabkey2-keymap-overlay + (eq (overlay-get tabkey2-keymap-overlay 'window) (selected-window)) + (not (active-minibuffer-window))) + (set-window-configuration old-wincfg)) + (let ((inhibit-read-only t)) + (when tabkey2-keymap-overlay + (delete-overlay tabkey2-keymap-overlay)) + (when tabkey2-overlay + (delete-overlay tabkey2-overlay))) + (remove-hook 'pre-command-hook 'tabkey2-completion-state-pre-command) + (remove-hook 'post-command-hook 'tabkey2-completion-state-post-command) + (tabkey2-overlay-message nil) + ;;(message "") + ))) + +(defun tabkey2-completion-state-off () + "Quit Tab completion state." + (interactive) + (tabkey2-completion-state-mode -1) + (let ((C-g-binding (or (key-binding [(control ?g)]) + (key-binding "\C-g"))) + did-more) + (when (and (boundp 'company-mode) + company-mode) + ;;(message "tabkey2:company-abort") + (company-abort) + (setq did-more t)) + (when (and C-g-binding + (not (eq C-g-binding this-command))) + ;;(message "tabkey2:c-g=%s" C-g-binding) + (call-interactively C-g-binding) + (setq did-more t)) + (message "Quit"))) + +(defvar tabkey2-message-is-shown nil) +(defun tabkey2-message-is-shown () + (case tabkey2-message-style + ('popup + (when tabkey2-overlay-message + (overlay-buffer tabkey2-overlay-message))) + ('echo-area + (get (current-message) 'tabkey2)))) + +(defun tabkey2-completion-state-pre-command () + "Run this in `pre-command-hook'. +Check if message is shown. +Remove overlay message. +Cancel delayed message." + ;;(message "=====> tabkey2-completion-state-pre-command") + (condition-case err + (progn + (setq tabkey2-message-is-shown (tabkey2-message-is-shown)) + ;;(message "tabkey2-overlay-message=%s, is-shown=%s" tabkey2-overlay-message tabkey2-message-is-shown) + (tabkey2-overlay-message nil) + (tabkey2-cancel-delayed-message) + ;;(message "here buffer=%s, this-command=%s" (current-buffer) this-command) + ) + (error (message "tabkey2 pre: %s" (error-message-string err))))) + +(defun tabkey2-completion-state-post-command () + "Turn off Tab completion state if not feasable any more. +This is run in `post-command-hook' after each command." + (condition-case err + ;;(save-match-data + ;; Delayed messages + (if (not (tabkey2-completion-state-p)) + (tabkey2-completion-state-mode -1) + ;;(message "tabkey2-current-tab-function=%s" tabkey2-current-tab-function) + (tabkey2-move-overlays)) + ;;) + (error (message "tabkey2 post: %s" (error-message-string err))))) + +(defun tabkey2-minibuffer-setup () + "Activate/deactivate function `tabkey2-mode' in minibuffer." + (set (make-local-variable 'tabkey2-mode) + (and tabkey2-mode + tabkey2-in-minibuffer)) + (unless tabkey2-mode + (set (make-local-variable 'emulation-mode-map-alists) + (delq 'tabkey2--emul-keymap-alist + (copy-sequence emulation-mode-map-alists))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Message functions + +;; Fix-me: Included in Emacs 23. +(unless (fboundp 'invisible-p) + (defun invisible-p (pos) + "Return non-nil if the character after POS is currently invisible." + (let ((prop + (get-char-property pos 'invisible))) + (if (eq buffer-invisibility-spec t) + prop + (if (listp prop) + (catch 'invis + (dolist (p prop) + (when (or (memq p buffer-invisibility-spec) + (assq p buffer-invisibility-spec)) + (throw 'invis t)))) + (or (memq prop buffer-invisibility-spec) + (assq prop buffer-invisibility-spec))))))) + +;; (defun test-scroll () +;; (interactive) +;; (setq debug-on-error t) +;; (let* ((buffer-name "test-scroll") +;; (buffer (get-buffer buffer-name))) +;; (when buffer (kill-buffer buffer)) +;; (setq buffer (get-buffer-create buffer-name)) +;; (switch-to-buffer buffer) +;; (message "here 1") (sit-for 1) +;; (condition-case err +;; (scroll-up 1) +;; (error (message "scroll-up error: %s" err) +;; (sit-for 1))) +;; (message "here 2") (sit-for 1) +;; (scroll-up 1) +;; (message "here 3") (sit-for 1) +;; )) + +(defun tabkey2-overlay-message (txt) + "Display TXT below or above current line using an overlay." + ;;(setq tabkey2-message-is-shown txt) + (if (not txt) + (when tabkey2-overlay-message + (delete-overlay tabkey2-overlay-message) + (setq tabkey2-overlay-message nil)) + (let ((ovl tabkey2-overlay-message) + (column (current-column)) + (txt-len (length txt)) + (here (point)) + beg end + (before "") + (after "") + ovl-str too-much + (is-eob (eobp)) + (direction 1)) + (unless ovl (setq ovl (make-overlay 0 0))) + (when tabkey2-overlay-message + (delete-overlay tabkey2-overlay-message)) + (setq tabkey2-overlay-message ovl) + + (when is-eob + (setq direction -1)) + (when (and (/= (point-min) (window-start)) + (not (pos-visible-in-window-p (min (point-max) (1+ (line-end-position)))))) + ;; Go back inside window to avoid aggressive scrolling: + (forward-line -1) + (scroll-up 1) + (forward-line 1)) + (forward-line direction) + ;; Fix-me: Emacs bug workaround + (if (when (< 1 (point)) + (invisible-p (1- (line-end-position)))) + (progn + (goto-char here) + (tabkey2-echo-area-message txt)) + ;; Fix-me: Does this really do anything now: + (when (invisible-p (point)) + (while (invisible-p (point)) + (forward-line direction))) + (setq beg (line-beginning-position)) + (setq end (line-end-position)) + + (if (or (invisible-p beg) (invisible-p end)) + ;; Give up, do not fight invisibility: + (progn + (tabkey2-overlay-message nil) + (tabkey2-echo-area-message txt)) + + ;; string before + (move-to-column column) + (setq before (buffer-substring beg (point))) + (when (< (current-column) column) + (setq before + (concat before + (make-string (- column (current-column)) ? )))) + (setq too-much (- (+ 1 txt-len (length before)) + (window-width))) + (when (> too-much 0) + (setq before (substring before 0 (- too-much)))) + + (unless (> too-much 0) + (move-to-column (+ txt-len (length before))) + (setq after (buffer-substring (point) end))) + + (setq ovl-str (concat before + (propertize txt 'face 'tabkey2-highlight-popup) + after + )) + + (overlay-put ovl 'after-string ovl-str) + (overlay-put ovl 'display "") + (overlay-put ovl 'window (selected-window)) + (move-overlay ovl beg end (current-buffer))) + + (goto-char here) + )))) + +;; Fix-me: This was not usable IMO. Too much flickering. +;; (defun tabkey2-tooltip (txt) +;; (let* ((params tooltip-frame-parameters) +;; (coord (car (point-to-coord (point)))) +;; (left (car coord)) +;; (top (cadr coord)) +;; tooltip-frame-parameters +;; ) +;; ;; Fix-me: how do you get char height?? +;; (setq top (+ top 50)) +;; (setq params (tooltip-set-param params 'left left)) +;; (setq params (tooltip-set-param params 'top top)) +;; (setq params (tooltip-set-param params 'top top)) +;; (setq tooltip-frame-parameters params) +;; (tooltip-hide) +;; (tooltip-show txt nil))) + +(defun tabkey2-echo-area-message (txt) + "Show TXT in the echo area with a special face. +Shown with the face `tabkey2-highlight-message'." + (message "%s" (propertize txt + 'face 'tabkey2-highlight-message + 'tabkey2 t))) + +(defun tabkey2-deliver-message (txt) + "Show message TXT to user." + (case tabkey2-message-style + (popup (tabkey2-overlay-message txt)) + (t (tabkey2-echo-area-message txt)))) + +(defun tabkey2-timer-deliver-message (txt where) + "Show message TXT to user. +Protect from errors cause this is run during a timer." + (save-match-data ;; runs in timer + (when (and tabkey2-completion-state-mode + (equal (point-marker) where)) + (condition-case err + (tabkey2-deliver-message txt) + (error (message "tabkey2-timer-deliver-message: %s" + (error-message-string err))))))) + +(defvar tabkey2-delayed-timer nil) + +(defun tabkey2-cancel-delayed-message () + "Cancel delayed message." + (when tabkey2-delayed-timer + (cancel-timer tabkey2-delayed-timer) + (setq tabkey2-delayed-timer))) + +(defun tabkey2-maybe-delayed-message (txt delay) + "Show message TXT, delay it if DELAY is non-nil." + (if delay + (setq tabkey2-delayed-timer + (run-with-idle-timer + delay nil + 'tabkey2-timer-deliver-message txt (point-marker))) + (tabkey2-deliver-message txt))) + +(defun tabkey2-message (delay format-string &rest args) + "Show, if DELAY delayed, otherwise immediately message. +FORMAT-STRING and ARGS are like for `message'." + (let ((txt (apply 'format format-string args))) + (tabkey2-maybe-delayed-message txt delay))) + +(defun tabkey2-show-current-message (&optional delay) + "Show current completion message, delayed if DELAY is non-nil." + (tabkey2-cancel-delayed-message) + (tabkey2-message delay "%s" tabkey2-current-tab-info)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Completion function selection etc + +(defun tabkey2-symbol-keys (comp-fun) + "Get a list of all key bindings for COMP-FUN." + (let* ((remapped (command-remapping comp-fun))) + (where-is-internal comp-fun + nil ;;overriding-local-map + nil nil remapped))) + +(defun tabkey2-get-active-completion-functions () + "Get a list of active completion functions. +Consider only those in `tabkey2-completion-functions'." + (delq nil + (mapcar (lambda (rec) + (let ((fun (nth 1 rec)) + (chk (nth 2 rec))) + (when (tabkey2-is-active fun chk) rec))) + tabkey2-completion-functions))) + +(defun tabkey2-make-current-default () + "Make current Tab completion function default. +Set the current Tab completion function at point as default for +the current buffer." + (interactive) + (let ((set-it + (y-or-n-p + (format + "Make %s default for Tab completion in current buffer? " + tabkey2-current-tab-function)))) + (when set-it + (setq tabkey2-chosen-completion-function + tabkey2-current-tab-function)) + (unless set-it + (when (local-variable-p 'tabkey2-chosen-completion-function) + (when (y-or-n-p "Use default Tab completion selection in buffer? ") + (setq set-it t)) + (kill-local-variable 'tabkey2-chosen-completion-function))) + (when (tabkey2-completion-state-p) + (tabkey2-message nil "%s%s" tabkey2-current-tab-info + (if set-it " - Done" ""))))) + +(defun tabkey2-activate-next-completion-function (wrap) + (let* ((active (mapcar (lambda (rec) + (nth 1 rec)) + (tabkey2-get-active-completion-functions))) + (first (car active)) + next) + ;;(message "is-shown=%s current=%s active=%s overlay=%s" tabkey2-message-is-shown tabkey2-current-tab-function active tabkey2-overlay) + (when tabkey2-current-tab-function + (while (and active (not next)) + (when (eq (car active) tabkey2-current-tab-function) + (setq next (cadr active))) + (setq active (cdr active)))) + (unless next + (when wrap (setq next first))) + ;;(if (eq first next) + (tabkey2-make-message-and-set-fun next))) + +(defun tabkey2-cycle-completion-functions (prefix) + "Cycle through cnd display ompletion functions. +If 'Tab completion state' is not on then turn it on. + +If PREFIX is given just show what this command will do." + (interactive "P") + (if (tabkey2-read-only-p) + (message "Buffer is read only at point") + (unless tabkey2-completion-state-mode (tabkey2-completion-state-mode 1)) + (save-match-data + (if prefix + ;; fix-me + (message "(TabKey2) %s: show/cycle completion function" + last-input-event) + (when tabkey2-message-is-shown + ;; Message is shown currently so change + (tabkey2-activate-next-completion-function 'wrap)) + (tabkey2-show-current-message))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Handling of Tab and alternate key + +;;;###autoload +(defun tabkey2-emma-without-tabkey2 () + ;; Remove keymaps from tabkey2 in this copy: + (delq 'tabkey2--emul-keymap-alist + (copy-sequence emulation-mode-map-alists))) + +(defvar tabkey2-step-out-of-the-way nil) +;;(remove-hook 'pre-command-hook 'tabkey2-pre-command) +;;(remove-hook 'post-command-hook 'tabkey2-pre-command) +;;(remove-hook 'post-command-hook 'tabkey2-post-command-2) +(defun tabkey2-post-command () + (setq tabkey2-step-out-of-the-way nil) + (condition-case err + (when tabkey2-mode + (when (and (boundp 'company-overriding-keymap-bound) company-overriding-keymap-bound) + (setq tabkey2-step-out-of-the-way + (let ((emulation-mode-map-alists (tabkey2-emma-without-tabkey2))) + (key-binding (this-command-keys)))) + ;;(message "tabkey2-step-out=%s, %s" (this-command-keys) tabkey2-step-out-of-the-way) + )) + (error "tabkey2-pre-command: %s" err))) + ;; (and (boundp 'company-preview-overlay) + ;; (or company-preview-overlay + ;; company-pseudo-tooltip-overlay))) +(defun tabkey2-first (prefix) + "Do something else after first Tab. +This function is bound to the Tab key \(or whatever key +`tabkey2-first-key' is) when minor mode command `tabkey2-mode' is +on. It works like this: + +1. The first time Tab is pressed do whatever Tab would have done + if minor mode command `tabkey2-mode' was off. + + Then before next command enter a new temporary 'Tab completion + state' for just the next command. Show this by a highlight on + the indentation and a marker \"Tab2\" in the mode line. + + However if either + - the minibuffer is active and `tabkey2-in-minibuffer' is nil + - `major-mode' is in `tabkey2-modes-that-use-more-tabs' then + do not enter this temporary 'Tab completion state'. + + For major modes where it make sense to press Tab several times + you can use `tabkey2-alternate-key' to enter 'Tab completion + state'. + + +2. As long as point is not move do completion when Tab is pressed + again. Show that this state is active with a highlighting at + the line beginning, a marker on the mode line (Tab2) and a + message in the echo area which tells what kind of completion + will be done. + + When deciding what kind of completion to do look in the table + below and do whatever it found first that is not nil: + + - `tabkey2-preferred' + - `tabkey2-completion-functions' + - `tabkey2-fallback' + +3. Of course, there must be some way for you to easily determine + what kind of completion because there are many in Emacs. If + you do not turn it off this function will show that to you. + And if you turn it off you can still display it, see the key + bindings below. + + If this function is used with a PREFIX argument then it just + shows what Tab will do. + + If the default kind of completion is not what you want then + you can choose completion function from any of the candidates + in `tabkey2-completion-functions'. During the 'Tab completion + state' the following extra key bindings are available: + +\\{tabkey2-completion-state-emul-map} + +Of course, some languages does not have a fixed indent as is +assumed above. You can put major modes for those in +`tabkey2-modes-that-just-complete'. + +Some major modes uses tab for something else already. Those are +in `tabkey2-modes-that-use-more-tabs'. There is an alternate +key, `tabkey2-alternate-key' if you want to do completion +there. Note that this key does not do completion. It however +enters 'Tab completion state' in which you have access to the +keys above for completion etc. \(This key also lets you cycle +through the completion functions too choose which one to use.) + +----- +NOTE: This uses `emulation-mode-map-alists' and it supposes that +nothing else is bound to Tab there." + (interactive "P") + ;;(message "first:tabkey2-step-out=%s, %s" (this-command-keys) tabkey2-step-out-of-the-way) + (if tabkey2-step-out-of-the-way + (progn + (message "step-out=%s" tabkey2-step-out-of-the-way) + (call-interactively tabkey2-step-out-of-the-way)) + (if (and tabkey2-keymap-overlay + (eq (overlay-buffer tabkey2-keymap-overlay) (current-buffer)) + (eq (overlay-get tabkey2-keymap-overlay 'window) (selected-window)) + (>= (point) (overlay-start tabkey2-keymap-overlay)) + (<= (point) (overlay-end tabkey2-keymap-overlay))) + ;; We should maybe not be here, but the keymap does not work at + ;; the end of the buffer so we call the second tab function from + ;; here: + (if (memq 'shift (event-modifiers last-input-event)) + (call-interactively 'tabkey2-cycle-completion-functions) + (call-interactively 'tabkey2-complete prefix)) + (let* ((emma-without-tabkey2 (tabkey2-emma-without-tabkey2)) + (at-word-end (looking-at "\\_>")) + (just-complete (or (memq major-mode tabkey2-modes-that-just-complete) + at-word-end)) + (what (if just-complete + 'complete + (if (or (unless tabkey2-in-minibuffer + (active-minibuffer-window)) + (when (fboundp 'use-region-p) (use-region-p)) + (not at-word-end) + (memq major-mode tabkey2-modes-that-use-more-tabs)) + 'indent + 'indent-complete + ))) + (to-do-1 (unless (or + ;; Skip action on tab if shift tab, + ;; backtab or a mode in the "just + ;; complete" list + (memq 'shift (event-modifiers last-input-event)) + (equal [backtab] (this-command-keys-vector)) + ) + (let ((emulation-mode-map-alists emma-without-tabkey2)) + ;; Fix-me: Is this the way to pick up "tab keys"? + (or (key-binding [tab] t) + (key-binding [?\t] t)) + ))) + (to-do-2 (unless (or ;;(memq what '(complete)) + (memq what '(indent)) + (memq to-do-1 '(widget-forward button-forward))) + (tabkey2-get-default-completion-fun)))) + ;;(message "step-out-of-the-way=%s to-do=%s/%s, emmaa-without-tabkey2=%s" step-out-of-the-way to-do-1 to-do-2 emma-without-tabkey2) + (if prefix + (if (memq 'shift (event-modifiers last-input-event)) + (message + "(TabKey2) First shift %s: turn on 'Tab completion state'" + last-input-event) + (message "(TabKey2) First %s: %s, next: maybe %s" + last-input-event to-do-1 + (if to-do-2 to-do-2 "(same)"))) + (when to-do-1 + (let (xmumamo-multi-major-mode) + (tabkey2-call-interactively to-do-1))) + (unless (tabkey2-read-only-p) + (when to-do-2 + (tabkey2-completion-state-mode 1)))))))) + +(defun tabkey2-call-interactively (function) + "Like `call-interactively, but handle `this-command'." + (setq this-command function) + (call-interactively function)) + +(defcustom tabkey2-choose-next-on-error t + "Choose next completion function on error." + :type 'boolean + :group 'tabkey2) + +(defun tabkey2-complete (prefix) + "Call current completion function. +If used with a PREFIX argument then just show what Tab will do." + (interactive "P") + (if (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode + (not (mumamo-syntax-maybe-completable (point)))) + (message "Please move out of chunk border before trying to complete.") + (if prefix + (message "(TabKey2) %s: %s" + last-input-event tabkey2-current-tab-function) + (let ((here (point)) + (res (if tabkey2-choose-next-on-error + (condition-case err + (tabkey2-call-interactively tabkey2-current-tab-function) + (error (message "%s" (error-message-string err)) + nil)) + (tabkey2-call-interactively tabkey2-current-tab-function)))) + (when (and (not res) (= here (point))) + (tabkey2-activate-next-completion-function nil) + ;;(message "complete.tabkey2-current-tab-function=%s" tabkey2-current-tab-function) + (if tabkey2-current-tab-function + (tabkey2-show-current-message) + (message "No more active completion functions in this buffer"))))))) + +;; Fix-me: I am not sure that it really is useful with a globalized +;; minor mode here because there are so many other ways to control +;; what happens in a specific buffer. Maybe it would just be +;; confusing? +;; +;; If found another problem with making it globalized: tabkey2-mode +;; uses emulation-mode-map-alist. I decided to remove this therefore. +;; +;; (defun tabkey2-turn-on () +;; "Turn on `tabkey2-mode' in current buffer." +;; (tabkey2-mode 1)) + +;; (defvar tabkey2-turn-on-function 'tabkey2-turn-on +;; "Function used to mabye turn on `tabkey2-mode' in current-buffer. +;; This function is used by `tabkey2-global-mode' to turn on +;; `tabkey2-mode'.") + +;; (defun tabkey2-turn-on-in-buffer () +;; (funcall tabkey2-turn-on-function)) + +;; (define-globalized-minor-mode tabkey2-global-mode +;; tabkey2-mode tabkey2-turn-on-in-buffer) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Help functions + +(defun tabkey2-show-completion-state-help () + "Help for 'Tab completion state'. +To get out of this state you can move out of the current line. + +During this state the keymap below is active. This state stops +as soon as you leave the current row. + +\\{tabkey2-completion-state-emul-map} +See function `tabkey2-mode' for more information. + +If you want to use Emacs normal help function then press F1 +again.") + +(defun tabkey2-completion-state-help () + "Show help for 'Tab completion state'." + (interactive) + ;;(message "tckv=%s" (this-command-keys-vector)) ;;(sit-for 1) + ;; Fix-me: There seems to be an Emacs bug lurking here. Sometimes + ;; invoked-by-f1 is not [f1]. + (let ((invoked-by-f1 (equal (this-command-keys-vector) [f1])) + normal-help) + ;;(message "invoked-by-f1=%s" invoked-by-f1) ;; fix-me + (if (not invoked-by-f1) + (describe-function 'tabkey2-show-completion-state-help) + (setq normal-help + (read-event + (propertize + (concat "Type a key for Emacs help." + " Or, wait for Tab completion state help: ") + 'face 'highlight) + nil + 4)) + (case normal-help + ((nil) + ;;(message "Tab completion state help") + (describe-function 'tabkey2-show-completion-state-help)) + (?c + (call-interactively 'describe-key-briefly)) + (?k + (call-interactively 'describe-key)) + (t + (tabkey2-completion-state-mode -1) + (setq unread-command-events + (reverse + (cons + normal-help + (append (this-command-keys) nil))))))))) + +(defun tabkey2-completion-function-help () + "Show help for current completion function." + (interactive) + (describe-function tabkey2-current-tab-function)) + + + + +(defun tabkey2-get-key-binding (fun t2) + "Get key binding for FUN during 'Tab completion state'." + (let* ((remapped (command-remapping fun)) + (key (where-is-internal fun + (when t2 tabkey2-completion-state-emul-map) + t + nil + remapped))) + key)) + +;; (defun tabkey2-reset-completion-function (comp-fun) +;; "Reset states for functions in `tabkey2-completion-functions'." +;; ;; Fix-me: remove hard-coding +;; (setq dabbrev--last-abbrev-location nil)) + +(defun tabkey2-make-message-and-set-fun (comp-fun) + "Set current completion function to COMP-FUN. +Build message but don't show it." + ;;(tabkey2-reset-completion-functions) + (let* ((chs-fun 'tabkey2-cycle-completion-functions) + (key (tabkey2-get-key-binding chs-fun t)) + ;;(def-fun (tabkey2-get-default-completion-fun)) + what + (comp-fun-key (tabkey2-get-key-binding comp-fun nil)) + reset) + (setq tabkey2-current-tab-function comp-fun) + (dolist (rec tabkey2-completion-functions) + (let ((fun (nth 1 rec)) + (txt (nth 0 rec)) + (res (nth 3 rec))) + (when (eq fun comp-fun) + (eval res) + (setq what txt)))) + (let ((info (concat (format "Tab: %s" what) + (if comp-fun-key + (format " (%s)" (key-description comp-fun-key)) + "") + (if (cdr (tabkey2-get-active-completion-functions)) + (format ", other %s, help F1" + (key-description key)) + "")))) + (setq tabkey2-current-tab-info info)))) + +(defun tabkey2-get-active-string (bnd fun buf) + "Get string to show for state. +BND: means active +FUN: function +BUF: buffer" + (if bnd + (if (with-current-buffer buf (tabkey2-read-only-p)) + (propertize "active, but read-only" 'face '( :foreground "red")) + (propertize "active" 'face '( :foreground "green3"))) + (if (and (fboundp fun) + (commandp fun)) + (propertize "not active" 'face '( :foreground "red2")) + (propertize "not defined" 'face '( :foreground "gray"))))) + +(defun tabkey2-show-completion-functions () + "Show what currently may be used for completion." + (interactive) + (let ((orig-buf (current-buffer)) + (orig-mn mode-name) + (active-mark (concat " " + (propertize "<= default" + 'face '( :background "yellow")))) + (act-found nil) + (chosen-fun tabkey2-chosen-completion-function) + what + chosen) + (when chosen-fun + (dolist (rec tabkey2-completion-functions) + (let ((fun (nth 1 rec)) + (txt (nth 0 rec))) + (when (eq fun chosen-fun) (setq what txt)))) + (setq chosen (list what chosen-fun))) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'tabkey2-show-completion-functions) + (interactive-p)) + (with-current-buffer (help-buffer) + (insert (concat "The completion functions available for" + " 'Tab completion' in buffer\n'" + (buffer-name orig-buf) + "' at point with mode " orig-mn " are shown below.\n" + "The first active function is used by default.\n\n")) + (if (not chosen) + (insert " No completion function is set as default.") + (let* ((txt (nth 0 chosen)) + (fun (nth 1 chosen)) + (chk (nth 2 chosen)) + (bnd (with-current-buffer orig-buf + (tabkey2-is-active fun chk))) + (act (tabkey2-get-active-string bnd fun orig-buf))) + (insert (format " Default is set to\n %s (%s): %s" + txt fun act)) + (when bnd (insert active-mark) (setq act-found t)))) + (insert "\n\n") +;;; (if (not tabkey2-preferred) +;;; (insert " None is preferred") +;;; (let* ((txt (nth 0 tabkey2-preferred)) +;;; (fun (nth 1 tabkey2-preferred)) +;;; (chk (nth 2 chosen)) +;;; (bnd (with-current-buffer orig-buf +;;; (tabkey2-is-active fun chk))) +;;; (act (tabkey2-get-active-string bnd fun orig-buf))) +;;; (insert (format " Preferred is %s (`%s')': %s" +;;; txt fun act)) +;;; (when bnd (insert active-mark) (setq act-found t)))) +;;; (insert "\n\n") + (dolist (comp-fun tabkey2-completion-functions) + (let* ((txt (nth 0 comp-fun)) + (fun (nth 1 comp-fun)) + (chk (nth 2 comp-fun)) + (bnd (with-current-buffer orig-buf + (tabkey2-is-active fun chk))) + (act (tabkey2-get-active-string bnd fun orig-buf)) + (keys (where-is-internal fun))) + (if (not keys) + (setq keys "") + (setq keys (mapconcat 'key-description keys ", ")) + (when (and (< 9 (length keys)) + (string= "<menu-bar>" (substring keys 0 10))) + (setq keys "Menu")) + (setq keys (propertize keys 'face 'highlight)) + (setq keys (concat ", " keys)) + ) + (insert + (format + " %s (`%s'%s): %s" + txt fun keys act)) + (when (and (not act-found) bnd) + (insert active-mark) (setq act-found t)) + (insert "\n"))) + (insert "\n") + (if (not tabkey2-fallback) + (insert " There is no fallback") + (let* ((txt (nth 0 tabkey2-fallback)) + (fun (nth 1 tabkey2-fallback)) + (chk (nth 2 tabkey2-fallback)) + (bnd (with-current-buffer orig-buf + (tabkey2-is-active fun chk))) + (act (tabkey2-get-active-string bnd fun orig-buf))) + (insert (format " Fallback is %s (`%s'): %s" + txt fun act)) + (when (and (not act-found) bnd) + (insert active-mark) + (setq act-found t)))) + (insert "\n\nYou an ") + (insert-text-button "customize this list" + 'action (lambda (button) + (customize-option + 'tabkey2-completion-functions))) + (insert ".\nSee function `tabkey2-mode' for more information.") + (with-no-warnings (print-help-return-message)))))) + +(defvar tabkey2-completing-read 'completing-read) + +(defun tabkey2-set-fun (fun) + "Use function FUN for Tab in 'Tab completion state'." + (setq tabkey2-chosen-completion-function fun) + (unless fun + (setq fun (tabkey2-first-active-from-completion-functions))) + (tabkey2-make-message-and-set-fun fun) + (when (tabkey2-completion-state-p) + (message "%s" tabkey2-current-tab-info))) + +(defun tabkey2-appmenu () + "Make a menu for minor mode command `appmenu-mode'." + (unless (tabkey2-read-only-p) + (let* ((cf-r (reverse (tabkey2-get-active-completion-functions))) + (tit "Complete") + (map (make-sparse-keymap tit))) + (define-key map [tabkey2-usage] + (list 'menu-item "Show Available Completion Functions for TabKey2" + 'tabkey2-show-completion-functions)) + (define-key map [tabkey2-divider-1] (list 'menu-item "--")) + (let ((set-map (make-sparse-keymap "Set Completion"))) + (define-key map [tabkey2-choose] + (list 'menu-item "Set Primary TabKey2 Tab Completion in Buffer" set-map)) + (dolist (cf-rec cf-r) + (let ((dsc (nth 0 cf-rec)) + (fun (nth 1 cf-rec))) + (define-key set-map + (vector (intern (format "tabkey2-set-%s" fun))) + (list 'menu-item dsc + `(lambda () + (interactive) + (tabkey2-set-fun ',fun)) + :button + `(:radio + . (eq ',fun tabkey2-chosen-completion-function)))))) + (define-key set-map [tabkey2-set-div] (list 'menu-item "--")) + (define-key set-map [tabkey2-set-default] + (list 'menu-item "Default Tab completion" + (lambda () + (interactive) + (tabkey2-set-fun nil)) + :button + '(:radio . (null tabkey2-chosen-completion-function)))) + (define-key set-map [tabkey2-set-header-div] (list 'menu-item "--")) + (define-key set-map [tabkey2-set-header] + (list 'menu-item "Set Primary Tab Completion for Buffer")) + ) + (define-key map [tabkey2-divider] (list 'menu-item "--")) + (dolist (cf-rec cf-r) + (let ((dsc (nth 0 cf-rec)) + (fun (nth 1 cf-rec))) + (define-key map + (vector (intern (format "tabkey2-call-%s" fun))) + (list 'menu-item dsc fun + :button + `(:toggle + . (eq ',fun tabkey2-chosen-completion-function)) + )))) + map))) + +;; (defun tabkey2-completion-menu-popup () +;; "Pop up a menu with completion alternatives." +;; (interactive) +;; (let ((menu (tabkey2-appmenu))) +;; (popup-menu-at-point menu))) + +;; (defun tabkey2-choose-completion-function () +;; "Set current completion function. +;; Let user choose completion function from those in +;; `tabkey2-completion-functions' that have some key binding at +;; point. + +;; Let the chosen completion function be the default for subsequent +;; completions in the current buffer." +;; ;; Fix-me: adjust to mumamo. +;; (interactive) +;; (save-match-data +;; (if (and (featurep 'popcmp) +;; tabkey2-use-popup-menus) +;; (tabkey2-completion-menu-popup) +;; (when (eq 'completing-read tabkey2-completing-read) (isearch-unread 'tab)) +;; (let* ((cf-r (reverse (tabkey2-get-active-completion-functions))) +;; (cf (cons '("- Use default Tab completion" nil) cf-r)) +;; (hist (mapcar (lambda (rec) +;; (car rec)) +;; cf)) +;; (tit (funcall tabkey2-completing-read "Set current completion function: " cf +;; nil ;; predicate +;; t ;; require-match +;; nil ;; initial-input +;; 'hist ;; hist +;; )) +;; (fun-rec (assoc-string tit cf)) +;; (fun (cadr fun-rec))) +;; (setq tabkey2-chosen-completion-function fun) +;; (unless fun +;; (setq fun (tabkey2-first-active-from-completion-functions))) +;; (tabkey2-make-message-and-set-fun fun) +;; (when (tabkey2-completion-state-p) +;; (tabkey2-show-current-message)))))) + +;; (defun tabkey2-add-to-appmenu () +;; "Add a menu to function `appmenu-mode'." +;; (appmenu-add 'tabkey2 nil t "Completion" 'tabkey2-appmenu)) + + +(provide 'tabkey2) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; tabkey2.el ends here diff --git a/emacs/nxhtml/util/tyda.el b/emacs/nxhtml/util/tyda.el new file mode 100644 index 0000000..d4f3ea6 --- /dev/null +++ b/emacs/nxhtml/util/tyda.el @@ -0,0 +1,94 @@ +;;; tyda.el --- Lookup words in swe/eng dictionary at tyda.se +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-26T02:51:27+0200 Tue +;; Version: 0.2 +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Lookup swedish or english words in the dictionary at +;; +;; http://www.tyda.se/ +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'appmenu)) + +(defun tyda-lookup-word (word) + "Look up word WORD at URL `http://tyda.se/'. +This site translates between English and Swedish. The site will +be opened in your webbrowser with WORD looked up." + (interactive (list (or (thing-at-point 'word) + (read-string "Lookup word: ")))) + ;; http://tyda.se/search?form=1&w=weird&w_lang=&x=0&y=0 + (browse-url + ;;(concat "http://www.tyda.se/?rid=651940&w=" word) + (format "http://tyda.se/search?form=1&w=%s&w_lang=&x=0&y=0" word) + )) + +(defvar tyda-appmenu-map + (let ((map (make-sparse-keymap))) + (define-key map [tyda-lookup] + (list 'menu-item "Lookup word at point in Tyda" + 'tyda-lookup-word)) + map)) + +(defvar tyda-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(alt mouse-1)] 'tyda-lookup-word) + (define-key map [(control ?c) ?=] 'tyda-lookup-word) + map)) + +;;;###autoload +(define-minor-mode tyda-mode + "Minor mode for key bindings for `tyda-lookup-word'. +It binds Alt-Mouse-1 just as the Tyda add-on does in Firefox. +Here are all key bindings + +\\{tyda-mode-map} +" + :global t + (if tyda-mode + (progn + (require 'appmenu nil t) + (when (featurep 'appmenu) + (appmenu-add 'tyda nil tyda-mode "Lookup word" tyda-appmenu-map))))) + + +(provide 'tyda) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; tyda.el ends here diff --git a/emacs/nxhtml/util/udev-ecb.el b/emacs/nxhtml/util/udev-ecb.el new file mode 100644 index 0000000..be3b35f --- /dev/null +++ b/emacs/nxhtml/util/udev-ecb.el @@ -0,0 +1,229 @@ +;;; udev-ecb.el --- Get ECB sources and set it up +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-25T04:02:37+0200 Mon +(defconst udev-ecb:version "0.2");; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + + +(eval-when-compile (require 'udev nil t)) + +(defgroup udev-ecb nil + "Customization group for udev-ecb." + :group 'nxhtml) + +(defcustom udev-ecb-dir "~/.emacs.d/udev/ecb-cvs/" + "Directory where to put CVS ECB sources." + :type 'directory + :group 'udev-ecb) + +(defun udev-ecb-cvs-dir () + "Return cvs root directory." + (file-name-as-directory (expand-file-name "ecb" udev-ecb-dir))) + +(defvar udev-ecb-miss-cedet nil) + +(defun udev-ecb-load-ecb () + "Load fetched ECB." + (setq udev-ecb-miss-cedet nil) + (unless (featurep 'ecb) + (add-to-list 'load-path (udev-ecb-cvs-dir)) + (let ((msg nil)) + (unless (or msg (featurep 'cedet)) (setq msg "CEDET is not loaded")) + (unless (or msg (locate-library "semantic")) (setq msg "can't find CEDET Semantic")) + (unless (or msg (locate-library "eieio")) (setq msg "can't find CEDET eieio")) + (if msg + (progn + (setq udev-ecb-miss-cedet (format "Can't load ECB because %s." msg)) + (ourcomments-warning udev-ecb-miss-cedet)) + (require 'ecb nil t))))) + +(defcustom udev-ecb-load-ecb nil + "To load or not to load ECB..." + :type 'boolean + :require 'udev-ecb + :set (lambda (sym val) + (set-default sym val) + (when val + (udev-ecb-load-ecb))) + ;; ecb-activate, ecb-customize-most-important to menu + :set-after '(udev-cedet-load-cedet) + :group 'udev-ecb) + +(defvar udev-ecb-steps + '(udev-ecb-fetch + udev-ecb-fix-bad-files + udev-ecb-fetch-diff + udev-ecb-check-diff + udev-ecb-install + )) + +(defun udev-ecb-buffer-name (mode) + "Return a name for current compilation buffer ignoring MODE." + (udev-buffer-name "*Updating ECB %s*" udev-ecb-update-buffer mode)) + +(defvar udev-ecb-update-buffer nil) + +(defun udev-ecb-has-cedet () + (cond + ((not (and (locate-library "semantic") + (locate-library "eieio"))) + (message (propertize "CEDET must be installed and loaded first" + 'face 'secondary-selection)) + nil) + ((not (featurep 'cedet)) + (message (propertize "CEDET must be loaded first" + 'face 'secondary-selection)) + nil) + (t t))) + +(defun udev-ecb-setup-when-finished (log-buffer) + (require 'cus-edit) + (let ((inhibit-read-only t)) + (with-current-buffer log-buffer + (widen) + (goto-char (point-max)) + (insert "\n\nYou must restart Emacs to load ECB properly.\n") + (let ((load-ecb-saved-value (get 'udev-ecb-load-ecb 'saved-value)) + (here (point)) + ) + (if load-ecb-saved-value + (insert "You have setup to load ECB the next time you start Emacs.\n\n") + (insert (propertize "Warning:" 'face 'compilation-warning) + " You have not setup to load ECB the next time you start Emacs.\n\n")) + (insert-button " Setup " + 'face 'custom-button + 'action (lambda (btn) + (interactive) + (customize-group-other-window 'udev-ecb))) + (insert " Setup to load ECB from fetched sources when starting Emacs."))))) + +;;;###autoload +(defun udev-ecb-update () + "Fetch and install ECB from the devel sources. +To determine where to store the sources see `udev-ecb-dir'. +For how to start ECB see `udev-ecb-load-ecb'." + (interactive) + (when (udev-ecb-has-cedet) + (let* ((has-it (file-exists-p (udev-ecb-cvs-dir))) + (prompt (if has-it + "Do you want to update ECB from devel sources? " + "Do you want to install ECB from devel sources? "))) + (when (y-or-n-p prompt) + (setq udev-ecb-update-buffer (get-buffer-create "*Update ECB*")) + (udev-call-first-step udev-ecb-update-buffer udev-ecb-steps + "Starting updating ECB from development sources" + 'udev-ecb-setup-when-finished))))) + +;;;###autoload +(defun udev-ecb-customize-startup () + "Customize ECB dev nXhtml startup group." + (interactive) + (if (file-exists-p (udev-ecb-cvs-dir)) + (customize-group-other-window 'udev-ecb) + (message (propertize "You must fetch ECB from nXhtml first" + 'face 'secondary-selection)))) + +(defun udev-ecb-fetch (log-buffer) + "Fetch ECB sources (asynchronously)." + (let ((default-directory (file-name-as-directory udev-ecb-dir))) + (unless (file-directory-p default-directory) + (make-directory default-directory)) + (with-current-buffer + (compilation-start + "cvs -z3 -d:pserver:anonymous@ecb.cvs.sourceforge.net:/cvsroot/ecb co -P ecb" + 'compilation-mode + 'udev-ecb-buffer-name) + (current-buffer)))) + +;;(udev-ecb-fix-bad-files nil) +(defun udev-ecb-fix-bad-files (log-buffer) + "Change files that can not be compiled." + (let* ((bad-file (expand-file-name "ecb/ecb-advice-test.el" udev-ecb-dir)) + (bad-file-buffer (find-buffer-visiting bad-file)) + (this-log-buf (get-buffer-create "*Fix bad ECB files*")) + (fixed-it nil)) + (when (file-exists-p bad-file) + (with-current-buffer (find-file-noselect bad-file) + (save-restriction + (widen) + (goto-char (point-min)) + (save-match-data + (while (re-search-forward "\r" nil t) + (setq fixed-it t) + (replace-match "")))) + (basic-save-buffer) + (with-current-buffer this-log-buf + (erase-buffer) + (if fixed-it + (insert "Fixed " bad-file "\n") + (insert "The file " bad-file " was already ok\n"))) + (unless bad-file-buffer (kill-buffer (current-buffer))))) + this-log-buf)) + +(defun udev-ecb-fetch-diff (log-buffer) + "Fetch diff between local ECB sources and repository." + (udev-fetch-cvs-diff (udev-ecb-cvs-dir) 'udev-ecb-buffer-name)) + +(defun udev-ecb-check-diff (log-buffer) + "Check cvs diff output for merge conflicts." + (udev-check-cvs-diff (expand-file-name "your-patches.diff" + (udev-ecb-cvs-dir)) + udev-ecb-update-buffer)) + +(defun udev-ecb-install (log-buffer) + "Install the ECB sources just fetched. +Note that they will not be installed in current Emacs session." + (udev-batch-compile "-l ecb-batch-compile.el" + udev-this-dir + 'udev-ecb-buffer-name)) + +;;(udev-ecb-install-help (get-buffer-create "*temp online-help*")) +(defun udev-ecb-install-help (log-buffer) + (let ((trc-buf (get-buffer-create "*temp online-help*"))) + (with-current-buffer trc-buf + (setq default-directory (udev-ecb-cvs-dir)) + (w32shell-with-shell "msys" (shell-command "make online-help&" trc-buf))))) + +(provide 'udev-ecb) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; udev-ecb.el ends here diff --git a/emacs/nxhtml/util/udev-rinari.el b/emacs/nxhtml/util/udev-rinari.el new file mode 100644 index 0000000..ed70c6c --- /dev/null +++ b/emacs/nxhtml/util/udev-rinari.el @@ -0,0 +1,204 @@ +;;; udev-rinari.el --- Get rinary sources and set it up +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-24T22:32:21+0200 Sun +(defconst udev-rinari:version "0.2");; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'udev nil t)) + +(defgroup udev-rinari nil + "Customization group for udev-rinari." + :group 'nxhtml) + +(defcustom udev-rinari-dir "~/rinari-svn/" + "Directory where to put SVN Rinari sources." + :type 'directory + :group 'udev-rinari) + +(defcustom udev-rinari-load-rinari nil + "To load or not to load Rinari..." + :type '(choice (const :tag "Don't load Rinari" nil) + (const :tag "Load Rinari" t)) + :set (lambda (sym val) + (set-default sym val) + (when val + (let* ((base-dir (expand-file-name "svn/trunk/" udev-rinari-dir)) + (rhtml-dir (expand-file-name "rhtml/" base-dir)) + (test-dir (expand-file-name "test/lisp/" base-dir))) + (unless (file-directory-p base-dir) (message "Can't find %s" base-dir)) + (unless (file-directory-p rhtml-dir) (message "Can't find %s" rhtml-dir)) + (unless (file-directory-p test-dir) (message "Can't find %s" test-dir)) + (add-to-list 'load-path base-dir) + (add-to-list 'load-path rhtml-dir) + (add-to-list 'load-path test-dir)) + (require 'rinari) + (require 'ruby-mode))) + :group 'udev-rinari) + +(defvar udev-rinari-steps + '(udev-rinari-fetch + udev-rinari-fetch-diff + udev-rinari-check-diff + ;;udev-rinari-install + )) + +(defvar udev-rinari-update-buffer nil) + +(defun udev-rinari-buffer-name (mode) + "Return a name for current compilation buffer ignoring MODE." + (udev-buffer-name "*Updating Rinari %s*" udev-rinari-update-buffer mode)) + +(defun udev-rinari-check-conflicts () + "Check if Rinari and ruby-mode already loaded and from where. +Give an error if they are loaded from somewhere else than +`udev-rinari-dir' tree." + (when (featurep 'rinari) + (let ((old-dir (file-name-directory (car (load-history-filename-element (load-history-regexp "rinari"))))) + (new-dir (expand-file-name "svn/trunk/" udev-rinari-dir))) + (unless (string= (file-truename old-dir) + (file-truename new-dir)) + (error "Rinari is already loaded from: %s" old-dir)))) + (when (featurep 'ruby-mode) + (let ((old-dir (file-name-directory (car (load-history-filename-element (load-history-regexp "ruby-mode"))))) + (new-dir (expand-file-name "svn/trunk/test/lisp/" udev-rinari-dir))) + (unless (string= (file-truename old-dir) + (file-truename new-dir)) + (error "Ruby-mode is already loaded from: %s" old-dir)))) + ) + +(defun udev-rinari-setup-when-finished (log-buffer) + (let ((inhibit-read-only t)) + (with-current-buffer log-buffer + (widen) + (goto-char (point-max)) + (insert "\n\nYou must restart Emacs to load Rinari properly.\n") + (let ((load-rinari-saved-value (get 'udev-rinari-load-rinari 'saved-value)) + (here (point)) + ) + (if load-rinari-saved-value + (insert "You have setup to load Rinari the next time you start Emacs.\n\n") + (insert (propertize "Warning:" 'face 'compilation-warning) + " You have not setup to load Rinari the next time you start Emacs.\n\n")) + (insert-button " Setup " + 'face 'custom-button + 'action (lambda (btn) + (interactive) + (customize-group-other-window 'udev-rinari))) + (insert " Setup to load Rinari from fetched sources when starting Emacs."))))) + +;;;###autoload +(defun udev-rinari-update () + "Fetch and install Rinari from the devel sources. +To determine where to store the sources and how to start rinari +see `udev-rinari-dir' and `udev-rinari-load-rinari'." + (interactive) + (udev-rinari-check-conflicts) + (setq udev-rinari-update-buffer (get-buffer-create "*Update Rinari*")) + (udev-call-first-step udev-rinari-update-buffer udev-rinari-steps + "Starting updating Rinari from development sources" + 'udev-rinari-setup-when-finished)) + +(defvar udev-rinari-fetch-buffer nil) + +(defun udev-rinari-fetch (log-buffer) + "Fetch Rinari from development sources." + (let* ((default-directory (file-name-as-directory udev-rinari-dir)) ;; fix-me: for emacs bug + ) + (unless (file-directory-p default-directory) + (make-directory default-directory)) + (with-current-buffer + (compilation-start + "svn checkout http://rinari.rubyforge.org/svn/" + 'compilation-mode + 'udev-rinari-buffer-name) + (setq udev-rinari-fetch-buffer (current-buffer))))) + +(defvar udev-rinari-diff-file nil) +(defvar udev-rinari-fetch-diff-buffer nil) + +(defun udev-rinari-fetch-diff (log-buffer) + "Fetch diff between local Rinari sources and dev repository." + (let ((must-fetch-diff t)) + (setq udev-rinari-fetch-diff-buffer + (when must-fetch-diff + (let* ((default-directory (file-name-as-directory + (expand-file-name "svn" + udev-rinari-dir)))) + (setq udev-rinari-diff-file (expand-file-name "../patches.diff")) + (with-current-buffer + (compilation-start + (concat "svn diff > " (shell-quote-argument udev-rinari-diff-file)) + 'compilation-mode + 'udev-rinari-buffer-name) + (setq udev-continue-on-error-function 'udev-cvs-diff-continue) + (current-buffer))))))) + +(defun udev-rinari-check-diff (log-buffer) + "Check output from svn diff command for merge conflicts." + ;; Fix-me: How can this be checked? + (when udev-rinari-fetch-diff-buffer + (let ((buf (find-buffer-visiting udev-rinari-diff-file))) + (if buf + (with-current-buffer buf (revert-buffer nil t)) + (setq buf (find-file-noselect udev-rinari-diff-file))) + (with-current-buffer buf + (widen) + (goto-char (point-min)) + (if (search-forward "<<<<<<<" nil t) + ;; Merge conflict + (udev-call-next-step udev-rinari-update-buffer 1 nil) + buf))))) + +;; (defun udev-rinari-install () +;; "Install Rinari and ruby-mode for use." +;; (if udev-rinari-load-rinari +;; (message "Rinari should be loaded now") +;; (when (y-or-n-p +;; "You need to set udev-rinari-load-rinari. Do that now? ") +;; (customize-group-other-window 'udev-rinari))) +;; nil) + + +(provide 'udev-rinari) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; udev-rinari.el ends here diff --git a/emacs/nxhtml/util/udev.el b/emacs/nxhtml/util/udev.el new file mode 100644 index 0000000..ee9d86a --- /dev/null +++ b/emacs/nxhtml/util/udev.el @@ -0,0 +1,456 @@ +;;; udev.el --- Helper functions for updating from dev sources +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-24 +(defconst udev:version "0.5");; Version: +;; Last-Updated: 2009-01-06 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `cus-edit', `cus-face', `cus-load', `cus-start', `wid-edit'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; When you want to fetch and install sources from a repository you +;; may have to call several async processes and wait for the answer +;; before calling the next function. These functions may help you with +;; this. +;; +;; See `udev-call-first-step' for more information. Or look in the +;; file udev-cedet.el for examples. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(eval-when-compile (require 'cl)) + +(require 'cus-edit) + +;;; Control/log buffer + +(defvar udev-log-buffer nil + "Log buffer pointer for sentinel function.") +(make-variable-buffer-local 'udev-log-buffer) + +(defvar udev-is-log-buffer nil + "This is t if this is an udev log/control buffer.") +(make-variable-buffer-local 'udev-is-log-buffer) + +(defun udev-check-is-log-buffer (buffer) + "Check that BUFFER is an udev log/control buffer." + (with-current-buffer buffer + (unless udev-is-log-buffer + (error "Internal error, not a log buffer: %s" buffer)))) + +(defvar udev-this-chain nil) +(make-variable-buffer-local 'udev-this-chain) + +(defvar udev-last-error nil + "Error found during last step.") +(make-variable-buffer-local 'udev-last-error) + +(defun udev-set-last-error (log-buffer msg) + (with-current-buffer log-buffer + (setq udev-last-error msg))) + +;;; Chain utils + +(defun udev-chain (log-buffer) + "Return value of `udev-this-chain' in buffer LOG-BUFFER." + (udev-check-is-log-buffer log-buffer) + (with-current-buffer log-buffer + udev-this-chain)) + +(defun udev-this-step (log-buffer) + "Return current function to call from LOG-BUFFER." + (let ((this-chain (udev-chain log-buffer))) + (caar this-chain))) + +(defun udev-goto-next-step (log-buffer) + "Set next function as current in LOG-BUFFER." + (let* ((this-chain (udev-chain log-buffer)) + (this-step (car this-chain))) + (setcar this-chain (cdr this-step)))) + +(defun udev-num-steps (log-buffer) + "Return number of steps." + (length (nth 2 (udev-chain log-buffer)))) + +(defun udev-step-num (log-buffer) + "Return current step number." + (let ((this-chain (udev-chain log-buffer))) + (when this-chain + (1+ (- (udev-num-steps log-buffer) + (length (car this-chain))))))) + +(defun udev-finish-function (log-buffer) + "Return setup function to be called when finished." + (nth 3 (udev-chain log-buffer))) + + +(defvar udev-control-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map button-buffer-map) + map)) + +(define-derived-mode udev-control-mode nil + "Udev-Src" + "Mode for udev control buffer." + (setq show-trailing-whitespace nil) + (setq buffer-read-only t) + (nxhtml-menu-mode 1)) + +;;; Calling steps + +;;;###autoload +(defun udev-call-first-step (log-buffer steps header finish-fun) + "Set up and call first step. +Set up buffer LOG-BUFFER to be used for log messages and +controling of the execution of the functions in list STEPS which +are executed one after another. + +Write HEADER at the end of LOG-BUFFER. + +Call first step. + +If FINISH-FUN non-nil it should be a function. This is called +after last step with LOG-BUFFER as parameter." + ;;(dolist (step steps) (unless (functionp step) (error "Not a known function: %s" step))) + (switch-to-buffer log-buffer) + (udev-control-mode) + (setq udev-is-log-buffer t) + (let ((this-chain + (cons nil + (cons log-buffer + (cons (copy-tree steps) + (cons finish-fun nil)))))) + (setcar this-chain (caddr this-chain)) + (setq udev-this-chain this-chain)) + (assert (eq (car steps) (udev-this-step log-buffer)) t) + (assert (eq finish-fun (udev-finish-function log-buffer)) t) + (widen) + (goto-char (point-max)) + (let ((inhibit-read-only t)) + (unless (= (point) (point-min)) (insert "\n\n")) + (insert header)) + (udev-call-this-step log-buffer nil) + (current-buffer)) + +(defvar udev-step-keymap + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?r] 'udev-rerun-this-step) + (define-key map [(control ?c) ?c] 'udev-continue-from-this-step) + (define-key map [(control ?c) ?s] 'udev-goto-this-step-source) + map)) + +(defun udev-step-at-point () + (get-text-property (point) 'udev-step)) + +(defun udev-rerun-this-step () + "Rerun this step." + (interactive) + (let ((this-step (udev-step-at-point))) + (udev-call-this-step (current-buffer) this-step))) + +(defun udev-continue-from-this-step () + "Continue from this step." + (interactive) + (let ((this-step (udev-step-at-point))) + (goto-char (point-max)) + (let ((inhibit-read-only t)) + (insert (format "\n\nContinuing from %s..." this-step))) + (udev-call-this-step (current-buffer) this-step))) + +(defun udev-goto-this-step-source () + "Find source function for this step." + (interactive) + (let ((this-step (udev-step-at-point))) + (find-function-other-window this-step))) + +(defun udev-call-this-step (log-buffer this-step) + "Call the current function in LOG-BUFFER. +If this function returns a buffer and the buffer has a process +then change the process sentinel to `udev-compilation-sentinel'. +Otherwise continue to call the next function. + +Also put a log message in in LOG-BUFFER with a link to the buffer +returned above if any." + (setq this-step (or this-step (udev-this-step log-buffer))) + (with-current-buffer log-buffer + (setq udev-last-error nil) + (widen) + (goto-char (point-max)) + (let* ((inhibit-read-only t) + here + buf + proc) + (if (not this-step) + (let ((finish-fun (udev-finish-function log-buffer))) + (insert (propertize "\nFinished\n" 'face 'compilation-info)) + (when finish-fun + (funcall finish-fun log-buffer))) + (insert (format "\nStep %s(%s): " + (udev-step-num log-buffer) + (udev-num-steps log-buffer))) + (setq here (point)) + (insert (pp-to-string this-step)) + (setq buf (funcall this-step log-buffer)) + (when (bufferp buf) + (make-text-button here (point) + 'udev-step this-step + 'keymap udev-step-keymap + 'buffer buf + 'help-echo "Push RET to see log buffer, <APPS> for other actions" + 'action (lambda (btn) + (display-buffer + (button-get btn 'buffer)))) + (setq proc (get-buffer-process buf))) + ;; Setup for next step + (if (and proc + (not udev-last-error)) + (progn + (with-current-buffer buf + ;; Make a copy here for the sentinel function. + (setq udev-log-buffer log-buffer) + (setq udev-orig-sentinel (process-sentinel proc)) + (set-process-sentinel proc 'udev-compilation-sentinel))) + ;;(message "proc is nil") + (if udev-last-error + (insert " " + (propertize udev-last-error 'face 'compilation-error)) + (udev-call-next-step log-buffer 0 nil))))))) + +(defun udev-call-next-step (log-buffer prev-exit-status exit-status-buffer) + "Go to next step in LOG-BUFFER and call `udev-call-this-step'. +However if PREV-EXIT-STATUS \(which is the exit status from the +previous step) is not 0 and there is in EXIT-STATUS-BUFFER no +`udev-continue-on-error-function' then stop and insert an error +message in LOG-BUFFER." + (with-current-buffer log-buffer + (let ((inhibit-read-only t)) + (widen) + (goto-char (point-max)) + (insert " ") + (if (or (= 0 prev-exit-status) + (with-current-buffer exit-status-buffer + (when udev-continue-on-error-function + (funcall udev-continue-on-error-function exit-status-buffer)))) + (progn + (insert + (if (= 0 prev-exit-status) + (propertize "Ok" 'face 'compilation-info) + (propertize "Warning, check next step" 'face 'compilation-warning))) + (udev-goto-next-step log-buffer) + (udev-call-this-step log-buffer nil)) + (insert (propertize "Error" 'face 'compilation-error)))))) + + +;;; Sentinel + +(defvar udev-orig-sentinel nil + "Old sentinel function remembered by `udev-call-this-step'.") +(make-variable-buffer-local 'udev-orig-sentinel) + +(defun udev-compilation-sentinel (proc msg) + "Sentinel to use for processes started by `udev-call-this-step'. +Check for error messages and call next step. PROC and MSG have +the same meaning as for `compilation-sentinel'." + ;;(message "udev-compilation-sentinel proc=%s msg=%s" proc msg) + (let ((buf (process-buffer proc)) + (exit-status (process-exit-status proc))) + (with-current-buffer buf + (when udev-orig-sentinel + (funcall udev-orig-sentinel proc msg)) + (when (and (eq 'exit (process-status proc)) + (= 0 exit-status)) + ;; Check for errors + (let ((here (point)) + (err-point 1) + (has-error nil)) + (widen) + (goto-char (point-min)) + (setq has-error + (catch 'found-error + (while err-point + (setq err-point + (next-single-property-change err-point 'face)) + (when err-point + (let ((face (get-text-property err-point 'face))) + (when (or (and (listp face) + (memq 'compilation-error face)) + (eq 'compilation-error face)) + (throw 'found-error t))))))) + (when has-error + (setq exit-status 1) + (goto-char (point-max)) + (let ((inhibit-read-only t)) + (insert (propertize "There were errors" 'font-lock-face 'compilation-error))) + (udev-set-compilation-end-message buf 'exit (cons "has errors" 1))) + (goto-char here) + )) + (unless (member proc compilation-in-progress) + (udev-call-next-step udev-log-buffer exit-status (current-buffer)))))) + +(defun udev-set-compilation-end-message (buffer process-status status) + "Change the message shown after compilation. +This is similar to `compilation-end-message' and BUFFER, +PROCESS-STATUS and STATUS have the same meaning as there." + (with-current-buffer buffer + (setq mode-line-process + (let ((out-string (format ":%s [%s]" process-status (cdr status))) + (msg (format "%s %s" mode-name + (replace-regexp-in-string "\n?$" "" (car status))))) + (message "%s" msg) + (propertize out-string + 'help-echo msg 'face (if (> (cdr status) 0) + 'compilation-error + 'compilation-info)))))) + +(defvar udev-continue-on-error-function nil + "One-time helper to resolve exit status error problem. +This can be used for example after calling `cvs diff' which +returns error exit status if there is a difference - even though +there does not have to be an error.") +(make-variable-buffer-local 'udev-continue-on-error-function) + + +;;; Convenience functions + +(defun udev-buffer-name (fmt log-buffer mode) + "Return a name for compilation buffer. +Use format string FMT and buffer LOG-BUFFER, but ignoring MODE." + (format fmt (when (buffer-live-p log-buffer) + (udev-this-step log-buffer)))) + +(defvar udev-this-dir + (let ((this-file (or load-file-name (buffer-file-name)))) + (file-name-directory this-file))) + +(defun udev-batch-compile (emacs-args defdir name-function) + "Compile elisp code in an inferior Emacs. +Start Emacs with + + emacs -Q -batch EMACS-ARGS + +in the default directory DEFDIR. + +Set the buffer name for the inferior process with NAME-FUNCTION +by giving this to `compilation-start'." + (let ((default-directory (file-name-as-directory defdir)) + (this-emacs (ourcomments-find-emacs))) + (compilation-start + (concat this-emacs " -Q -batch " emacs-args) + 'compilation-mode + name-function))) + +;;; Convenience functions for CVS + +(defun udev-fetch-cvs-diff (defdir name-function) + "Fetch cvs diff in directory DEFDIR. +Put the diff in file 'your-patches.diff' in DEFDIR. +Give inferior buffer name with NAME-FUNCTION." + (let ((default-directory (file-name-as-directory defdir))) + (with-current-buffer + (compilation-start + (concat "cvs diff -b -u > " (shell-quote-argument "your-patches.diff")) + 'compilation-mode + name-function) + (setq udev-continue-on-error-function 'udev-cvs-diff-continue) + (current-buffer)))) + +(defun udev-cvs-diff-continue (cvs-diff-buffer) + "Return non-nil if it is ok to continue. +Check the output from the `cvs diff' command in buffer +CVS-DIFF-BUFFER. + +The cvs command exits with a failure status if there is a +difference, which means that it is hard to know whether there was +an error or just a difference. This function tries to find out." + (with-current-buffer cvs-diff-buffer + (let ((here (point)) + (ret t)) + (goto-char (point-min)) + (when (search-forward "cvs [diff aborted]" nil t) (setq ret nil)) + (goto-char (point-min)) + (when (search-forward "merge conflict" nil t) (setq ret t)) + ;; From cvs co command: + ;; rcsmerge: warning: conflicts during merge + (goto-char (point-min)) + (when (search-forward "conflicts during merge" nil t) (setq ret t)) + ;; cvs checkout: conflicts found in emacs/lisp/startup.el + (goto-char (point-min)) + (when (search-forward "conflicts found in" nil t) (setq ret t)) + (goto-char here) + ret))) + +(defun udev-check-cvs-diff (diff-file log-buffer) + "Check cvs diff output in file DIFF-FILE for merge conflicts. +Return buffer containing DIFF-FILE." + (let ((buf (find-buffer-visiting diff-file))) + ;; Kill buffer to avoid question about revert. + (when buf (kill-buffer buf)) + (setq buf (find-file-noselect diff-file)) + (with-current-buffer buf + (widen) + (let ((here (point))) + (goto-char (point-min)) + ;; Fix-me: Better pattern: + (if (search-forward "<<<<<<<" nil t) + ;; Merge conflict + (with-current-buffer log-buffer + (let ((inhibit-read-only t)) + (setq udev-last-error "Error: merge conflict"))) + (goto-char here)))) + buf)) + +;;(setq compilation-scroll-output t) +;;(add-to-list 'compilation-error-regexp-alist 'cvs) +;;(setq compilation-error-regexp-alist (delq 'cvs compilation-error-regexp-alist)) + +;;; Misc + +(defun udev-send-buffer-process (str) + (interactive "sString to send to process: ") + (let* ((procs (process-list)) + (proc (catch 'found + (dolist (p procs) + (when (eq (process-buffer p) (current-buffer)) + (throw 'found p)))))) + (unless proc (error "Can't find process in buffer")) + ;;(message "str=%s" str) + ;;(message "proc=%s" proc) + (process-send-string proc (concat str "\n")) + )) + + +(provide 'udev) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; udev.el ends here diff --git a/emacs/nxhtml/util/useful-commands.el b/emacs/nxhtml/util/useful-commands.el new file mode 100644 index 0000000..414d2f7 --- /dev/null +++ b/emacs/nxhtml/util/useful-commands.el @@ -0,0 +1,63 @@ +;;; useful-commands.el --- Menu with useful Emacs commands +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-09-29T12:56:24+0200 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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: + +(defvar useful-commands-definitions nil + "Defines the menus using a org like syntax. +* Search and Replace +** Occur in multiple buffers `multi-occur' +** Grep in Directory `lgrep' +** Occur `occur' +** Grep in Directory Tree `rgrep' +* END +" +) + +(defun useful-commands-build-menu () + ) + +(provide 'useful-commands) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; useful-commands.el ends here diff --git a/emacs/nxhtml/util/viper-tut.el b/emacs/nxhtml/util/viper-tut.el new file mode 100644 index 0000000..a941045 --- /dev/null +++ b/emacs/nxhtml/util/viper-tut.el @@ -0,0 +1,1009 @@ +;;; viper-tut.el --- Viper tutorial +;; +;; Author: Lennart Borgman +;; Created: Fri Sep 08 2006 +(defconst viper-tut:version "0.2") ;;Version: 0.2 +;; Last-Updated: +;; Keywords: +;; Compatibility: Emacs 22 +;; +;; Features that might be required by this library: +;; +;; `button', `cus-edit', `cus-face', `cus-load', `cus-start', +;; `help-mode', `tutorial', `view', `wid-edit'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'mumamo)) +(eval-when-compile (require 'ourcomments-util)) +(require 'tutorial) +(require 'cus-edit) + +(defface viper-tut-header-top + '((t (:foreground "black" :background "goldenrod3"))) + "Face for headers." + :group 'web-vcs) + +(defface viper-tut-header + '((t (:foreground "black" :background "goldenrod2" :height 1.8))) + "Face for headers." + :group 'web-vcs) + +(defvar tutorial--tab-map + (let ((map (make-sparse-keymap))) + (define-key map [tab] 'forward-button) + (define-key map [(shift tab)] 'backward-button) + (define-key map [(meta tab)] 'backward-button) + map) + "Keymap that allows tabbing between buttons.") + +(defconst viper-tut--emacs-part 6) + +(defconst viper-tut--default-keys + `( +;;;;;;;;;;;;;; Part 1 + ;; ^D Move DOWN one half-screen + ;;(viper-scroll-up [(control ?d)]) + (viper-scroll-up [?\C-d]) + + ;; ^U Move UP one half-screen + ;;(viper-scroll-down [(control ?u)]) + (viper-scroll-down [?\C-u]) + + ;; h Move left one character + (viper-backward-char [?h]) + + ;; j Move down one line + (viper-next-line [?j]) + + ;; k Move up one line + (viper-previous-line [?k]) + + ;; l Move right one character + (viper-forward-char [?l]) + + ;; dd DELETE one line + (viper-command-argument [?d]) + + ;; x X-OUT one character + (viper-delete-char [?x]) + + ;; u UNDO last change + (viper-undo [?u]) + + ;; :q!<RETURN> QUIT without saving changes + (viper-ex [?:]) + + ;; ZZ Exit and save any changes + (viper-save-kill-buffer [?Z ?Z]) + + ;; o OPEN a line for inserting text + (viper-open-line [?o]) + + ;; i INSERT starting at the cursor + (viper-insert [?i]) + + ;; ESC ESCAPE from insert mode + ;;(viper-intercept-ESC-key [(escape)]) + ;(viper-intercept-ESC-key [27]) + (viper-intercept-ESC-key [escape]) + ;; chagned-keys= + ;; (([27] + ;; viper-intercept-ESC-key + ;; viper-intercept-ESC-key + ;; <escape> + ;; (more info current-binding (keymap (118 . cua-repeat-replace-region)) viper-intercept-ESC-key [27] <escape>))) + + +;;;;;;;;;;;;;; Part 2 + ;; w Move to the beginning of the next WORD + (viper-forward-word [?w]) + ;; e Move to the END of the next word + (viper-end-of-word [?e]) + ;; b Move BACK to the beginning to the previous word + (viper-backward-word [?b]) + + ;; $ Move to the end of the line + (viper-goto-eol [?$]) + + ;; ^ Move to the first non-white character on the line + (viper-bol-and-skip-white [?^]) + + ;; 0 Move to the first column on the line (column zero) + (viper-beginning-of-line [?0]) + ;; #| Move to an exact column on the line (column #) e.g. 5| 12| + (viper-goto-col [?|]) + + ;; f char FIND the next occurrence of char on the line + (viper-find-char-forward [?f]) + ;; t char Move 'TIL the next occurrence of char on the line + (viper-goto-char-forward [?t]) + + ;; F char FIND the previous occurrence of char on the line + (viper-find-char-backward [?F]) + ;; T char Move 'TIL the previous occurrence of char on the line + (viper-goto-char-backward [?T]) + + ;; ; Repeat the last f, t, F, or T + (viper-repeat-find [?\;]) + ;; , Reverse the last f, t, F, or T + (viper-repeat-find-opposite [?,]) + + ;; % Show matching () or {} or [] + (viper-exec-mapped-kbd-macro [?%]) + + ;; H Move to the HIGHEST position in the window + (viper-window-top [?H]) + ;; M Move to the MIDDLE position in the window + (viper-window-middle [?M]) + ;; L Move to the LOWEST position in the window + (viper-window-bottom [?L]) + + ;; m char MARK this location and name it char + (viper-mark-point [?m]) + ;; ' char (quote character) return to line named char + ;; '' (quote quote) return from last movement + (viper-goto-mark-and-skip-white [?']) + + ;; G GO to the last line in the file + ;; #G GO to line #. (e.g., 3G , 5G , 175G ) + (viper-goto-line [?G]) + + ;; { (left brace) Move to the beginning of a paragraph + ;; } (right brace) Move to the end of a paragraph + (viper-backward-paragraph [?{]) + (viper-forward-paragraph [?}]) + + ;; ( (left paren) Move to the beginning of a sentence + ;; ) (right paren) Move to the beginning of the next sentence + (viper-backward-sentence [?\(]) + (viper-forward-sentence [?\)]) + + ;; [[ Move to the beginning of a section + ;; ]] Move to the end of a section + (viper-brac-function [?\[]) + (viper-ket-function [?\]]) + + ;; /string Find string looking forward + (viper-exec-mapped-kbd-macro [?/]) + ;; ?string Find string looking backward + (viper-search-backward [??]) + + ;; n Repeat last / or ? command + ;; N Reverse last / or ? command + (viper-search-next [?n]) + (viper-search-Next [?N]) + + +;;;;;;;;;;;;;; Part 3 + + ;; #movement repeat movement # times + (viper-digit-argument [?1]) + (viper-digit-argument [?2]) + (viper-digit-argument [?3]) + (viper-digit-argument [?4]) + (viper-digit-argument [?5]) + (viper-digit-argument [?6]) + (viper-digit-argument [?7]) + (viper-digit-argument [?8]) + (viper-digit-argument [?9]) + + ;; dmovement DELETE to where "movement" command specifies + ;; d#movement DELETE to where the #movement command specifies + ;; d runs the command viper-command-argument + + ;; ymovement YANK to where "movement" command specifies + ;; y#movement YANK to where the #movement command specifies + (viper-command-argument [?y]) + + ;; P (upper p) PUT the contents of the buffer before the cursor + ;; p (lower p) PUT the contents of the buffer after the cursor + (viper-put-back [?p]) + (viper-Put-back [?P]) + + ;; "#P (upper p) PUT contents of buffer # before the cursor + ;; "#p (lower p) PUT contents of buffer # after the cursor + ;; + ;; "aDELETE DELETE text into buffer a + ;; "aYANK YANK text into buffer a + ;; "aPUT PUT text from named buffer a + (viper-command-argument [?\"]) + + ;; :w<RETURN> WRITE contents of the file (without quitting) + + ;; :e filename<RETURN> Begin EDITing the file called "filename" + + + +;;;;;;;;;;;;;; Part 4 + + + ;; o OPEN a line below the cursor + ;; O OPEN a line above the cursor + (viper-open-line [?o]) + (viper-Open-line [?O]) + + ;; i INSERT starting before the cursor + ;; I INSERT at the beginning of the line + (viper-insert [?i]) + (viper-Insert [?I]) + + ;; a APPEND starting after the cursor + ;; A APPEND at the end of the line + (viper-append [?a]) + (viper-Append [?A]) + + ;; ESC ESCAPE from insert mode + (viper-intercept-ESC-key [(escape)]) + + ;; J JOIN two lines + (viper-join-lines [?J]) + + ;; #s SUBSTITUTE for # characters + ;; #S SUBSTITUTE for # whole lines + (viper-substitute [?s]) + (viper-substitute-line [?S]) + + ;; r REPLACE character (NO need to press ESC) + ;; R enter over-type mode + (viper-replace-char [?r]) + (viper-overwrite [?R]) + + ;; cmovement CHANGE to where the movement commands specifies + (viper-command-argument [?c]) + + +;;;;;;;;;;;;;; Part 5 + + ;; ~ (tilde) Convert case of current character + (viper-toggle-case [?~]) + ;; U (upper u) UNDO all changes made to the current line + ;; not implemented + ;;(viper-undo [?U]) + + ;; . (dot) repeat last change + (viper-repeat [?.]) + + ;; ^F Move FORWARD one full-screen + ;; ^B Move BACKWARD one full-screen + ;;(viper-scroll-screen [(control ?f)]) + (viper-scroll-screen [?\C-f]) + ;;(viper-scroll-screen-back [(control ?b)]) + (viper-scroll-screen-back [?\C-b]) + + ;; ^E Move the window down one line without moving cursor + ;; ^Y Move the window up one line without moving cursor + ;;(viper-scroll-up-one [(control ?e)]) + (viper-scroll-up-one [?\C-e]) + ;;(viper-scroll-down-one [(control ?y)]) + (viper-scroll-down-one [?\C-y]) + + ;; z<RETURN> Position the current line to top of window + ;; z. Position the current line to middle of window + ;; z- Position the current line to bottom of window + (viper-line-to-top "z\C-m") + (viper-line-to-middle [?z ?.]) + (viper-line-to-bottom [?z ?-]) + + ;; ^G Show status of current file + ;;(viper-info-on-file [(control ?c)(control ?g)]) + (viper-info-on-file [?\C-c ?\C-g]) + ;; ^L Refresh screen + ;;(recenter [(control ?l)]) + (recenter-top-bottom [?\C-l]) + + ;; !}fmt Format the paragraph, joining and filling lines to + ;; !}sort Sort lines of a paragraph alphabetically + (viper-command-argument [?!]) + + ;; >movement Shift right to where the movement command specifies + ;; <movement Shift left to where the movement command specifies + (viper-command-argument [?>]) + (viper-command-argument [?<]) + + )) + +(defun viper-tut--detailed-help (button) + "Give detailed help about changed keys." + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'viper-tut--detailed-help button) + (interactive-p)) + (with-current-buffer (help-buffer) + (let* ((tutorial-buffer (button-get button 'tutorial-buffer)) + ;;(tutorial-arg (button-get button 'tutorial-arg)) + (explain-key-desc (button-get button 'explain-key-desc)) + (part (button-get button 'part)) + (changed-keys (with-current-buffer tutorial-buffer + (let ((tutorial--lang "English")) + (tutorial--find-changed-keys + (if (= part viper-tut--emacs-part) + tutorial--default-keys + viper-tut--default-keys)))))) + (when changed-keys + (insert + "The following key bindings used in the tutorial had been changed\n" + (if (= part viper-tut--emacs-part) + "from Emacs default in the " + "from Viper default in the ") + (buffer-name tutorial-buffer) " buffer:\n\n" ) + (let ((frm " %-9s %-27s %-11s %s\n")) + (insert (format frm "Key" "Standard Binding" "Is Now On" "Remark"))) + (dolist (tk changed-keys) + (let* ((def-fun (nth 1 tk)) + (key (nth 0 tk)) + (def-fun-txt (nth 2 tk)) + (where (nth 3 tk)) + (remark (nth 4 tk)) + (rem-fun (command-remapping def-fun)) + (key-txt (key-description key)) + (key-fun (with-current-buffer tutorial-buffer (key-binding key))) + tot-len) + (unless (eq def-fun key-fun) + ;; Insert key binding description: + (when (string= key-txt explain-key-desc) + (put-text-property 0 (length key-txt) 'face '(:background "yellow") key-txt)) + (insert " " key-txt " ") + (setq tot-len (length key-txt)) + (when (> 9 tot-len) + (insert (make-string (- 9 tot-len) ? )) + (setq tot-len 9)) + ;; Insert a link describing the old binding: + (insert-button def-fun-txt + 'help-echo (format "Describe function '%s" def-fun-txt) + 'action `(lambda(button) (interactive) + (describe-function ',def-fun)) + 'follow-link t) + (setq tot-len (+ tot-len (length def-fun-txt))) + (when (> 36 tot-len) + (insert (make-string (- 36 tot-len) ? ))) + (when (listp where) + (setq where "list")) + ;; Tell where the old binding is now: + (insert (format " %-11s " where)) + ;; Insert a link with more information, for example + ;; current binding and keymap or information about + ;; cua-mode replacements: + (insert-button (car remark) + 'help-echo "Give more information about the changed key binding" + 'action `(lambda(b) (interactive) + (let ((value ,(cdr remark))) + ;; Fix-me: + (tutorial--describe-nonstandard-key value))) + 'follow-link t) + (insert "\n"))))) + + + + (insert " +It is legitimate to change key bindings, but changed bindings do not +correspond to what the tutorial says. +\(See also " ) + (insert-button "Key Binding Conventions" + 'action + (lambda(button) (interactive) + (info + "(elisp) Key Binding Conventions") + (message "Type C-x 0 to close the new window")) + 'follow-link t) + (insert ".)\n\n") + (with-no-warnings (print-help-return-message)))))) + + +(defvar viper-tut--part nil + "Viper tutorial part.") +(make-variable-buffer-local 'viper-tut--part) + +(defun viper-tut--saved-file () + "File name in which to save tutorials." + (let* ((file-name + (file-name-nondirectory (viper-tut--file viper-tut--part))) + (ext (file-name-extension file-name))) + (when (or (not ext) + (string= ext "")) + (setq file-name (concat file-name ".tut"))) + (expand-file-name file-name (tutorial--saved-dir)))) + +(defun viper-tut--save-tutorial () + "Save the tutorial buffer. +This saves the part of the tutorial before and after the area +showing changed keys. It also saves point position and the +position where the display of changed bindings was inserted. + +Do not save anything if not `viper-mode' is enabled in the +tutorial buffer." + ;; This runs in a hook so protect it: + (condition-case err + (when (boundp 'viper-mode-string) + (tutorial--save-tutorial-to (viper-tut--saved-file))) + (error (warn "Error saving tutorial state: %s" (error-message-string err))))) + + +(defvar viper-tut--parts + '( + (0 "0intro" "Introduction") + (1 "1basics" "Basic Editing") + (2 "2moving" "Moving Efficiently") + (3 "3cutpaste" "Cutting and Pasting") + (4 "4inserting" "Inserting Techniques") + (5 "5tricks" "Tricks and Timesavers") + (6 "(no file)" "Emacs tutorial for Viper Users") + )) + +(defcustom viper-tut-directory + (let* ((this-file (if load-file-name + load-file-name + (buffer-file-name))) + (this-dir (file-name-directory this-file))) + (file-name-as-directory + (expand-file-name "../etc/viper-tut" this-dir))) + "Directory where the Viper tutorial files lives." + :type 'directory + :group 'viper) + +(defun viper-tut--file(part) + "Get file name for part." + (let ((tut-file)) + (mapc (lambda(rec) + (when (= part (nth 0 rec)) + (setq tut-file + (if (= part viper-tut--emacs-part) + (let ((tf (expand-file-name (get-language-info "English" 'tutorial) tutorial-directory))) + (unless (file-exists-p tf) + (error "Can't find the English tutorial file for Emacs: %S" tf)) + tf) + (expand-file-name (nth 1 rec) viper-tut-directory))))) + viper-tut--parts) + tut-file)) + +(defun viper-tut-viper-is-on () + ;;(message "viper-tut-viper-is-on, vms=%s, cb=%s" (boundp 'viper-mode-string) (current-buffer)) + ;;(boundp 'viper-mode-string) + (boundp 'viper-current-state)) + +(defun viper-tut--display-changes (changed-keys part) + "Display changes to some default Viper key bindings. +If some of the default key bindings that the Viper tutorial +depends on have been changed then display the changes in the +tutorial buffer with some explanatory links. + +CHANGED-KEYS should be a list in the format returned by +`tutorial--find-changed-keys'." + (when (or changed-keys + (viper-tut-viper-is-on)) + ;; Need the custom button face for viper buttons: + ;;(when (and (boundp 'viper-mode) viper-mode) (require 'cus-edit)) + (goto-char tutorial--point-before-chkeys) + (let* ((start (point)) + end + (head + (if (viper-tut-viper-is-on) + (if (= part viper-tut--emacs-part) + " + NOTICE: This part of the Viper tutorial runs the Emacs tutorial. + Several keybindings are changed from Emacs default (either + because of Viper or some other customization) and doesn't + correspond to the tutorial. + + We have inserted colored notices where the altered commands have + been introduced. If you change Viper state (vi state, insert + state, etc) these notices will be changed to reflect the new + state. [" + " + NOTICE: The main purpose of the Viper tutorial is to teach you + the most important vi commands (key bindings). However, your + Emacs has been customized by changing some of these basic Viper + editing commands, so it doesn't correspond to the tutorial. We + have inserted colored notices where the altered commands have + been introduced. [") + " + NOTICE: You have currently not turned on Viper. Nothing in this + tutorial \(the Viper Tutorial\) will work unless you do that. [" + )) + (head2 (if (viper-tut-viper-is-on) + (get-lang-string tutorial--lang 'tut-chgdhead2) + "More information"))) + (when (and head head2) + (insert head) + (insert-button head2 + 'tutorial-buffer + (current-buffer) + ;;'tutorial-arg arg + 'part part + 'action + (if (viper-tut-viper-is-on) + 'viper-tut--detailed-help + 'go-home-blaha) + 'follow-link t + 'echo "Click for more information" + 'face '(:inherit link :background "yellow")) + (insert "]\n\n" ) + (when changed-keys + (dolist (tk changed-keys) + (let* ((def-fun (nth 1 tk)) + (key (nth 0 tk)) + (def-fun-txt (nth 2 tk)) + (where (nth 3 tk)) + (remark (nth 4 tk)) + (rem-fun (command-remapping def-fun)) + (key-txt (key-description key)) + (key-fun (key-binding key)) + tot-len) + (unless (eq def-fun key-fun) + ;; Mark the key in the tutorial text + (unless (string= "Same key" where) + (let* ((here (point)) + (key-desc (key-description key)) + (vi-char (= 1 (length key-desc))) + vi-char-pos + hit) + (when (string= "RET" key-desc) + (setq key-desc "Return")) + (when (string= "DEL" key-desc) + (setq key-desc "Delback")) + (while (if (not vi-char) + (unless hit ;; Only tell once + (setq hit t) + (re-search-forward + (concat "[^[:alpha:]]\\(" + (regexp-quote key-desc) + "\\)[^[:alpha:]]") nil t)) + (setq vi-char-pos + (next-single-property-change + (point) 'vi-char))) + (if (not vi-char) + (put-text-property (match-beginning 0) + (match-end 0) + 'tutorial-remark nil) ;;'only-colored) + (put-text-property (match-beginning 0) + (match-end 0) + 'face '(:background "yellow")) + (goto-char (1+ vi-char-pos)) + (setq hit (string= key-desc (char-to-string (char-before)))) + (when hit + (put-text-property vi-char-pos (1+ vi-char-pos) + 'face '(:background "yellow")))) + (when hit + (forward-line) + (let ((s (get-lang-string tutorial--lang 'tut-chgdkey)) + (s2 (get-lang-string tutorial--lang 'tut-chgdkey2)) + (start (point)) + end) + ;; key-desc " has been rebound, but you can use " where " instead [")) + (when (and s s2) + (when (or (not where) (= 0 (length where))) + (setq where (concat "`M-x " def-fun-txt "'"))) + (setq s (format s key-desc where s2)) + (insert s " [") + (insert-button s2 + 'tutorial-buffer + (current-buffer) + ;;'tutorial-arg arg + 'part part + 'action + 'viper-tut--detailed-help + 'explain-key-desc key-desc + 'follow-link t + 'face '(:inherit link :background "yellow")) + (insert "] **") + (insert "\n") + (setq end (point)) + (put-text-property start end 'local-map tutorial--tab-map) + (put-text-property start end 'tutorial-remark t) + (put-text-property start end + 'face '(:background "yellow" :foreground "#c00")) + (put-text-property start end 'read-only t))))) + (goto-char here))))))) + + + (setq end (point)) + ;; Make the area with information about change key + ;; bindings stand out: + (put-text-property start end + 'face + ;; The default warning face does not + ;;look good in this situation. Instead + ;;try something that could be + ;;recognized from warnings in normal + ;;life: + ;; 'font-lock-warning-face + (list :background "yellow" :foreground "#c00")) + ;; Make it possible to use Tab/S-Tab between fields in + ;; this area: + (put-text-property start end 'local-map tutorial--tab-map) + (put-text-property start end 'tutorial-remark t) + (setq tutorial--point-after-chkeys (point-marker)) + ;; Make this area read-only: + (put-text-property start end 'read-only t))))) + +(defun viper-tut--at-change-state() + (condition-case err + (progn + (let ((inhibit-read-only t) + (here (point))) + ;; Delete the remarks: + ;;(tutorial--remove-remarks) + ;; Add them again + ;;(viper-tut--add-remarks) + (goto-char here) + ) + ) + (error (message "error in viper-tut--at-change-state: %s" (error-message-string err))))) + + +;;;###autoload +(defun viper-tutorial(part &optional dont-ask-for-revert) + "Run a tutorial for Viper. + +A simple classic tutorial in 5 parts that have been used by many +people starting to learn vi keys. You may learn enough to start +using `viper-mode' in Emacs. + +Some people find that vi keys helps against repetetive strain +injury, see URL + + `http://www.emacswiki.org/emacs/RepeatedStrainInjury'. + +Note: There might be a few clashes between vi key binding and +Emacs standard key bindings. You will be notified about those in +the tutorial. Even more, if your own key bindings comes in +between you will be notified about that too." + (interactive (list + ;; (condition-case nil + ;; (widget-choose "The following viper tutorials are available" + ;; (mapcar (lambda(rec) + ;; (cons (nth 2 rec) (nth 0 rec))) + ;; viper-tut--parts)) + ;; (error nil)) + 0 + )) + (if (not (boundp 'viper-current-state)) + (let ((prompt + " + You can not run the Viper tutorial in this Emacs because you + have not enabled Viper. + + Do you want to run the Viper tutorial in a new Emacs? ")) + (if (y-or-n-p prompt) + (let ((ret (funcall 'emacs--no-desktop + "-eval" + (concat + "(progn" + " (setq viper-mode t)" + " (require 'viper)" + " (require 'viper-tut)" + " (call-interactively 'viper-tutorial))")))) + (message "Starting Viper tutorial in a new Emacs")) + (message "Viper tutorial aborted by user"))) + + (let* ((filename (viper-tut--file part)) + ;; Choose a buffer name including the language so that + ;; several languages can be tested simultaneously: + (tut-buf-name "Viper TUTORIAL") + (old-tut-buf (get-buffer tut-buf-name)) + (old-tut-part (when old-tut-buf + (with-current-buffer old-tut-buf + viper-tut--part))) + (old-tut-win (when old-tut-buf (get-buffer-window old-tut-buf t))) + (old-tut-is-ok (when old-tut-buf + (and + (= part old-tut-part) + (not (buffer-modified-p old-tut-buf))))) + old-tut-file + (old-tut-point 1)) + (unless (file-exists-p filename) (error "Can't fine %s" filename)) + (setq tutorial--point-after-chkeys (point-min)) + ;; Try to display the tutorial buffer before asking to revert it. + ;; If the tutorial buffer is shown in some window make sure it is + ;; selected and displayed: + (if old-tut-win + (raise-frame + (window-frame + (select-window (get-buffer-window old-tut-buf t)))) + ;; Else, is there an old tutorial buffer? Then display it: + (when old-tut-buf + (switch-to-buffer old-tut-buf))) + ;; Use whole frame for tutorial + ;;(delete-other-windows) + ;; If the tutorial buffer has been changed then ask if it should + ;; be reverted: + (when (and old-tut-buf + (not old-tut-is-ok) + (= part old-tut-part)) + (setq old-tut-is-ok + (if dont-ask-for-revert + nil + (not (y-or-n-p + "You have changed the Tutorial buffer. Revert it? "))))) + ;; (Re)build the tutorial buffer if it is not ok + (unless old-tut-is-ok + (switch-to-buffer (get-buffer-create tut-buf-name)) + (unless old-tut-buf (text-mode)) + (setq viper-tut--part part) + (setq old-tut-file (file-exists-p (viper-tut--saved-file))) + (when (= part 0) (setq old-tut-file nil)) ;; You do not edit in the intro + (setq buffer-read-only nil) + (let ((inhibit-read-only t)) ;; For the text property + (erase-buffer)) + (message "Preparing Viper tutorial ...") (sit-for 0) + + ;; Do not associate the tutorial buffer with a file. Instead use + ;; a hook to save it when the buffer is killed. + (setq buffer-auto-save-file-name nil) + (add-hook 'kill-buffer-hook 'viper-tut--save-tutorial nil t) + + ;; Insert the tutorial. First offer to resume last tutorial + ;; editing session. + (when dont-ask-for-revert + (setq old-tut-file nil)) + (when old-tut-file + (setq old-tut-file + (y-or-n-p + (format + "Resume your last saved Viper tutorial part %s? " + part)))) + (if old-tut-file + (progn + (insert-file-contents (viper-tut--saved-file)) + (goto-char (point-min)) + (setq old-tut-point + (string-to-number + (buffer-substring-no-properties + (line-beginning-position) (line-end-position)))) + (forward-line) + (setq tutorial--point-before-chkeys + (string-to-number + (buffer-substring-no-properties + (line-beginning-position) (line-end-position)))) + (forward-line) + (delete-region (point-min) (point)) + (goto-char tutorial--point-before-chkeys) + (setq tutorial--point-before-chkeys (point-marker))) + ;;(insert-file-contents (expand-file-name filename data-directory)) + (insert-file-contents filename) + (viper-tut--replace-links) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "'\\([][+a-zA-Z~<>!;,:.'\"%/?(){}$^0|-]\\)'" nil t) + (let ((matched-char (match-string 1)) + (inhibit-read-only t)) + (put-text-property 0 1 'vi-char t matched-char) + (put-text-property 0 1 'face '(:foreground "blue") matched-char) + (replace-match matched-char)))) + (forward-line) + (setq tutorial--point-before-chkeys (point-marker))) + + (viper-tut--add-remarks) + + (goto-char (point-min)) + (when old-tut-file + ;; Just move to old point in saved tutorial. + (let ((old-point + (if (> 0 old-tut-point) + (- old-tut-point) + (+ old-tut-point tutorial--point-after-chkeys)))) + (when (< old-point 1) + (setq old-point 1)) + (goto-char old-point))) + + (viper-tut-fix-header-and-footer) + + ;; Clear message: + (message "") (sit-for 0) + + (setq buffer-undo-list nil) + (set-buffer-modified-p nil)) + (setq buffer-read-only (= 0 part))))) + +;;(tutorial--find-changed-keys '((scroll-up [?\C-v]))) +(defun viper-tut--add-remarks() + ;; Check if there are key bindings that may disturb the + ;; tutorial. If so tell the user. + (let* ((tutorial--lang "English") + (changed-keys + (if (= viper-tut--part viper-tut--emacs-part) + (tutorial--find-changed-keys tutorial--default-keys) + (tutorial--find-changed-keys viper-tut--default-keys)))) + (viper-tut--display-changes changed-keys viper-tut--part)) + + (if (= viper-tut--part viper-tut--emacs-part) + (progn + (add-hook 'viper-vi-state-hook 'viper-tut--at-change-state nil t) + (add-hook 'viper-insert-state-hook 'viper-tut--at-change-state nil t) + (add-hook 'viper-replace-state-hook 'viper-tut--at-change-state nil t) + (add-hook 'viper-emacs-state-hook 'viper-tut--at-change-state nil t) + ) + (remove-hook 'viper-vi-state-hook 'viper-tut--at-change-state t) + (remove-hook 'viper-insert-statehook 'viper-tut--at-change-state t) + (remove-hook 'viper-replace-state-hook 'viper-tut--at-change-state t) + (remove-hook 'viper-emacs-state-hook 'viper-tut--at-change-state t) + )) + +(defun viper-tut-fix-header-and-footer () + (save-excursion + (goto-char (point-min)) + (add-text-properties (point) (1+ (line-end-position)) + '( read-only t face viper-tut-header)) + (goto-char (point-min)) + (viper-tut--insert-goto-row nil) + (goto-char (point-max)) + (viper-tut--insert-goto-row t))) + +(defun viper-tut--insert-goto-row(last) + (let ((start (point)) + end) + (insert " Go to part: ") + (dolist (rec viper-tut--parts) + (let ((n (nth 0 rec)) + (file (nth 1 rec)) + (title (nth 2 rec))) + (if (= n viper-tut--part) + (insert (format "%s" n)) + (insert-button (format "%s" n) + 'help-echo (concat "Go to part: " title) + 'follow-link t + 'action + `(lambda (button) + (viper-tutorial ,n t)))) + (insert " "))) + (insert " ") + (insert-button "Exit Tutorial" + 'help-echo "Exit tutorial and close tutorial buffer" + 'follow-link t + 'action + (lambda (button) + (kill-buffer (current-buffer)))) + (unless last (insert "\n")) + (setq end (point)) + (put-text-property start end 'local-map tutorial--tab-map) + (put-text-property start end 'tutorial-remark t) + (put-text-property start end + 'face 'viper-tut-header-top) + (put-text-property start end 'read-only t))) + +(defun viper-tut--replace-links() + "Replace markers for links with actual links." + (let ((re-links (regexp-opt '("VIPER-MANUAL" + "README-FILE" + "DIGIT-ARGUMENT" + "KILL-BUFFER" + "ISEARCH-FORWARD" + "UNIVERSAL-ARGUMENT" + "SEARCH-COMMANDS" + "R-AND-R" + "CUA-MODE" + "KEYBOARD-MACROS" + "VIPER-TOGGLE-KEY" + "* EMACS-NOTICE:"))) + (case-fold-search nil) + (inhibit-read-only t)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward re-links nil t) + (let ((matched (match-string 0)) + start + end) + (replace-match "") + (setq start (point)) + (cond + ((string= matched "VIPER-TOGGLE-KEY") + (insert-button "viper-toggle-key" + 'action + (lambda(button) (interactive) + (describe-variable 'viper-toggle-key)) + 'follow-link t)) + ((string= matched "CUA-MODE") + (insert-button "cua-mode" + 'action + (lambda(button) (interactive) + (describe-function 'cua-mode)) + 'follow-link t)) + ((string= matched "ISEARCH-FORWARD") + (insert-button "isearch-forward" + 'action + (lambda(button) (interactive) + (describe-function 'isearch-forward)) + 'follow-link t)) + ((string= matched "KILL-BUFFER") + (insert-button "kill-buffer" + 'action + (lambda(button) (interactive) + (describe-function 'kill-buffer)) + 'follow-link t)) + ((string= matched "UNIVERSAL-ARGUMENT") + (insert-button "universal-argument" + 'action + (lambda(button) (interactive) + (describe-function 'universal-argument)) + 'follow-link t)) + ((string= matched "DIGIT-ARGUMENT") + (insert-button "digit-argument" + 'action + (lambda(button) (interactive) + (describe-function 'digit-argument)) + 'follow-link t)) + ((string= matched "* EMACS-NOTICE:") + (insert "* Emacs NOTICE:") + (while (progn + (forward-line 1) + (not (looking-at "^$")))) + (put-text-property start (point) + 'face '(:background + "#ffe4b5" + :foreground "#999999")) + (put-text-property start (point) 'read-only t) + ) + ((string= matched "SEARCH-COMMANDS") + (insert-button "search commands" + 'action + (lambda(button) (interactive) + (info-other-window "(emacs) Search") + (message "Type C-x 0 to close the new window")) + 'follow-link t)) + ((string= matched "KEYBOARD-MACROS") + (insert-button "keyboard macros" + 'action + (lambda(button) (interactive) + (info-other-window "(emacs) Keyboard Macros") + (message "Type C-x 0 to close the new window")) + 'follow-link t)) + ((string= matched "VIPER-MANUAL") + (insert-button "Viper manual" + 'action + (lambda(button) (interactive) + (info-other-window "(viper)") + (message "Type C-x 0 to close the new window")) + 'follow-link t)) + ((string= matched "R-AND-R") + (insert-button "r and R" + 'action + (lambda(button) (interactive) + (info-other-window "(viper) Basics") + (message "Type C-x 0 to close the new window")) + 'follow-link t)) + ((string= matched "README-FILE") + (insert-button "README file" + 'action + (lambda(button) (interactive) + (find-file-other-window (expand-file-name "README" viper-tut-directory)) + (message "Type C-x 0 to close the new window")) + 'follow-link t)) + (t + (error "Unmatched text: %s" matched))) + (put-text-property start (point) 'tutorial-remark t) + (put-text-property start (point) 'tutorial-orig matched) + (put-text-property start (point) 'local-map tutorial--tab-map) + (put-text-property start (point) 'read-only t)))))) + +(provide 'viper-tut) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; viper-tut.el ends here diff --git a/emacs/nxhtml/util/vline.el b/emacs/nxhtml/util/vline.el new file mode 100644 index 0000000..62bc8dd --- /dev/null +++ b/emacs/nxhtml/util/vline.el @@ -0,0 +1,350 @@ +;;; vline.el --- show vertical line (column highlighting) mode. + +;; Copyright (C) 2002, 2008, 2009 by Taiki SUGAWARA <buzz.taiki@gmail.com> + +;; Author: Taiki SUGAWARA <buzz.taiki@gmail.com> +;; Keywords: faces, editing, emulating +;; Version: 1.09 +;; Time-stamp: <2009-10-12 16:55:13 UTC taiki> +;; URL: http://www.emacswiki.org/cgi-bin/wiki/vline.el + +;; 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. + +;;; Usage +;; put followings your .emacs +;; (require 'vline) +;; +;; if you display a vertical line, type M-x vline-mode. `vline-mode' doesn't +;; effect other buffers, because it is a buffer local minor mode. if you hide +;; a vertical line, type M-x vline-mode again. +;; +;; if you display a vertical line in all buffers, type M-x vline-global-mode. +;; +;; `vline-style' provides a display style of vertical line. see +;; `vline-style' docstring. +;; +;; if you don't want to visual line highlighting (ex. for performance issue), please to set `vline-visual' to nil. + +;;; Changes +;; 2009-08-26 taiki +;; support org-mode, outline-mode + +;; 2009-08-18 taiki +;; add autoload cookies. + +;; 2009-08-18 taiki +;; fix last line highlighting probrem. + +;; 2009-08-18 taiki +;; support visual line highlighting. +;; - Added face vline-visual. +;; - Added defcustom vline-visual-face. +;; - Added defcustom vline-visual. +;; +;; 2009-08-17 taiki +;; fix continuas line problem. +;; - Don't display vline when cursor into fringe +;; - Don't expand eol more than window width. +;; +;; 2008-10-22 taiki +;; fix coding-system problem. +;; - Added vline-multiwidth-space-list +;; - Use ucs code-point for japanese fullwidth space. +;; +;; 2008-01-22 taiki +;; applied patch from Lennart Borgman +;; - Added :group 'vline +;; - Added defcustom vline-current-window-only +;; - Added header items to simplify for users + +;;; TODO: +;; - track window-scroll-functions, window-size-change-functions. +;; - consider other minor modes (using {after,before}-string overlay). +;; - don't use {post,after}-command-hook for performance?? + +;;; Code: + +(defvar vline-overlay-table-size 200) +(defvar vline-overlay-table (make-vector vline-overlay-table-size nil)) +(defvar vline-line-char ?|) +(defvar vline-multiwidth-space-list + (list + ?\t + (decode-char 'ucs #x3000) ; japanese fullwidth space + )) + +(defcustom vline-style 'face + "*This variable holds vertical line display style. +Available values are followings: +`face' : use face. +`compose' : use composit char. +`mixed' : use face and composit char." + :type '(radio + (const face) + (const compose) + (const mixed)) + :group 'vline) + + +(defface vline + '((t (:background "light steel blue"))) + "*A default face for vertical line highlighting." + :group 'vline) + +(defface vline-visual + '((t (:background "gray90"))) + "*A default face for vertical line highlighting in visual lines." + :group 'vline) + +(defcustom vline-face 'vline + "*A face for vertical line highlighting." + :type 'face + :group 'vline) + +(defcustom vline-visual-face 'vline-visual + "*A face for vertical line highlighting in visual lines." + :type 'face + :group 'vline) + +(defcustom vline-current-window-only nil + "*If non-nil then show column in current window only. +If the buffer is shown in several windows then show column only +in the currently selected window." + :type 'boolean + :group 'vline) + +(defcustom vline-visual t + "*If non-nil then show column in visual lines. +If you specified `force' then use force visual line highlighting even +if `truncate-lines' is non-nil." + :type '(radio + (const nil) + (const t) + (const force)) + :group 'vline) + +;;;###autoload +(define-minor-mode vline-mode + "Display vertical line mode." + :global nil + :lighter " VL" + :group 'vline + (if vline-mode + (progn + (add-hook 'pre-command-hook 'vline-pre-command-hook nil t) + (add-hook 'post-command-hook 'vline-post-command-hook nil t)) + (vline-clear) + (remove-hook 'pre-command-hook 'vline-pre-command-hook t) + (remove-hook 'post-command-hook 'vline-post-command-hook t))) + +;;;###autoload +(define-minor-mode vline-global-mode + "Display vertical line mode as globally." + :global t + :lighter " VL" + :group 'vline + (if vline-global-mode + (progn + (add-hook 'pre-command-hook 'vline-global-pre-command-hook) + (add-hook 'post-command-hook 'vline-global-post-command-hook)) + (vline-clear) + (remove-hook 'pre-command-hook 'vline-global-pre-command-hook) + (remove-hook 'post-command-hook 'vline-global-post-command-hook))) + +(defun vline-pre-command-hook () + (when (and vline-mode (not (minibufferp))) + (vline-clear))) + +(defun vline-post-command-hook () + (when (and vline-mode (not (minibufferp))) + (vline-show))) + +(defun vline-global-pre-command-hook () + (when (and vline-global-mode (not (minibufferp))) + (vline-clear))) + +(defun vline-global-post-command-hook () + (when (and vline-global-mode (not (minibufferp))) + (vline-show))) + +(defun vline-clear () + (mapcar (lambda (ovr) + (and ovr (delete-overlay ovr))) + vline-overlay-table)) + +(defsubst vline-into-fringe-p () + (eq (nth 1 (posn-at-point)) 'right-fringe)) + +(defsubst vline-visual-p () + (or (eq vline-visual 'force) + (and (not truncate-lines) + vline-visual))) + +(defsubst vline-current-column () + (if (or (not (vline-visual-p)) + ;; margin for full-width char + (< (1+ (current-column)) (window-width))) + (current-column) + ;; hmm.. posn-at-point is not consider tab width. + (- (current-column) + (save-excursion + (vertical-motion 0) + (current-column))))) + +(defsubst vline-move-to-column (col &optional bol-p) + (if (or (not (vline-visual-p)) + ;; margin for full-width char + (< (1+ (current-column)) (window-width))) + (move-to-column col) + (unless bol-p + (vertical-motion 0)) + (let ((bol-col (current-column))) + (- (move-to-column (+ bol-col col)) + bol-col)))) + +(defsubst vline-forward (n) + (unless (memq n '(-1 0 1)) + (error "n(%s) must be 0 or 1" n)) + (if (not (vline-visual-p)) + (progn + (forward-line n) + ;; take care of org-mode, outline-mode + (when (and (not (bobp)) + (invisible-p (1- (point)))) + (goto-char (1- (point)))) + (when (invisible-p (point)) + (if (< n 0) + (while (and (not (bobp)) (invisible-p (point))) + (goto-char (previous-char-property-change (point)))) + (while (and (not (bobp)) (invisible-p (point))) + (goto-char (next-char-property-change (point)))) + (forward-line 1)))) + (vertical-motion n))) + +(defun vline-face (visual-p) + (if visual-p + vline-visual-face + vline-face)) + +(defun vline-show (&optional point) + (vline-clear) + (save-window-excursion + (save-excursion + (if point + (goto-char point) + (setq point (point))) + (let* ((column (vline-current-column)) + (lcolumn (current-column)) + (i 0) + (compose-p (memq vline-style '(compose mixed))) + (face-p (memq vline-style '(face mixed))) + (line-char (if compose-p vline-line-char ? )) + (line-str (make-string 1 line-char)) + (visual-line-str line-str) + (in-fringe-p (vline-into-fringe-p))) + (when face-p + (setq line-str (propertize line-str 'face (vline-face nil))) + (setq visual-line-str (propertize visual-line-str 'face (vline-face t)))) + (goto-char (window-end nil t)) + (vline-forward 0) + (while (and (not in-fringe-p) + (< i (window-height)) + (< i (length vline-overlay-table)) + (not (bobp))) + (let ((cur-column (vline-move-to-column column t)) + (cur-lcolumn (current-column))) + ;; non-cursor line only (workaround of eol probrem. + (unless (= (point) point) + ;; if column over the cursor's column (when tab or wide char is appered. + (when (> cur-column column) + (let ((lcol (current-column))) + (backward-char) + (setq cur-column (- cur-column (- lcol (current-column)))))) + (let* ((ovr (aref vline-overlay-table i)) + (visual-p (or (< lcolumn (current-column)) + (> lcolumn (+ (current-column) + (- column cur-column))))) + ;; consider a newline, tab and wide char. + (str (concat (make-string (- column cur-column) ? ) + (if visual-p visual-line-str line-str))) + (char (char-after))) + ;; create overlay if not found. + (unless ovr + (setq ovr (make-overlay 0 0)) + (overlay-put ovr 'rear-nonsticky t) + (aset vline-overlay-table i ovr)) + + ;; initialize overlay. + (overlay-put ovr 'face nil) + (overlay-put ovr 'before-string nil) + (overlay-put ovr 'after-string nil) + (overlay-put ovr 'invisible nil) + (overlay-put ovr 'window + (if vline-current-window-only + (selected-window) + nil)) + + (cond + ;; multiwidth space + ((memq char vline-multiwidth-space-list) + (setq str + (concat str + (make-string (- (save-excursion (forward-char) + (current-column)) + (current-column) + (string-width str)) + ? ))) + (move-overlay ovr (point) (1+ (point))) + (overlay-put ovr 'invisible t) + (overlay-put ovr 'after-string str)) + ;; eol + ((eolp) + (move-overlay ovr (point) (point)) + (overlay-put ovr 'after-string str) + ;; don't expand eol more than window width + (when (and (not truncate-lines) + (>= (1+ column) (window-width)) + (>= column (vline-current-column)) + (not (vline-into-fringe-p))) + (delete-overlay ovr))) + (t + (cond + (compose-p + (let (str) + (when char + (setq str (compose-chars + char + (cond ((= (char-width char) 1) + '(tc . tc)) + ((= cur-column column) + '(tc . tr)) + (t + '(tc . tl))) + line-char)) + (when face-p + (setq str (propertize str 'face (vline-face visual-p)))) + (move-overlay ovr (point) (1+ (point))) + (overlay-put ovr 'invisible t) + (overlay-put ovr 'after-string str)))) + (face-p + (move-overlay ovr (point) (1+ (point))) + (overlay-put ovr 'face (vline-face visual-p)))))))) + (setq i (1+ i)) + (vline-forward -1))))))) + +(provide 'vline) + +;;; vline.el ends here diff --git a/emacs/nxhtml/util/web-vcs-revision.txt b/emacs/nxhtml/util/web-vcs-revision.txt new file mode 100644 index 0000000..27943c8 --- /dev/null +++ b/emacs/nxhtml/util/web-vcs-revision.txt @@ -0,0 +1 @@ +321 diff --git a/emacs/nxhtml/util/whelp.el b/emacs/nxhtml/util/whelp.el new file mode 100644 index 0000000..77b8149 --- /dev/null +++ b/emacs/nxhtml/util/whelp.el @@ -0,0 +1,988 @@ +;; This is a test file for some enhancement to the possibilities to +;; find out about widgets or buttons at point in a buffer. +;; +;; To use this just load the file. Then put point on a widget or +;; button and do +;; +;; M-x describe-field +;; +;; You find a lot of widgets in a Custom buffer. You can find buttons +;; in for example a help buffer. (Please tell me more places so I can +;; test!) +;; +;; TODO: Add backtrace collecting to some more functions! + +;; For widget-get-backtrace-info +;;(require 'debug) +(eval-when-compile (require 'cl)) ;; gensym +(require 'help-mode) + +;; Last wins! +(require 'wid-browse) + +(intern ":created-in-function") + +(define-widget 'widget-browse-link 'item + "Button for creating a link style button. +The :value of the widget shuld be the widget to be browsed." + :format "%[%v%]" + ;;:value-create 'widget-browse-value-create + ;;:action 'widget-browse-action + ) + +(defun define-button-type (name &rest properties) + "Define a `button type' called NAME. +The remaining arguments form a sequence of PROPERTY VALUE pairs, +specifying properties to use as defaults for buttons with this type +\(a button's type may be set by giving it a `type' property when +creating the button, using the :type keyword argument). + +In addition, the keyword argument :supertype may be used to specify a +button-type from which NAME inherits its default property values +\(however, the inheritance happens only when NAME is defined; subsequent +changes to a supertype are not reflected in its subtypes)." + (let ((catsym (make-symbol (concat (symbol-name name) "-button"))) + (super-catsym + (button-category-symbol + (or (plist-get properties 'supertype) + (plist-get properties :supertype) + 'button)))) + ;; Provide a link so that it's easy to find the real symbol. + (put name 'button-category-symbol catsym) + ;; Initialize NAME's properties using the global defaults. + (let ((default-props (symbol-plist super-catsym)) + (where-fun (widget-get-backtrace-info 8))) + (setq default-props + (cons :created-in-function + (cons where-fun + default-props))) + (while default-props + (put catsym (pop default-props) (pop default-props)))) + ;; Add NAME as the `type' property, which will then be returned as + ;; the type property of individual buttons. + (put catsym 'type name) + ;; Add the properties in PROPERTIES to the real symbol. + (while properties + (let ((prop (pop properties))) + (when (eq prop :supertype) + (setq prop 'supertype)) + (put catsym prop (pop properties)))) + ;; Make sure there's a `supertype' property + (unless (get catsym 'supertype) + (put catsym 'supertype 'button)) + name)) + +(defun define-widget (name class doc &rest args) + "Define a new widget type named NAME from CLASS. + +NAME and CLASS should both be symbols, CLASS should be one of the +existing widget types, or nil to create the widget from scratch. + +After the new widget has been defined, the following two calls will +create identical widgets: + +* (widget-create NAME) + +* (apply 'widget-create CLASS ARGS) + +The third argument DOC is a documentation string for the widget." + (put name 'widget-type (cons class args)) + (put name 'widget-documentation doc) + (put name :created-in-function (widget-get-backtrace-info 8)) + name) + +(defvar describe-temp-help-buffer nil) +(defun describe-get-temp-help-buffer () + (setq describe-temp-help-buffer (get-buffer-create "*Copy of *Help* Buffer for Description*"))) + +(defun describe-field (pos) + "Describe field at marker POS." + (interactive (list (point))) + (unless (markerp pos) (setq pos (copy-marker pos))) + (when (eq (marker-buffer pos) (get-buffer (help-buffer))) + (with-current-buffer (describe-get-temp-help-buffer) + (erase-buffer) + (insert (with-current-buffer (help-buffer) + (buffer-string))) + (goto-char (marker-position pos)) + (setq pos (point-marker)))) + (let (field wbutton doc button widget) + (with-current-buffer (marker-buffer pos) + (setq field (get-char-property pos 'field)) + (setq wbutton (get-char-property pos 'button)) + (setq doc (get-char-property pos 'widget-doc)) + (setq button (button-at pos)) + (setq widget (or field wbutton doc))) + (cond ((and widget + (if (symbolp widget) + (get widget 'widget-type) + (and (consp widget) + (get (widget-type widget) 'widget-type)))) + (describe-widget pos)) + (button + (describe-button pos)) + ((and (eq major-mode 'Info-mode) + (memq (get-text-property pos 'font-lock-face) + '(info-xref info-xref-visited))) + (message "info link")) + (t + (message "No widget or button at point"))))) + +(defun describe-insert-header (pos) + (widget-insert + (add-string-property + (concat + (format "Description of the field at position %d in " + (marker-position pos)) + (format "\"%s\"" (marker-buffer pos)) + ":\n\n") + 'face '(italic)))) + +(defun describe-widget (pos) + ;;(interactive (list (point-marker))) + (unless (markerp pos) (setq pos (copy-marker pos))) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'describe-widget pos) (interactive-p)) + (with-current-buffer (help-buffer) + (let ((inhibit-read-only t)) + (describe-insert-header pos) + (insert-text-button "This field" + 'action (lambda (button) + (let* ((m (button-get button 'field-location)) + (p (marker-position m)) + (b (marker-buffer m))) + (if (not (buffer-live-p b)) + (message "Sorry the markers buffer is gone") + (switch-to-buffer b) + (goto-char p)))) + 'field-location pos) + (princ " is of type ") + (insert-text-button "widget" + 'action (lambda (button) + (info "(widget)"))) + (princ ". You can ") + (insert-text-button "browse the widget's properties" + 'action (lambda (button) + (widget-browse-at + (button-get button 'field-location))) + 'field-location pos)) + (princ " to find out more about it.") + (fill-region (point-min) (point-max)) + ) + (with-no-warnings (print-help-return-message)))) + +(defun describe-button (pos) + (let ((button (button-at pos))) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'describe-button pos) (interactive-p)) + (with-current-buffer (help-buffer) + (let ((inhibit-read-only t) + ;;(button-marker (gensym)) + ) + (describe-insert-header pos) + (insert-text-button "This field" + 'action (lambda (button) + (let* ((m (button-get button 'field-location)) + (p (marker-position m)) + (b (marker-buffer m))) + (switch-to-buffer b) + (goto-char p))) + 'field-location pos) + (princ " is of type ") + (insert-text-button "button" + 'action (lambda (button) + (info "(elisp) Buttons"))) + (princ ". You can ") + ;;(set button-marker pos) + (insert-text-button "browse the button's properties" + 'action `(lambda (button) + ;;(button-browse-at (symbol-value ',button-marker))))) + (button-browse-at ,pos)))) + (princ " to find out more about it.") + (fill-region (point-min) (point-max)) + ) + (with-no-warnings (print-help-return-message))))) + +;; Obsolete +;; (defun whelp-describe-symbol (sym) +;; (interactive "SSymbol: ") +;; (with-output-to-temp-buffer (help-buffer) +;; (help-setup-xref (list #'describe-symbol sym) (interactive-p)) +;; (with-current-buffer (help-buffer) +;; (let ((inhibit-read-only t)) +;; (if (not (symbolp sym)) +;; (progn +;; (princ "Argument does not look like it is a ") +;; (insert-text-button "symbol" +;; 'action (lambda (button) +;; (info "(elisp) Symbols"))) +;; (princ ".")) +;; (let ((n 0)) +;; (when (fboundp sym) (setq n (1+ n))) +;; (when (boundp sym) (setq n (1+ n))) +;; (when (facep sym) (setq n (1+ n))) +;; (when (custom-group-p sym) (setq n (1+ n))) +;; (if (= n 0) +;; (progn +;; (princ "Can't determine usage for the ") +;; (insert-text-button "symbol" +;; 'action (lambda (button) +;; (info "(elisp) Symbols"))) +;; (princ " '") +;; (princ (symbol-name sym)) +;; (princ ".")) +;; (princ "The ") +;; (insert-text-button "symbol" +;; 'action (lambda (button) +;; (info "(elisp) Symbols"))) +;; (princ " '") +;; (princ (symbol-name sym)) +;; (if (= n 1) +;; (progn +;; (princ " is a ") +;; (cond ((fboundp sym) +;; (princ "function (") +;; (insert-text-button +;; "describe it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (describe-function value))) +;; 'value sym) +;; (insert ")")) +;; ((boundp sym) +;; (insert "variable (") +;; (insert-text-button +;; "describe it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (describe-variable value))) +;; 'value sym) +;; (insert ")")) +;; ((facep sym) +;; (insert "face (") +;; (insert-text-button +;; "describe it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (describe-face value))) +;; 'value sym) +;; (insert ")")) +;; ((custom-group-p sym) +;; (insert "customize group (") +;; (insert-text-button +;; "customize it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (customize-group value))) +;; 'value sym) +;; (insert ")"))) +;; (princ ".")) +;; (princ " has several usages currently.") +;; (princ " It can be:\n\n") +;; (when (fboundp sym) +;; (princ " - A function (") +;; (insert-text-button "describe it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (describe-function value))) +;; 'value sym) +;; (princ ")\n")) +;; (when (boundp sym) +;; (princ " - A variable (") +;; (insert-text-button "describe it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (describe-variable value))) +;; 'value sym) +;; (princ ")\n")) +;; (when (facep sym) +;; (princ " - A face (") +;; (insert-text-button "describe it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (describe-face value))) +;; 'value sym) +;; (princ ")\n")) +;; (when (custom-group-p sym) +;; (princ " - A customization group (") +;; (insert-text-button "customize it" +;; 'action (lambda (button) +;; (let ((value (button-get button 'value))) +;; (customize-group value))) +;; 'value sym) +;; (princ ")\n")) +;; ))) +;; (princ "\n\nSymbol's property list:\n\n") +;; (let ((pl (symbol-plist sym)) +;; key +;; val) +;; (princ (format " %25s %s\n" "Key" "Value")) +;; (princ (format " %25s %s\n" "---" "-----")) +;; (while pl +;; (setq key (car pl)) +;; (setq pl (cdr pl)) +;; (setq val (car pl)) +;; (setq pl (cdr pl)) +;; (let ((first (point-marker)) +;; last) +;; (princ (format " %25s - %s" key val)) +;; (setq last (point-marker)) +;; (let ((adaptive-fill-function +;; (lambda () +;; (format " %25s - " key)))) +;; (fill-region first last) +;; )) +;; (princ "\n") +;; ))) +;; (with-no-warnings (print-help-return-message)))))) + + + +(defun widget-browse-sexp (widget key value) + "Insert description of WIDGET's KEY VALUE. +Nothing is assumed about value." + (let ((pp (condition-case signal + (pp-to-string value) + (error (prin1-to-string signal))))) + (when (string-match "\n\\'" pp) + (setq pp (substring pp 0 (1- (length pp))))) + (if (cond ((string-match "\n" pp) + nil) + ((> (length pp) (- (window-width) (current-column))) + nil) + (t t)) + (cond + ( (and value + (symbolp value) + (or (fboundp value) + (boundp value) + (facep value))) + (widget-create 'push-button + :tag pp + :value value + :action '(lambda (widget &optional event) + (let ((value (widget-get widget :value)) + (n 0)) + (when (fboundp value) (setq n (1+ n))) + (when (boundp value) (setq n (1+ n))) + (when (facep value) (setq n (1+ n))) + (if (= n 1) + (cond ((fboundp value) + (describe-function value)) + ((boundp value) + (describe-variable value)) + ((facep value) + (describe-face value))) + (describe-symbol value)))))) + ( (markerp value) + (widget-create 'push-button + :tag pp + :value (list (marker-position value) (marker-buffer value)) + :action '(lambda (widget &optional event) + (let ((value (widget-get widget :value))) + (let ((pos (car value)) + (buf (cadr value))) + (switch-to-buffer-other-window buf) + (goto-char pos)))))) + ( (overlayp value) + (widget-create 'push-button + :tag pp + :value (list (overlay-start value) (overlay-buffer value)) + :action '(lambda (widget &optional event) + (let ((value (widget-get widget :value))) + (let ((pos (car value)) + (buf (cadr value))) + (switch-to-buffer-other-window buf) + (goto-char pos)))))) + ( t + (widget-insert pp))) + + (widget-create 'push-button + :tag "show" + :action (lambda (widget &optional event) + (with-output-to-temp-buffer + "*Pp Eval Output*" + (princ (widget-get widget :value)))) + pp)))) + + +(defvar widget-get-backtrace-active t + "Whether to collect backtrace info for widgets and buttons. +Turn this on only for debugging purposes. + +Note: This must be t when Emacs is loading to collect the needed +information.") + +(defun widget-get-backtrace-info (n) + (if widget-get-backtrace-active + (let ((frame-n t) + fun) + (while (and frame-n + (not fun)) + (setq frame-n (backtrace-frame n)) + (when frame-n + ;;(message "**BT %s: %s" n (cadr frame-n)) + (when (car frame-n) + (setq fun (cadr frame-n)) + (when (or (listp fun) + (member fun + '( + backtrace-frame + widget-get-backtrace-info + + eval + eval-expression + call-interactively + apply + funcall + ;;lambda + + if + when + cond + condition + mapc + mapcar + while + + let + let* + set + setq + set-variable + set-default + + widget-create + widget-create-child-and-convert + widget-create-child + widget-create-child-value + define-button-type + define-widget + make-text-button + insert-text-button + make-button + insert-button + ))) + (setq fun))) + (setq n (1+ n)))) + ;;(message "---------- fun=%s" fun) + fun) + "Set widget-get-backtrace-info to show this")) + +(defun widget-create (type &rest args) + "Create widget of TYPE. +The optional ARGS are additional keyword arguments." + (unless (keywordp :created-in-function) (error ":wcw not interned")) + (let ((where-fun (widget-get-backtrace-info 8)) + yargs) + (setq args + (cons :created-in-function + (cons where-fun + args))) + (let ((widget (apply 'widget-convert type args))) + (widget-apply widget :create) + widget))) + + +(defun widget-create-child-and-convert (parent type &rest args) + "As part of the widget PARENT, create a child widget TYPE. +The child is converted, using the keyword arguments ARGS." + (let ((widget (apply 'widget-convert type args))) + (widget-put widget :parent parent) + (widget-put widget :created-in-function (widget-get-backtrace-info 15)) + (unless (widget-get widget :indent) + (widget-put widget :indent (+ (or (widget-get parent :indent) 0) + (or (widget-get widget :extra-offset) 0) + (widget-get parent :offset)))) + (widget-apply widget :create) + widget)) + +(defun widget-create-child (parent type) + "Create widget of TYPE." + (let ((widget (widget-copy type))) + (widget-put widget :parent parent) + (widget-put widget :created-in-function (widget-get-backtrace-info 15)) + (unless (widget-get widget :indent) + (widget-put widget :indent (+ (or (widget-get parent :indent) 0) + (or (widget-get widget :extra-offset) 0) + (widget-get parent :offset)))) + (widget-apply widget :create) + widget)) + +(defun widget-create-child-value (parent type value) + "Create widget of TYPE with value VALUE." + (let ((widget (widget-copy type))) + (widget-put widget :value (widget-apply widget :value-to-internal value)) + (widget-put widget :parent parent) + (widget-put widget :created-in-function (widget-get-backtrace-info 15)) + (unless (widget-get widget :indent) + (widget-put widget :indent (+ (or (widget-get parent :indent) 0) + (or (widget-get widget :extra-offset) 0) + (widget-get parent :offset)))) + (widget-apply widget :create) + widget)) + +(defvar widget-browse-fb-history nil + "Forward/backward history.") +(setq widget-browse-fb-history nil) + +(defun widget-fb-button-action (widget &ignore) + (let* ((num (widget-get widget :history-number)) + (rec (nth num widget-browse-fb-history)) + (fun (nth 0 rec)) + (val (nth 1 rec)) + (loc (nth 2 rec))) + ;;(message "fun=%s, val=%s, loc=%s" fun val loc)(sit-for 4) + (funcall fun num))) + +(defun widget-insert-fb-buttons (current-number) + ;;(message "current-number=%s" current-number)(sit-for 2) + (if (<= 0 (1- current-number)) + (widget-create 'push-button + :action 'widget-fb-button-action + :history-number (1- current-number) + :format "%[%v%]" + "back") + (widget-insert (add-string-property "[back]" + 'face 'shadow))) + (widget-insert " ") + (if (< (1+ current-number) (length widget-browse-fb-history)) + (widget-create 'push-button + :action 'widget-fb-button-action + :history-number (1+ current-number) + :format "%[%v%]" + "forward") + (widget-insert (add-string-property "[forward]" + 'face 'shadow))) + (widget-insert "\n")) + +(defun widget-add-fb-history (elt) + (let ((last (car widget-browse-fb-history))) + (unless (equal elt last) + (setq widget-browse-fb-history + (reverse (cons elt + (reverse widget-browse-fb-history))))))) + +(defun widget-browse (widget &optional location) + "Create a widget browser for WIDGET." + (interactive (list (completing-read "Widget: " + obarray + (lambda (symbol) + (get symbol 'widget-type)) + t nil 'widget-browse-history))) + (let (history-number) + (if (integerp widget) + (progn + ;;(message "was integer=%s" widget)(sit-for 2) + (setq history-number widget) + (setq widget (nth 1 (nth widget widget-browse-fb-history)))) + ;;(message "was NOT integer=%s" widget)(sit-for 2) + (widget-add-fb-history (list 'widget-browse widget location)) + (setq history-number (1- (length widget-browse-fb-history)))) + ;;(message "history-number=%s" history-number)(sit-for 2) + + (if (stringp widget) + (setq widget (intern widget))) + (unless (if (symbolp widget) + (get widget 'widget-type) + (and (consp widget) + (get (widget-type widget) 'widget-type))) + (error "Not a widget")) + + ;; Create the buffer. + (if (symbolp widget) + (let ((buffer (format "*Browse %s Widget*" widget))) + (kill-buffer (get-buffer-create buffer)) + (switch-to-buffer (get-buffer-create buffer))) + (kill-buffer (get-buffer-create "*Browse Widget*")) + (switch-to-buffer (get-buffer-create "*Browse Widget*"))) + (widget-browse-mode) + + (make-local-variable 'widget-button-face) + (setq widget-button-face 'link) + (set (make-local-variable 'widget-push-button-prefix) "") + (set (make-local-variable 'widget-push-button-suffix) "") + (set (make-local-variable 'widget-link-prefix) "") + (set (make-local-variable 'widget-link-suffix) "") + + ;; Top text indicating whether it is a class or object browser. + (widget-insert-fb-buttons history-number) + (widget-insert "----------------\n") + (if (listp widget) + (progn + (widget-insert (add-string-property + "Widget object browser" + 'face 'widget-browse-h1)) + (widget-insert "\n\n") + (when location + (let ((b (marker-buffer location)) + (p (marker-position location))) + (widget-insert (add-string-property "Location: " + 'face 'italic)) + (widget-create 'push-button + :tag (format "position %s in buffer %s" p b) + :value (list p b) + :action '(lambda (widget &optional event) + (let ((value (widget-get widget :value))) + (let ((pos (car value)) + (buf (cadr value))) + (switch-to-buffer-other-window buf) + (goto-char pos))))) + (widget-insert "\n\n"))) + (widget-insert (add-string-property "Class: " + 'face 'italic))) + (widget-insert (add-string-property "Widget class browser" + 'face 'widget-browse-h1)) + (widget-insert ".\n\n") + (widget-insert (add-string-property "Class: " 'face 'italic)) + (widget-insert (add-string-property (format "%s\n" widget) + 'face '(bold))) + (widget-insert (format "%s" (get widget 'widget-documentation))) + (unless (eq (preceding-char) ?\n) (widget-insert "\n")) + (widget-insert (add-string-property "\nSuper: " 'face 'italic)) + (setq widget (get widget 'widget-type)) + ) + + ;(widget-insert (format "%s\n" widget)) + + ;; Now show the attributes. + (let ((name (car widget)) + (items (cdr widget)) + key value printer) + (if (not name) + (widget-insert "none\n") + (let ((ancestors (list name)) + a + (i1 7) + i + ) + (setq i i1) + (while name + (setq a (intern-soft name)) + (if a + (progn + (setq a (get a 'widget-type)) + (setq name (car a)) + (when (intern-soft name) + (push name ancestors))) + (setq name))) + ;;(widget-insert (format "ancestors=%s\n" ancestors)) + (mapc (lambda (w) + (widget-insert (make-string (if (= i i1) 0 i) ? )) + (widget-create 'widget-browse + :format "%[%v%]" + w) + (widget-insert "\n") + (setq i (+ i 2))) + ancestors))) + (while items + (setq key (nth 0 items) + value (nth 1 items) + printer (or (get key 'widget-keyword-printer) + 'widget-browse-sexp) + items (cdr (cdr items))) + (widget-insert "\n" + (add-string-property (symbol-name key) + 'face 'italic)) + (when (widget-browse-explained key) + (widget-insert " (") + (widget-create + ;;'push-button + ;;:tag "explain" + ;;:format "%[%v%]" + ;;:button-prefix "" + ;;:button-suffix "" + 'widget-browse-link + :value key + :tag "explain" + :format "%[%t%]" + :action '(lambda (widget &optional event) + (widget-browse-explain + ;;(widget-get widget :value) + (widget-value widget) + )) + ) + (widget-insert ")")) + (widget-insert "\n\t") + (funcall printer widget key value) + (widget-insert "\n"))) + + (widget-insert "\n-----------\n") + (widget-insert-fb-buttons history-number) + + (widget-setup) + (goto-char (point-min)) +;; (when wid-to-history +;; (setq widget-browse-fb-history +;; (reverse (cons (list 'widget-browse wid-to-history location) +;; (reverse widget-browse-fb-history))))) + )) + +(defun widget-browse-at (pos) + "Browse the widget under point." + (interactive "d") + (let ((mp pos) + (b (if (markerp pos) (marker-buffer pos) + (current-buffer)))) + (if (not (buffer-live-p b)) + (message "Sorry the markers buffer is gone") + (with-current-buffer b + (when (markerp pos) + (setq pos (marker-position pos))) + (let* ((field (get-char-property pos 'field)) + (button (get-char-property pos 'button)) + (doc (get-char-property pos 'widget-doc)) + (text (cond (field "This is an editable text area.") + (button "This is an active area.") + (doc "This is documentation text.") + (t "This is unidentified text."))) + (widget (or field button doc))) + (when widget + (widget-browse widget mp)) + (message text)))))) + +(defun button-at (pos) + "Return the button at marker or position POS, or nil. +If not a marker use the current buffer." + (with-current-buffer (if (markerp pos) (marker-buffer pos) + (current-buffer)) + (when (markerp pos) + (setq pos (marker-position pos))) + (let ((button (get-char-property pos 'button))) + (if (or (overlayp button) (null button)) + button + ;; Must be a text-property button; return a marker pointing to it. + (copy-marker pos t))))) + +(defun button-browse-at (pos) + (interactive "d") + (let ((b (if (markerp pos) (marker-buffer pos) + (current-buffer)))) + (if (not (buffer-live-p b)) + (message "Sorry the button's buffer is gone") + (button-browse (button-at pos))))) + +(defun button-browse (button) + "Create a widget browser for WIDGET." + (interactive (list (completing-read "Button: " + obarray + (lambda (symbol) + (or (get symbol 'button-category-symbol) + (get symbol 'supertype))) + t nil 'button-browse-history))) + (let (history-number) + (if (integerp button) + (progn + (setq history-number button) + (setq button (nth 1 (nth button widget-browse-fb-history)))) + (widget-add-fb-history (list 'button-browse button)) + (setq history-number (1- (length widget-browse-fb-history)))) + + (when (stringp button) + (setq button (intern-soft button))) + (when (symbolp button) + (unless (and button + (or (eq button 'default-button) + (get button 'supertype) + (get button 'button-category-symbol) + (save-match-data + (string-match "-button$" (symbol-name button))))) + (error "Not a button"))) + ;; Create the buffer. + (kill-buffer (get-buffer-create "*Browse Button*")) + (switch-to-buffer (get-buffer-create "*Browse Button*")) + (widget-browse-mode) + + (make-local-variable 'widget-button-face) + (setq widget-button-face 'link) + + (widget-insert-fb-buttons history-number) + (widget-insert "----------------\n") + + ;; Top text indicating whether it is a class or object browser. + (if (or (overlayp button) + (markerp button)) + (progn + (widget-insert (add-string-property "Button object browser" + 'face 'widget-browse-h1)) + (widget-insert "\n\n") + (let ((b (if (markerp button) + (marker-buffer button) + (overlay-buffer button))) + (p (if (markerp button) + (marker-position button) + (overlay-start button)))) + (widget-insert (add-string-property "Location: " + 'face 'italic)) + (widget-create 'push-button + :tag (format "position %s in buffer %s" p b) + :value (list p b) + :action '(lambda (widget &optional event) + (let ((value (widget-get widget :value))) + (let ((pos (car value)) + (buf (cadr value))) + (switch-to-buffer-other-window buf) + (goto-char pos))))) + (widget-insert "\n\n"))) + (widget-insert (add-string-property "Button class browser" + 'face 'widget-browse-h1)) + (widget-insert "\n\n") + (widget-insert (add-string-property "Type: " + 'face 'italic)) + (widget-insert (add-string-property (symbol-name button) + 'face 'bold)) + (widget-insert "\n")) + + ;; Now show the attributes. + (let ( + (items + (if (symbolp button) + (if (get button 'button-category-symbol) + (symbol-plist (get button 'button-category-symbol)) + (symbol-plist button)) + (if (markerp button) + (let ((pos (marker-position button)) + (buf (marker-buffer button))) + (text-properties-at pos buf)) + (overlay-properties button)))) + rest-items + name + key value printer) + ;;(insert (format "\n%s\n\n" items)) + (let ((copied-items (copy-seq items))) + (while copied-items + (setq key (nth 0 copied-items) + value (nth 1 copied-items) + copied-items (cdr (cdr copied-items))) + (if (eq key 'category) + (setq name value) + (if (eq key 'supertype) + (setq name (make-symbol (concat (symbol-name value) "-button"))) + (push value rest-items) + (push key rest-items))))) + ;;(insert "\nname=" (symbol-name value) "\n\n") + (when name + (widget-insert (add-string-property + (if (symbolp button) + (if (get button 'supertype) + "Supertype: " + "") + "Category: ") + 'face 'italic)) + (let* (a + (ancestors + (list name)) + (i1 11) + (i i1)) + (while name + (setq a (or (get name 'supertype) + (get name :supertype))) + ;;(message "name=%s, a=%s\n name plist=%s" name a (symbol-plist name));(sit-for 4) + (if (or (not a) + (eq a 'default-button)) + (setq name) + (setq name (make-symbol (concat (symbol-name a) "-button"))) + (setq ancestors (cons name ancestors)))) + ;;(message "ancestors=%s" ancestors)(sit-for 2) + (mapc (lambda (w) + (widget-insert (make-string (if (= i i1) 0 i) ? )) + (widget-create 'button-browse + :format "%[%v%]" + w) + (widget-insert "\n") + (setq i (+ i 2))) + ancestors))) + (while rest-items + (setq key (nth 0 rest-items) + value (nth 1 rest-items) + printer (or (get key 'widget-keyword-printer) + 'widget-browse-sexp) + rest-items (cdr (cdr rest-items))) + (widget-insert "\n" + (add-string-property (symbol-name key) + 'face 'italic)) + (when (widget-browse-explained key) + (widget-insert " (") + (widget-create 'push-button + :tag "explain" + :value key + :action '(lambda (widget &optional event) + (widget-browse-explain + (widget-get widget :value)))) + (widget-insert ")")) + (widget-insert "\n\t") + (funcall printer button key value) + (widget-insert "\n"))) + (widget-setup) + (goto-char (point-min)) + +;; (when button-to-history +;; (setq widget-browse-fb-history +;; (reverse (cons (list 'button-browse button-to-history) +;; (reverse widget-browse-fb-history))))) + )) + + +;;;###autoload +(defgroup whelp nil + "Customization group for whelp." + :group 'emacs) + +(defface widget-browse-h1 + '((t (:weight bold :height 1.5))) + "Face for top header in widget/button browse buffers." + :group 'whelp) + +(defun add-string-property (str prop val) + (let ((s (copy-seq str))) + (put-text-property 0 (length s) + prop val + s) + s)) + +;;; The `button-browse' Widget. + +(define-widget 'button-browse 'push-button + "Widget button for creating a button browser. +The :value of the widget shuld be the button to be browsed." + :format "%[[%v]%]" + :value-create 'widget-browse-button-value-create + :action 'widget-browse-button-action) + +(defun widget-browse-button-action (widget &optional event) + ;; Create widget browser for WIDGET's :value. + (button-browse (widget-get widget :value))) + +(defun widget-browse-button-value-create (widget) + ;; Insert type name. + (let ((value (widget-get widget :value))) + (cond ((symbolp value) + (insert (symbol-name value))) + ((consp value) + (insert (symbol-name (widget-type value)))) + (t + (insert "strange"))))) + + +(defun widget-browse-explained (property) + (memq property + '( + :created-in-function + ))) + +(defun widget-browse-explain (property) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'widget-browse-explain property) (interactive-p)) + (with-current-buffer (help-buffer) + (let ((inhibit-read-only t)) + (cond + ( (eq property :created-in-function) + (princ "Property :created-in-function tells where a field object or class is created.") + ) + ( t + (princ (format "No explanation found for %s" property)) + ) + ) + (with-no-warnings (print-help-return-message)))))) + +(provide 'whelp) diff --git a/emacs/nxhtml/util/winsav.el b/emacs/nxhtml/util/winsav.el new file mode 100644 index 0000000..771f6ce --- /dev/null +++ b/emacs/nxhtml/util/winsav.el @@ -0,0 +1,1585 @@ +;;; winsav.el --- Save and restore window structure +;; +;; Author: Lennart Borgman +;; Created: Sun Jan 14 2007 +(defconst winsav:version "0.77") ;;Version: 0.77 +;; Last-Updated: 2009-08-04 Tue +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This library contains both user level commands and options and +;; functions for use in other elisp libraries. +;; +;;;; User level commands and options +;; +;; The user level commands and options are for saving frame, windows +;; and buffers between Emacs sessions. To do that you can customize +;; the options `desktop-save-mode' and `winsav-save-mode' or put this +;; at the end of your .emacs: +;; +;; (desktop-save-mode 1) +;; (winsav-save-mode 1) +;; +;; You can also save configurations that you later switch between. +;; For more information see the command `winsav-save-mode'. +;; +;; (There is also a command in this library for rotating window +;; borders in a frame, `winsav-rotate'. It is here just because the +;; needed support functions lives here.) +;; +;; +;; +;;;; Commands for other elisp libraries +;; +;; This library was orignally written to solve the problem of adding a +;; window to the left of some windows in a frame like the one below +;; +;; ___________ +;; | | | +;; | 1 | 2 | +;; |____|____| +;; | | +;; | 3 | +;; |_________| +;; +;; so that the window structure on the frame becomes +;; +;; ___________ +;; | | | | +;; | | 1| 2 | +;; | B|__|___| +;; | A| | +;; | R| 3 | +;; |__|______| +;; +;; +;; This problem can be solved by this library. However the solution in +;; this library is a bit more general: You first copy the window +;; structure and then restore that into another window. To do the +;; above you first copy the window structure in the first frame above +;; with `winsav-get-window-tree'. Then you create windows like this: +;; +;; ___________ +;; | | | +;; | | | +;; | B| | +;; | A| | +;; | R| | +;; |__|______| +;; +;; +;; Finally you use `winsav-put-window-tree' to put the window +;; structure into the right window. (Of course you could have put BAR +;; above, under etc.) +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Bugs and limitations: +;; +;; Juanma Barranquero has pointed out there is a serious limitation in +;; this way of doing it when overlays with 'window properties are +;; used. The problem is that any pointers to windows are made invalid +;; since they are deleted. So in fact any code that relies on saved +;; pointers to windows will have problem if the window is one of those +;; that are involved here. +;; +;; To overcome this problem when doing something like inserting a BAR +;; window (see above) a new window has to be inserted in the existing +;; window tree on a frame in a way that is currently not supported in +;; Emacs. +;; +;; It would be nice to be have primitives to manipulate the window +;; tree more generally from elisp. That requires implementation of +;; them at the C level of course. +;; +;; However it is probably much easier to implement it quite a bit less +;; general. The concept of splitting is maybe then the right level to +;; search for primitives at. +;; +;; My conclusion is that it will take some time to find suitable +;; primitives for this. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; Version 0.72: +;; +;; - Format of window structure changed in Emacs 23. Adopted to that. +;; - Added save and restore of frame/window configurations between +;; Emacs sessions. +;; - Added named winsav configurations for save and restore of frames, +;; windows, buffers and files. +;; +;; Version 0.71: +;; +;; - Added rotation of window structure. +;; +;; Version 0.70: +;; +;; - Support for save and restore from file. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + + +(eval-when-compile (require 'cl)) +(eval-and-compile (require 'desktop)) + +;; (defun winsav-upper-left-window(&optional frame w) +;; (let* ((tree (if w w (car (window-tree frame)))) +;; (is-split (not (windowp tree)))) +;; (if (not is-split) +;; tree +;; (winsav-upper-left-window frame (nth 2 tree))))) + + +(defcustom winsav-after-get-hook nil + "Hook to run after at the end of `winsav-get-window-tree'. +The functions in this hook are called with one parameter which is +the same as the return value from the function above." + :type 'hook + :group 'winsav) + +(defcustom winsav-after-put-hook nil + "Hook to run after at the end of `winsav-put-window-tree'. +The functions in this hook are called with one parameter which is +a list where each element is a list \(old-win new-win) where +OLD-WIN are the window from `winsav-get-window-tree' and NEW-WIN +is the newly created corresponding window. This list is the same +as the return value from the function above." + :type 'hook + :group 'winsav) + +(defun winsav-get-window-tree(&optional frame) + "Get window structure. +This returns an object with current windows with values, buffers, +points and the selected window. + +FRAME is the frame to save structure from. If nil use selected. + +At the very end of this function the hook `winsav-after-get' is +run." + ;;(let* ((upper-left (winsav-upper-left-window frame)) + (let* ((upper-left (frame-first-window frame)) + (num -1) + sel-num) + (dolist (w (window-list frame nil upper-left)) + (setq num (1+ num)) + (when (eq w (selected-window)) + (setq sel-num num))) + (let ((ret (list sel-num + (winsav-get-window-tree-1 frame nil)))) + (run-hook-with-args 'winsav-after-get-hook ret) + ret))) + +;; Fix-me: add window-hscroll +(defun winsav-get-window-tree-1(frame w) + (let ((tree (if w w (car (window-tree frame))))) + (if (windowp tree) + ;; Note: Desktop is used for saving buffers. + (with-current-buffer (window-buffer tree) + (list (window-buffer tree) + ;; buffer + (buffer-name) + (buffer-file-name) + ;;buffer-read-only + ;;(if mumamo-multi-major-mode mumamo-multi-major-mode major-mode) + ;;minor-modes + ;;buffer locals + ;;(cons (+ 0 (mark-marker)) (mark-active)) + ;; window + (window-point tree) + (window-edges tree) + (window-scroll-bars tree) + (window-fringes tree) + (window-margins tree) + (window-hscroll tree) + ;; misc + (window-dedicated-p tree) + (when (fboundp 'window-redisplay-end-trigger) + (window-redisplay-end-trigger tree)) + (window-start tree) + tree)) + (let* ((dir (nth 0 tree)) + (split (nth 1 tree)) + (wt (cddr tree)) + (wsubs (mapcar (lambda(wc) + (winsav-get-window-tree-1 nil wc)) + wt))) + (append (list dir split) wsubs))))) + +;;;###autoload +(defun winsav-put-window-tree (saved-tree window &optional copy-win-ovl win-ovl-all-bufs) + "Put window structure SAVED-TREE into WINDOW. +Restore a structure SAVED-TREE returned from +`winsav-get-window-tree' into window WINDOW. + +If COPY-WIN-OVL is non-nil then overlays having a 'window +property pointing to one of the windows in SAVED-TREE where this +window still is shown will be copied to a new overlay with +'window property pointing to the corresponding new window. + +If WIN-OVL-ALL-BUFS is non-nil then all buffers will be searched +for overlays with a 'window property of the kind above. + +At the very end of this function the hook `winsav-after-put' is +run." + (let* ((sel-num (nth 0 saved-tree)) + (tree (nth 1 saved-tree)) + nsiz + nh + nw + osiz + oh + ow + scale-w + scale-h + first-win + winsav-put-return) + (unless (or (bufferp (car tree)) + (eq 'buffer (car tree))) + (setq nsiz (window-edges window)) + (setq nh (- (nth 3 nsiz) (nth 1 nsiz))) + (setq nw (- (nth 2 nsiz) (nth 0 nsiz))) + (setq osiz (cadr tree)) + (setq oh (- (nth 3 osiz) (nth 1 osiz))) + (setq ow (- (nth 2 osiz) (nth 0 osiz))) + (setq scale-w (unless (= ow nw) (/ nw (float ow)))) + (setq scale-h (unless (= oh nh) (/ nh (float oh))))) + (setq first-win (winsav-put-window-tree-1 tree window scale-w scale-h t 1)) + (select-window first-win) + (when sel-num (other-window sel-num)) + (winsav-fix-win-ovl winsav-put-return copy-win-ovl win-ovl-all-bufs) + (run-hook-with-args 'winsav-after-put-hook winsav-put-return) + winsav-put-return)) + +(defun winsav-put-window-tree-1 (saved-tree window scale-w scale-h first-call level) + "Helper for `winsav-put-window-tree'. +For the arguments SAVED-TREE and WINDOW see that function. + +The arguments SCALE-W and SCALE-H are used to make the saved +window config fit into its new place. FIRST-CALL is a state +variable telling if this is the first round. LEVEL helps +debugging by tells how far down we are in the call chain." + (if (or (bufferp (car saved-tree)) + ;;(not (car saved-tree)) + (eq 'buffer (car saved-tree)) + ) + (let ((buffer (nth 0 saved-tree)) + ;; buffer + (bufnam (nth 1 saved-tree)) + (filnam (nth 2 saved-tree)) + ;;(mark (nth 3 saved-tree)) + ;; window + (point (nth 3 saved-tree)) + (edges (nth 4 saved-tree)) + (scroll (nth 5 saved-tree)) + (fringe (nth 6 saved-tree)) + (margs (nth 7 saved-tree)) + (hscroll (nth 8 saved-tree)) + (dedic (nth 9 saved-tree)) + (trigger (nth 10 saved-tree)) + (start (nth 11 saved-tree)) + (ovlwin (nth 12 saved-tree)) + scr2 + (misbuf " *Winsav information: Buffer is gone*")) + (or (windowp ovlwin) + (not ovlwin) + (error "Parameter mismatch, ovlwin not window: %s" ovlwin)) + (when first-call + (add-to-list 'winsav-put-return (list ovlwin window)) + (when (eq 'buffer buffer) + (when filnam + (setq buffer (winsav-find-file-noselect filnam))) + (if (buffer-live-p buffer) + (or (string= bufnam (buffer-name buffer)) + (eq (string-to-char bufnam) 32) ;; Avoid system buffer names + (rename-buffer bufnam)) + (when (eq (string-to-char bufnam) 32) + (setq bufnam " *Winsav dummy buffer*")) + ;; Fix-me, this might need some tweaking: Don't restore + ;; buffers without a file name and without + ;; content. (desktop-mode will make that when + ;; necessary.) Just show the scratch buffer instead. + (setq buffer (get-buffer bufnam)) + (unless (and buffer + (< 0 (buffer-size buffer))) + (setq buffer (get-buffer-create "*scratch*"))))) + (set-window-buffer window buffer) + (set-window-dedicated-p window dedic) + ;; Strange incompatibility in scroll args: + (setq scr2 (list (nth 0 scroll) (nth 2 scroll) (nth 3 scroll))) + (apply 'set-window-scroll-bars (append (list window) scr2)) + (apply 'set-window-fringes (append (list window) fringe)) + (set-window-margins window (car margs) (cdr margs)) + (set-window-hscroll window hscroll) + (unless (>= emacs-major-version 23) + (with-no-warnings + (set-window-redisplay-end-trigger window trigger)))) + (let* ((nsiz (window-edges window)) + (nh (- (nth 3 nsiz) (nth 1 nsiz))) + (nw (- (nth 2 nsiz) (nth 0 nsiz))) + (osiz edges) ;(nth 2 saved-tree)) + (oh (- (nth 3 osiz) (nth 1 osiz))) + (ow (- (nth 2 osiz) (nth 0 osiz))) + (diff-w (- (if scale-w + (round (* scale-w ow)) + ow) + nw)) + (diff-h (- (if scale-h + (round (* scale-h oh)) + oh) + nh))) + ;; Avoid rounding naggings: + (when (> (abs diff-h) 1) + (bw-adjust-window window diff-h nil)) + (when (> (abs diff-w) 1) + (bw-adjust-window window diff-w t))) + ;; Fix-me: there were some problems getting point correctly. Don't know why... + (with-selected-window window + (with-current-buffer (window-buffer window) + (goto-char point)) + (set-window-point window point) + ;;(unless (buffer-live-p buffer) (setq point 1) (setq start 1)) + (set-window-start window start) + ;; Maybe point got off screen? + (when (/= point (window-point window)) + (set-window-point window point))) + window) + (let* ((ver (car saved-tree)) + (wtree (list (cons window (caddr saved-tree)))) + (nwin window) + pwin + pdelta + (first-win nwin)) + ;; First split to get it in correct order + (when first-call + (dolist (subtree (cdddr saved-tree)) + (setq pwin nwin) + ;;(message "nwin edges=%s, ver=%s" (window-edges nwin) ver) + (let ((split-err nil) + (window-min-height 1) + (window-min-width 1)) + (setq nwin (split-window nwin nil (not ver)))) + ;; Make the previous window as small as permitted to allow + ;; splitting as many times as possible + (setq pdelta (- + (if ver + window-min-height + window-min-width) + (if ver + (window-width pwin) + (window-height pwin)))) + ;;(message "pwin=%s, edges=%s, pdelta=%s, ver=%s" pwin (window-edges pwin) pdelta ver) + ;; No reason to fail here: + (condition-case err + (adjust-window-trailing-edge pwin pdelta (not ver)) + (error + ;;(message "awt=>%s" (error-message-string err)) + nil + )) + ;; Add to traverse + (add-to-list 'wtree + (cons nwin subtree) + t))) + ;; Now traverse. Sizing is a bit tricky, multiple runs have to + ;; be done (as in balance-windows). + (let (tried-sizes + last-sizes + (windows (window-list (selected-frame)))) + (while (not (member last-sizes tried-sizes)) + (when last-sizes (setq tried-sizes (cons last-sizes tried-sizes))) + (setq last-sizes (mapcar (lambda (w) + (window-edges w)) + windows)) + (dolist (wsub (reverse wtree)) + (select-window (car wsub)) + (winsav-put-window-tree-1 (cdr wsub) (selected-window) + scale-w scale-h + first-call + (1+ level) + )) + (setq first-call nil) + )) + first-win))) + +(defun winsav-fix-win-ovl(win-list copy-win-ovl win-ovl-all-bufs) + (let ((oldwins (mapcar (lambda(elt) + (car elt)) + win-list)) + ovlwin + window) + (let (buffers) + (if win-ovl-all-bufs + (setq buffers (buffer-list)) + (mapc (lambda(w) + (when (window-live-p w) + (add-to-list 'buffers (window-buffer w)))) + oldwins)) + (dolist (buf buffers) + (with-current-buffer buf + (save-restriction + (widen) + (dolist (overlay (overlays-in (point-min) (point-max))) + (when (setq ovlwin (car (memq (overlay-get overlay 'window) oldwins))) + (setq window (cadr (assoc ovlwin win-list))) + ;; If the old window is still alive then maybe copy + ;; overlay, otherwise change the 'window prop. However + ;; copy only if COPY-WIN-OVL is non-nil. + (if (not (and (window-live-p ovlwin) + (window-frame ovlwin))) + (overlay-put overlay 'window window) + (when copy-win-ovl + (let* ((props (overlay-properties overlay)) + (start (overlay-start overlay)) + (end (overlay-end overlay)) + ;; Fix-me: start and end marker props + (newovl (make-overlay start end))) + (while props + (let ((key (car props)) + (val (cadr props))) + (setq props (cddr props)) + (when (eq key 'window) + (setq val window)) + (overlay-put newovl key val)))))))))))))) + + + +(defun winsav-transform-edges (edges) + "Just rotate the arguments in EDGES to make them fit next function." + (let ((le (nth 0 edges)) + (te (nth 1 edges)) + (re (nth 2 edges)) + (be (nth 3 edges))) + (list te le be re))) + +(defun winsav-transform-1 (tree mirror transpose) + "Mirroring of the window tree TREE. +MIRROR could be 'mirror-top-bottom or 'mirror-left-right which I +think explain what it does here. TRANSPOSE shifts the tree +between a horisontal and vertical tree." + (let* ((vertical (nth 0 tree)) + (edges (nth 1 tree)) + (subtrees (nthcdr 2 tree)) + ) + ;;(winsav-log "tree 1" tree) + (when transpose + (cond + ((eq vertical nil) + (setcar tree t)) + ((eq vertical t) + (setcar tree nil)) + (t + (error "Uh? vertical=%S" vertical)))) + (setcar (nthcdr 1 tree) (winsav-transform-edges edges)) + (dolist (subtree subtrees) + (if (bufferp (car subtree)) + (when transpose + (let ((edges (nth 4 subtree))) + ;;(winsav-log "subtree 1" subtree) + (setcar (nthcdr 4 subtree) (winsav-transform-edges edges)) + ;;(winsav-log "subtree 2" subtree) + )) + (winsav-transform-1 subtree mirror transpose))) + (when (case mirror + ('mirror-top-bottom vertical) + ('mirror-left-right (not vertical)) + (nil) ;; Don't mirror + (t + (error "Uh? mirror=%s" mirror))) + (setcdr (nthcdr 1 tree) (reverse subtrees)) + ) + )) + +(defun winsav-find-file-noselect (filename) + "Read file FILENAME into a buffer and return the buffer. +Like `find-file-noselect', but if file is not find then creates a +buffer with a message about that." + (let ((buf (find-file-noselect filename))) + (unless buf + (setq buf (generate-new-buffer filename)) + (with-current-buffer buf + (insert "Winsav could not find the file " filename) + (set-buffer-modified-p nil))) + buf)) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Session saving and restore etc + +;;;###autoload +(defgroup winsav nil + "Save frames and windows when you exit Emacs." + :group 'frames) + +;;;###autoload +(define-minor-mode winsav-save-mode + "Toggle winsav configuration saving mode. +With numeric ARG, turn winsav saving on if ARG is positive, off +otherwise. + +When this mode is turned on, winsav configurations are saved from +one session to another. A winsav configuration consists of +frames, windows and visible buffers configurations plus +optionally buffers and files managed by the functions used by +option `desktop-save-mode' + +By default this is integrated with `desktop-save-mode'. If +`desktop-save-mode' is on and `winsav-handle-also-desktop' is +non-nil then save and restore also desktop. + +See the command `winsav-switch-config' for more information and +other possibilities. + +Note: If you want to avoid saving when you exit just turn off +this minor mode. + +For information about what is saved and restored and how to save +and restore additional information see the function +`winsav-save-configuration'." + :global t + :group 'winsav) + +(defun winsav-save-mode-on () + "Ensable option `winsav-save-mode'. Provided for use in hooks." + (winsav-save-mode 1)) + +(defun winsav-save-mode-off () + "Disable option `winsav-save-mode'. Provided for use in hooks." + (winsav-save-mode -1)) + +(defcustom winsav-save 'ask-if-new + "Specifies whether the winsav config should be saved when it is killed. +A winsav config \(winsav frame configuration) is killed when the +user changes winsav directory or quits Emacs. + +Possible values are: + t -- always save. + ask -- always ask. + ask-if-new -- ask if no winsav file exists, otherwise just save. + ask-if-exists -- ask if winsav file exists, otherwise don't save. + if-exists -- save if winsav file exists, otherwise don't save. + nil -- never save. +The winsav config is never saved when the option `winsav-save-mode' is nil. +The variables `winsav-dirname' and `winsav-base-file-name' +determine where the winsav config is saved." + :type + '(choice + (const :tag "Always save" t) + (const :tag "Always ask" ask) + (const :tag "Ask if winsav file is new, else do save" ask-if-new) + (const :tag "Ask if winsav file exists, else don't save" ask-if-exists) + (const :tag "Save if winsav file exists, else don't" if-exists) + (const :tag "Never save" nil)) + :group 'winsav) + +(defcustom winsav-handle-also-desktop t + "If this is non-nil then desktop is also saved and restored. +See option `winsav-save-mode' for more information." + :type 'boolean + :group 'winsav) + +(defcustom winsav-base-file-name + (convert-standard-filename ".emacs.winsav") + "Base name of file for Emacs winsav, excluding directory part. +The actual file name will have a system identifier added too." + :type 'file + :group 'winsav) + +(defvar winsav-dirname nil + "The directory in which the winsav file should be saved.") + +(defun winsav-current-default-dir () + "Current winsav configuration directory." + (or winsav-dirname "~/")) + +;;(find-file (winsav-full-file-name)) +(defun winsav-default-file-name () + "Default winsav save file name. +The file name consist of `winsav-base-file-name' with a system +identifier added. This will be '-nw' for a terminal and '-' + +the value of `window-system' otherwise." + (let ((sys-id (if (not window-system) + "nw" + (format "%s" window-system)))) + (concat winsav-base-file-name "-" sys-id))) + +(defun winsav-full-file-name (&optional dirname) + "Return the full name of the winsav session file in DIRNAME. +DIRNAME omitted or nil means use `~'. + +The file name part is given by `winsav-default-file-name'." + ;; Fix-me: Different frames in different files? Can multi-tty be handled?? + (expand-file-name (winsav-default-file-name) (or dirname + (winsav-current-default-dir)))) + + + +(defun winsav-serialize (obj) + "Return a string with the printed representation of OBJ. +This should be possible to eval and get a similar object like OBJ +again." + ;;(message "winsav-serialize a") + (prin1-to-string obj) + ;;(message "winsav-serialize b") + ) + +(defcustom winsav-before-save-configuration-hook nil + "Hook called before saving frames. +Hook for writing elisp code at the beginning of a winsav +configuration file. When this hook is called the current buffer +and point is where the code should be written. + +This is a normal hook. For more information see +`winsav-save-configuration'." + :type 'hook + :group 'winsav) + +(defcustom winsav-after-save-configuration-hook nil + "Hook called after saving frames. +Hook for writing elisp code at the end of a winsav configuration +file. When this hook is called the current buffer and point is +where the code should be written. + +This is a normal hook. For more information see +`winsav-save-configuration'." + :type 'hook + :group 'winsav) + +(defcustom winsav-after-save-frame-hook nil + "Hook called when saving a frame after saving frame data. +Hook for writing elisp code in a winsav configuration file after +each frame creation. When this hook is called code for restoring +a frame has been written and code that sets +`winsav-last-loaded-frame' to point to it. Point is in the +configuration file buffer right after this. + +This is a normal hook. For more information see +`winsav-save-configuration'." + :type 'hook + :group 'winsav) + +(defvar winsav-loaded-frames nil) +(defvar winsav-last-loaded-frame nil) + +(defun winsav-restore-frame (frame-params + window-tree-params + use-minibuffer-frame + window-state + window-visible) + "Restore a frame with specified values. +If this is a minibuffer only frame then just apply the frame +parameters FRAME-PARAMS. Otherwise create a new frame using +FRAME-PARAMS and set up windows and buffers according to +WINDOW-TREE-PARAMS. Also, if USE-MINIBUFFER-FRAME let the new +frame have this minibuffer frame. + +WINDOW-STATE is 1 for minimized, 2 for normal and 3 for +maximized." + (let* ((default-minibuffer-frame use-minibuffer-frame) + (frame-name (cdr (assoc 'name frame-params))) + (minibuffer-val (cdr (assoc 'minibuffer frame-params))) + (minibuffer-only (eq 'only minibuffer-val)) + (mini-frames + (delq nil (mapcar (lambda (frm) + (when (eq 'only (frame-parameter frm 'minibuffer)) + frm)) + (frame-list)))) + (frame-with-that-name + (when (and frame-name minibuffer-only) + (catch 'frame + (dolist (frame (frame-list)) + (when (string= frame-name (frame-parameter frame 'name)) + (throw 'frame frame)))))) + ;; If this is a minibuffer only frame then if it is already + ;; there under a correct name then do not create it because + ;; there might be variables pointing to it; just set the + ;; parameters. Perhaps even better: if it is not already + ;; there give an error - because it might be impossible to + ;; set things up correctly then. + (frame-with-that-name-has-mini + (when frame-with-that-name + (eq 'only + (frame-parameter frame-with-that-name 'minibuffer)))) + (this-mini-frame (when minibuffer-only + (or frame-with-that-name + (and (= 1 (length mini-frames)) + (car mini-frames))))) + (create-new + (if minibuffer-only + (if this-mini-frame ;frame-with-that-name-has-mini + nil + (error "Winsav: Can't find minibuffer only frame with name %s" + frame-name)) + t)) + (this-frame (if create-new + (make-frame frame-params) + this-mini-frame)) + (win (frame-first-window this-frame))) + ;;(message "create-new=%s, frame-with-that-name=%s" create-new frame-with-that-name) + ;; (when was-max + ;; (winsav-set-maximized-size this-frame) + ;; ;; Wait for maximize to occur so horizontal scrolling gets ok. + ;; (sit-for 1.5) + ;; ) + (case window-state + (1 (winsav-set-minimized-state this-frame)) + (3 (winsav-set-maximized-state this-frame))) + (unless window-visible + (make-frame-invisible this-frame)) + (if create-new + (winsav-put-window-tree window-tree-params win) + (modify-frame-parameters this-frame frame-params)) + (setq winsav-last-loaded-frame this-frame) + (setq winsav-loaded-frames (cons this-frame winsav-loaded-frames)) + )) + +(defcustom winsav-frame-parameters-to-save + '( + ;;explicit-name + ;;name + ;;parent-id + ;;title + alpha + auto-lower + auto-raise + background-color + background-mode + border-color + border-width + buffer-predicate + cursor-color + cursor-type + font + font-backend + foreground-color + fullscreen + icon-name + icon-type + icon-left + icon-top + internal-border-width + left-fringe + line-spacing + menu-bar-lines + modeline + mouse-color + right-fringe + screen-gamma + scroll-bar-width + tool-bar-lines + top left width height + tty-color-mode ;; ?? + unsplittable + user-position + user-size + vertical-scroll-bars + visibility + ) + "Parameters saved for frames by `winsav-save-configuration'. +Parameters are those returned by `frame-parameters'." + :type '(repeat (symbol :tag "Frame parameter")) + :group 'winsav) + +(defun frame-visible-really-p (frame) + "Return t if FRAME is visible. +This tries to be more corrent on w32 than `frame-visible-p'." + (cond ((fboundp 'w32-frame-placement) + (< 0 (nth 4 (w32-frame-placement frame)))) + (t + (frame-visible-p frame)))) + +(defun frame-maximized-p (frame) + "Return t if it is known that frame is maximized." + (cond ((fboundp 'w32-frame-placement) + (= 3 (abs (nth 4 (w32-frame-placement frame))))) + (t nil))) + +(defun frame-minimized-p (frame) + "Return t if it is known that frame is minimized." + (cond ((fboundp 'w32-frame-placement) + (= 3 (abs (nth 4 (w32-frame-placement frame))))) + (t nil))) + +;;(winsav-set-restore-size nil) +;; (defun winsav-set-restore-size (frame) +;; (when (fboundp 'w32-send-sys-command) +;; (let ((cur-frm (selected-frame))) +;; (select-frame-set-input-focus frame) +;; (w32-send-sys-command #xf120) +;; ;; Note: sit-for must be used, not sleep-for. Using the latter +;; ;; prevents the fetching of the new size (for some reason I do not +;; ;; understand). +;; (sit-for 1.5) +;; (select-frame-set-input-focus cur-frm)) +;; t)) + +(defun winsav-set-maximized-state (frame) + (when (fboundp 'w32-send-sys-command) + (select-frame-set-input-focus frame) + (w32-send-sys-command #xf030) + (sit-for 1.0) + t)) + +(defun winsav-set-minimized-state (frame) + (when (fboundp 'w32-send-sys-command) + (select-frame-set-input-focus frame) + (w32-send-sys-command #xf020) + (sit-for 1.0) + t)) + +(defun winsav-save-frame (frame mb-frm-nr buffer) + "Write into buffer BUFFER elisp code to recreate frame FRAME. +If MB-FRM-NR is a number then it is the order number of the frame +whose minibuffer should be used." + (message "winsav-save-frame buffer=%s" buffer) + (message "winsav-save-frame buffer 2=%s" (current-buffer)) + (let* ((start nil) + (end nil) + (obj (winsav-get-window-tree frame)) + (dummy (message "winsav-save-frame buffer 3=%s" (current-buffer))) + (frm-size-now (cons (frame-pixel-height frame) + (frame-pixel-width frame))) + (dummy (message "winsav-save-frame buffer 4=%s" (current-buffer))) + (placement (when (fboundp 'w32-frame-placement) (w32-frame-placement frame))) + ;; (was-max (and frm-size-rst + ;; (not (equal frm-size-now frm-size-rst)))) + (window-state (abs (nth 4 placement))) + ;; (frm-size-rst (when (winsav-set-restore-size frame) + ;; (cons (frame-pixel-height frame) + ;; (frame-pixel-width frame)))) + ;;(frm-size-rst (when was-max)) + ;;(frm-size-rst (when (= 3 (abs (nth 4 placement))))) + (dummy (message "winsav-save-frame buffer 5=%s" (current-buffer))) + (frm-par (frame-parameters frame)) + (dummy (message "winsav-save-frame buffer 6=%s" (current-buffer))) + ) + (message "winsav-save-frame a1 cb=%s" (current-buffer)) + (with-current-buffer buffer + ;;(y-or-n-p (format "was-max=%s" was-max)) + (message "winsav-save-frame a2 cb=%s" (current-buffer)) + (setq frm-par + (delq nil + (mapcar (lambda (elt) + (cond + ((memq (car elt) winsav-frame-parameters-to-save) + elt) + ((eq (car elt) 'minibuffer) + (let ((val (cdr elt))) + (if (not (windowp val)) + elt + (if (eq (window-frame val) frame) + nil + (cons 'minibuffer nil))))))) + frm-par))) + (message "winsav-save-frame b cb=%s" (current-buffer)) + (insert "(winsav-restore-frame\n'" + ;;make-frame-params + (winsav-serialize frm-par)) + (message "winsav-save-frame b.0.1") + ;;window-tree-params + (setq start (point)) + (insert "'" (winsav-serialize obj) "\n") + (message "winsav-save-frame b.0.2") + (setq end (copy-marker (point) t)) + (message "winsav-save-frame b.0.3") + (message "winsav-save-frame b.1") + ;; (replace-regexp (rx "#<buffer " + ;; (1+ (not (any ">"))) + ;; (1+ ">")) ;; 1+ for indirect buffers ... + ;; "buffer" + ;; nil start end) + (goto-char start) + (while (re-search-forward (rx "#<buffer " + (1+ (not (any ">"))) + (1+ ">")) ;; 1+ for indirect buffers ... + end t) + (replace-match "buffer" nil t)) + (message "winsav-save-frame b.2") + ;; (replace-regexp (rx "#<window " + ;; (1+ (not (any ">"))) + ;; (1+ ">")) + ;; "nil" + ;; nil start end) + (goto-char start) + (while (re-search-forward (rx "#<window " + (1+ (not (any ">"))) + (1+ ">")) ;; 1+ for indirect buffers ... + end t) + (replace-match "nil" nil t)) + (message "winsav-save-frame c") + (goto-char end) + ;;use-minibuffer-frame + (insert (if mb-frm-nr + (format "(nth %s (reverse winsav-loaded-frames))" mb-frm-nr) + "nil") + (format " %s" window-state) + (if (frame-visible-really-p frame) " t " " nil ") + ")\n\n") + + (insert " ;; ---- before after-save-frame-hook ----\n") + ;; (dolist (fun winsav-after-save-frame-hook) + ;; (funcall fun frame (current-buffer))) + (run-hooks winsav-after-save-frame-hook) + (message "winsav-save-frame d") + (insert " ;; ---- after after-save-frame-hook ----\n") + + ;;(insert " )\n\n\n") + ))) + +(defvar winsav-file-version "1" + "Version number of winsav file format. +Written into the winsav file and used at winsav read to provide +backward compatibility.") + + +;; fix-me: This should be in desktop.el +;; Fix-me: incomplete, not ready. +(defun winsav-restore-indirect-file-buffer (file name) + "Make indirect buffer from file buffer visiting file FILE. +Give it the name NAME." + (let* ((fbuf (find-file-noselect file))) + (when fbuf + (make-indirect-buffer fbuf name)))) + +(defun winsav-save-indirect-buffers (to-buffer) + "Save information about indirect buffers. +Only file visiting buffers currently. Clone the base buffers." + (with-current-buffer to-buffer + (dolist (buf (buffer-list)) + (when (buffer-base-buffer buf) + (let* ((base-buf (buffer-base-buffer buf)) + (file (buffer-file-name base-buf))) + (when file + (insert "(winsav-restore-indirect-file-buffer \"" + file "\" \"" (buffer-name buf) "\")\n"))))))) + +;; Fix-me: test +;; (defun winsav-restore-minibuffer (frame-num frm-num win-num) +;; (let* ((frame (nth (1- frame-num) winsav-loaded-frames)) +;; (mini-frm (nth (1- frm-num) winsav-loaded-frames)) +;; (mini-win (nth (1- win-num) (reverse (window-list mini-frm)))) +;; ) +;; (with-selected-frame frame +;; (set-minibuffer-window mini-win)))) + +(defvar winsav-minibuffer-alist nil) +(defun winsav-save-minibuffers (sorted-frames to-buffer) + "Save information about minibuffer frames. +SORTED-FRAMES should be a list of all frames sorted using +`winsav-frame-sort-predicate'." + (with-current-buffer to-buffer + (setq winsav-minibuffer-alist nil) + (dolist (frame sorted-frames) + (let* ((num-frames (length sorted-frames)) + (mini-win (minibuffer-window frame)) + (mini-frm (window-frame mini-win)) + (win-num (length + (memq mini-win + (window-list mini-frm t (frame-first-window mini-frm))))) + (frm-num (- num-frames (length (memq mini-frm sorted-frames)))) + (frame-num (- num-frames (length (memq frame sorted-frames))))) + (unless (and (eq mini-frm frame) + (= win-num 1)) + ;; Not the normal minibuffer window + ;;(insert (format ";;(winsav-restore-minibuffer %s %s %s)\n" + ;;(insert (format "'(%s %s)\n" frame-num frm-num) + (setq winsav-minibuffer-alist (cons (list frame-num frm-num) winsav-minibuffer-alist)) + ))) + (insert "(setq winsav-minibuffer-alist '" + (winsav-serialize winsav-minibuffer-alist) + ")\n"))) + +(defun winsav-restore-dedicated-window (frame-num win-num dedicate-flag) + "Set dedicated window flag. +On frame number FRAME-NUM in `winsav-loaded-frames' set the +dedicated flag on window number WIN-NUM to DEDICATE-FLAG." + (let* ((frame (nth (1- frame-num) winsav-loaded-frames)) + (win (nth (1- win-num) (reverse (window-list frame t + (frame-first-window frame)))))) + (set-window-dedicated-p win dedicate-flag))) + +(defun winsav-save-dedicated-windows (sorted-frames) + "Save information about dedicated windows on frames in SORTED-FRAMES. +Write this to current buffer." + (dolist (frame sorted-frames) + (dolist (win (window-list frame)) + (when (window-dedicated-p win) + (let ((frame-num (length (memq frame sorted-frames))) + (win-num (length + (memq win + (window-list frame t (frame-first-window frame))))) + (flag (window-dedicated-p win))) + (insert (format "(winsav-restore-dedicated-window %s %s %S)\n" frame-num win-num flag)) + ))))) + +(defun winsav-restore-ecb (frame-num layout-ecb) + "Restore ECB. +On frame number FRAME-NUM-ECB in `winsav-loaded-frames' restore +ECB layout LAYOUT-ECB." + (when (boundp 'ecb-minor-mode) + (let* ((frame (nth (1- frame-num) winsav-loaded-frames))) + (select-frame frame) + (unless (string= layout-ecb ecb-layout-name) + (setq ecb-layout-name layout-ecb)) + (ecb-minor-mode 1)))) + +(defun winsav-save-ecb (frame-ecb layout-ecb sorted-frames) + "Save information about ECB layout on frames in SORTED-FRAMES. +Write this in current buffer." + (dolist (frame sorted-frames) + (when (eq frame frame-ecb) + (let ((frame-num (length (memq frame sorted-frames)))) + (insert (format "(winsav-restore-ecb %s %S)\n" frame-num layout-ecb)))))) + +;; (make-frame '((minibuffer))) +;; (sort (frame-list) 'winsav-frame-sort-predicate) +(defun winsav-frame-sort-predicate (a b) + "Compare frame A and B for sorting. +Sort in the order frames can be created. + +- Frames without minibuffers will come later since the need to + refer to the minibuffer frame when they are created. + +- Invisible frames comes last since there must be at least one + visible frame from the beginning." + (let* ((a-mbw (minibuffer-window a)) + (a-mbw-frm (window-frame a-mbw)) + (b-mbw (minibuffer-window b)) + (b-mbw-frm (window-frame b-mbw)) + (a-visible (frame-visible-really-p a)) + (b-visible (frame-visible-really-p b)) + ) + ;;(message "a-mbw-frm=%s, b=%s" a-mbw-frm b) + ;;(message "b-mbw-frm=%s, a=%s" a-mbw-frm b) + (when (or (not b-visible) + (eq a-mbw-frm b) + (not (eq b-mbw-frm b))) + ;;(message "a > b") + t + ))) + +(defun winsav-can-read-config (config-version) + "Return t we can read config file version CONFIG-VERSION." + (when (<= config-version 1) + t)) + +(defvar winsav-file-modtime nil) + +;; Like desktop-save, fix-me +(defun winsav-save-configuration (&optional dirname release) + "Write elisp code to recreate all frames. +Write into the file name computed by `winsav-full-file-name' +given the argument DIRNAME. + +The information that is saved for each frame is its size and +position, the window configuration including buffers and the +parameters in `winsav-frame-parameters-to-save'. If you want save +more information for frames you can do that in the hook +`winsav-after-save-frame-hook'. + +See also the hook variables +`winsav-before-save-configuration-hook' and +`winsav-after-save-configuration-hook'. + +Fix-me: RELEASE is not implemented." + (winsav-save-config-to-file (winsav-full-file-name dirname))) + +(defun winsav-save-config-to-file (conf-file) + "Write elisp code to recreate all frames to CONF-FILE." + (let (start + end + (sorted-frames (sort (frame-list) 'winsav-frame-sort-predicate)) + (frm-nr 0) + frame-ecb + layout-ecb) + ;; Recreating invisible frames hits Emacs bug 3859 + (setq sorted-frames + (delq nil + (mapcar (lambda (f) + (when (frame-parameter f 'visibility) f)) + sorted-frames))) + (when (and (boundp 'ecb-minor-mode) ecb-minor-mode) + (when (frame-live-p ecb-frame) + (setq layout-ecb ecb-layout-name) + (setq frame-ecb ecb-frame)) + (ecb-minor-mode -1) + (sit-for 0) ;; Fix-me: is this needed? + ) + (message "winsav-save-config:here a") + (with-temp-buffer + (let ((this-buffer (current-buffer))) + (message "winsav-save-config:here b") + ;;(erase-buffer) + (insert + ";; -*- mode: emacs-lisp; coding: utf-8; -*-\n" + ";; --------------------------------------------------------------------------\n" + ";; Winsav File for Emacs\n" + ";; --------------------------------------------------------------------------\n" + ";; Created " (current-time-string) "\n" + ";; Winsav file format version " winsav-file-version "\n" + ";; Emacs version " emacs-version "\n\n" + "(if (not (winsav-can-read-config " winsav-file-version "))\n\n" + " (message \"Winsav: Can't read config file with version " winsav-file-version "\")\n") + (message "winsav-save-config:here c") + (insert ";; ---- indirect buffers ------------------------\n") + (winsav-save-indirect-buffers this-buffer) + (message "winsav-save-config:here c.1") + ;;(insert ";; ---- special minibuffers ------------------------\n") + (winsav-save-minibuffers sorted-frames this-buffer) + (message "winsav-save-config:here c.2") + (insert "(setq winsav-loaded-frames nil)\n") + (insert ";; ---- before winsav-before-save-configuration-hook ------------------------\n") + (run-hooks 'winsav-before-save-configuration-hook) + (message "winsav-save-config:here c.2a cb=%s" (current-buffer)) + (insert ";; ---- after winsav-before-save-configuration-hook ------------------------\n\n") + (dolist (frm sorted-frames) + (let ((mb-frm-nr (cadr (assoc frm-nr winsav-minibuffer-alist))) + ;;(mb-frm (when mb-frm-nr (nth mb-frm-nr sorted-frames))) + ) + (message "winsav-save-config:here c.2b.1 tb=%s cb=%s frm=%s" this-buffer (current-buffer) frm) + (winsav-save-frame frm mb-frm-nr this-buffer) + (message "winsav-save-config:here c.2b.2") + (setq frm-nr (1+ frm-nr)))) + (message "winsav-save-config:here c.2c cb=%s" (current-buffer)) + (insert ";; ---- dedicated windows ------------------------\n") + (winsav-save-dedicated-windows sorted-frames) + (message "winsav-save-config:here c.3") + (insert ";; ---- ECB --------------------------------------\n") + (winsav-save-ecb frame-ecb layout-ecb sorted-frames) + (message "winsav-save-config:here c.4") + (insert "\n\n;; ---- before winsav-after-save-configuration-hook ------------------------\n") + (run-hooks 'winsav-after-save-configuration-hook) + (message "winsav-save-config:here c.5") + (insert "\n\n;; ---- before winsav-after-save-configuration-hook ------------------------\n") + (run-hooks 'winsav-after-save-configuration-hook) + (message "winsav-save-config:here c.6") + (insert ";; ---- after winsav-after-save-configuration-hook ------------------------\n") + (insert "\n)\n") + (message "winsav-save-config:here d") + ;; For pp-buffer: + (let (emacs-lisp-mode-hook + after-change-major-mode-hook + change-major-mode-hook) + (font-lock-mode -1) + (emacs-lisp-mode)) + (message "winsav-save-config:here e") + (pp-buffer) + (message "winsav-save-config:here f") + (indent-region (point-min) (point-max)) + (message "winsav-save-config:here g") + ;;(save-buffer 0) ;; No backups + ;;(kill-buffer) + + ;;(with-current-buffer (find-file-noselect file) + (let ((coding-system-for-write 'utf-8)) + (write-region (point-min) (point-max) conf-file nil 'nomessage)) + (setq winsav-file-modtime (nth 5 (file-attributes conf-file))) + (setq winsav-dirname (file-name-as-directory (file-name-directory conf-file))) + (message "winsav-save-config:here h") + )))) + +(defvar winsav-current-config-name nil) + +;;(winsav-restore-configuration) +;;(winsav-full-file-name "~") +;; (defun winsav-restore-winsav-configuration () +;; ) + +(defcustom winsav-after-restore-hook nil + "Normal hook run after a successful `winsav-restore-configuration'." + :type 'hook + :group 'winsav) + +;; Like desktop-read, fix-me +(defun winsav-restore-configuration (&optional dirname) + "Restore frames from default file in directory DIRNAME. +The default file is given by `winsav-default-file-name'. + +The file was probably written by `winsav-save-configuration'. +Delete the frames that were used before." + ;;(message "winsav-restore-configuration %s" dirname) + (winsav-restore-config-from-file (winsav-full-file-name dirname))) + +(defun winsav-restore-config-from-file (conf-file) + "Restore frames from configuration file CONF-FILE. +The file was probably written by `winsav-save-configuration'. +Delete the frames that were used before." + (let ((old-frames (sort (frame-list) 'winsav-frame-sort-predicate)) + (num-old-deleted 0) + ;; Avoid winsav saving during restore. + (winsav-save nil)) + ;;(message "winsav:conf-file=%s" conf-file) + (if (or (not conf-file) + (not (file-exists-p conf-file))) + (progn + (message (propertize "Winsav: No default configuration file found" + 'face 'secondary-selection)) + t) ;; Ok + (setq debug-on-error t) ;; fix-me + (if (file-exists-p conf-file) + (progn + (load conf-file nil nil t) + (setq winsav-file-modtime (nth 5 (file-attributes conf-file))) + (setq winsav-dirname (file-name-as-directory (file-name-directory conf-file))) + (when (< 0 (length winsav-loaded-frames)) + (dolist (old (reverse old-frames)) + (unless (eq 'only (frame-parameter old 'minibuffer)) + (setq num-old-deleted (1+ num-old-deleted)) + (delete-frame old))) + ) + (message "winsav-after-restore-hook =%S" winsav-after-restore-hook) + (run-hooks 'winsav-after-restore-hook) + (message "Winsav: %s frame(s) restored" (length winsav-loaded-frames)) + t) + ;; No winsav file found + ;;(winsav-clear) + (message "No winsav file: %s" conf-file) + nil)))) + +;; (defcustom winsav-add-to-desktop nil +;; "Set this to let desktop save and restore also winsav configurations." +;; :type 'boolean +;; :set (lambda (sym val) +;; (set-default sym val) +;; (if value +;; (progn +;; (add-hook 'desktop-after-read-hook 'winsav-restore-configuration) +;; (add-hook 'desktop-save-hook 'winsav-save-configuration)) +;; (remove-hook 'desktop-after-read-hook 'winsav-restore-configuration) +;; (remove-hook 'desktop-save-hook 'winsav-save-configuration)) ) +;; :group 'winsav) + +(defun winsav-restore-configuration-protected (&optional dirname) + "Like `winsav-restore-configuration' but protect for errors. +DIRNAME has the same meaning." + (condition-case err + (winsav-restore-configuration dirname) + (error + (message "winsav-restore-configuration: %s" err)))) + +(defun winsav-relative-~-or-full (dirname) + (let* ((rel-dir (file-relative-name dirname + (file-name-directory + (winsav-full-file-name "~")))) + (confname (if (string= ".." (substring rel-dir 0 2)) + winsav-dirname + (if (string= rel-dir "./") + "(default)" + (concat "~/" rel-dir))))) + confname)) + +(defun winsav-tell-configuration () + "Tell which winsav configuration that is used." + (interactive) + (save-match-data ;; runs in timer + (let ((confname (if (not winsav-dirname) + "(none)" + (winsav-relative-~-or-full winsav-dirname)))) + (if t ;;(called-interactively-p) + (message (propertize (format "Current winsav config is '%s'" confname) + 'face 'secondary-selection)) + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) + (get-buffer-create " *winsav*")) + (with-current-buffer (window-buffer) + (momentary-string-display + (propertize + (format "\n\n\n Current winsav config is '%s'\n\n\n\n" confname) + 'face 'secondary-selection) + (window-start) + (kill-buffer)))))))) + +(defun winsav-tell-configuration-request () + "Start an idle timer to call `winsav-tell-configuration'." + (run-with-idle-timer 1 nil 'winsav-tell-configuration)) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Startup and shut down + +;; Run after desktop at startup so that desktop has loaded files and +;; buffers. +(defun winsav-after-init () + "Restore frames and windows. +Run this once after Emacs startup, after desktop in the +`after-init-hook'." + ;; Turn off with --no-deskttop: + (unless desktop-save-mode (winsav-save-mode -1)) + (when winsav-save-mode + ;;(run-with-idle-timer 0.1 nil 'winsav-restore-configuration-protected) + ;;(message "winsav-after-init") + ;;(winsav-restore-configuration-protected) + ;; In case of error make sure winsav-save-mode is turned off + (setq inhibit-startup-screen t) + (winsav-save-mode -1) + (winsav-restore-configuration) + (winsav-save-mode 1) + )) + +(add-hook 'after-init-hook 'winsav-after-init t) + +(add-hook 'kill-emacs-hook 'winsav-kill) +;;(remove-hook 'kill-emacs-hook 'winsav-kill) + +(defun winsav-kill () + "Save winsav frame configuration. +Run this before Emacs exits." + ;; (when winsav-save-mode + ;; (let ((conf-dir (when winsav-current-config-name + ;; (winsav-full-config-dir-name winsav-current-config-name)))) + ;; (winsav-save-configuration conf-dir)))) + (when (and winsav-save-mode + (let ((exists (file-exists-p (winsav-full-file-name)))) + (or (eq winsav-save t) + (and exists (memq winsav-save '(ask-if-new if-exists))) + (and + (or (memq winsav-save '(ask ask-if-new)) + (and exists (eq winsav-save 'ask-if-exists))) + (y-or-n-p "Save winsav? "))))) + (unless winsav-dirname + ;; Fix-me: Since this can be a new user of winsav I think the + ;; best thing to do here is to encourage the user to save in the + ;; default directory since otherwise the winsav file will not be + ;; loaded at startup. Desktop does not currently do that however + ;; (report that!). + (when (y-or-n-p "Winsav was not loaded from file. Save it to file? ") + (let* ((full-file (winsav-full-file-name)) + (default-directory (directory-file-name + (file-name-directory full-file)))) + (setq winsav-dirname + (file-name-as-directory + (expand-file-name + (read-directory-name "Directory for winsav file: " nil nil t))))))) + (when winsav-dirname + (condition-case err + ;;(winsav-save winsav-dirname t) + (winsav-save-configuration winsav-dirname) + (file-error + (unless (yes-or-no-p + (format "Error while saving winsav config: %s Save anyway? " + (error-message-string err))) + (signal (car err) (cdr err))))))) + ;; If we own it, we don't anymore. + ;;(when (eq (emacs-pid) (winsav-owner)) (winsav-release-lock)) + ) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Switching configurations + +(defun winsav-restore-full-config (dirname) + "Restore the winsav configuration in directory DIRNAME. +If NAME is nil then restore the startup configuration." + ;;(desktop-change-dir dirname) + (when (and winsav-handle-also-desktop desktop-save-mode) + (when (eq (emacs-pid) (desktop-owner)) (desktop-release-lock)) + (desktop-clear) + (desktop-read dirname)) + (winsav-restore-configuration dirname) + ;;(setq winsav-current-config-name name) + (winsav-tell-configuration-request)) + +(defun winsav-full-config-dir-name (name) + "Return full directory path where configuration NAME is stored." + (let* ((base-dir (concat (winsav-full-file-name) ".d")) + (conf-dir (expand-file-name name base-dir))) + (setq conf-dir (file-name-as-directory conf-dir)) + ;;(message "conf-dir=%s" conf-dir) + conf-dir)) + +;;;###autoload +(defun winsav-save-full-config (dirname) + "Saved current winsav configuration in directory DIRNAME. +Then change to this configuration. + +See also `winsav-switch-config'." + (unless (file-name-absolute-p dirname) + (error "Directory ame must be absolute: %s" dirname)) + (let* ((conf-dir (or dirname "~")) + (old-conf-dir winsav-dirname)) + (make-directory conf-dir t) + (winsav-save-configuration conf-dir) + (when (and winsav-handle-also-desktop desktop-save-mode) + (desktop-release-lock) + (desktop-save conf-dir)) + ;;(unless (string= winsav-current-config-name name) + (unless (string= old-conf-dir conf-dir) + ;;(setq winsav-current-config-name name) + (winsav-tell-configuration-request)))) + +;; Fix-me: remove named configurations, use just dir as desktop +(defun winsav-switch-to-default-config () + "Change to default winsav configuration. +See also `winsav-switch-config'." + (interactive) + (winsav-switch-config "~")) + +;;;###autoload +(defun winsav-switch-config (dirname) + "Change to winsav configuration in directory DIRNAME. +If DIRNAME is the current winsav configuration directory then +offer to save it or restore it from saved values. + +Otherwise, before switching offer to save the current winsav +configuration. Then finally switch to the new winsav +configuration, creating it if it does not exist. + +If option `desktop-save-mode' is on then buffers and files are also +restored and saved the same way. + +See also option `winsav-save-mode' and command +`winsav-tell-configuration'." + (interactive + (list + (let ((default-directory (or winsav-dirname default-directory)) + (base-dir (concat (winsav-full-file-name) ".d")) + new-dir) + (make-directory base-dir t) + (setq new-dir + (read-directory-name "Winsav: Switch config directory: ")) + (when (string= "" new-dir) (setq new-dir nil)) + (or new-dir + "~")))) + (setq dirname (file-name-as-directory (expand-file-name dirname))) + (catch 'stop + (let ((conf-file (expand-file-name winsav-base-file-name dirname)) + config-exists) + (if (file-exists-p conf-file) + (setq config-exists t) + (unless (y-or-n-p (format "%s was not found. Create it? " conf-file)) + (throw 'stop nil))) + (if (string= winsav-dirname dirname) + (if (y-or-n-p "You are already using this configuration, restore it from saved values? ") + (winsav-restore-full-config winsav-dirname) + (when (y-or-n-p "You are already using this winsav configuration, save it? ") + (winsav-save-full-config winsav-dirname))) + (when (y-or-n-p + (format "Save current config, %s,\n first before switching to %s? " + (if (and winsav-dirname + (not (string= winsav-dirname + (file-name-directory (winsav-full-file-name "~"))))) + winsav-dirname + "the startup config") + dirname)) + (winsav-save-full-config winsav-dirname)) + (if config-exists + (winsav-restore-full-config dirname) + (winsav-save-full-config dirname)))))) + + + + +;;; Old things + +;; (defun winsav-log-buffer () +;; (get-buffer-create "winsav log buffer")) + +;; (defun winsav-log (mark obj) +;; (with-current-buffer (winsav-log-buffer) +;; (insert "=== " mark "===\n" (pp-to-string obj)))) + +;; (global-set-key [f2] 'winsav-test-get) +;; (global-set-key [f3] 'winsav-test-put) +;; (defvar winsav-saved-window-tree nil) + +;; (defun winsav-test-get() +;; (interactive) +;; (setq winsav-saved-window-tree (winsav-get-window-tree))) + +;; (defun winsav-test-put() +;; (interactive) +;; (let ((ret (winsav-put-window-tree winsav-saved-window-tree +;; (selected-window)))) +;; ;;(message "ret=%s" ret) +;; )) + +;; (defun winsav-serialize-to-file (obj file) +;; (with-current-buffer (find-file-noselect file) +;; ;;(erase-buffer) +;; (save-restriction +;; (widen) +;; (goto-char (point-max)) +;; (insert (winsav-serialize obj) +;; "\n")) +;; ;;(basic-save-buffer) +;; )) + +;;(global-set-key [f11] 'winsav-rotate) + +;; (defun winsav-de-serialize-window-tree-from-file (file) +;; (with-current-buffer (find-file-noselect file) +;; (save-restriction +;; (widen) +;; (let ((start (point)) +;; (end nil)) +;; (forward-list) +;; (setq end (point)) +;; ;;(goto-char (point-min)) +;; (winsav-de-serialize-window-tree (buffer-substring-no-properties start end)))))) + +;; (defun winsav-restore-from-file (file) +;; (winsav-put-window-tree +;; (winsav-de-serialize-window-tree-from-file file) +;; (selected-window))) + +;; (defun winsav-de-serialize-window-tree (str) +;; (save-match-data +;; (let ((read-str +;; (replace-regexp-in-string (rx "#<buffer " +;; (1+ (not (any ">"))) +;; ">") +;; "buffer" +;; str)) +;; obj-last +;; obj +;; last) +;; (setq read-str +;; (replace-regexp-in-string (rx "#<window " +;; (1+ (not (any ">"))) +;; ">") +;; "nil" +;; read-str)) +;; (setq obj-last (read-from-string read-str)) +;; (setq obj (car obj-last)) +;; (setq last (cdr obj-last)) +;; ;; Fix me, maby check there are only spaces left (or trim them above...) +;; obj))) + +(provide 'winsav) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; winsav.el ends here diff --git a/emacs/nxhtml/util/winsize.el b/emacs/nxhtml/util/winsize.el new file mode 100644 index 0000000..808daf5 --- /dev/null +++ b/emacs/nxhtml/util/winsize.el @@ -0,0 +1,1173 @@ +;;; winsize.el --- Interactive window structure editing +;; +;; Author: Lennart Borgman <lennart dot borgman at gmail dot com > +;; Maintainer: +;; Created: Wed Dec 07 15:35:09 2005 +(defconst winsize:version "0.98") ;;Version: 0.97 +;; Lxast-Updated: Sun Nov 18 02:14:52 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Fxeatures that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file contains functions for interactive resizing of Emacs +;; windows. To use it put it in your `load-path' and add the following +;; to your .emacs: +;; +;; (require 'winsize) +;; (global-set-key [(control x) ?+] 'resize-windows) +;; +;; For more information see `resize-windows'. +;; +;; These functions are a slightly rewritten version of the second part +;; of the second part my proposal for a new `balance-windows' function +;; for Emacs 22. The rewrite is mostly a restructure to more easily +;; add new functions. All functions and variables have been renamed. +;; The file was originally named bw-interactive.el. +;; +;; New ideas for functionality have been to a large part adopted from +;; the Emacs Devel mailing list. Probably most of them originated from +;; Drew Adams and Bastien. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; TODO: Change mouse pointer shape during resizing. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'windmove)) +(eval-when-compile (require 'view)) +(eval-when-compile (require 'winsav nil t)) +(eval-when-compile (require 'ourcomments-widgets)) +(eval-when-compile (require 'ring)) + +;;; Custom variables + +(defcustom winsize-juris-way t + "" + :type 'boolean + :group 'winsize) + +(defcustom winsize-autoselect-borders t + "Determines how borders are selected by default. +If nil hever select borders automatically (but keep them on the +same side while changing window). If 'when-single select border +automatically if there is only one possible choice. If t alwasy +select borders automatically if they are not selected." + :type '(choice (const :tag "Always" t) + (const :tag "When only one possbility" when-single) + (const :tag "Never" nil)) + :group 'winsize) + +(defcustom winsize-mode-line-colors (list t (list "green" "green4")) + "Mode line colors used during resizing." + :type '(list (boolean :tag "Enable mode line color changes during resizing") + (list + (color :tag "- Active window mode line color") + (color :tag "- Inactive window mode line color"))) + :group 'winsize) + +(defcustom winsize-mark-selected-window t + "Mark selected window if non-nil." + :type 'boolean + :group 'winsize) + +(defcustom winsize-make-mouse-prominent t + "Try to make mouse more visible during resizing. +The mouse is positioned next to the borders that you can move. +It can however be hard to see if where it is. Setting this to on +makes the mouse jump a few times." + :type 'boolean + :group 'winsize) + +(defvar widget-command-prompt-value-history nil + "History of input to `widget-function-prompt-value'.") + +(defvar winsize-keymap nil + "Keymap used by `resize-windows'.") + +(defun winsize-make-keymap (let-me-use) + "Build the keymap that should be used by `winsize-keymap'." + (let ((map (make-sparse-keymap "Window Resizing"))) + (when (featurep 'winsav) + (define-key map [menu-bar bw rotate] + '("Rotate window configuration" . winsav-rotate)) + (define-key map [menu-bar bw sep3] '(menu-item "--"))) + (define-key map [menu-bar bw] + (cons "Resize" (make-sparse-keymap "second"))) + (define-key map [menu-bar bw save-config] + '("Save window configuration" . winsize-save-window-configuration)) + (define-key map [menu-bar bw next-config] + '("Next saved window configuration" . winsize-next-window-configuration)) + (define-key map [menu-bar bw prev-config] + '("Previous saved window configuration" . winsize-previous-window-configuration)) + (define-key map [menu-bar bw sep2] '(menu-item "--")) + (define-key map [menu-bar bw fit] + '("Fit Window to Buffer" . fit-window-to-buffer)) + (define-key map [menu-bar bw shrink] + '("Shrink Window to Buffer" . shrink-window-if-larger-than-buffer)) + (define-key map [menu-bar bw sep1] '(menu-item "--")) + (define-key map [menu-bar bw siblings] + '("Balance Window Siblings" . winsize-balance-siblings)) + (define-key map [menu-bar bw balance] + '("Balance Windows" . balance-windows)) + + (when (featurep 'winsav) + (define-key map [?|] 'winsav-rotate)) + (define-key map [?+] 'balance-windows) + (define-key map [?.] 'winsize-balance-siblings) + (define-key map [?=] 'fit-window-to-buffer) + (define-key map [?-] 'shrink-window-if-larger-than-buffer) + + (define-key map [(up)] 'winsize-move-border-up) + (define-key map [(down)] 'winsize-move-border-down) + (define-key map [(left)] 'winsize-move-border-left) + (define-key map [(right)] 'winsize-move-border-right) + + (define-key map [(shift up)] 'winsize-move-other-border-up) + (define-key map [(shift down)] 'winsize-move-other-border-down) + (define-key map [(shift left)] 'winsize-move-other-border-left) + (define-key map [(shift right)] 'winsize-move-other-border-right) + + (define-key map [(meta left)] 'winsize-to-border-or-window-left) + (define-key map [(meta up)] 'winsize-to-border-or-window-up) + (define-key map [(meta right)] 'winsize-to-border-or-window-right) + (define-key map [(meta down)] 'winsize-to-border-or-window-down) + + (define-key map [?0] 'delete-window) + (define-key map [?1] 'delete-other-windows) + (define-key map [?2] 'split-window-vertically) + (define-key map [?3] 'split-window-horizontally) + (define-key map [?4] 'other-window) + + (define-key map [?!] 'winsize-save-window-configuration) + (define-key map [?>] 'winsize-next-window-configuration) + (define-key map [?<] 'winsize-previous-window-configuration) + + ;; Fix-me: These keys could also be set to nil + (define-key map [mouse-1] 'mouse-set-point) + ;;(define-key map [down-mouse-1] 'mouse-set-point) + (define-key map [(mode-line) (down-mouse-1)] 'mouse-drag-mode-line) + (define-key map [(vertical-line) (down-mouse-1)] 'mouse-drag-vertical-line) + (define-key map [(vertical-scroll-bar) (mouse-1)] 'scroll-bar-toolkit-scroll) + + (define-key map [??] 'winsize-help) + (define-key map [(control ?g)] 'winsize-quit) + (define-key map [(control return)] 'winsize-stop-go-back) + (define-key map [(return)] 'winsize-stop) + (define-key map [t] 'winsize-stop-and-execute) + + (dolist (ks let-me-use) + (if (and (not (vectorp ks)) + (not (stringp ks)) + (commandp ks)) + (let ((ks-list (where-is-internal ks))) + (dolist (ks ks-list) + (unless (lookup-key map ks) + (define-key map ks nil)))) + (unless (lookup-key map ks) + (define-key map ks nil)))) + + (setq winsize-keymap map))) + +(defcustom winsize-let-me-use '(next-line ;;[(control ?n)] + previous-line ;;[(control ?p)] + forward-char ;;[(control ?f)] + backward-char ;;[(control ?b)] + [(home)] + [(end)] + ;; Fix-me: replace this with something + ;; pulling in help-event-list: + [(f1)] + execute-extended-command + eval-expression) + "Key sequences or commands that should not be overriden during resize. +The purpose is to make it easier to switch windows. The functions +`windmove-left' etc depends on the position when chosing the +window to move to." + :type '(repeat + (choice + ;; Note: key-sequence must be before command here, since + ;; the key sequences seems to match command too. + key-sequence command)) + :set (lambda (sym val) + (set-default sym val) + (winsize-make-keymap val)) + :group 'winsize) + +(defcustom winsize-selected-window-face 'winsize-selected-window-face + "Variable holding face for marking selected window. +This variable may be nil or a face symbol." + :type '(choice (const :tag "Do not mark selected window" nil) + face) + :group 'winsize) + +(defface winsize-selected-window-face + '((t (:inherit secondary-selection))) + "Face for marking selected window." + :group 'winsize) + + +;;; These variables all holds values to be reset when exiting resizing: + +(defvar winsize-old-mode-line-bg nil) +(defvar winsize-old-mode-line-inactive-bg nil) +(defvar winsize-old-overriding-terminal-local-map nil) +(defvar winsize-old-overriding-local-map-menu-flag nil) +(defvar winsize-old-temp-buffer-show-function nil) +(defvar winsize-old-mouse-avoidance-mode nil + "Hold the value of `mouse-avoidance-mode' at resizing start.") +(defvar winsize-old-view-exit-action nil) +(make-variable-buffer-local 'winsize-old-view-exit-action) + +(defvar winsize-message-end nil + "Marker, maybe at end of message buffer.") + +(defvar winsize-resizing nil + "t during resizing, nil otherwise.") + +(defvar winsize-window-config-init nil + "Hold window configuration from resizing start.") + +(defvar winsize-frame nil + "Frame that `resize-windows' is operating on.") + + +;;; Borders + +(defvar winsize-window-for-side-hor nil + "Window used internally for resizing in vertical direction.") + +(defvar winsize-window-for-side-ver nil + "Window used internally for resizing in horizontal direction.") + +(defvar winsize-border-hor nil + "Use internally to remember border choice. +This is set by `winsize-pre-command' and checked by +`winsize-post-command', see the latter for more information. + +The value should be either nil, 'left or 'right.") + +(defvar winsize-border-ver nil + "Use internally to remember border choice. +This is set by `winsize-pre-command' and checked by +`winsize-post-command', see the latter for more information. + +The value should be either nil, 'up or 'down.") + +(defvar winsize-window-at-entry nil + "Window that was selected when `resize-windows' started.") + + +;;; Keymap, interactive functions etc + +(defun winsize-pre-command () + "Do this before every command. +Runs this in `pre-command-hook'. + +Remember the currently used border sides for resizing. Also +remember position in message buffer to be able to see if next +command outputs some message. + +For more information see `winsize-post-command'." + (setq winsize-message-end (winsize-message-end)) + (setq winsize-border-hor (winsize-border-used-hor)) + (setq winsize-border-ver (winsize-border-used-ver))) + +(defun winsize-post-command () + "Done after every command. +Run this in `post-command-hook'. + +Check the border sides \(left/right, up/down) remembered in +`winsize-pre-command' and use the the same side if possible, +otherwise the opposite side if that is possible. \(This check is +of course not done if the last command changed the border side.) + +The reason for selecting borders this way is to try to give the +user a coherent and easy picture of what is going on when +changing window or when window structure is changed. \(Note that +the commands moving to another window or changing the window +structure does not have to belong to this package. Those commands +can therefore not select the border sides.) + +Give the user feedback about selected window and borders. Also +give a short help message unless last command gave some message." + (unless winsize-juris-way + (unless winsize-border-hor + (winsize-select-initial-border-hor)) + (when winsize-border-hor + (winsize-set-border winsize-border-hor t)) + (unless winsize-border-ver + (winsize-select-initial-border-ver)) + (when winsize-border-ver + (winsize-set-border winsize-border-ver t))) + (winsize-tell-user)) + +;;;###autoload +(defun resize-windows () + "Start window resizing. +During resizing a window is selected. You can move its +borders. In the default configuration the arrow keys moves the +right or bottom border if they are there. To move the opposite +border use S-arrowkeys. + +You can also do other window operations, like splitting, deleting +and balancing the sizes. The keybindings below describes the key +bindings during resizing:\\<winsize-keymap> + + `balance-windows' \\[balance-windows] + `winsize-balance-siblings' \\[winsize-balance-siblings] + `fit-window-to-buffer' \\[fit-window-to-buffer] + `shrink-window-if-larger-than-buffer' \\[shrink-window-if-larger-than-buffer] + + `winsav-rotate' \\[winsav-rotate] + + `winsize-move-border-up' \\[winsize-move-border-up] + `winsize-move-border-down' \\[winsize-move-border-down] + `winsize-move-border-left' \\[winsize-move-border-left] + `winsize-move-border-right' \\[winsize-move-border-right] + + `winsize-to-border-or-window-left' \\[winsize-to-border-or-window-left] + `winsize-to-border-or-window-up' \\[winsize-to-border-or-window-up] + `winsize-to-border-or-window-right' \\[winsize-to-border-or-window-right] + `winsize-to-border-or-window-down' \\[winsize-to-border-or-window-down] + + Note that you can also use your normal keys for + `forward-char', `backward-char', `next-line', `previous-line' + and what you have on HOME and END to move in the windows. That + might sometimes be necessary to directly select a + window. \(You may however also use `other-window' or click + with the mouse, see below.) + + `delete-window' \\[delete-window] + `delete-other-windows' \\[delete-other-windows] + `split-window-vertically' \\[split-window-vertically] + `split-window-horizontally' \\[split-window-horizontally] + `other-window' \\[other-window] + + `winsize-save-window-configuration' \\[winsize-save-window-configuration] + `winsize-next-window-configuration' \\[winsize-next-window-configuration] + `winsize-previous-window-configuration' \\[winsize-previous-window-configuration] + + `mouse-set-point' \\[mouse-set-point] + + `winsize-quit' \\[winsize-quit] + `winsize-stop-go-back' \\[winsize-stop-go-back] + `winsize-stop' \\[winsize-stop] + `winsize-stop-and-execute' \\[winsize-stop-and-execute] + + `winsize-help' \\[winsize-help] + `describe-key' \\[describe-key] + `describe-key-briefly' \\[describe-key-briefly] + (All the normal help keys work, and at least those above will + play well with resizing.) + +Nearly all other keys exits window resizing and they are also +executed. However, the key sequences in `winsize-let-me-use' and +dito for commands there are also executed without exiting +resizing. + +The colors of the modelines are changed to those given in +`winsize-mode-line-colors' to indicate that you are resizing +windows. To make this indication more prominent the text in the +selected window is marked with the face hold in the variable +`winsize-selected-window-face'. + +The option `winsize-juris-way' decides how the borders to move +are selected. If this option is non-nil then the right or bottom +border are the ones that are moved with the arrow keys and the +opposite border with shift arrow keys. + +If `winsize-juris-way' is nil then the following apply: + +As you select other borders or move to new a window the mouse +pointer is moved inside the selected window to show which borders +are beeing moved. The mouse jumps a little bit to make its +position more visible. You can turn this off by customizing +`winsize-make-mouse-prominent'. + +Which borders initially are choosen are controlled by the +variable `winsize-autoselect-borders'. + +** Example: Border selection, movements and windows. + + Suppose you have a frame divided into windows like in the + figure below. If window B is selected when you start resizing + then \(with default settings) the borders marked with 'v' and + 'h' will be the ones that the arrow keys moves. To indicate + this the mouse pointer is placed in the right lower corner of + the selected window B. + + +----------+-----------+--------+ + | | v | + | | v | + | A | _B_ v | + | | v | + | | v | + | | x v | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + Now if you press M-<left> then the picture below shows what has + happened. Note that the selected vertical border is now the one + between A and B. The mouse pointer has moved to the + corresponding corner in the window B, which is still selected. + + +----------+-----------+--------+ + | v | | + | v | | + | A v _B_ | | + | v | | + | v | | + | v x | | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + Press M-<left> once again. This gives this picture: + + +----------+-----------+--------+ + | v | | + | v | | + | _A_ v B | | + | v | | + | v | | + | x v | | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + Note that the window A is now selected. However there is no + border that could be moved to the left of this window \(which + would otherwise be chosen now) so the border between A and B is + still the one that <left> and <right> moves. The mouse has + moved to A. + + If we now delete window A the new situation will look like + this: + + +----------+-----------+--------+ + | | | + | | | + | _B_ | | + | | | + | | | + | x | | + +hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh+ + | | | + | | | + | | | + | | | + | | | + | | | + +----------+---------+----------+ + + + +>>>> testing stuff >>>> +`help-mode-hook' +`temp-buffer-show-function' +`view-exit-action' +<<<<<<<<<<<<<<<<<<<<<<< +" + (interactive) + (setq winsize-resizing t) + ;; Save old values: + (unless winsize-old-mouse-avoidance-mode + (setq winsize-old-mouse-avoidance-mode mouse-avoidance-mode)) + ;; Setup user feedback things: + (mouse-avoidance-mode 'none) + (winsize-set-mode-line-colors t) + (winsize-create-short-help-message) + (setq winsize-message-end (winsize-message-end)) + ;; Save config for exiting: + (setq winsize-window-config-init (current-window-configuration)) + (setq winsize-window-at-entry (selected-window)) + (setq winsize-frame (selected-frame)) + ;; Setup keymap and command hooks etc: + (winsize-setup-local-map) + (winsize-add-command-hooks) + (setq winsize-window-for-side-hor nil) + (setq winsize-window-for-side-ver nil)) + + +(defun winsize-setup-local-map () + "Setup an overriding keymap and use this during resizing. +Save current keymaps." + ;; Fix-me: use copy-keymap for old? + (unless winsize-old-overriding-terminal-local-map + (setq winsize-old-overriding-terminal-local-map overriding-terminal-local-map)) + (setq overriding-terminal-local-map (copy-keymap winsize-keymap)) + (setq winsize-old-overriding-local-map-menu-flag overriding-local-map-menu-flag) + (setq overriding-local-map-menu-flag t)) + +(defun winsize-restore-local-map () + "Restore keymaps saved by `winsize-setup-local-map'." + (setq overriding-terminal-local-map winsize-old-overriding-terminal-local-map) + (setq winsize-old-overriding-terminal-local-map nil) + (setq overriding-local-map-menu-flag winsize-old-overriding-local-map-menu-flag) + (setq winsize-old-overriding-local-map-menu-flag nil)) + + +(defvar winsize-window-config-help nil + "Hold window configuration when help is shown.") + +(defvar winsize-window-config-init-help nil + "Hold window configuration from resizing start during help.") + +(defvar winsize-help-frame nil + "The frame from which help was called.") + +(defun winsize-restore-after-help (buffer) + "Restore window configuration after help. +Raise frame and reactivate resizing." + (remove-hook 'temp-buffer-setup-hook 'winsize-help-mode-hook-function) + (setq temp-buffer-show-function winsize-old-temp-buffer-show-function) + ;; Get rid of the view exit action and the extra text in the help + ;; buffer: + (with-current-buffer (help-buffer) + (setq view-exit-action winsize-old-view-exit-action) + (setq winsize-old-view-exit-action nil) + (let ((here (point-marker)) + (inhibit-read-only t)) + (goto-char (point-min)) + (forward-line 2) + (delete-region (point-min) (point)) + (goto-char (point-max)) + (forward-line -2) + (delete-region (point) (point-max)) + (goto-char here))) + ;; Restart resizing, restoring window configurations: + (when (select-frame winsize-help-frame) + (raise-frame) + (set-window-configuration winsize-window-config-help) + (resize-windows) + (setq winsize-window-config-init winsize-window-config-init-help))) + +(defun winsize-help-mode-hook-function () + "Setup temp buffer show function to only run second step. +The first step, `winsize-temp-buffer-show-function', has already been run." + (setq temp-buffer-show-function 'winsize-temp-buffer-show-function-1)) + +(defun winsize-temp-buffer-show-function (buffer) + "First step of setup for showing help during resizing. +This step is run when showing help during resizing. + +Save window configuration etc to be able to resume resizing. Stop +resizing. Delete other windows. + +Run second step (`winsize-temp-buffer-show-function-1') and +arrange so that second step is run when following help links." + (setq winsize-window-config-help (current-window-configuration)) + (setq winsize-window-config-init-help winsize-window-config-init) + (setq winsize-help-frame (selected-frame)) + (winsize-stop) + (delete-other-windows) + (winsize-temp-buffer-show-function-1 buffer) + (add-hook 'temp-buffer-setup-hook 'winsize-help-mode-hook-function)) + +(defun winsize-temp-buffer-show-function-1 (buffer) + "Second step of setup for showing help during resizing. +This is run after the first step when accessing help during +resizing. It is also when following help links." + (with-current-buffer buffer + (let ((inhibit-read-only t) + (buffer-read-only t) ;; It is reverted in `help-mode-finish' + ) + (run-hooks 'temp-buffer-show-hook)) + (let ((here (point-marker)) + (str "*** Type q to return to window resizing ***")) + (put-text-property 0 (length str) 'face 'highlight str) + (goto-char (point-min)) + (insert str "\n\n") + (goto-char (point-max)) + (insert "\n\n" str) + (goto-char here) + (setq buffer-read-only t)) + (unless winsize-old-view-exit-action + (setq winsize-old-view-exit-action view-exit-action) + (setq view-exit-action 'winsize-restore-after-help))) + (set-window-buffer (selected-window) buffer) + (message "Type q to return to window resizing")) + +(defun winsize-help () + "Give help during resizing. +Save current window configuration and pause resizing." + (interactive) + (if pop-up-frames + (progn + (winsize-exit-resizing nil) + (describe-function 'resize-windows)) + ;; Fix-me: move setup of view-exit-action etc here. Or was it + ;; temp-buffer-show-function? + ;; Setup help hooks etc: + (unless (or winsize-old-temp-buffer-show-function + ;; These things should not happen... : + (eq temp-buffer-show-function 'winsize-temp-buffer-show-function) + (eq temp-buffer-show-function 'winsize-temp-buffer-show-function-1)) + (setq winsize-old-temp-buffer-show-function temp-buffer-show-function)) + (setq temp-buffer-show-function 'winsize-temp-buffer-show-function) + (with-output-to-temp-buffer (help-buffer) + (with-current-buffer (help-buffer) + (insert "resize-windows is ") + (describe-function-1 'resize-windows))))) + +(defun winsize-quit () + "Quit resing, restore window configuration at start." + (interactive) + (set-window-configuration winsize-window-config-init) + (winsize-exit-resizing nil)) + +(defun winsize-stop-go-back () + "Exit window resizing. Go back to the window started in." + (interactive) + (winsize-exit-resizing nil t)) + +(defun winsize-stop-and-execute () + "Exit window resizing and put last key on the input queue. +Select the window marked during resizing before putting back the +last key." + ;; Fix-me: maybe replace this with a check of this-command in + ;; post-command-hook instead? + (interactive) + (winsize-exit-resizing t)) + +(defun winsize-stop () + "Exit window resizing. +Select the window marked during resizing." + (interactive) + (winsize-exit-resizing nil)) + +;;;###autoload +(defun winsize-balance-siblings () + "Make current window siblings the same height or width. +It works the same way as `balance-windows', but only for the +current window and its siblings." + (interactive) + (balance-windows (selected-window))) + +(defun winsize-to-border-or-window-left () + "Switch to border leftwards, maybe moving to next window. +If already at the left border, then move to left window, the same +way `windmove-left' does." + (interactive) (winsize-switch-border 'left t)) + +(defun winsize-to-border-or-window-right () + "Switch to border rightwards, maybe moving to next window. +For more information see `winsize-to-border-or-window-left'." + (interactive) (winsize-switch-border 'right t)) + +(defun winsize-to-border-or-window-up () + "Switch to border upwards, maybe moving to next window. +For more information see `winsize-to-border-or-window-left'." + (interactive) (winsize-switch-border 'up t)) + +(defun winsize-to-border-or-window-down () + "Switch to border downwards, maybe moving to next window. +For more information see `winsize-to-border-or-window-left'." + (interactive) (winsize-switch-border 'down t)) + + +(defun winsize-move-border-left () + "Move border left, but select border first if not done." + (interactive) (winsize-resize 'left nil)) + +(defun winsize-move-border-right () + "Move border right, but select border first if not done." + (interactive) (winsize-resize 'right nil)) + +(defun winsize-move-border-up () + "Move border up, but select border first if not done." + (interactive) (winsize-resize 'up nil)) + +(defun winsize-move-border-down () + "Move border down, but select border first if not done." + (interactive) (winsize-resize 'down nil)) + + +(defun winsize-move-other-border-left () + "Move border left, but select border first if not done." + (interactive) (winsize-resize 'left t)) + +(defun winsize-move-other-border-right () + "Move border right, but select border first if not done." + (interactive) (winsize-resize 'right t)) + +(defun winsize-move-other-border-up () + "Move border up, but select border first if not done." + (interactive) (winsize-resize 'up t)) + +(defun winsize-move-other-border-down () + "Move border down, but select border first if not done." + (interactive) (winsize-resize 'down t)) + + +;;; Internals + + + +(defun winsize-exit-resizing (put-back-last-event &optional stay) + "Stop window resizing. +Put back mode line colors and keymaps that were changed. + +Upon exit first select window. If STAY is non-nil then select +the window which was selected when `resize-windows' was called, +otherwise select the last window used during resizing. After +that, if PUT-BACK-LAST-EVENT is non-nil, put back the last input +event on the input queue." + (setq winsize-resizing nil) + ;; Reset user feedback things: + (mouse-avoidance-mode winsize-old-mouse-avoidance-mode) + (setq winsize-old-mouse-avoidance-mode nil) + (winsize-set-mode-line-colors nil) + (winsize-mark-selected-window nil) + ;; Remove all hooks etc for help: + (if (or (eq winsize-old-temp-buffer-show-function 'winsize-temp-buffer-show-function) + (eq winsize-old-temp-buffer-show-function 'winsize-temp-buffer-show-function-1)) + (setq temp-buffer-show-function nil) + (setq temp-buffer-show-function winsize-old-temp-buffer-show-function)) + (setq winsize-old-temp-buffer-show-function nil) + (remove-hook 'help-mode-hook 'winsize-help-mode-hook-function) + (remove-hook 'temp-buffer-setup-hook 'winsize-help-mode-hook-function) + ;; Restore keymap and command hooks: + (winsize-restore-local-map) + (winsize-remove-command-hooks) + ;; Exit: + (when stay (select-window winsize-window-at-entry)) + (message "Exited window resizing") + (when (and put-back-last-event) + ;; Add this to the input queue again: + (isearch-unread last-command-event))) + +(defun winsize-add-command-hooks () + (add-hook 'pre-command-hook 'winsize-pre-command) + (add-hook 'post-command-hook 'winsize-post-command)) + +(defun winsize-remove-command-hooks () + (remove-hook 'pre-command-hook 'winsize-pre-command) + (remove-hook 'post-command-hook 'winsize-post-command)) + + +;;; Borders + +(defun winsize-border-used-hor () + "Return the border side used for horizontal resizing." + (let ((hor (when winsize-window-for-side-hor + (if (eq (selected-window) winsize-window-for-side-hor) + 'right + 'left)))) + hor)) + +(defun winsize-border-used-ver () + "Return the border side used for vertical resizing." + (let ((ver (when winsize-window-for-side-ver + (if (eq (selected-window) winsize-window-for-side-ver) + 'down + 'up)))) + ver)) + +(defun winsize-switch-border (dir allow-windmove) + "Switch border that is beeing resized. +Switch to border in direction DIR. If ALLOW-WINDMOVE is non-nil +then change window if necessary, otherwise stay and do not change +border." + (let* ((window-in-that-dir (windmove-find-other-window + dir nil (selected-window)))) + (when (window-minibuffer-p window-in-that-dir) + (setq window-in-that-dir nil)) + (if winsize-juris-way + (if (not window-in-that-dir) + (message "No window in that direction") + (windmove-do-window-select dir nil)) + (if (not window-in-that-dir) + (message "No window or border in that direction") + (let* ((is-hor (memq dir '(left right))) + (border-used (if is-hor + (winsize-border-used-hor) + (winsize-border-used-ver))) + (using-dir-border (eq dir border-used))) + (if using-dir-border + (when allow-windmove + (setq winsize-window-for-side-hor nil) + (setq winsize-window-for-side-ver nil) + (windmove-do-window-select dir nil) + (message "Moved to new window")) + (winsize-select-border dir) + (message "Switched to border %swards" dir))))))) + + +(defun winsize-select-initial-border-hor () + "Select a default border horizontally." + (if winsize-juris-way + (winsize-set-border 'right t) + (let ((has-left (winsize-window-beside (selected-window) 'left)) + (has-right (winsize-window-beside (selected-window) 'right))) + (cond + ((not winsize-autoselect-borders) t) + ((eq winsize-autoselect-borders 'when-single) + (when (= 1 (length (delq nil (list has-left has-right)))) + (winsize-select-border 'right))) + (t + (winsize-select-border 'right)))))) + +(defun winsize-select-initial-border-ver () + "Select a default border vertically." + (if winsize-juris-way + (winsize-set-border 'up t) + (let ((has-up (winsize-window-beside (selected-window) 'up)) + (has-down (winsize-window-beside (selected-window) 'down))) + (cond + ((not winsize-autoselect-borders) t) + ((eq winsize-autoselect-borders 'when-single) + (when (= 1 (length (delq nil (list has-up has-down)))) + (winsize-select-border 'up))) + (t + (winsize-select-border 'up)))))) + +(defun winsize-select-border (dir) + "Select border to be set for resizing. +The actually setting is done in `post-command-hook'." + (cond + ((memq dir '(left right)) + (setq winsize-border-hor dir)) + ((memq dir '(up down)) + (setq winsize-border-ver dir)) + (t (error "Bad DIR=%s" dir)))) + +(defun winsize-set-border (dir allow-other-side) + "Set border for resizing." + (let ((window-beside (winsize-window-beside (selected-window) dir)) + (horizontal (memq dir '(left right)))) + (unless window-beside + (when allow-other-side + (setq dir (winsize-other-side dir)) + (setq window-beside + (winsize-window-beside (selected-window) dir)))) + (if horizontal + (progn + (setq winsize-border-hor nil) + (setq winsize-window-for-side-hor nil)) + (setq winsize-border-ver nil) + (setq winsize-window-for-side-ver nil)) + (when window-beside + (let ((window-for-side (if (memq dir '(right down)) + (selected-window) + window-beside))) + (if horizontal + (setq winsize-window-for-side-hor window-for-side) + (setq winsize-window-for-side-ver window-for-side)))))) + +(defun winsize-resize (dir other-side) + "Choose border to move. Or if border is chosen move that border. +Used by `winsize-move-border-left' etc." + (when winsize-juris-way + (let ((bside (if (memq dir '(left right)) + (if other-side 'left 'right) + (if other-side 'up 'down)))) + (winsize-set-border bside t))) + (let* ((horizontal (memq dir '(left right))) + (arg (if (memq dir '(left up)) -1 1)) + (window-for-side (if horizontal 'winsize-window-for-side-hor 'winsize-window-for-side-ver)) + (window-for-side-val (symbol-value window-for-side))) + (if (not window-for-side-val) + (winsize-select-border dir) + (when (and winsize-resizing + (not (eq window-for-side-val 'checked))) + (condition-case err + (adjust-window-trailing-edge (symbol-value window-for-side) arg horizontal) + (error (message "%s" (error-message-string err)))))))) + +(defun winsize-other-side (side) + "Return other side for 'left etc, ie 'left => 'right." + (cond + ((eq side 'left) 'right) + ((eq side 'right) 'left) + ((eq side 'up) 'down) + ((eq side 'down) 'up) + (t (error "Invalid SIDE=%s" side)))) + +(defun winsize-window-beside (window side) + "Return a window directly beside WINDOW at side SIDE. +That means one whose edge on SIDE is touching WINDOW. SIDE +should be one of 'left, 'up, 'right and 'down." + (require 'windmove) + (let* ((windmove-wrap-around nil) + (win (windmove-find-other-window side nil window))) + (unless (window-minibuffer-p win) + win))) + + +;;; Window configs + +(defconst winsize-window-configuration-ring (make-ring 20) + "Hold window configurations.") + +(defun winsize-ring-rotate (ring forward) + (when (< 1 (ring-length ring)) + (if forward + (ring-insert ring (ring-remove ring nil)) + (ring-insert-at-beginning ring (ring-remove ring 0))))) + +(defun winsize-ring-index (ring elem) + (let ((memb (member elem (ring-elements ring)))) + (when memb + (- (ring-length ring) + (length memb))))) + +(defun winsize-previous-window-configuration () + (interactive) + (winsize-goto-window-configuration nil)) + +(defun winsize-next-window-configuration () + (interactive) + (winsize-goto-window-configuration t)) + +(defun winsize-goto-window-configuration (forward) + (let* ((curr-conf (current-window-configuration)) + (ring winsize-window-configuration-ring) + (idx (winsize-ring-index ring curr-conf))) + (if idx + (progn + (setq idx (if forward (1- idx) (1+ idx))) + (set-window-configuration (ring-ref ring idx))) + ;; Unfortunately idx often seems to be nil so we will have to + ;; rotate the ring (or something similar). + (winsize-ring-rotate ring forward) + (set-window-configuration (ring-ref ring 0))))) + +;;;###autoload +(defun winsize-save-window-configuration () + (interactive) + (let* ((curr-conf (current-window-configuration)) + (ring winsize-window-configuration-ring)) + (if (winsize-ring-index ring curr-conf) + (error "Current configuration was already stored") + (ring-insert ring curr-conf) + (message "Saved window config, use '<' or '>' to get it back")))) + + +;;; User feedback + +;;;###autoload +(defun winsize-set-mode-line-colors (on) + "Turn mode line colors on if ON is non-nil, otherwise off." + (if on + (progn + (unless winsize-old-mode-line-inactive-bg + (setq winsize-old-mode-line-inactive-bg (face-attribute 'mode-line-inactive :background))) + (unless winsize-old-mode-line-bg + (setq winsize-old-mode-line-bg (face-attribute 'mode-line :background))) + (let* ((use-colors (car winsize-mode-line-colors)) + (colors (cadr winsize-mode-line-colors)) + (active-color (elt colors 0)) + (inactive-color (elt colors 1))) + (when use-colors + (set-face-attribute 'mode-line-inactive nil :background inactive-color) + (set-face-attribute 'mode-line nil :background active-color)))) + (when winsize-old-mode-line-inactive-bg + (set-face-attribute 'mode-line-inactive nil :background winsize-old-mode-line-inactive-bg)) + (setq winsize-old-mode-line-inactive-bg nil) + (when winsize-old-mode-line-bg + (set-face-attribute 'mode-line nil :background winsize-old-mode-line-bg)) + (setq winsize-old-mode-line-bg nil))) + +(defvar winsize-short-help-message nil + "Short help message shown in echo area.") + +(defun winsize-create-short-help-message () + "Create short help message to show in echo area." + (let ((msg "")) + (mapc (lambda (rec) + (let ((fun (elt rec 0)) + (desc (elt rec 1)) + (etc (elt rec 2))) + (when (< 0 (length msg)) + (setq msg (concat msg ", "))) + (setq msg (concat msg + desc + ":" + (key-description + (where-is-internal fun winsize-keymap t)) + (if etc " etc" ""))))) + '( + (balance-windows "balance" nil) + (winsize-move-border-left "resize" t) + (winsize-to-border-or-window-left "border" nil) + )) + (setq msg (concat msg ", exit:RET, help:?")) + (setq winsize-short-help-message msg))) + +(defun winsize-move-mouse-to-resized () + "Move mouse to show which border(s) are beeing moved." + (let* ((edges (window-edges (selected-window))) + (L (nth 0 edges)) + (T (nth 1 edges)) + (R (nth 2 edges)) + (B (nth 3 edges)) + (x (/ (+ L R) 2)) + (y (/ (+ T B) 2))) + (when (and winsize-window-for-side-hor + (not (eq winsize-window-for-side-hor 'checked))) + (setq x (if (eq (selected-window) winsize-window-for-side-hor) (- R 6) (+ L 2)))) + (when (and winsize-window-for-side-ver + (not (eq winsize-window-for-side-ver 'checked))) + (setq y (if (eq (selected-window) winsize-window-for-side-ver) (- B 2) (+ T 0)))) + (set-mouse-position (selected-frame) x y))) + +(defvar winsize-selected-window-overlay nil) + +(defun winsize-mark-selected-window (active) + (when winsize-selected-window-overlay + (delete-overlay winsize-selected-window-overlay) + (setq winsize-selected-window-overlay nil)) + (when active + (with-current-buffer (window-buffer (selected-window)) + (let ((ovl (make-overlay (point-min) (point-max) nil t))) + (setq winsize-selected-window-overlay ovl) + (overlay-put ovl 'window (selected-window)) + (overlay-put ovl 'pointer 'arrow) + (overlay-put ovl 'priority 1000) + (when winsize-selected-window-face + (overlay-put ovl 'face winsize-selected-window-face)))))) + +(defun winsize-message-end () + "Return a marker at the end of the message buffer." + (with-current-buffer (get-buffer-create "*Messages*") + (point-max-marker))) + +(defvar winsize-move-mouse 1) + +(defvar winsize-make-mouse-prominent-timer nil) + +(defun winsize-move-mouse () + ;;(setq winsize-move-mouse (- winsize-move-mouse)) + (save-match-data ;; runs in timer + (let* ((fxy (mouse-pixel-position)) + (f (car fxy)) + (x (cadr fxy)) + (y (cddr fxy)) + (m (mod winsize-move-mouse 2)) + (d (* (if (= 0 m) 1 -1) 1))) + (set-mouse-pixel-position f (+ d x) (+ d y)) + (when (< 1 winsize-move-mouse) + (setq winsize-move-mouse (1- winsize-move-mouse)) + (setq winsize-make-mouse-prominent-timer + (run-with-timer 0.2 nil 'winsize-move-mouse)))))) + +(defun winsize-make-mouse-prominent-f (doit) + (when (and winsize-make-mouse-prominent-timer + (timerp winsize-make-mouse-prominent-timer)) + (cancel-timer winsize-make-mouse-prominent-timer)) + (when doit + (setq winsize-move-mouse 3) + (setq winsize-make-mouse-prominent-timer + (run-with-idle-timer 0.1 nil 'winsize-move-mouse)))) + +(defun winsize-tell-user () + "Give the user feedback." + (when winsize-mark-selected-window + (winsize-mark-selected-window t)) + (unless winsize-juris-way + (let ((move-mouse (not (member this-command + '(mouse-drag-mode-line + mouse-drag-vertical-line + scroll-bar-toolkit-scroll))))) + ;;(message "%s, move-mouse=%s" this-command move-mouse);(sit-for 2) + (when move-mouse + (winsize-move-mouse-to-resized)) + (when winsize-make-mouse-prominent + (winsize-make-mouse-prominent-f move-mouse)))) + (when (= winsize-message-end (winsize-message-end)) + (message "%s" winsize-short-help-message))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Window rotating and mirroring + +;;;###autoload +(defun winsav-rotate (mirror transpose) + "Rotate window configuration on selected frame. +MIRROR should be either 'mirror-left-right, 'mirror-top-bottom or +nil. In the first case the window configuration is mirrored +vertically and in the second case horizontally. If MIRROR is nil +the configuration is not mirrored. + +If TRANSPOSE is non-nil then the window structure is transposed +along the diagonal from top left to bottom right (in analogy with +matrix transosition). + +If called interactively MIRROR will is 'mirror-left-right by +default, but 'mirror-top-bottom if called with prefix. TRANSPOSE +is t. This mean that the window configuration will be turned one +quarter clockwise (or counter clockwise with prefix)." + (interactive (list + (if current-prefix-arg + 'mirror-left-right + 'mirror-top-bottom) + t)) + (require 'winsav) + (let* ((wintree (winsav-get-window-tree)) + (tree (cadr wintree)) + (win-config (current-window-configuration))) + ;;(winsav-log "old-wintree" wintree) + (winsav-transform-1 tree mirror transpose) + ;;(winsav-log "new-wintree" wintree) + ;; + ;; Fix-me: Stay in corresponding window. How? + (delete-other-windows) + (condition-case err + (winsav-put-window-tree wintree (selected-window)) + (error + (set-window-configuration win-config) + (message "Can't rotate: %s" (error-message-string err)))) + )) + + +(provide 'winsize) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; winsize.el ends here diff --git a/emacs/nxhtml/util/wrap-to-fill.el b/emacs/nxhtml/util/wrap-to-fill.el new file mode 100644 index 0000000..223ce1b --- /dev/null +++ b/emacs/nxhtml/util/wrap-to-fill.el @@ -0,0 +1,364 @@ +;;; wrap-to-fill.el --- Make a fill-column wide space for editing +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-08-12 Wed +;; Version: +;; Last-Updated: x +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(eval-when-compile (require 'mumamo)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Wrapping + +;;;###autoload +(defgroup wrap-to-fill nil + "Customizing of `wrap-to-fill-column-mode'." + :group 'convenience) + +;;;###autoload +(defcustom wrap-to-fill-left-marg nil + "Left margin handling for `wrap-to-fill-column-mode'. +Used by `wrap-to-fill-column-mode'. If nil then center the +display columns. Otherwise it should be a number which will be +the left margin." + :type '(choice (const :tag "Center" nil) + (integer :tag "Left margin")) + :group 'wrap-to-fill) +(make-variable-buffer-local 'wrap-to-fill-left-marg) + +(defvar wrap-to-fill--saved-state nil) +;;(make-variable-buffer-local 'wrap-to-fill--saved-state) +(put 'wrap-to-fill--saved-state 'permanent-local t) + +;;;###autoload +(defcustom wrap-to-fill-left-marg-modes + '(text-mode + fundamental-mode) + "Major modes where `wrap-to-fill-left-margin' may be nil." + :type '(repeat command) + :group 'wrap-to-fill) + + + ;;ThisisaVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongWord ThisisaVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongWord + +(defun wrap-to-fill-wider () + "Increase `fill-column' with 10." + (interactive) + (setq fill-column (+ fill-column 10)) + (wrap-to-fill-set-values-in-buffer-windows)) + +(defun wrap-to-fill-narrower () + "Decrease `fill-column' with 10." + (interactive) + (setq fill-column (- fill-column 10)) + (wrap-to-fill-set-values-in-buffer-windows)) + +(defun wrap-to-fill-normal () + "Reset `fill-column' to global value." + (interactive) + ;;(setq fill-column (default-value 'fill-column)) + (kill-local-variable 'fill-column) + (wrap-to-fill-set-values-in-buffer-windows)) + +(defvar wrap-to-fill-column-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?+] 'wrap-to-fill-wider) + (define-key map [(control ?c) ?-] 'wrap-to-fill-narrower) + (define-key map [(control ?c) ?0] 'wrap-to-fill-normal) + map)) + +;; Fix-me: Maybe make the `wrap-prefix' behavior an option or separate +;; minor mode. + +;; Fix-me: better handling of left-column in mumamo buffers (and other +;; if possible). + +;;;###autoload +(define-minor-mode wrap-to-fill-column-mode + "Use `fill-column' display columns in buffer windows. +By default the display columns are centered, but see the option +`wrap-to-fill-left-marg'. + +Fix-me: +Note 1: When turning this on `visual-line-mode' is also turned on. This +is not reset when turning off this mode. + +Note 2: The text properties 'wrap-prefix and 'wrap-to-fill-prefix +is set by this mode to indent continuation lines. + +Key bindings added by this minor mode: + +\\{wrap-to-fill-column-mode-map}" + :lighter " WrapFill" + :group 'wrap-to-fill + ;; (message "wrap-to-fill-column-mode %s, cb=%s, major=%s, multi=%s" wrap-to-fill-column-mode (current-buffer) + ;; major-mode mumamo-multi-major-mode) + (if wrap-to-fill-column-mode + (progn + ;; Old values (idea from visual-line-mode) + (set (make-local-variable 'wrap-to-fill--saved-state) nil) + (dolist (var '(visual-line-mode + ;;left-margin-width + ;;right-margin-width + )) + (push (list var (symbol-value var) (local-variable-p var)) + wrap-to-fill--saved-state)) + ;; Hooks + (add-hook 'window-configuration-change-hook 'wrap-to-fill-set-values nil t) + ;; Wrapping + (visual-line-mode 1) + (wrap-to-fill-set-values-in-buffer-windows)) + ;; Hooks + (remove-hook 'window-configuration-change-hook 'wrap-to-fill-set-values t) + ;; Old values + (dolist (saved wrap-to-fill--saved-state) + (let ((var (nth 0 saved)) + (val (nth 1 saved)) + (loc (nth 2 saved))) + (cond + ((eq var 'visual-line-mode) + (unless val (visual-line-mode -1))) + (t + (if loc + (set (make-local-variable var) val) + (kill-local-variable var)))))) + (kill-local-variable 'wrap-to-fill--saved-state) + ;; Margins + (dolist (win (get-buffer-window-list (current-buffer))) + (set-window-margins win left-margin-width right-margin-width)) + ;; Indentation + (let ((here (point)) + (inhibit-field-text-motion t) + beg-pos + end-pos) + (mumamo-with-buffer-prepared-for-jit-lock + (save-restriction + (widen) + (goto-char (point-min)) + (while (< (point) (point-max)) + (setq beg-pos (point)) + (setq end-pos (line-end-position)) + (when (equal (get-text-property beg-pos 'wrap-prefix) + (get-text-property beg-pos 'wrap-to-fill-prefix)) + (remove-list-of-text-properties + beg-pos end-pos + '(wrap-prefix))) + (forward-line)) + (remove-list-of-text-properties + (point-min) (point-max) + '(wrap-to-fill-prefix))) + (goto-char here)))) + (wrap-to-fill-font-lock wrap-to-fill-column-mode)) +(put 'wrap-to-fill-column-mode 'permanent-local t) + +(defcustom wrap-to-fill-major-modes '(org-mode + html-mode + nxhtml-mode) + "Major modes where to turn on `wrap-to-fill-column-mode'" + ;;:type '(repeat major-mode) + :type '(repeat command) + :group 'wrap-to-fill) + +(defun wrap-to-fill-turn-on-in-buffer () + "Turn on fun for globalization." + (when (catch 'turn-on + (dolist (m wrap-to-fill-major-modes) + (when (derived-mode-p m) + (throw 'turn-on t)))) + (wrap-to-fill-column-mode 1))) + +(define-globalized-minor-mode wrap-to-fill-column-global-mode wrap-to-fill-column-mode + wrap-to-fill-turn-on-in-buffer + :group 'wrap-to-fill) + +;; Fix-me: There is a confusion between buffer and window margins +;; here. Also the doc says that left-margin-width and dito right may +;; be nil. However they seem to be 0 by default, but when displaying a +;; buffer in a window then window-margins returns (nil). + +(defvar wrap-to-fill-timer nil) +(make-variable-buffer-local 'wrap-to-fill-timer) + +(defun wrap-to-fill-set-values () + (when (timerp wrap-to-fill-timer) + (cancel-timer wrap-to-fill-timer)) + (setq wrap-to-fill-timer + (run-with-idle-timer 0 nil 'wrap-to-fill-set-values-in-timer + (selected-window) (current-buffer)))) +(put 'wrap-to-fill-set-values 'permanent-local-hook t) + +(defun wrap-to-fill-set-values-in-timer (win buf) + (condition-case err + (when (buffer-live-p buf) + (wrap-to-fill-set-values-in-buffer-windows buf)) + (error (message "ERROR wrap-to-fill-set-values-in-timer: %s" + (error-message-string err))))) + +(defun wrap-to-fill-set-values-in-timer-old (win buf) + (when (and (window-live-p win) (buffer-live-p buf) + (eq buf (window-buffer win))) + (condition-case err + (with-current-buffer buf + (when wrap-to-fill-column-mode + (wrap-to-fill-set-values-in-window win))) + (error (message "ERROR wrap-to-fill-set-values: %s" + (error-message-string err)))))) + +(defun wrap-to-fill-set-values-in-buffer-windows (&optional buffer) + "Use `fill-column' display columns in buffer windows." + (let ((buf-windows (get-buffer-window-list (or buffer + (current-buffer)) + nil + t))) + (dolist (win buf-windows) + (if wrap-to-fill-column-mode + (wrap-to-fill-set-values-in-window win) + (set-window-buffer nil (current-buffer)))))) + +(defvar wrap-old-win-width nil) +(make-variable-buffer-local 'wrap-old-win-width) +;; Fix-me: compensate for left-margin-width etc +(defun wrap-to-fill-set-values-in-window (win) + (with-current-buffer (window-buffer win) + (when wrap-to-fill-column-mode + (let* ((win-width (window-width win)) + (win-margs (window-margins win)) + (win-full (+ win-width + (or (car win-margs) 0) + (or (cdr win-margs) 0))) + (extra-width (- win-full fill-column)) + (fill-left-marg (unless (memq major-mode wrap-to-fill-left-marg-modes) + (or (when (> left-margin-width 0) left-margin-width) + wrap-to-fill-left-marg))) + (left-marg (if fill-left-marg + fill-left-marg + (- (/ extra-width 2) 1))) + ;; Fix-me: Why do I have to subtract 1 here...??? + (right-marg (- win-full fill-column left-marg 1)) + (need-update nil) + ) + ;; (when wrap-old-win-width + ;; (unless (= wrap-old-win-width win-width) + ;; (message "-") + ;; (message "win-width 0: %s => %s, win-full=%s, e=%s l/r=%s/%s %S %S %S" wrap-old-win-width win-width win-full extra-width left-marg right-marg (window-edges) (window-inside-edges) (window-margins)) + ;; )) + (setq wrap-old-win-width win-width) + (unless (> left-marg 0) (setq left-marg 0)) + (unless (> right-marg 0) (setq right-marg 0)) + (unless nil;(= left-marg (or left-margin-width 0)) + ;;(setq left-margin-width left-marg) + (setq need-update t)) + (unless nil;(= right-marg (or right-margin-width 0)) + ;;(setq right-margin-width right-marg) + (setq need-update t)) + ;;(message "win-width a: %s => %s, win-full=%s, e=%s l/r=%s/%s %S %S %S" wrap-old-win-width win-width win-full extra-width left-margin-width right-margin-width (window-edges) (window-inside-edges) (window-margins)) + (when need-update + ;;(set-window-buffer win (window-buffer win)) + ;;(run-with-idle-timer 0 nil 'set-window-buffer win (window-buffer win)) + ;;(dolist (win (get-buffer-window-list (current-buffer))) + ;; Fix-me: check window width... + (set-window-margins win left-marg right-marg) + ;;) + ;;(message "win-width b: %s => %s, win-full=%s, e=%s l/r=%s/%s %S %S %S" wrap-old-win-width win-width win-full extra-width left-marg right-marg (window-edges) (window-inside-edges) (window-margins)) + ) + )))) + +;; (add-hook 'post-command-hook 'my-win-post-command nil t) +;; (remove-hook 'post-command-hook 'my-win-post-command t) +(defun my-win-post-command () + (message "win-post-command: l/r=%s/%s %S %S %S" left-margin-width right-margin-width (window-edges) (window-inside-edges) (window-margins)) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font lock + +(defun wrap-to-fill-fontify (bound) + (save-restriction + (widen) + (while (< (point) bound) + (let ((this-bol (if (bolp) (point) + (1+ (line-end-position))))) + (unless (< this-bol bound) (setq this-bol nil)) + (when this-bol + (goto-char (+ this-bol 0)) + (let (ind-str + ind-str-fill + (beg-pos this-bol) + (end-pos (line-end-position))) + (when (equal (get-text-property beg-pos 'wrap-prefix) + (get-text-property beg-pos 'wrap-to-fill-prefix)) + ;; Find indentation + (skip-chars-forward "[:blank:]") + (setq ind-str (buffer-substring-no-properties beg-pos (point))) + ;; Any special markers like -, * etc + (if (and (< (1+ (point)) (point-max)) + (memq (char-after) '(?- ;; 45 + ?â ;; 8211 + ?* + )) + (eq (char-after (1+ (point))) ?\ )) + (setq ind-str-fill (concat " " ind-str)) + (setq ind-str-fill ind-str)) + ;;(setq ind-str-fill (concat " " ind-str)) + (mumamo-with-buffer-prepared-for-jit-lock + (put-text-property beg-pos end-pos 'wrap-prefix ind-str-fill) + (put-text-property beg-pos end-pos 'wrap-to-fill-prefix ind-str-fill)))))) + (forward-line 1)) + ;; Note: doing it line by line and returning t gave problem in mumamo. + (when nil ;this-bol + (set-match-data (list (point) (point))) + t))) + +(defun wrap-to-fill-font-lock (on) + ;; See mlinks.el + (let* ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords)) + (fontify-fun 'wrap-to-fill-fontify) + (args (list nil `(( ,fontify-fun ( 0 'font-lock-warning-face t )))))) + (when fontify-fun + (when on (setq args (append args (list t)))) + (apply add-or-remove args) + (font-lock-mode -1) + (font-lock-mode 1)))) + +(provide 'wrap-to-fill) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; wrap-to-fill.el ends here diff --git a/emacs/nxhtml/util/zencoding-mode.el b/emacs/nxhtml/util/zencoding-mode.el new file mode 100644 index 0000000..2545491 --- /dev/null +++ b/emacs/nxhtml/util/zencoding-mode.el @@ -0,0 +1,801 @@ +;;; zencoding-mode.el --- Unfold CSS-selector-like expressions to markup +;; +;; Copyright (C) 2009, Chris Done +;; +;; Author: Chris Done <chrisdone@gmail.com> +(defconst zencoding-mode:version "0.5") +;; Last-Updated: 2009-11-20 Fri +;; Keywords: convenience +;; +;; 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 3, 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: +;; +;; Unfold CSS-selector-like expressions to markup. Intended to be used +;; with sgml-like languages; xml, html, xhtml, xsl, etc. +;; +;; See `zencoding-mode' for more information. +;; +;; Copy zencoding-mode.el to your load-path and add to your .emacs: +;; +;; (require 'zencoding-mode) +;; +;; Example setup: +;; +;; (add-to-list 'load-path "~/Emacs/zencoding/") +;; (require 'zencoding-mode) +;; (add-hook 'sgml-mode-hook 'zencoding-mode) ;; Auto-start on any markup modes +;; +;; Enable the minor mode with M-x zencoding-mode. +;; +;; See ``Test cases'' section for a complete set of expression types. +;; +;; If you are hacking on this project, eval (zencoding-test-cases) to +;; ensure that your changes have not broken anything. Feel free to add +;; new test cases if you add new features. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; History: +;; +;; Modified by Lennart Borgman. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Generic parsing macros and utilities + +(eval-when-compile (require 'cl)) + +(defcustom zencoding-preview-default t + "If non-nil then preview is the default action. +This determines how `zencoding-expand-line' works by default." + :type 'boolean + :group 'zencoding) + +(defcustom zencoding-insert-flash-time 0.5 + "Time to flash insertion. +Set this to a negative number if you do not want flashing the +expansion after insertion." + :type '(number :tag "Seconds") + :group 'zencoding) + +(defmacro zencoding-aif (test-form then-form &rest else-forms) + "Anaphoric if. Temporary variable `it' is the result of test-form." + `(let ((it ,test-form)) + (if it ,then-form ,@(or else-forms '(it))))) + +(defmacro zencoding-pif (test-form then-form &rest else-forms) + "Parser anaphoric if. Temporary variable `it' is the result of test-form." + `(let ((it ,test-form)) + (if (not (eq 'error (car it))) ,then-form ,@(or else-forms '(it))))) + +(defmacro zencoding-parse (regex nums label &rest body) + "Parse according to a regex and update the `input' variable." + `(zencoding-aif (zencoding-regex ,regex input ',(number-sequence 0 nums)) + (let ((input (elt it ,nums))) + ,@body) + `,`(error ,(concat "expected " ,label)))) + +(defmacro zencoding-run (parser then-form &rest else-forms) + "Run a parser and update the input properly, extract the parsed + expression." + `(zencoding-pif (,parser input) + (let ((input (cdr it)) + (expr (car it))) + ,then-form) + ,@(or else-forms '(it)))) + +(defmacro zencoding-por (parser1 parser2 then-form &rest else-forms) + "OR two parsers. Try one parser, if it fails try the next." + `(zencoding-pif (,parser1 input) + (let ((input (cdr it)) + (expr (car it))) + ,then-form) + (zencoding-pif (,parser2 input) + (let ((input (cdr it)) + (expr (car it))) + ,then-form) + ,@else-forms))) + +(defun zencoding-regex (regexp string refs) + "Return a list of (`ref') matches for a `regex' on a `string' or nil." + (if (string-match (concat "^" regexp "\\([^\n]*\\)$") string) + (mapcar (lambda (ref) (match-string ref string)) + (if (sequencep refs) refs (list refs))) + nil)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Zen coding parsers + +(defun zencoding-expr (input) + "Parse a zen coding expression. This pretty much defines precedence." + (zencoding-run zencoding-siblings + it + (zencoding-run zencoding-parent-child + it + (zencoding-run zencoding-multiplier + it + (zencoding-run zencoding-pexpr + it + (zencoding-run zencoding-tag + it + '(error "no match, expecting ( or a-zA-Z0-9"))))))) + +(defun zencoding-multiplier (input) + (zencoding-por zencoding-pexpr zencoding-tag + (let ((multiplier expr)) + (zencoding-parse "\\*\\([0-9]+\\)" 2 "*n where n is a number" + (let ((multiplicand (read (elt it 1)))) + `((list ,(make-list multiplicand multiplier)) . ,input)))) + '(error "expected *n multiplier"))) + +(defun zencoding-tag (input) + "Parse a tag." + (zencoding-run zencoding-tagname + (let ((result it) + (tagname (cdr expr))) + (zencoding-pif (zencoding-run zencoding-identifier + (zencoding-tag-classes + `(tag ,tagname ((id ,(cddr expr)))) input) + (zencoding-tag-classes `(tag ,tagname ()) input)) + (let ((expr-and-input it) (expr (car it)) (input (cdr it))) + (zencoding-pif (zencoding-tag-props expr input) + it + expr-and-input)))) + '(error "expected tagname"))) + +(defun zencoding-tag-props (tag input) + (zencoding-run zencoding-props + (let ((tagname (cadr tag)) + (existing-props (caddr tag)) + (props (cdr expr))) + `((tag ,tagname + ,(append existing-props props)) + . ,input)))) + +(defun zencoding-props (input) + "Parse many props." + (zencoding-run zencoding-prop + (zencoding-pif (zencoding-props input) + `((props . ,(cons expr (cdar it))) . ,(cdr it)) + `((props . ,(list expr)) . ,input)))) + +(defun zencoding-prop (input) + (zencoding-parse + " " 1 "space" + (zencoding-run + zencoding-name + (let ((name (cdr expr))) + (zencoding-parse "=\\([^\\,\\+\\>\\ )]*\\)" 2 + "=property value" + (let ((value (elt it 1)) + (input (elt it 2))) + `((,(read name) ,value) . ,input))))))) + +(defun zencoding-tag-classes (tag input) + (zencoding-run zencoding-classes + (let ((tagname (cadr tag)) + (props (caddr tag)) + (classes `(class ,(mapconcat + (lambda (prop) + (cdadr prop)) + (cdr expr) + " ")))) + `((tag ,tagname ,(append props (list classes))) . ,input)) + `(,tag . ,input))) + +(defun zencoding-tagname (input) + "Parse a tagname a-zA-Z0-9 tagname (e.g. html/head/xsl:if/br)." + (zencoding-parse "\\([a-zA-Z][a-zA-Z0-9:-]*\\)" 2 "tagname, a-zA-Z0-9" + `((tagname . ,(elt it 1)) . ,input))) + +(defun zencoding-pexpr (input) + "A zen coding expression with parentheses around it." + (zencoding-parse "(" 1 "(" + (zencoding-run zencoding-expr + (zencoding-aif (zencoding-regex ")" input '(0 1)) + `(,expr . ,(elt it 1)) + '(error "expecting `)'"))))) + +(defun zencoding-parent-child (input) + "Parse an tag>e expression, where `n' is an tag and `e' is any + expression." + (zencoding-run zencoding-multiplier + (let* ((items (cadr expr)) + (rest (zencoding-child-sans expr input))) + (if (not (eq (car rest) 'error)) + (let ((child (car rest)) + (input (cdr rest))) + (cons (cons 'list + (cons (mapcar (lambda (parent) + `(parent-child ,parent ,child)) + items) + nil)) + input)) + '(error "expected child"))) + (zencoding-run zencoding-tag + (zencoding-child expr input) + '(error "expected parent")))) + +(defun zencoding-child-sans (parent input) + (zencoding-parse ">" 1 ">" + (zencoding-run zencoding-expr + it + '(error "expected child")))) + +(defun zencoding-child (parent input) + (zencoding-parse ">" 1 ">" + (zencoding-run zencoding-expr + (let ((child expr)) + `((parent-child ,parent ,child) . ,input)) + '(error "expected child")))) + +(defun zencoding-sibling (input) + (zencoding-por zencoding-pexpr zencoding-multiplier + it + (zencoding-run zencoding-tag + it + '(error "expected sibling")))) + +(defun zencoding-siblings (input) + "Parse an e+e expression, where e is an tag or a pexpr." + (zencoding-run zencoding-sibling + (let ((parent expr)) + (zencoding-parse "\\+" 1 "+" + (zencoding-run zencoding-expr + (let ((child expr)) + `((zencoding-siblings ,parent ,child) . ,input)) + '(error "expected second sibling")))) + '(error "expected first sibling"))) + +(defun zencoding-name (input) + "Parse a class or identifier name, e.g. news, footer, mainimage" + (zencoding-parse "\\([a-zA-Z][a-zA-Z0-9-_]*\\)" 2 "class or identifer name" + `((name . ,(elt it 1)) . ,input))) + +(defun zencoding-class (input) + "Parse a classname expression, e.g. .foo" + (zencoding-parse "\\." 1 "." + (zencoding-run zencoding-name + `((class ,expr) . ,input) + '(error "expected class name")))) + +(defun zencoding-identifier (input) + "Parse an identifier expression, e.g. #foo" + (zencoding-parse "#" 1 "#" + (zencoding-run zencoding-name + `((identifier . ,expr) . ,input)))) + +(defun zencoding-classes (input) + "Parse many classes." + (zencoding-run zencoding-class + (zencoding-pif (zencoding-classes input) + `((classes . ,(cons expr (cdar it))) . ,(cdr it)) + `((classes . ,(list expr)) . ,input)) + '(error "expected class"))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Zen coding transformer from AST to HTML + +;; Fix-me: make mode specific +(defvar zencoding-single-tags + '("br" + "img")) + +(defvar zencoding-inline-tags + '("a" + "abbr" + "acronym" + "cite" + "code" + "dfn" + "em" + "h1" "h2" "h3" "h4" "h5" "h6" + "kbd" + "q" + "span" + "strong" + "var")) + +(defvar zencoding-block-tags + '("p")) + +;; li +;; a +;; em +;; p + +(defvar zencoding-leaf-function nil + "Function to execute when expanding a leaf node in the + Zencoding AST.") + +(defun zencoding-make-tag (tag &optional content) + (let* ((name (car tag)) + (lf (if + (or + (member name zencoding-block-tags) + (and + (> (length name) 1) + (not (member name zencoding-inline-tags)) + )) + "\n" "")) + (single (member name zencoding-single-tags)) + (props (apply 'concat (mapcar + (lambda (prop) + (concat " " (symbol-name (car prop)) + "=\"" (cadr prop) "\"")) + (cadr tag))))) + (concat lf "<" name props ">" lf + (if single + "" + (concat + (if content content + (if zencoding-leaf-function + (funcall zencoding-leaf-function) + "")) + lf "</" name ">"))))) + +(defun zencoding-transform (ast) + (let ((type (car ast))) + (cond + ((eq type 'list) + (mapconcat 'zencoding-transform (cadr ast) "")) + ((eq type 'tag) + (zencoding-make-tag (cdr ast))) + ((eq type 'parent-child) + (let ((parent (cdadr ast)) + (children (zencoding-transform (caddr ast)))) + (zencoding-make-tag parent children))) + ((eq type 'zencoding-siblings) + (let ((sib1 (zencoding-transform (cadr ast))) + (sib2 (zencoding-transform (caddr ast)))) + (concat sib1 sib2)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Test-cases + +(defun zencoding-test-cases () + (let ((tests '(;; Tags + ("a" "<a></a>") + ("a.x" "<a class=\"x\"></a>") + ("a#q.x" "<a id=\"q\" class=\"x\"></a>") + ("a#q.x.y.z" "<a id=\"q\" class=\"x y z\"></a>") + ;; Siblings + ("a+b" "<a></a><b></b>") + ("a+b+c" "<a></a><b></b><c></c>") + ("a.x+b" "<a class=\"x\"></a><b></b>") + ("a#q.x+b" "<a id=\"q\" class=\"x\"></a><b></b>") + ("a#q.x.y.z+b" "<a id=\"q\" class=\"x y z\"></a><b></b>") + ("a#q.x.y.z+b#p.l.m.n" "<a id=\"q\" class=\"x y z\"></a><b id=\"p\" class=\"l m n\"></b>") + ;; Parent > child + ("a>b" "<a><b></b></a>") + ("a>b>c" "<a><b><c></c></b></a>") + ("a.x>b" "<a class=\"x\"><b></b></a>") + ("a#q.x>b" "<a id=\"q\" class=\"x\"><b></b></a>") + ("a#q.x.y.z>b" "<a id=\"q\" class=\"x y z\"><b></b></a>") + ("a#q.x.y.z>b#p.l.m.n" "<a id=\"q\" class=\"x y z\"><b id=\"p\" class=\"l m n\"></b></a>") + ("a>b+c" "<a><b></b><c></c></a>") + ("a>b+c>d" "<a><b></b><c><d></d></c></a>") + ;; Multiplication + ("a*1" "<a></a>") + ("a*2" "<a></a><a></a>") + ("a*2+b*2" "<a></a><a></a><b></b><b></b>") + ("a*2>b*2" "<a><b></b><b></b></a><a><b></b><b></b></a>") + ("a>b*2" "<a><b></b><b></b></a>") + ("a#q.x>b#q.x*2" "<a id=\"q\" class=\"x\"><b id=\"q\" class=\"x\"></b><b id=\"q\" class=\"x\"></b></a>") + ;; Properties + ("a x=y" "<a x=\"y\"></a>") + ("a x=y m=l" "<a x=\"y\" m=\"l\"></a>") + ("a#foo x=y m=l" "<a id=\"foo\" x=\"y\" m=\"l\"></a>") + ("a.foo x=y m=l" "<a class=\"foo\" x=\"y\" m=\"l\"></a>") + ("a#foo.bar.mu x=y m=l" "<a id=\"foo\" class=\"bar mu\" x=\"y\" m=\"l\"></a>") + ("a x=y+b" "<a x=\"y\"></a><b></b>") + ("a x=y+b x=y" "<a x=\"y\"></a><b x=\"y\"></b>") + ("a x=y>b" "<a x=\"y\"><b></b></a>") + ("a x=y>b x=y" "<a x=\"y\"><b x=\"y\"></b></a>") + ("a x=y>b x=y+c x=y" "<a x=\"y\"><b x=\"y\"></b><c x=\"y\"></c></a>") + ;; Parentheses + ("(a)" "<a></a>") + ("(a)+(b)" "<a></a><b></b>") + ("a>(b)" "<a><b></b></a>") + ("(a>b)>c" "<a><b></b></a>") + ("(a>b)+c" "<a><b></b></a><c></c>") + ("z+(a>b)+c+k" "<z></z><a><b></b></a><c></c><k></k>") + ("(a)*2" "<a></a><a></a>") + ("((a)*2)" "<a></a><a></a>") + ("((a)*2)" "<a></a><a></a>") + ("(a>b)*2" "<a><b></b></a><a><b></b></a>") + ("(a+b)*2" "<a></a><b></b><a></a><b></b>") + ))) + (mapc (lambda (input) + (let ((expected (cadr input)) + (actual (zencoding-transform (car (zencoding-expr (car input)))))) + (if (not (equal expected actual)) + (error (concat "Assertion " (car input) " failed:" + expected + " == " + actual))))) + tests) + (concat (number-to-string (length tests)) " tests performed. All OK."))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Zencoding minor mode + +;;;###autoload +(defgroup zencoding nil + "Customization group for zencoding-mode." + :group 'convenience) + +(defun zencoding-expr-on-line () + "Extract a zencoding expression and the corresponding bounds + for the current line." + (let* ((start (line-beginning-position)) + (end (line-end-position)) + (line (buffer-substring-no-properties start end)) + (expr (zencoding-regex "\\([ \t]*\\)\\([^\n]+\\)" line 2))) + (if (first expr) + (list (first expr) start end)))) + +(defun zencoding-prettify (markup indent) + (save-match-data + ;;(setq markup (replace-regexp-in-string "><" ">\n<" markup)) + (setq markup (replace-regexp-in-string "\n\n" "\n" markup)) + (setq markup (replace-regexp-in-string "^\n" "" markup))) + (with-temp-buffer + (indent-to indent) + (insert "<i></i>") + (insert "\n") + (let ((here (point))) + (insert markup) + (sgml-mode) + (indent-region here (point-max)) + (buffer-substring-no-properties here (point-max))))) + +;;;###autoload +(defun zencoding-expand-line (arg) + "Replace the current line's zencode expression with the corresponding expansion. +If prefix ARG is given or region is visible call `zencoding-preview' to start an +interactive preview. + +Otherwise expand line directly. + +For more information see `zencoding-mode'." + (interactive "P") + (let* ((here (point)) + (preview (if zencoding-preview-default (not arg) arg)) + (beg (if preview + (progn + (beginning-of-line) + (skip-chars-forward " \t") + (point)) + (when mark-active (region-beginning)))) + (end (if preview + (progn + (end-of-line) + (skip-chars-backward " \t") + (point)) + (when mark-active (region-end))))) + (if beg + (progn + (goto-char here) + (zencoding-preview beg end)) + (let ((expr (zencoding-expr-on-line))) + (if expr + (let* ((markup (zencoding-transform (car (zencoding-expr (first expr))))) + (pretty (zencoding-prettify markup (current-indentation)))) + (save-excursion + (delete-region (second expr) (third expr)) + (zencoding-insert-and-flash pretty)))))))) + +(defvar zencoding-mode-keymap nil + "Keymap for zencode minor mode.") + +(if zencoding-mode-keymap + nil + (progn + (setq zencoding-mode-keymap (make-sparse-keymap)) + (define-key zencoding-mode-keymap (kbd "<C-return>") 'zencoding-expand-line))) + +;;;###autoload +(define-minor-mode zencoding-mode + "Minor mode for writing HTML and CSS markup. +With zen coding for HTML and CSS you can write a line like + + ul#name>li.item*2 + +and have it expanded to + + <ul id=\"name\"> + <li class=\"item\"></li> + <li class=\"item\"></li> + </ul> + +This minor mode defines keys for quick access: + +\\{zencoding-mode-keymap} + +Home page URL `http://www.emacswiki.org/emacs/ZenCoding'. + +See also `zencoding-expand-line'." + :lighter " Zen" + :keymap zencoding-mode-keymap) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Zencoding yasnippet integration + +(defun zencoding-transform-yas (ast) + (let* ((leaf-count 0) + (zencoding-leaf-function + (lambda () + (format "$%d" (incf leaf-count))))) + (zencoding-transform ast))) + +;;;###autoload +(defun zencoding-expand-yas () + (interactive) + (let ((expr (zencoding-expr-on-line))) + (if expr + (let* ((markup (zencoding-transform-yas (car (zencoding-expr (first expr))))) + (filled (replace-regexp-in-string "><" ">\n<" markup))) + (delete-region (second expr) (third expr)) + (insert filled) + (indent-region (second expr) (point)) + (yas/expand-snippet + (buffer-substring (second expr) (point)) + (second expr) (point)))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Real-time preview +;; + +;;;;;;;;;; +;; Lennart's version + +(defvar zencoding-preview-input nil) +(make-local-variable 'zencoding-preview-input) +(defvar zencoding-preview-output nil) +(make-local-variable 'zencoding-preview-output) +(defvar zencoding-old-show-paren nil) +(make-local-variable 'zencoding-old-show-paren) + +(defface zencoding-preview-input + '((default :box t :inherit secondary-selection)) + "Face for preview input field." + :group 'zencoding) + +(defface zencoding-preview-output + '((default :inherit highlight)) + "Face for preview output field." + :group 'zencoding) + +(defvar zencoding-preview-keymap + (let ((map (make-sparse-keymap))) + (define-key map (kbd "<return>") 'zencoding-preview-accept) + (define-key map [(control ?g)] 'zencoding-preview-abort) + map)) + +(defun zencoding-preview-accept () + (interactive) + (let ((ovli zencoding-preview-input)) + (if (not (and (overlayp ovli) + (bufferp (overlay-buffer ovli)))) + (message "Preview is not active") + (let* ((indent (current-indentation)) + (markup (zencoding-preview-transformed indent))) + (when markup + (delete-region (line-beginning-position) (overlay-end ovli)) + (zencoding-insert-and-flash markup))))) + (zencoding-preview-abort)) + +(defvar zencoding-flash-ovl nil) +(make-variable-buffer-local 'zencoding-flash-ovl) + +(defun zencoding-remove-flash-ovl (buf) + (with-current-buffer buf + (when (overlayp zencoding-flash-ovl) + (delete-overlay zencoding-flash-ovl)) + (setq zencoding-flash-ovl nil))) + +(defun zencoding-insert-and-flash (markup) + (zencoding-remove-flash-ovl (current-buffer)) + (let ((here (point))) + (insert markup) + (setq zencoding-flash-ovl (make-overlay here (point))) + (overlay-put zencoding-flash-ovl 'face 'zencoding-preview-output) + (when (< 0 zencoding-insert-flash-time) + (run-with-idle-timer zencoding-insert-flash-time + nil 'zencoding-remove-flash-ovl (current-buffer))))) + +;;;###autoload +(defun zencoding-preview (beg end) + "Expand zencode between BEG and END interactively. +This will show a preview of the expanded zen code and you can +accept it or skip it." + (interactive (if mark-active + (list (region-beginning) (region-end)) + (list nil nil))) + (zencoding-preview-abort) + (if (not beg) + (message "Region not active") + (setq zencoding-old-show-paren show-paren-mode) + (show-paren-mode -1) + (let ((here (point))) + (goto-char beg) + (forward-line 1) + (unless (= 0 (current-column)) + (insert "\n")) + (let* ((opos (point)) + (ovli (make-overlay beg end nil nil t)) + (ovlo (make-overlay opos opos)) + (info (propertize " Zen preview. Choose with RET. Cancel by stepping out. \n" + 'face 'tooltip))) + (overlay-put ovli 'face 'zencoding-preview-input) + (overlay-put ovli 'keymap zencoding-preview-keymap) + (overlay-put ovlo 'face 'zencoding-preview-output) + (overlay-put ovlo 'before-string info) + (setq zencoding-preview-input ovli) + (setq zencoding-preview-output ovlo) + (add-hook 'before-change-functions 'zencoding-preview-before-change t t) + (goto-char here) + (add-hook 'post-command-hook 'zencoding-preview-post-command t t))))) + +(defvar zencoding-preview-pending-abort nil) +(make-variable-buffer-local 'zencoding-preview-pending-abort) + +(defun zencoding-preview-before-change (beg end) + (when + (or (> beg (overlay-end zencoding-preview-input)) + (< beg (overlay-start zencoding-preview-input)) + (> end (overlay-end zencoding-preview-input)) + (< end (overlay-start zencoding-preview-input))) + (setq zencoding-preview-pending-abort t))) + +(defun zencoding-preview-abort () + "Abort zen code preview." + (interactive) + (setq zencoding-preview-pending-abort nil) + (remove-hook 'before-change-functions 'zencoding-preview-before-change t) + (when (overlayp zencoding-preview-input) + (delete-overlay zencoding-preview-input)) + (setq zencoding-preview-input nil) + (when (overlayp zencoding-preview-output) + (delete-overlay zencoding-preview-output)) + (setq zencoding-preview-output nil) + (remove-hook 'post-command-hook 'zencoding-preview-post-command t) + (when zencoding-old-show-paren (show-paren-mode 1))) + +(defun zencoding-preview-post-command () + (condition-case err + (zencoding-preview-post-command-1) + (error (message "zencoding-preview-post: %s" err)))) + +(defun zencoding-preview-post-command-1 () + (if (and (not zencoding-preview-pending-abort) + (<= (point) (overlay-end zencoding-preview-input)) + (>= (point) (overlay-start zencoding-preview-input))) + (zencoding-update-preview (current-indentation)) + (zencoding-preview-abort))) + +(defun zencoding-preview-transformed (indent) + (let* ((string (buffer-substring-no-properties + (overlay-start zencoding-preview-input) + (overlay-end zencoding-preview-input))) + (ast (car (zencoding-expr string)))) + (when (not (eq ast 'error)) + (zencoding-prettify (zencoding-transform ast) + indent)))) + +(defun zencoding-update-preview (indent) + (let* ((pretty (zencoding-preview-transformed indent)) + (show (when pretty + (propertize pretty 'face 'highlight)))) + (when show + (overlay-put zencoding-preview-output 'after-string + (concat show "\n"))))) +;; a+bc + +;;;;;;;;;; +;; Chris's version + +;; (defvar zencoding-realtime-preview-keymap +;; (let ((map (make-sparse-keymap))) +;; (define-key map "\C-c\C-c" 'zencoding-delete-overlay-pair) + +;; map) +;; "Keymap used in zencoding realtime preview overlays.") + +;; ;;;###autoload +;; (defun zencoding-realtime-preview-of-region (beg end) +;; "Construct a real-time preview for the region BEG to END." +;; (interactive "r") +;; (let ((beg2) +;; (end2)) +;; (save-excursion +;; (goto-char beg) +;; (forward-line) +;; (setq beg2 (point) +;; end2 (point)) +;; (insert "\n")) +;; (let ((input-and-output (zencoding-make-overlay-pair beg end beg2 end2))) +;; (zencoding-handle-overlay-change (car input-and-output) nil nil nil))) +;; ) + +;; (defun zencoding-make-overlay-pair (beg1 end1 beg2 end2) +;; "Construct an input and an output overlay for BEG1 END1 and BEG2 END2" +;; (let ((input (make-overlay beg1 end1 nil t t)) +;; (output (make-overlay beg2 end2))) +;; ;; Setup input overlay +;; (overlay-put input 'face '(:underline t)) +;; (overlay-put input 'modification-hooks +;; (list #'zencoding-handle-overlay-change)) +;; (overlay-put input 'output output) +;; (overlay-put input 'keymap zencoding-realtime-preview-keymap) +;; ;; Setup output overlay +;; (overlay-put output 'face '(:overline t)) +;; (overlay-put output 'intangible t) +;; (overlay-put output 'input input) +;; ;; Return the overlays. +;; (list input output)) +;; ) + +;; (defun zencoding-delete-overlay-pair (&optional one) +;; "Delete a pair of input and output overlays based on ONE." +;; (interactive) ;; Since called from keymap +;; (unless one +;; (let ((overlays (overlays-at (point)))) +;; (while (and overlays +;; (not (or (overlay-get (car overlays) 'input) +;; (overlay-get (car overlays) 'output)))) +;; (setq overlays (cdr overlays))) +;; (setq one (car overlays)))) +;; (when one +;; (let ((other (or (overlay-get one 'input) +;; (overlay-get one 'output)))) +;; (delete-overlay one) +;; (delete-overlay other))) +;; ) + +;; (defun zencoding-handle-overlay-change (input del beg end &optional old) +;; "Update preview after overlay change." +;; (let* ((output (overlay-get input 'output)) +;; (start (overlay-start output)) +;; (string (buffer-substring-no-properties +;; (overlay-start input) +;; (overlay-end input))) +;; (ast (car (zencoding-expr string))) +;; (markup (when (not (eq ast 'error)) +;; (zencoding-transform ast)))) +;; (save-excursion +;; (delete-region start (overlay-end output)) +;; (goto-char start) +;; (if markup +;; (insert markup) +;; (insert (propertize "error" 'face 'font-lock-error-face))) +;; (move-overlay output start (point)))) +;; ) + +(provide 'zencoding-mode) + +;;; zencoding-mode.el ends here diff --git a/emacs/nxhtml/web-autoload.el b/emacs/nxhtml/web-autoload.el new file mode 100644 index 0000000..418d32a --- /dev/null +++ b/emacs/nxhtml/web-autoload.el @@ -0,0 +1,262 @@ +;;; web-autoload.el --- Autoload from web site +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-12-26 Sat +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Experimental code. Not ready to use at all. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +;;(eval-when-compile (require 'web-vcs)) ;; Gives recursion +;;(eval-when-compile (require 'nxhtml-base)) + +(defcustom web-autoload-autocompile t + "Byt compile downloaded files if t." + :type 'boolean + :group 'web-vcs) + +(defun web-autoload (fun src docstring interactive type) + "Set up FUN to be autoloaded from SRC. +This works similar to `autoload' and the arguments DOCSTRING, +INTERACTIVE and TYPE are handled similary. + +However loading can be done from a web url. +In that case SRC should have the format + + (WEB-VCS BASE-URL RELATIVE-URL BASE-DIR) + +where + + - WEB-VCS is specifies a web repository type, see + `web-vcs-get-files-from-root'. + - BASE-URL is the base url, similar to the URL argument to the + function above. + + - RELATIVE-URL is relative location. This will be relative to + BASE-DIR in file tree and to BASE-URL on the web \(only + logically in the latter case). + +Loading will be done from the file resulting from expanding +RELATIVE-URL relative to BASE-DIR. If this file exists load it +directly, otherwise download it first." + (unless (functionp fun) + (let ((int (when interactive '(interactive)))) + (cond + ((eq type 'macro) + (setq type 'defmacro)) + (t + (setq type 'defun))) + (put fun 'web-autoload src) + (eval + `(web-autoload-1 ,fun ,src ,docstring ,int ,type))))) + +;; (defun web-autoload-default-filename-element () +;; ;; Fix-me: el or elc? +;; ;; Fix-me: remove nxhtml binding +;; (expand-file-name "nxhtml-loaddefs.elc" nxhtml-install-dir)) + +;; Fix-me: change name +(defvar web-autoload-skip-require-advice nil) + +;; Fix-me: Use TYPE +(defmacro web-autoload-1 (fun src docstring interactive type) + `(progn + (,type ,fun (&rest args) + ,(concat docstring + "\n\nArguments are not yet known since the real function is not loaded." + "\nFunction is defined by `web-autoload' to be loaded using definition\n\n " + (format "%S" + src)) + ,interactive + ;; (find-lisp-object-file-name 'chart-complete 'defun) + (let* ((lib-web (or (find-lisp-object-file-name ',fun 'defun) + ;;(web-autoload-default-filename-element) + )) + (old-hist-elt (when lib-web (load-history-filename-element lib-web))) + (auto-fun (symbol-function ',fun)) + err) + ;; Fix-me: Can't do this because we may have to go back here again... + ;;(fset ',fun nil) + (if (not (listp ',src)) + ;; Just a local file, for testing of logics. + (let ((lib-file (locate-library ',src))) + (load ',src) + (unless (symbol-function ',fun) + (setq err (format "%s is not in library %s" ',fun lib-file)))) + ;; If file is a list then it should be a web url: + ;; (web-vcs base-url relative-url base-dir) + ;; Convert from repository url to file download url. + (let* (;;(vcs (nth 0 ',src)) + ;;(base-url (nth 1 ',src)) + (rel-url (nth 2 ',src)) + ;;(base-dir (nth 3 ',src)) + ;;(rel-url-el (concat rel-url ".el")) + ;;file-url + ;;dl-file + ) + ;;(unless (stringp base-url) (setq base-url (symbol-value base-url))) + ;;(unless (stringp base-dir) (setq base-dir (symbol-value base-dir))) + ;;(setq dl-file (expand-file-name rel-url-el base-dir)) + (web-vcs-message-with-face 'web-vcs-gold "web-autoload-1: BEG fun=%s" ',fun) + ;; Fix-me: assume we can do require (instead of load, so + ;; we do not have to defadvice load to). + (unless (ad-is-advised 'require) + (error "web-autoload-1: require is not advised")) + (unless (ad-is-active 'require) + (error "web-autoload-1: require advice is not active")) + (when (catch 'web-autoload-comp-restart + (require (intern (file-name-nondirectory rel-url))) + nil) + (web-autoload-byte-compile-queue)) + (when (equal (symbol-function ',fun) auto-fun) + (error "Couldn't web autoload function %s" ',fun)) + (web-vcs-message-with-face 'web-vcs-gold "web-autoload-1: END fun=%s" ',fun) + (web-vcs-log-save) + )) + ;; Fix-me: Wrong place to do the cleanup! It must be done + ;; after loading a file. All autoload in that file must be + ;; deleted from the nxhtml-loaddefs entry. + ;; + ;; Delete old load-history entry for ,fun. A new entry + ;; has been added. + (let* ((tail (cdr old-hist-elt)) + (new-tail (when tail (delete (cons 'defun ',fun) tail)))) + (when tail (setcdr old-hist-elt new-tail))) + ;; Finally call the real function + (if (called-interactively-p ',fun) + (call-interactively ',fun) + (if (functionp ',fun) + (apply ',fun args) + ;; It is a macro + (let ((the-macro (append '(,fun) args nil))) + (eval the-macro)))))))) + +;; Fix-me: Set up a byte compilation queue. Move function for byte compiling here. + +(defvar web-autoload-cleanup-dummy-el + (let* ((this-dir (file-name-directory (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)))) + (expand-file-name "temp-cleanup.el" this-dir))) + +(defun web-autoload-try-cleanup-after-failed-compile (active-comp) + (let* ((bc-input-buffer (get-buffer " *Compiler Input*")) + (bc-outbuffer (get-buffer " *Compiler Output*")) + ;;(active-comp (car web-autoload-compile-queue)) + (active-file (car active-comp)) + (active-elc (byte-compile-dest-file active-file))) + ;; Delete bytecomp buffers + (display-buffer "*Messages*") + (web-vcs-message-with-face 'web-vcs-red "Trying to cleanup (%s %s %s)" bc-input-buffer bc-outbuffer active-elc) + (when bc-input-buffer (kill-buffer bc-input-buffer)) + (when bc-outbuffer + (kill-buffer bc-outbuffer) + (setq bytecomp-outbuffer nil)) + ;; Delete half finished elc file + (when (file-exists-p active-elc) + (delete-file active-elc)) + ;; Delete load-history entry + (when nil + (setq load-history (cdr load-history))) + ;; Try to reset some variables (just guesses) + (when nil + (setq byte-compile-constants nil) + (setq byte-compile-variables nil) + (setq byte-compile-bound-variables nil) + (setq byte-compile-const-variables nil) + ;;(setq byte-compile-macro-environment byte-compile-initial-macro-environment) + (setq byte-compile-function-environment nil) + (setq byte-compile-unresolved-functions nil) + (setq byte-compile-noruntime-functions nil) + (setq byte-compile-tag-number 0) + (setq byte-compile-output nil) + (setq byte-compile-depth 0) + (setq byte-compile-maxdepth 0) + ;;(setq byte-code-vector nil) + (setq byte-compile-current-form nil) + (setq byte-compile-dest-file nil) + (setq byte-compile-current-file nil) + (setq byte-compile-current-group nil) + (setq byte-compile-current-buffer nil) + (setq byte-compile-read-position nil) + (setq byte-compile-last-position nil) + (setq byte-compile-last-warned-form nil) + (setq byte-compile-last-logged-file nil) + ;;(defvar bytecomp-outbuffer) + ;;(defvar byte-code-meter) + ) + ;; Try compiling something go get right state ... + (when nil + (unless (file-exists-p web-autoload-cleanup-dummy-el) + (let ((buf (find-file-noselect web-autoload-cleanup-dummy-el))) + (with-current-buffer buf + (insert ";; Dummy") + (basic-save-buffer) + (kill-buffer)))) + (byte-compile-file web-autoload-cleanup-dummy-el nil)))) + +(defun big-trace () + (setq trace-buffer "*Messages*") + (trace-function-background 'byte-compile-form) + (trace-function-background 'byte-compile-file-form) + (trace-function-background 'byte-optimize-form) + (trace-function-background 'byte-compile-normal-call) + (trace-function-background 'byte-compile-cl-warn) + (trace-function-background 'byte-compile-const-symbol-p) + (trace-function-background 'byte-compile-warn) + (trace-function-background 'byte-compile-warning-enabled-p) + (trace-function-background 'byte-compile-callargs-warn) + (trace-function-background 'byte-compile-splice-in-already-compiled-code) + (trace-function-background 'byte-inline-lapcode) + (trace-function-background 'byte-decompile-bytecode-1) + ) + +(defvar web-autoload-require-list nil) + +(defun web-autoload-require (feature web-vcs base-url relative-url base-dir compile-fun) + "Prepare to download file if necessary when `require' is called. +WEB-VCS BASE-URL RELATIVE-URL" + (add-to-list 'web-autoload-require-list `(,feature ,web-vcs ,base-url ,relative-url ,base-dir ,compile-fun))) + +;;(big-trace) + +(provide 'web-autoload) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; web-autoload.el ends here diff --git a/emacs/nxhtml/web-vcs.el b/emacs/nxhtml/web-vcs.el new file mode 100644 index 0000000..fac58db --- /dev/null +++ b/emacs/nxhtml/web-vcs.el @@ -0,0 +1,2069 @@ +;;; web-vcs.el --- Download file trees from VCS web pages +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-11-26 Thu +(defconst web-vcs:version "0.61") ;; Version: +;; Last-Updated: 2009-12-11 Fri +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Update file trees within Emacs from VCS systems using information +;; on their web pages. +;; +;; Available download commands are currently: +;; +;; `web-vcs-nxhtml' +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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: + +(eval-when-compile (require 'cl)) +(eval-and-compile (require 'cus-edit)) +(eval-and-compile (require 'mm-decode)) +(eval-when-compile (require 'url-http)) + +(require 'advice) +(require 'web-autoload nil t) +;; (require 'url-util) +;; (require 'url) +;;(require 'url-parse) + +(defvar web-vcs-comp-dir nil) + +(defgroup web-vcs nil + "Customization group for web-vcs." + :group 'nxhtml) + +(defcustom web-vcs-links-regexp + `( + (lp ;; Id + ;; Comment: + "http://www.launchpad.com/ uses this 2009-11-29 with Loggerhead 1.10 (generic?)" + ;; Files URL regexp: + ;; + ;; Extend this format to catch date/time too. + ;; + ;; ((patt (rx ...)) + ;; ;; use subexp numbers + ;; (url 1) + ;; (time 2) + ;; (rev 3)) + + ((time 1) + (url 2) + (patt ,(rx "<td class=\"date\">" + (submatch (regexp "[^<]*")) + "</td>" + (0+ space) + "<td class=\"timedate2\">" + (regexp ".+") + "</td>" + (*? (regexp ".\\|\n")) + "href=\"" + (submatch (regexp ".*/download/[^\"]*")) + "\""))) + + ;; ,(rx "href=\"" + ;; (submatch (regexp ".*/download/[^\"]*")) + ;; "\"") + + ;; Dirs URL regexp: + ,(rx "href=\"" + (submatch (regexp ".*%3A/[^\"]*/")) + "\"") + ;; File name URL part regexp: + "\\([^\/]*\\)$" + ;; Page revision regexp: + ,(rx "for revision" + (+ whitespace) + "<span>" + (submatch (+ digit)) + "</span>") + ;; Release revision regexp: + ,(rx "/" + (submatch (+ digit)) + "\"" (+ (not (any ">"))) ">" + (optional "Release ") + (+ digit) "." (+ digit) "<") + ) + ) + "Regexp patterns for matching links on a VCS web page. +The patterns are grouped by VCS web system type. + +*Note: It is always sub match 1 from these patterns that are + used." + :type '(repeat + (list + (symbol :tag "VCS web system type specifier") + (string :tag "Description") + (regexp :tag "Files URL regexp") + (regexp :tag "Dirs URL regexp") + (regexp :tag "File name URL part regexp") + (regexp :tag "Page revision regexp") + (regexp :tag "Release revision regexp") + )) + :group 'web-vcs) + +(defface web-vcs-mode-line + '((t (:foreground "black" :background "OrangeRed"))) + "Mode line face during download." + :group 'web-vcs) + +(defface web-vcs-mode-line-inactive + '((t (:foreground "black" :background "Orange"))) + "Mode line face during download." + :group 'web-vcs) + +(defface web-vcs-gold + '((t (:foreground "black" :background "gold"))) + "Face for web-vcs messages." + :group 'web-vcs) + +(defface web-vcs-red + '((t (:foreground "black" :background "#f86"))) + "Face for web-vcs messages." + :group 'web-vcs) + +(defface web-vcs-green + '((t (:foreground "black" :background "#8f6"))) + "Face for web-vcs messages." + :group 'web-vcs) + +(defface web-vcs-yellow + '((t (:foreground "black" :background "yellow"))) + "Face for web-vcs messages." + :group 'web-vcs) + +(defface web-vcs-pink + '((t (:foreground "black" :background "pink"))) + "Face for web-vcs messages." + :group 'web-vcs) + +(defcustom web-vcs-default-download-directory + '~/.emacs.d/ + "Default download directory." + :type '(choice (const :tag "~/.emacs.d/" '~/.emacs.d/) + (const :tag "Fist site-lisp in `load-path'" 'site-lisp-dir) + (const :tag "Directory where `site-run-file' lives" 'site-run-dir) + (string :tag "Specify directory")) + :group 'web-vcs) + +;;(web-vcs-default-download-directory) +;;;###autoload +(defun web-vcs-default-download-directory () + "Try to find a suitable place. +Considers site-start.el, site- +" + (let ((site-run-dir (when site-run-file + (file-name-directory (locate-library site-run-file)))) + (site-lisp-dir (catch 'first-site-lisp + (dolist (d load-path) + (let ((dir (file-name-nondirectory (directory-file-name d)))) + (when (string= dir "site-lisp") + (throw 'first-site-lisp (file-name-as-directory d))))))) + ) + (message "site-run-dir=%S site-lisp-dir=%S" site-run-dir site-lisp-dir) + (case web-vcs-default-download-directory + ('~/.emacs.d/ "~/.emacs.d/") + ('site-lisp-dir site-lisp-dir) + ('site-run-dir site-run-dir) + (t web-vcs-default-download-directory)) + )) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Logging + +(defcustom web-vcs-log-file "~/.emacs.d/web-vcs-log.org" + "Log file for web-vcs." + :type 'file + :group 'web-vcs) + +;;;###autoload +(defun web-vcs-log-edit () + "Open log file." + (interactive) + (find-file web-vcs-log-file)) + +(defvar web-vcs-log-save-timer nil) + +(defun web-vcs-log-save-when-idle () + (when (timerp web-vcs-log-save-timer) (cancel-timer web-vcs-log-save-timer)) + (run-with-idle-timer 0 nil 'web-vcs-log-save)) + +(defun web-vcs-log-save () + (let ((log-buf (find-buffer-visiting web-vcs-log-file))) + (when (and log-buf (buffer-modified-p log-buf)) + (with-current-buffer log-buf + (basic-save-buffer))) + log-buf)) + +(defun web-vcs-log-close () + (let ((log-buf (web-vcs-log-save))) + (when log-buf + (kill-buffer log-buf)))) + +;; Fix-me: Add some package descriptor to log +(defun web-vcs-log (url dl-file msg) + (unless (file-exists-p web-vcs-log-file) + (let ((dir (file-name-directory web-vcs-log-file))) + (unless (file-directory-p dir) + (make-directory dir)))) + (with-current-buffer (find-file-noselect web-vcs-log-file) + (setq buffer-save-without-query t) + (web-vcs-log-save-when-idle) + (save-restriction + (widen) + (let ((today-entries (format-time-string "* %Y-%m-%d")) + (now (format-time-string "%H:%M:%S GMT" nil t))) + (goto-char (point-max)) + (unless (re-search-backward (concat "^" today-entries) nil t) + (goto-char (point-max)) + (insert "\n" today-entries "\n")) + (goto-char (point-max)) + (when url + (insert "** Downloading file " now "\n" + (format " file [[file:%s][%s]]\n from %s\n" dl-file dl-file url) + )) + (cond + ((stringp msg) + (goto-char (point-max)) + (insert msg "\n")) + (msg (basic-save-buffer))))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Finding and downloading files + +;;;###autoload +(defun web-vcs-get-files-from-root (web-vcs url dl-dir) + "Download a file tree from VCS system using the web interface. +Use WEB-VCS entry in variable `web-vcs-links-regexp' to download +files via http from URL to directory DL-DIR. + +Show URL first and offer to visit the page. That page will give +you information about version control system \(VCS) system used +etc." + (unless (web-vcs-contains-moved-files dl-dir) + (when (if (not (y-or-n-p (concat "Download files from \"" url "\".\n" + "You can see on that page which files will be downloaded.\n\n" + "Visit that page before downloading? "))) + t + (browse-url url) + (if (y-or-n-p "Start downloading? ") + t + (message "Aborted") + nil)) + (message "") + (web-vcs-get-files-on-page web-vcs url t (file-name-as-directory dl-dir) nil) + t))) + +(defun web-vcs-get-files-on-page (web-vcs url recursive dl-dir test) + "Download files listed by WEB-VCS on web page URL. +WEB-VCS is a specifier in `web-vcs-links-regexp'. + +If RECURSIVE go into sub folders on the web page and download +files from them too. + +Place the files under DL-DIR. + +Before downloading check if the downloaded revision already is +the same as the one on the web page. This is stored in the file +web-vcs-revision.txt. After downloading update this file. + +If TEST is non-nil then do not download, just list the files." + (unless (string= dl-dir (file-name-as-directory (expand-file-name dl-dir))) + (error "Download dir dl-dir=%S must be a full directory path" dl-dir)) + (catch 'command-level + (when (web-vcs-contains-moved-files dl-dir) + (throw 'command-level nil)) + (let ((vcs-rec (or (assq web-vcs web-vcs-links-regexp) + (error "Does not know web-cvs %S" web-vcs))) + (start-time (current-time))) + (unless (file-directory-p dl-dir) + (if (yes-or-no-p (format "Directory %S does not exist, create it? " + (file-name-as-directory + (expand-file-name dl-dir)))) + (make-directory dl-dir t) + (message "Can't download then") + (throw 'command-level nil))) + ;; (let ((old-win (selected-window))) + ;; (unless (eq (get-buffer "*Messages*") (window-buffer old-win)) + ;; (switch-to-buffer-other-window "*Messages*")) + ;; (goto-char (point-max)) + ;; (insert "\n") + ;; (insert (propertize (format "\n\nWeb-Vcs Download: %S\n" url) 'face 'web-vcs-gold)) + ;; (insert "\n") + ;; (redisplay t) + ;; (set-window-point (selected-window) (point-max)) + ;; (select-window old-win)) + (web-vcs-message-with-face 'web-vcs-gold "\n\nWeb-Vcs Download: %S\n" url) + (web-vcs-display-messages nil) + (let* ((rev-file (expand-file-name "web-vcs-revision.txt" dl-dir)) + (rev-buf (find-file-noselect rev-file)) + ;; Fix-me: Per web vcs speficier. + (old-rev-range (with-current-buffer rev-buf + (widen) + (goto-char (point-min)) + (when (re-search-forward (format "%s:\\(.*\\)\n" web-vcs) nil t) + ;;(buffer-substring-no-properties (point-min) (line-end-position)) + ;;(match-string 1) + (cons (match-beginning 1) (match-end 1)) + ))) + (old-revision (when old-rev-range + (with-current-buffer rev-buf + (buffer-substring-no-properties (car old-rev-range) + (cdr old-rev-range))))) + (dl-revision (web-vcs-get-revision-on-page vcs-rec url)) + ret + moved) + (when (and old-revision (string= old-revision dl-revision)) + (when (y-or-n-p (format "You already have revision %s. Quit? " dl-revision)) + (message "Aborted") + (kill-buffer rev-buf) + (throw 'command-level nil))) + ;; We do not have a revision number once we start download. + (with-current-buffer rev-buf + (when old-rev-range + (delete-region (car old-rev-range) (cdr old-rev-range)) + (basic-save-buffer))) + (setq ret (web-vcs-get-files-on-page-1 + vcs-rec url + dl-dir + "" + nil + (if recursive 0 nil) + dl-revision test)) + (setq moved (nth 1 ret)) + ;; Now we have a revision number again. + (with-current-buffer rev-buf + (when (= 0 (buffer-size)) + (insert "WEB VCS Revisions\n\n")) + (goto-char (point-max)) + (unless (eolp) (insert "\n")) + (insert (format "%s:%s\n" web-vcs dl-revision)) + (basic-save-buffer) + (kill-buffer)) + (message "-----------------") + (web-vcs-message-with-face 'web-vcs-gold "Web-Vcs Download Ready: %S" url) + (web-vcs-message-with-face 'web-vcs-gold " Time elapsed: %S" + (web-vcs-nice-elapsed start-time (current-time))) + (when (> moved 0) + (web-vcs-message-with-face 'web-vcs-yellow + " %i files updated (old versions renamed to *.moved)" + moved)))))) + +(defun web-vcs-get-files-on-page-1 (vcs-rec url dl-root dl-relative file-mask recursive dl-revision test) + "Download files listed by VCS-REC on web page URL. +VCS-REC should be an entry like the entries in the list +`web-vcs-links-regexp'. + +If FILE-MASK is non nil then it is used to match a file path. +Only matching files will be downloaded. FILE-MASK can have two +forms, a regular expression or a function. + +If FILE-MASK is a regular expression then each part of the path +may be a regular expresion \(not containing /). + +If FILE-MASK is a function then this function is called in each +directory under DL-ROOT. The function is called with the +directory as a parameter and should return a cons. The first +element of the cons should be a regular expression matching file +names in that directory that should be downloaded. The cdr +should be t if subdirectories should be visited. + +If RECURSIVE go into sub folders on the web page and download +files from them too. + +Place the files under DL-DIR. + +The revision on the page URL should match DL-REVISION if this is non-nil. + +If TEST is non-nil then do not download, just list the files" + ;;(web-vcs-message-with-face 'font-lock-comment-face "web-vcs-get-files-on-page-1 %S %S %S %S" url dl-root dl-relative file-mask) + (let* ((files-matcher (nth 2 vcs-rec)) + (dirs-href-regexp (nth 3 vcs-rec)) + (revision-regexp (nth 5 vcs-rec)) + (dl-dir (file-name-as-directory (expand-file-name dl-relative dl-root))) + (lst-dl-relative (web-vcs-file-name-as-list dl-relative)) + (lst-file-mask (when (stringp file-mask) (web-vcs-file-name-as-list file-mask))) + ;;(url-buf (url-retrieve-synchronously url)) + this-page-revision + files + suburls + (moved 0) + (temp-file-base (expand-file-name "web-vcs-temp-list.tmp" dl-dir)) + temp-list-file + temp-list-buf + folder-res + http-sts) + ;; Fix-me: It looks like there is maybe a bug in url-copy-file so + ;; that it runs synchronously. Try to workaround the problem by + ;; making a new file temp file name. + (web-vcs-display-messages nil) + (unless (file-directory-p dl-dir) (make-directory dl-dir t)) + ;;(message "TRACE: dl-dir=%S" dl-dir) + (setq temp-list-file (make-temp-name temp-file-base)) + (setq temp-list-buf (web-vcs-ass-folder-cache url)) + (unless temp-list-buf + ;;(setq temp-list-buf (generate-new-buffer "web-wcs-folder")) + ;;(web-vcs-url-copy-file-and-check url temp-list-file nil) + (setq folder-res (web-vcs-url-retrieve-synch url)) + ;; (with-current-buffer temp-list-buf + ;; (insert-file-contents temp-list-file)) + (unless (memq (cdr folder-res) '(200 201)) + (web-vcs-message-with-face 'web-vcs-red "Could not get %S" url) + (web-vcs-display-messages t) + (throw 'command-level nil))) + ;;(with-current-buffer temp-list-buf + (with-current-buffer (car folder-res) + ;;(delete-file temp-list-file) + ;;(find-file-noselect temp-list-file) + (when dl-revision + (setq this-page-revision (web-vcs-get-revision-from-url-buf vcs-rec (current-buffer) url))) + (when dl-revision + (unless (string= dl-revision this-page-revision) + (web-vcs-message-with-face 'web-vcs-red "Revision on %S is %S, but should be %S" + url this-page-revision dl-revision) + (web-vcs-display-messages t) + (throw 'command-level nil))) + ;; Find files + (goto-char (point-min)) + (let ((files-href-regexp (nth 1 (assq 'patt files-matcher))) + (url-num (nth 1 (assq 'url files-matcher))) + (time-num (nth 1 (assq 'time files-matcher)))) + (while (re-search-forward files-href-regexp nil t) + (let ((file (match-string url-num)) + (time (match-string time-num))) + (add-to-list 'files (list file time))))) + ;; Find subdirs + (when recursive + (goto-char (point-min)) + (while (re-search-forward dirs-href-regexp nil t) + (let ((suburl (match-string 1)) + (lenurl (length url))) + (when (and (> (length suburl) lenurl) + (string= (substring suburl 0 lenurl) url)) + (add-to-list 'suburls suburl))))) + (kill-buffer)) + ;; Download files + ;;(message "TRACE: files=%S" files) + (web-vcs-download-files vcs-rec files dl-dir dl-root file-mask) + ;; Download subdirs + (when suburls + (dolist (suburl (reverse suburls)) + (let* ((dl-sub-dir (substring suburl (length url))) + (full-dl-sub-dir (file-name-as-directory + (expand-file-name dl-sub-dir dl-dir))) + (rel-dl-sub-dir (file-relative-name full-dl-sub-dir dl-root))) + ;;(message "web-vcs-get-revision-from-url-buf dir: %S %S" file-mask rel-dl-sub-dir) + (when (or (not file-mask) + (not (stringp file-mask)) + (web-vcs-match-folderwise file-mask rel-dl-sub-dir)) + ;;(message "matched dir %S" rel-dl-sub-dir) + (unless (web-vcs-contains-file dl-dir full-dl-sub-dir) + (error "Subdir %S not in %S" dl-sub-dir dl-dir)) + (let* ((ret (web-vcs-get-files-on-page-1 vcs-rec + suburl + dl-root + rel-dl-sub-dir + file-mask + (1+ recursive) + this-page-revision + test))) + (setq moved (+ moved (nth 1 ret)))))))) + (list this-page-revision moved))) + +(defun web-vcs-get-missing-matching-files (web-vcs url dl-dir file-mask) + "Download missing files from VCS system using the web interface. +Use WEB-VCS entry in variable `web-vcs-links-regexp' to download +files via http from URL to directory DL-DIR. + +Before downloading offer to visit the page from which the +downloading will be made. +" + (let ((vcs-rec (or (assq web-vcs web-vcs-links-regexp) + (error "Does not know web-cvs %S" web-vcs)))) + (web-vcs-get-files-on-page-1 vcs-rec url dl-dir "" file-mask 0 nil nil))) + + +;; (web-vcs-get-files-on-page 'lp "http://bazaar.launchpad.net/%7Enxhtml/nxhtml/main/files/head%3A/" t "c:/test/temp13/" t) + +(defvar web-vcs-folder-cache nil) ;; dyn var +(defun web-vcs-add-folder-cache (url buf) + (add-to-list 'web-vcs-folder-cache (list url buf))) +(defun web-vcs-ass-folder-cache (url) + (assoc url web-vcs-folder-cache)) +(defun web-vcs-clear-folder-cache () + (while web-vcs-folder-cache + (let ((ub (car web-vcs-folder-cache))) + (setq web-vcs-folder-cache (cdr web-vcs-folder-cache)) + (kill-buffer (nth 1 ub))))) + +(defun web-vcs-url-copy-file-and-check (url dl-file dest-file) + "Copy URL to DL-FILE. +Log what happened. Use DEST-FILE in the log, not DL-FILE which is +a temporary file." + (let ((http-sts nil) + (file-nonempty nil) + (fail-reason nil)) + (when dest-file (web-vcs-log url dest-file nil)) + (web-vcs-display-messages nil) + ;;(message "before url-copy-file %S" dl-file) + (setq http-sts (web-vcs-url-copy-file url dl-file nil t)) ;; don't overwrite, keep time + ;;(message "after url-copy-file %S" dl-file) + (if (and (file-exists-p dl-file) + (setq file-nonempty (< 0 (nth 7 (file-attributes dl-file)))) ;; file size 0 + (memq http-sts '(200 201))) + (when dest-file + (web-vcs-log nil nil " Done.\n")) + (setq fail-reason + (cond + (http-sts (format "HTTP %s" http-sts)) + (file-nonempty "File looks bad") + (t "Server did not respond"))) + (unless dest-file (web-vcs-log url dl-file "TEMP FILE")) + (web-vcs-log nil nil (format " *Failed:* %s\n" fail-reason)) + ;; Requires user attention and intervention + (web-vcs-message-with-face 'web-vcs-red "Download failed: %s, %S" fail-reason url) + (web-vcs-display-messages t) + (message "\n") + (web-vcs-message-with-face 'web-vcs-yellow "Please retry what you did before!\n") + (throw 'command-level nil)))) + +(defvar web-autoload-temp-file-prefix "TEMPORARY-WEB-AUTO-LOAD-") +(defvar web-autoload-active-file-sub-url) ;; Dyn var, active during file download check +(defun web-autoload-acvtive () + (and (boundp 'web-autoload-active-file-sub-url) + web-autoload-active-file-sub-url)) + +(defun web-vcs-download-files (vcs-rec files dl-dir dl-root file-mask) + (dolist (file (reverse files)) + (let* ((url-file (nth 0 file)) + (url-file-time-str (nth 1 file)) + ;; date-to-time assumes GMT so this is ok: + (url-file-time (when url-file-time-str (date-to-time url-file-time-str))) + (url-file-name-regexp (nth 4 vcs-rec)) + (url-file-rel-name (progn + (when (string-match url-file-name-regexp url-file) + (match-string 1 url-file)))) + (dl-file-name (expand-file-name url-file-rel-name dl-dir)) + (dl-file-time (nth 5 (file-attributes dl-file-name))) + (file-rel-name (file-relative-name dl-file-name dl-root)) + (file-name (file-name-nondirectory dl-file-name)) + (temp-file (expand-file-name (concat web-autoload-temp-file-prefix file-name) dl-dir)) + temp-buf) + (cond + ((and file-mask (not (web-vcs-match-folderwise file-mask file-rel-name)))) + ((and dl-file-time + url-file-time + (progn + ;;(message "dl-file-time =%s" (when dl-file-time (current-time-string dl-file-time))) + ;;(message "url-file-time=%s" (when url-file-time (current-time-string url-file-time))) + ;;(message "url-file-tstr=%s" (when url-file-time url-file-time-str)) + t) + (time-less-p url-file-time + (time-add dl-file-time (seconds-to-time 1)))) + (web-vcs-message-with-face 'web-vcs-green "Local file %s is newer or same age" file-rel-name)) + ;;(test (progn (message "TEST url-file=%S" url-file) (message "TEST url-file-rel-name=%S" url-file-rel-name) (message "TEST dl-file-name=%S" dl-file-name) )) + (t + ;; Avoid trouble with temp file + (while (setq temp-buf (find-buffer-visiting temp-file)) + (set-buffer-modified-p nil) (kill-buffer temp-buf)) + (when (file-exists-p temp-file) (delete-file temp-file)) + ;;(web-vcs-message-with-face 'font-lock-comment-face "Starting url-copy-file %S %S t t" url-file temp-file) + (web-vcs-url-copy-file-and-check url-file temp-file dl-file-name) + ;;(web-vcs-message-with-face 'font-lock-comment-face "Finished url-copy-file %S %S t t" url-file temp-file) + (let* ((time-after-url-copy (current-time)) + (old-buf-open (find-buffer-visiting dl-file-name))) + (when (and old-buf-open (buffer-modified-p old-buf-open)) + (save-excursion + (switch-to-buffer old-buf-open) + (when (y-or-n-p (format "Buffer %S is modified, save to make a backup? " dl-file-name)) + (save-buffer)))) + (if (and dl-file-time (web-vcs-equal-files dl-file-name temp-file)) + (progn + (delete-file temp-file) + (when url-file-time (set-file-times dl-file-name url-file-time)) + (web-vcs-message-with-face 'web-vcs-green "File %S was ok" dl-file-name)) + (when dl-file-time + (let ((backup (concat dl-file-name ".moved"))) + (rename-file dl-file-name backup t))) + ;; Be paranoid and let user check here. I actually + ;; believe that is a very good thing here. + (web-vcs-be-paranoid temp-file dl-file-name file-rel-name) + (rename-file temp-file dl-file-name) + (when url-file-time (set-file-times dl-file-name url-file-time)) + ;; (let ((buf (find-buffer-visiting dl-file-name))) + ;; (when buf + ;; (with-current-buffer buf + ;; (message "before revert-buffer") + ;; (revert-buffer nil t t) + ;; (message "after revert-buffer") + ;; ))) + (if dl-file-time + (web-vcs-message-with-face 'web-vcs-yellow "Updated %S" dl-file-name) + (web-vcs-message-with-face 'web-vcs-green "Downloaded %S" dl-file-name)) + (when old-buf-open + (with-current-buffer old-buf-open + (set-buffer-modified-p nil) + (revert-buffer nil t t))) + (with-current-buffer (find-file-noselect dl-file-name) + (setq header-line-format + (propertize (format-time-string "This file was downloaded %Y-%m-%d %H:%M") + 'face 'web-vcs-green)))) + (web-vcs-display-messages nil) + ;; This is both for user and remote server load. Do not remove this. + (redisplay t) (sit-for (- 1.0 (float-time (time-subtract (current-time) time-after-url-copy)))) + ;; (unless old-buf-open + ;; (when old-buf + ;; (kill-buffer old-buf))) + ))) + (redisplay t)))) + +(defun web-vcs-get-revision-on-page (vcs-rec url) + "Get revision number using VCS-REC on page URL. +VCS-REC should be an entry like the entries in the list +`web-vcs-links-regexp'." + ;; url-insert-file-contents + (let ((url-buf (url-retrieve-synchronously url))) + (web-vcs-get-revision-from-url-buf vcs-rec url-buf url))) + +(defun web-vcs-get-revision-from-url-buf (vcs-rec url-buf url) + "Get revision number using VCS-REC. +VCS-REC should be an entry in the list `web-vcs-links-regexp'. +The buffer URL-BUF should contain the content on page URL." + (let ((revision-regexp (nth 5 vcs-rec))) + ;; Get revision number + (with-current-buffer url-buf + (goto-char (point-min)) + (if (not (re-search-forward revision-regexp nil t)) + (progn + (web-vcs-message-with-face 'web-vcs-red "Can't find revision number on %S" url) + (web-vcs-display-messages t) + (throw 'command-level nil)) + (match-string 1))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Auto Download + + +;; fix-me: To emulation-mode-map +;; Fix-me: put this on better keys +(defvar web-vcs-paranoid-state-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c)(control ?c)] 'exit-recursive-edit) + (define-key map [(control ?c)(control ?n)] 'web-autoload-continue-no-stop) + (define-key map [(control ?c)(control ?r)] 'web-vcs-investigate-elisp-file) + (define-key map [(control ?c)(control ?q)] 'web-vcs-quit-auto-download) + map)) + +(defun web-vcs-quit-auto-download () + "Quit download process. +This stops the current web autoload processing." + (interactive) + ;; Fix-me. + (when (y-or-n-p "Stop web autoload processing? You can resume it later. ") + (web-vcs-message-with-face 'web-vcs-red + "Stopped autoloading in process. It will be resumed when necessary again.") + (web-vcs-log nil nil "User stopped autoloading") + (throw 'top-level 'web-autoload-stop))) + +(define-minor-mode web-vcs-paranoid-state-mode + "Mode used temporarily during user check of downloaded file. +Do not turn on this yourself." + :lighter (concat " " (propertize "Download file check" 'face 'font-lock-warning-face)) + :global t + :group 'web-vcs + (or (not web-vcs-paranoid-state-mode) + (web-autoload-acvtive) + (error "This mode can't be used when not downloading"))) + +(defcustom web-autoload-paranoid t + "Be paranoid and break to check each file after download." + :type 'boolean + :group 'web-vcs) + +(defun web-autoload-continue-no-stop () + "Continue web auto download. +This is used after inspecting downloaded elisp files. Set +`web-autoload-paranoid' to nil before contiuning to avoid further +breaks to check downloaded files." + (interactive) + (setq web-autoload-paranoid nil) + (web-autoload-continue)) + +(defun web-autoload-continue () + "Continue web auto download. +This is used after inspecting downloaded elisp files." + (interactive) + (if (< 0 (recursion-depth)) + (exit-recursive-edit) + (web-autoload-byte-compile-queue))) + +(defun web-vcs-be-paranoid (temp-file file-dl-name file-sub-url) + "Be paranoid and check FILE-DL-NAME." + (when (or (not (boundp 'web-autoload-paranoid)) + web-autoload-paranoid) + (save-window-excursion + (let* ((comp-buf (get-buffer "*Compilation*")) + (comp-win (and comp-buf + (get-buffer-window comp-buf))) + (msg-win (web-vcs-display-messages nil)) + temp-buf + (kf-desc (lambda (fun) + (let* ((key (where-is-internal fun nil t)) + (k-desc (when key (key-description key))) + (fmt-kf "\n %s (or %s)") + (fmt-f "\n %s")) + (if key + (format fmt-kf k-desc fun) + (format fmt-f fun) + ))))) + (if comp-win + (progn + (select-window comp-win) + (find-file file-dl-name)) + (select-window msg-win) + (find-file-other-window temp-file)) + (setq temp-buf (current-buffer)) + (web-vcs-log-save) + (message "-") + (message "") + (with-selected-window msg-win + (goto-char (point-max))) + (let ((proceed nil) + (web-autoload-active-file-sub-url file-sub-url)) ;; Dyn var, active during file download check + (web-vcs-paranoid-state-mode 1) + (web-vcs-message-with-face + 'secondary-selection + (concat "Please check the downloaded file and then continue by doing" + (funcall kf-desc 'exit-recursive-edit) + (if (fboundp 'web-autoload-continue-no-stop) + (concat + "\n\nOr, for no more breaks to check files do" + (funcall kf-desc 'web-autoload-continue-no-stop)) + "") + "\n\nTo stop the web autoloading process for now do" + (funcall kf-desc 'web-autoload-quit-download) + "\n\nTo see the log file you can do" + (funcall kf-desc 'web-vcs-log-edit) + "\n")) + (message "") + (while (not proceed) + (condition-case err + (when (eq 'web-autoload-stop + (catch 'top-level + ;; Fix-me: review file before rename! + (setq header-line-format + (propertize + (format "Review for downloading. Continue: C-c C-c%s. Destination: %S" + (if (string= "el" (file-name-extension file-dl-name)) + ", Check: C-c C-r" + "") + file-dl-name) + 'face 'web-vcs-red)) + (unwind-protect + (progn + (recursive-edit)) + (web-vcs-paranoid-state-mode -1)) + (with-current-buffer temp-buf + (set-buffer-modified-p nil) + (kill-buffer temp-buf)) + (setq proceed t))) + (throw 'top-level t)) + (error (message "%s" (error-message-string err)))))) + (web-vcs-display-messages t) + )))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Auto Download Compile Queue +;; +;; Downloaded elisp files are placed in a compile queue. They are not +;; compiled until all required elisp files are downloaded (and +;; optionally compiled). +;; +;; This mechanism works through +;; - reading (eval-when-compile ...) etc in the files +;; - a defadviced require that is the driver of the process + +(defvar web-autoload-compile-queue nil) + +(defvar web-autoload-byte-compile-queue-active nil) ;; Dyn var + +(defun web-autoload-byte-compile-file (file load comp-fun) + (if nil ;;(file-exists-p file) + (byte-compile-file file load) + (let ((added-entry (list file load comp-fun nil))) + (if (member added-entry web-autoload-compile-queue) + (setq added-entry nil) + (web-vcs-message-with-face 'web-vcs-gold "Add to compile queue (%S %s)" file load) + (setq web-autoload-compile-queue (cons added-entry + web-autoload-compile-queue))) + (when added-entry + (if web-autoload-byte-compile-queue-active + (throw 'web-autoload-comp-restart t) + (web-autoload-byte-compile-queue)))))) + +;;(web-autoload-byte-compile-queue) +(defun web-autoload-byte-compile-queue () + (let ((top-entry) + (web-autoload-byte-compile-queue-active t)) + (while (and web-autoload-compile-queue + (not (equal top-entry + (car web-autoload-compile-queue)))) + (setq top-entry (car web-autoload-compile-queue)) + (catch 'web-autoload-comp-restart + (web-autoload-byte-compile-first) + (setq web-autoload-compile-queue (cdr web-autoload-compile-queue)))))) + +(defun web-autoload-byte-compile-first () + "Compile first file on compile queue and maybe load it. +Compile the car of `web-autoload-compile-queue' and load if this +entry says so." + (let* ((compiled-it nil) + (first-entry (car web-autoload-compile-queue)) + (el-file (nth 0 first-entry)) + (load (nth 1 first-entry)) + (comp-fun (nth 2 first-entry)) + (req-done (nth 3 first-entry)) + (elc-file (byte-compile-dest-file el-file)) + (need-compile (or (not (file-exists-p elc-file)) + (file-newer-than-file-p el-file elc-file)))) + (if (not need-compile) + nil ;;(when load (load elc-file)) + (unless req-done + (web-autoload-do-eval-requires el-file) + (setcar (nthcdr 3 first-entry) t)) + (when (catch 'web-autoload-comp-restart + (condition-case err + (progn + (web-vcs-message-with-face 'font-lock-comment-face "Start byte compiling %S" el-file) + (web-vcs-message-with-face 'web-vcs-pink "Compiling QUEUE: %S" web-autoload-compile-queue) + (let ((web-autoload-skip-require-advice t)) (funcall comp-fun el-file load)) + (web-vcs-message-with-face 'font-lock-comment-face "Ready byte compiling %S" el-file) + ;; Return nil to tell there are no known problems + (if (file-exists-p elc-file) + nil + (web-vcs-message-with-face + 'web-vcs-red "Error: byte compiling did not produce %S" elc-file) + (web-vcs-display-messages nil) + ;; Clean up before restart + (web-autoload-try-cleanup-after-failed-compile first-entry) + t)) + (error + (web-vcs-message-with-face + 'web-vcs-red "Error in byte compiling %S: %s" el-file (error-message-string err)) + (web-vcs-display-messages nil) + ;; Clean up before restart + (web-autoload-try-cleanup-after-failed-compile first-entry) + t ;; error + ))) + (throw 'web-autoload-comp-restart t) + )))) + +(defun web-autoload-do-eval-requires (el-file) + "Do eval-when-compile and eval-and-compile." + ;;(message "web-autoload-do-eval-requires %S" el-file) + (let ((old-buf (find-buffer-visiting el-file))) + (with-current-buffer (or old-buf (find-file-noselect el-file)) + (let ((here (point)) + (web-autoload-require-skip-noerror-entries t)) + (save-restriction + (widen) + (goto-char (point-min)) + ;;(message "web-autoload-do-eval-requires cb=%s" (current-buffer)) + (while (progn + (while (progn (skip-chars-forward " \t\n\^l") + (looking-at ";")) + (forward-line 1)) + (not (eobp))) + (let ((form (read (current-buffer)))) + (when (memq (car form) '(eval-when-compile eval-and-compile)) + (web-vcs-message-with-face 'web-vcs-gold " eval %S" form) + (eval form)) + ))) + (if old-buf (kill-buffer) (goto-char here)))))) + + +;; Fix-me: protect against deep nesting +(defun web-autoload-do-require (feature filename noerror) + (let* ((feat-name (symbol-name feature)) + (lib (or filename feat-name))) + (if (load lib noerror t) + (progn + (unless (featurep feature) + (error "web-autoload: Required feature `%s' was not provided" feature)) + feature) + nil + ))) + +(defvar web-autoload-require-skip-noerror-entries nil) + +(defadvice require (around + web-autoload-ad-require) + (let ((feature (ad-get-arg 0)) + (filename (ad-get-arg 1)) + (noerror (ad-get-arg 2))) + (if (featurep feature) + feature + (if (or filename + (and noerror + (or (not (boundp 'web-autoload-skip-require-advice)) + web-autoload-skip-require-advice))) + (progn + (message "Doing nearly original require %s, because skipping" (ad-get-arg 0)) + ;; Can't ad-do-it because defadviced functions in load + ;;(web-autoload-do-require feature filename noerror) + ;; + ;; Fix-me: Implement lazy loading here? Could it be done with while-no-input? + ;; + ;;(when (assq feature web-autoload-require-list) ) + ad-do-it) + (unless (and noerror + web-autoload-require-skip-noerror-entries) + (let* ((auto-rec (assq feature web-autoload-require-list)) + (web-vcs (nth 1 auto-rec)) + (base-url (nth 2 auto-rec)) + (relative-url (nth 3 auto-rec)) + (base-dir (nth 4 auto-rec)) + (comp-fun (nth 5 auto-rec))) + (if (not auto-rec) + ad-do-it + (let* ((full-el (concat (expand-file-name relative-url base-dir) ".el")) + (full-elc (byte-compile-dest-file full-el)) + (our-buffer (current-buffer)) ;; Need to come back here + (our-wcfg (current-window-configuration)) + (mode-line-old (web-vcs-redefine-face 'mode-line 'web-vcs-mode-line)) + (mode-line-inactive-old (web-vcs-redefine-face 'mode-line-inactive 'web-vcs-mode-line-inactive)) + (header-line-format-old (with-current-buffer "*Messages*" + (prog1 + header-line-format + (setq header-line-format + (propertize "Downloading needed files..." + 'face 'web-vcs-mode-line + ;;'face '(:height 1.5) ;; does not work + )))))) + ;; Fix-me: can't update while accessing the menus + ;;(message "trying (redisplay t) ;; mode line") + ;;(sit-for 1) (redisplay t) ;; mode line + (unwind-protect + (progn + (web-vcs-message-with-face 'web-vcs-gold "Doing the really adviced require for %s" feature) + ;; Check if already downloaded first + (unless (file-exists-p full-el) + (setq base-url (eval base-url)) + ;; Download and try again + (setq relative-url (concat relative-url ".el")) + (web-vcs-message-with-face 'web-vcs-green "Need to download feature '%s" feature) + (catch 'web-autoload-comp-restart + (web-vcs-get-missing-matching-files web-vcs base-url base-dir relative-url))) + (set-buffer our-buffer) ;; Before we load.. + (when web-autoload-autocompile + (unless (file-exists-p full-elc) + ;; Byte compile the downloaded file + (web-autoload-byte-compile-file full-el t comp-fun))) + (web-vcs-message-with-face 'web-vcs-gold "Doing finally require for %s" feature) + (set-buffer our-buffer) ;; ... and after we load + (set-window-configuration our-wcfg)) + (with-current-buffer "*Messages*" (setq header-line-format header-line-format-old)) + (web-vcs-redefine-face 'mode-line mode-line-old) + (web-vcs-redefine-face 'mode-line-inactive mode-line-inactive-old))) + ad-do-it))))))) + +;; (setq x (web-vcs-redefine-face 'mode-line (setq z (face-all-attributes 'web-vcs-mode-line (selected-frame))))) +;; (setq x (web-vcs-redefine-face 'mode-line 'web-vcs-mode-line)) +;; (setq y (web-vcs-redefine-face 'mode-line x)) +;; (describe-face 'web-vcs-mode-line) +(defun web-vcs-redefine-face (face as-new) + "Redefine FACE to use the attributes in AS-NEW. +AS-NEW may be either a face or a list returned by `face-all-attributes'. +Return an alist with old attributes." + (let ((ret (face-all-attributes face (selected-frame))) + (new-face-att (if (facep as-new) + (face-all-attributes as-new (selected-frame)) + as-new)) + new-at-prop-list + ) + (dolist (at new-face-att) + (let ((sym (car at)) + (val (cdr at))) + (unless (eq val 'unspecified) + (setq new-at-prop-list (cons sym + (cons val + new-at-prop-list))) + ;;(message "new=%S" new-at-prop-list) + ))) + (apply 'set-face-attribute face (selected-frame) new-at-prop-list) + ret + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Web Autoload Define + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Helpers + +;;(web-vcs-file-name-as-list "/a/b/c.el") +;;(web-vcs-file-name-as-list "a/b/c.el") +;;(web-vcs-file-name-as-list "c:/a/b/c.el") +;;(web-vcs-file-name-as-list ".*/a/c/") +;;(web-vcs-file-name-as-list "[^/]*/a/c/") ;; Just avoid this. +(defun web-vcs-file-name-as-list (filename) + "Split file name FILENAME into a list with file names." + ;; We can't use the primitives since they converts \ to / and + ;; therefore damages the reg exps. Just use our knowledge of the + ;; internal file name representation instead. + (split-string filename "/")) +;; (let ((lst-name nil) +;; (head filename) +;; (old-head "")) +;; (while (and (not (string= old-head head)) +;; (> (length head) 0)) +;; (let* ((file-head (directory-file-name head)) +;; (tail (file-name-nondirectory (directory-file-name head)))) +;; (setq old-head head) +;; (setq head (file-name-directory file-head)) +;; ;; For an abs path the final tail is "", use root instead: +;; (when (= 0 (length tail)) +;; (setq tail head)) +;; (setq lst-name (cons tail lst-name)))) +;; lst-name)) + +;;(web-vcs-match-folderwise ".*/util/mum.el" "top/util/mum.el") +;;(web-vcs-match-folderwise ".*/util/mu.el" "top/util/mum.el") +;;(web-vcs-match-folderwise ".*/ut/mum.el" "top/util/mum.el") +;;(web-vcs-match-folderwise ".*/ut../mum.el" "top/util/mum.el") +;;(web-vcs-match-folderwise ".*/ut../mum.el" "top/util") +;;(web-vcs-match-folderwise ".*/ut../mum.el" "top") +;;(web-vcs-match-folderwise "top/ut../mum.el" "top") +(defun web-vcs-match-folderwise (regex file) + "Split REGEXP as a file path and match against FILE parts." + ;;(message "folderwise %S %S" regex file) + (let ((lst-regex (web-vcs-file-name-as-list regex)) + (lst-file (web-vcs-file-name-as-list file))) + (when (>= (length lst-regex) (length lst-file)) + (catch 'match + (while lst-file + (let ((head-file (car lst-file)) + (head-regex (car lst-regex))) + (unless (or (= 0 (length head-file)) ;; Last /, if present, gives "" + (string-match-p (concat "^" head-regex "$") head-file)) + (throw 'match nil))) + (setq lst-file (cdr lst-file)) + (setq lst-regex (cdr lst-regex))) + t)))) + +(defun web-vcs-contains-file (dir file) + "Return t if DIR contain FILE." + (assert (string= dir (file-name-as-directory (expand-file-name dir))) t) + (assert (or (string= file (file-name-as-directory (expand-file-name file))) + (string= file (expand-file-name file))) t) + (let ((dir-len (length dir))) + (assert (string= "/" (substring dir (1- dir-len)))) + (when (> (length file) dir-len) + (string= dir (substring file 0 dir-len))))) + +(defun web-vcs-nice-elapsed (start-time end-time) + "Format elapsed time between START-TIME and END-TIME nicely. +Those times should have the same format as time returned by +`current-time'." + (format-seconds "%h h %m m %z%s s" (float-time (time-subtract end-time start-time)))) + +;; (web-vcs-equal-files "web-vcs.el" "temp.tmp") +;; (web-vcs-equal-files "../.nosearch" "temp.tmp") +(defun web-vcs-equal-files (file-a file-b) + "Return t if files FILE-A and FILE-B are equal." + (let* ((cmd (if (eq system-type 'windows-nt) + (list "fc" nil nil nil + "/B" "/OFF" + (convert-standard-filename file-a) + (convert-standard-filename file-b)) + (list diff-command nil nil nil + "--binary" "-q" file-a file-b))) + (ret (apply 'call-process cmd))) + ;;(message "ret=%s, cmd=%S" ret cmd) (sit-for 2) + (cond + ((= 1 ret) + nil) + ((= 0 ret) + t) + (t + (error "%S returned %d" cmd ret))))) + +(defun web-vcs-display-messages (select) + "Display *Messages* buffer. Select its window if SELECT." + (let ((msg-win (display-buffer "*Messages*"))) + (with-selected-window msg-win (goto-char (point-max))) + (when select (select-window msg-win)) + msg-win)) + +;; (web-vcs-message-with-face 'secondary-selection "I am saying: %s and %s" "Hi" "Farwell!") +;;;###autoload +(defun web-vcs-message-with-face (face format-string &rest args) + "Display a colored message at the bottom of the string. +FACE is the face to use for the message. +FORMAT-STRING and ARGS are the same as for `message'. + +Also put FACE on the message in *Messages* buffer." + (with-current-buffer "*Messages*" + (save-restriction + (widen) + (let* ((start (let ((here (point))) + (goto-char (point-max)) + (prog1 + (copy-marker + (if (bolp) (point-max) + (1+ (point-max)))) + (goto-char here)))) + (msg-with-face (propertize (apply 'format format-string args) + 'face face))) + ;; This is for the echo area: + (message "%s" msg-with-face) + ;; This is for the buffer: + (when (< 0 (length msg-with-face)) + (goto-char (1- (point-max))) + ;;(backward-char) + ;;(unless (eolp) (goto-char (line-end-position))) + (put-text-property start (point) + 'face face)))))) + +(defun web-vcs-num-moved (root) + "Return nof files matching *.moved inside directory ROOT." + (let* ((file-regexp ".*\\.moved$") + (files (directory-files root t file-regexp)) + (subdirs (directory-files root t))) + (dolist (subdir subdirs) + (when (and (file-directory-p subdir) + (not (or (string= "/." (substring subdir -2)) + (string= "/.." (substring subdir -3))))) + (setq files (append files (web-vcs-rdir-get-files subdir file-regexp) nil)))) + (length files))) + +;; Copy of rdir-get-files in ourcomment-util.el +(defun web-vcs-rdir-get-files (root file-regexp) + (let ((files (directory-files root t file-regexp)) + (subdirs (directory-files root t))) + (dolist (subdir subdirs) + (when (and (file-directory-p subdir) + (not (or (string= "/." (substring subdir -2)) + (string= "/.." (substring subdir -3))))) + (setq files (append files (web-vcs-rdir-get-files subdir file-regexp) nil)))) + files)) + +(defun web-vcs-contains-moved-files (dl-dir) + "Return t if there are *.moved files in DL-DIR." + (let ((num-moved (web-vcs-num-moved dl-dir))) + (when (> num-moved 0) + (web-vcs-message-with-face 'font-lock-warning-face + (concat "There are %d *.moved files (probably from prev download)\n" + "in %S.\nPlease delete them first.") + num-moved dl-dir) + t))) + + +(defun web-vcs-set&save-option (symbol value) + (customize-set-variable symbol value) + (customize-set-value symbol value) + (when (condition-case nil (custom-file) (error nil)) + (customize-mark-to-save symbol) + (custom-save-all) + (message "web-vcs: Saved option %s with value %s" symbol value))) + +(defvar web-vcs-el-this (or load-file-name + (when (boundp 'bytecomp-filename) bytecomp-filename) + buffer-file-name)) + + +(require 'bytecomp) +(defun web-vcs-byte-compile-newer-file (el-file load) + (let ((elc-file (byte-compile-dest-file el-file))) + (when (or (not (file-exists-p elc-file)) + (file-newer-than-file-p el-file elc-file)) + (byte-compile-file el-file load)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Compiling + +;;;###autoload +(defun web-vcs-byte-compile-file (file &optional load extra-load-path comp-dir) + "Byte compile FILE in a new Emacs sub process. +EXTRA-LOAD-PATH is added to the front of `load-path' during +compilation. + +FILE is set to `buffer-file-name' when called interactively. +If LOAD" + (interactive (list (buffer-file-name) + t)) + (when (with-no-warnings (called-interactively-p)) + (unless (eq major-mode 'emacs-lisp-mode) + (error "Must be in emacs-lisp-mode"))) + (let* ((old-env-load-path (getenv "EMACSLOADPATH")) + (sub-env-load-path (or old-env-load-path + ;;(mapconcat 'identity load-path ";"))) + (mapconcat 'identity load-path path-separator))) + ;; Fix-me: name of compile log buffer. When should it be + ;; deleted? How do I bind it to byte-compile-file? Or do I? + (file-buf (find-buffer-visiting file)) + (out-buf (get-buffer-create "*Compile-Log*")) + (elc-file (byte-compile-dest-file file)) + (this-emacs-exe (locate-file invocation-name + (list invocation-directory) + exec-suffixes)) + (default-directory (or comp-dir default-directory)) + (debug-on-error t) + start) + ;; (when (and file-buf + ;; (buffer-modified-p file-buf)) + ;; (switch-to-buffer file-buf) + ;; (error "Buffer must be saved first: %S" file-buf)) + (dolist (full-p extra-load-path) + ;;(setq sub-env-load-path (concat full-p ";" sub-env-load-path))) + (setq sub-env-load-path (concat full-p path-separator sub-env-load-path))) + (unless (get-buffer-window out-buf (selected-frame)) + (if (string= file (buffer-file-name)) + (display-buffer out-buf) + (unless (eq (current-buffer) out-buf) + (switch-to-buffer out-buf)))) + (with-selected-window (get-buffer-window out-buf) + (with-current-buffer out-buf + (unless (local-variable-p 'web-vcs-comp-dir) + (set (make-local-variable 'web-vcs-comp-dir) (or comp-dir default-directory))) + (setq default-directory web-vcs-comp-dir) + (widen) + (goto-char (point-max)) + (when (or (= 0 (buffer-size)) + (not (derived-mode-p 'compilation-mode))) + (insert (propertize "\nWeb VCS compilation output" 'font-lock-face 'font-lock-comment-face)) + (compilation-mode) + (setq font-lock-verbose nil) + (font-lock-add-keywords nil + '(("\\<Compile\\>" . 'compilation-info)))) + (let ((inhibit-read-only t) + (rel-file (file-relative-name file))) + (insert "\n\n") + (insert "** Compile " rel-file "\n")) + (setq start (point)) + (when (file-exists-p elc-file) (delete-file elc-file)) + (if (or (not window-system) + (< emacs-major-version 23)) + (byte-compile-file file) + ;;(message "web-vcs-byte-compile-file:sub-env-load-path=%s" sub-env-load-path) + (unless (file-exists-p this-emacs-exe) + (error "Can't find this-emacs-exe=%s" this-emacs-exe)) + (unless (stringp sub-env-load-path) (error "I did it again, sub-env-load-path=%S" sub-env-load-path)) + (setenv "EMACSLOADPATH" sub-env-load-path) + ;; Fix-me: status + (let* ((inhibit-read-only t) + (ret (apply 'call-process this-emacs-exe nil out-buf t + "-Q" "--batch" + "--eval" "(setq debug-on-error t)" + "--eval" "(remove-hook 'find-file-hook 'vc-find-file-hook)" + "--file" file + "-f" "emacs-lisp-byte-compile" + nil))) + ;;(insert (format "call-process returned: %s\n" ret)) + ) + (setenv "EMACSLOADPATH" old-env-load-path)) + (goto-char start) + (while (re-search-forward "^\\([a-zA-Z0-9/\._-]+\\):[0-9]+:[0-9]+:" nil t) + (let ((rel-file (file-relative-name file)) + (inhibit-read-only t)) + (replace-match rel-file nil nil nil 1))) + (goto-char (point-max)))) + (when (file-exists-p elc-file) + (when (and load window-system) (load elc-file)) + t))) + + +;;;;;;;;;;;;;;;;;;;;;;;; +;;; Temporary helpers, possibly included in Emacs + +;; (setq x (web-vcs-url-retrieve-synch "http://emacswiki.org/")) +(defun web-vcs-url-retrieve-synch (url) + "Retrieve URL, return cons with buffer and http status." + (let* ((url-show-status nil) ;; just annoying showing status here + (buffer (url-retrieve-synchronously url)) + (handle nil) + (http-status nil)) + (if (not buffer) + (error "Retrieving url %s gave no buffer" url)) + (with-current-buffer buffer + (if (= 0 (buffer-size)) + (progn + (kill-buffer) + nil) + (require 'url-http) + (setq http-status (url-http-parse-response)) + (if (memq http-status '(200 201)) + (progn + (goto-char (point-min)) + (unless (search-forward "\n\n" nil t) + (error "Could not find header end in buffer for %s" url)) + (delete-region (point-min) (point)) + (set-buffer-modified-p nil) + (goto-char (point-min))) + (kill-buffer buffer) + (setq buffer nil)))) + (cons buffer http-status))) + +;; Modified just to return http status +(defun web-vcs-url-copy-file (url newname &optional ok-if-already-exists + keep-time preserve-uid-gid) + "Copy URL to NEWNAME. Both args must be strings. +Signals a `file-already-exists' error if file NEWNAME already exists, +unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil. +A number as third arg means request confirmation if NEWNAME already exists. +This is what happens in interactive use with M-x. +Fourth arg KEEP-TIME non-nil means give the new file the same +last-modified time as the old one. (This works on only some systems.) +Fifth arg PRESERVE-UID-GID is ignored. +A prefix arg makes KEEP-TIME non-nil." + (if (and (file-exists-p newname) + (not ok-if-already-exists)) + (error "Opening output file: File already exists, %s" newname)) + (let ((buffer (url-retrieve-synchronously url)) + (handle nil) + (ret nil)) + (if (not buffer) + (error "Retrieving url %s gave no buffer" url)) + (with-current-buffer buffer + (if (= 0 (buffer-size)) + (progn + (kill-buffer) + nil) + (require 'url-http) + (setq ret (url-http-parse-response)) + (setq handle (mm-dissect-buffer t)) + (mm-save-part-to-file handle newname) + (kill-buffer buffer) + (mm-destroy-parts handle))) + ret)) + +(defun web-vcs-read-and-accept-key (prompt accepted &optional reject-message help-function) + (let ((key nil) + rejected) + (while (not (member key accepted)) + (if (and help-function + (or (member key help-event-list) + (eq key ??))) + (funcall help-function) + (unless rejected + (setq rejected t) + (setq prompt (concat (or reject-message "Please answer with one of the alternatives.") + "\n\n" + prompt)) + (setq key (web-vcs-read-key prompt))))) + key)) + +(defconst web-vcs-read-key-empty-map (make-sparse-keymap)) + +(defvar web-vcs-read-key-delay 0.01) ;Fast enough for 100Hz repeat rate, hopefully. + +(defun web-vcs-read-key (&optional prompt) + "Read a key from the keyboard. +Contrary to `read-event' this will not return a raw event but instead will +obey the input decoding and translations usually done by `read-key-sequence'. +So escape sequences and keyboard encoding are taken into account. +When there's an ambiguity because the key looks like the prefix of +some sort of escape sequence, the ambiguity is resolved via `web-vcs-read-key-delay'." + (let ((overriding-terminal-local-map web-vcs-read-key-empty-map) + (overriding-local-map nil) + (old-global-map (current-global-map)) + (timer (run-with-idle-timer + ;; Wait long enough that Emacs has the time to receive and + ;; process all the raw events associated with the single-key. + ;; But don't wait too long, or the user may find the delay + ;; annoying (or keep hitting more keys which may then get + ;; lost or misinterpreted). + ;; This is only relevant for keys which Emacs perceives as + ;; "prefixes", such as C-x (because of the C-x 8 map in + ;; key-translate-table and the C-x @ map in function-key-map) + ;; or ESC (because of terminal escape sequences in + ;; input-decode-map). + web-vcs-read-key-delay t + (lambda () + (let ((keys (this-command-keys-vector))) + (unless (zerop (length keys)) + ;; `keys' is non-empty, so the user has hit at least + ;; one key; there's no point waiting any longer, even + ;; though read-key-sequence thinks we should wait + ;; for more input to decide how to interpret the + ;; current input. + (throw 'read-key keys))))))) + (unwind-protect + (progn + (use-global-map web-vcs-read-key-empty-map) + (message (concat (apply 'propertize prompt (member 'face minibuffer-prompt-properties)) + (propertize " " 'face 'cursor))) + (aref (catch 'read-key (read-key-sequence-vector nil nil t)) 0)) + (cancel-timer timer) + (use-global-map old-global-map)))) + +;; End temp helpers +;;;;;;;;;;;;;;;;;;;;;;;; + +;;(web-vcs-existing-files-matcher default-directory) +(defun web-vcs-existing-files-matcher (dir) + (let ((files-and-dirs (directory-files dir nil "[^#~]$")) + files + (default-directory dir)) + (dolist (df files-and-dirs) + (unless (file-directory-p df) + (setq files (cons df files)))) + (cons (regexp-opt files) t))) + +(defun web-vcs-update-existing-files (vcs base-url dl-dir this-dir) + (let ((files-and-dirs (directory-files this-dir nil "\\(?:\\.elc\\|\\.moved\\|[^#~]\\)$")) + files + dirs + (this-rel (file-relative-name this-dir dl-dir)) + file-mask) + (when (string= "./" this-rel) (setq this-rel "")) + (dolist (df files-and-dirs) + (if (and (file-directory-p df) + (not (member df '("." "..")))) + (setq dirs (cons df dirs)) + (setq files (cons df files)))) + ;;(web-vcs-message-with-face 'hi-blue "this-rel=%S %S %S" this-rel dl-dir this-dir) + (setq file-mask (concat this-rel (regexp-opt files))) + ;;(web-vcs-message-with-face 'hi-blue "r=%S" file-mask) + (web-vcs-get-missing-matching-files vcs base-url dl-dir file-mask) + (dolist (d dirs) + (web-vcs-update-existing-files vcs base-url dl-dir + (file-name-as-directory + (expand-file-name d this-dir)))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Some small bits for security and just overview. + +(defun web-vcs-fontify-as-ps-print() + (save-restriction + (widen) + (let ((start (point-min)) + (end (point-max))) + (cond ((and (boundp 'jit-lock-mode) (symbol-value 'jit-lock-mode)) + (jit-lock-fontify-now start end)) + ((and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode)) + (lazy-lock-fontify-region start end)))))) + + +;;(web-vcs-get-fun-details 'describe-function) +;;(web-vcs-get-fun-details 'require) +;;(describe-function 'describe-function) +(defun web-vcs-get-fun-details (function) + (unless (symbolp function) (error "Not a symbol: %s" function)) + (unless (functionp function) (error "Not a function: %s" function)) + ;; Do as in `describe-function': + (let* ((advised (and (symbolp function) (featurep 'advice) + (ad-get-advice-info function))) + ;; If the function is advised, use the symbol that has the + ;; real definition, if that symbol is already set up. + (real-function + (or (and advised + (let ((origname (cdr (assq 'origname advised)))) + (and (fboundp origname) origname))) + function)) + ;; Get the real definition. + (def (if (symbolp real-function) + (symbol-function real-function) + function)) + errtype file-name (beg "") string) + ;; Just keep this as it is to more easily compare with `describe-function-1'. + (setq string + (cond ((or (stringp def) + (vectorp def)) + "a keyboard macro") + ((subrp def) + (if (eq 'unevalled (cdr (subr-arity def))) + (concat beg "special form") + (concat beg "built-in function"))) + ((byte-code-function-p def) + (concat beg "compiled Lisp function")) + ((symbolp def) + (while (and (fboundp def) + (symbolp (symbol-function def))) + (setq def (symbol-function def))) + ;; Handle (defalias 'foo 'bar), where bar is undefined. + (or (fboundp def) (setq errtype 'alias)) + (format "an alias for `%s'" def)) + ((eq (car-safe def) 'lambda) + (concat beg "Lisp function")) + ((eq (car-safe def) 'macro) + "a Lisp macro") + ((eq (car-safe def) 'autoload) + ;;(setq file-name-auto (nth 1 def)) + ;;(setq file-name-auto (find-lisp-object-file-name function def)) + ;;(setq file-auto-noext (file-name-sans-extension file-name-auto)) + (format "%s autoloaded %s" + (if (commandp def) "an interactive" "an") + (if (eq (nth 4 def) 'keymap) "keymap" + (if (nth 4 def) "Lisp macro" "Lisp function")))) + ((keymapp def) + (let ((is-full nil) + (elts (cdr-safe def))) + (while elts + (if (char-table-p (car-safe elts)) + (setq is-full t + elts nil)) + (setq elts (cdr-safe elts))) + (if is-full + "a full keymap" + "a sparse keymap"))) + (t ""))) + (setq file-name (find-lisp-object-file-name function def)) + (list errtype advised file-name string) + )) + +;;(web-vcs-investigate-read "c:/emacsw32/nxhtml/nxhtml/nxhtml-autoload.el" "*Messages*") +(defun web-vcs-investigate-read (elisp out-buf) + "Check forms in buffer by reading it." + (let* ((here (point)) + unsafe-eval re-fun re-var + elisp-el-file + (is-same-file (lambda (file) + (when file + (setq file (concat (file-name-sans-extension file) ".el")) + (string= (file-truename file) elisp-el-file))))) + (with-current-buffer elisp + (setq elisp-el-file (when (buffer-file-name) + (file-truename (buffer-file-name)))) + (save-restriction + (widen) + (web-vcs-fontify-as-ps-print) + (goto-char (point-min)) + (while (progn + (while (progn (skip-chars-forward " \t\n\^l") + (looking-at ";")) + (forward-line 1)) + (not (eobp))) + (let* ((pos (point)) + (form (read (current-buffer))) + (def (nth 0 form)) + (sym (and (listp form) + (symbolp (nth 1 form)) + (nth 1 form))) + (form-fun (and sym + (functionp sym) + (symbol-function sym))) + (form-var (boundp sym)) + (safe-forms '( defun defmacro + define-minor-mode define-globalized-minor-mode + defvar defconst + defcustom + defface defgroup + ;; fix-me: check if these do re-fun too: + define-derived-mode + define-global-minor-mode + define-globalized-minor-mode + + make-local-variable make-variable-buffer-local + provide + require + message)) + (safe-eval (or (memq def safe-forms) + (and (memq def '( eval-when-compile eval-and-compile)) + (or (not (consp (nth 1 form))) + (memq (car (nth 1 form)) safe-forms))))) + ) + (cond + ((not safe-eval) + (setq unsafe-eval + (cons (list form (copy-marker pos) (buffer-substring pos (point))) + unsafe-eval))) + ((and form-fun + (memq def '( defun defmacro define-minor-mode define-globalized-minor-mode))) + (setq re-fun (cons (cons sym pos) re-fun))) + ((and form-var + (memq def '( defvar defconst defcustom)) + (or (not (eq sym 'defvar)) + (< 2 (length form)))) + (setq re-var (cons sym re-var))))))) + (goto-char here)) + (with-current-buffer out-buf + (save-restriction + (widen) + (goto-char (point-max)) + (unless (bobp) (insert "\n\n")) + (insert (propertize "Found these possible problems when reading the file:\n" + 'face '(:height 1.5))) + (or unsafe-eval + re-fun + (insert "\n" + "Found no problems (but there may still be)" + "\n")) + + ;; Fix-me: Link + (when unsafe-eval + (insert (propertize + (format "\n* Forms that are executed when loading the file (found %s):\n\n" + (length unsafe-eval)) + 'face '(:height 1.2))) + (dolist (u unsafe-eval) + (insert-text-button "Go to form below" + 'action + `(lambda (button) + (let* ((marker ,(nth 1 u)) + (buf (marker-buffer marker))) + (switch-to-buffer-other-window buf) + (unless (and (< marker (point-max)) + (> marker (point-min))) + (widen)) + (goto-char marker)))) + (insert "\n") + (insert (nth 2 u) "\n\n")) + (insert "\n")) + (when re-fun + (insert (propertize + (format "\n* The file will possibly redefine these functions that are currently defined (%s):\n" + (length re-fun)) + 'face '(:height 1.2))) + (setq re-fun (sort re-fun (lambda (a b) (string< (symbol-name (car a)) (symbol-name (car b)))))) + (let ((row 0) + (re-fun-with-info (mapcar (lambda (fun) + (cons fun (web-vcs-get-fun-details (car fun)))) + re-fun)) + re-fun-other-files + (n-same 0) + (n-web-auto 0)) + ;; Check same file + (dolist (info re-fun-with-info) + (let* ((file-name (nth 3 info)) + (fun (car (nth 0 info))) + (web-auto (get fun 'web-autoload))) + (cond ((funcall is-same-file file-name) + (setq n-same (1+ n-same))) + (web-auto + (setq n-web-auto (1+ n-web-auto)) + (setq re-fun-other-files (cons info re-fun-other-files))) + (t + (setq re-fun-other-files (cons info re-fun-other-files)))))) + + (when (< 0 n-same) + (insert "\n " + (propertize (format "%s functions alreay defined by this file (which seems ok)" n-same) + 'face 'web-vcs-green) + "\n")) + + (dolist (info re-fun-other-files) + (let* ((fun-rec (nth 0 info)) + (errtype (nth 1 info)) + (advised (nth 2 info)) + (file-name (nth 3 info)) + (string (nth 4 info)) + (fun (car fun-rec)) + (fun-pos (cdr fun-rec)) + (fun-web-auto (get fun 'web-autoload)) + ) + (when (= 0 (% row 5)) (insert "\n")) + (setq row (1+ row)) + (insert " `") + (insert-text-button (format "%s" fun) + 'action + `(lambda (button) + (describe-function ',fun))) + (insert "'") + (insert " (" string) + (when fun-web-auto + (insert " autoloaded from web, ") + (insert-text-button "info" + 'action + `(lambda (button) + ;; Fix-me: maybe a bit more informative ... ;-) + (message "%S" ',fun-web-auto)))) + (insert ")") + (when advised (insert ", " (propertize "adviced" 'face 'font-lock-warning-face))) + (insert ", " + (cond + ((funcall is-same-file file-name) + (propertize "defined in this file" 'face 'web-vcs-green) + ) + (fun-web-auto + (if (not (web-autoload-acvtive)) + (propertize "web download not active" 'face 'web-vcs-yellow) + ;; See if file matches + (let ((active-sub-url web-autoload-active-file-sub-url) + (fun-sub-url (nth 2 fun-web-auto))) + (setq active-sub-url (file-name-sans-extension active-sub-url)) + (if (string-match-p fun-sub-url active-sub-url) + (propertize "web download, matches" 'face 'web-vcs-yellow) + (propertize "web download, doesn't matches" 'face 'web-vcs-red) + )))) + (t + (propertize "defined in other file" 'face 'web-vcs-red)))) + (unless (funcall is-same-file file-name) + (insert " (") + (insert-text-button "go to new definition" + 'action + `(lambda (button) + (interactive) + (let ((m-pos ,(with-current-buffer elisp + (copy-marker fun-pos)))) + (switch-to-buffer-other-window (marker-buffer m-pos)) + (goto-char m-pos)))) + (insert ")")) + (insert "\n") + )))))))) + +;; I am quite tired of doing this over and over again. Why is this not +;; in Emacs? +(defvar web-vcs-button-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [tab] 'forward-button) + (define-key map [(shift tab)] 'backward-button) + map)) +(define-minor-mode web-vcs-button-mode + "Just to bind `forward-button' etc" + :lighter nil) + +(defvar web-vcs-eval-output-start nil) + +;;(web-vcs-investigate-file) +;;;###autoload +(defun web-vcs-investigate-elisp-file (file-or-buffer) + (interactive (list + (if (derived-mode-p 'emacs-lisp-mode) + (current-buffer) + (read-file-name "Elisp file to check: ")))) + (let* ((elisp (if (bufferp file-or-buffer) + file-or-buffer + (find-file-noselect file-or-buffer))) + (elisp-file (with-current-buffer elisp (buffer-file-name))) + (out-buf (get-buffer-create "Web VCS Sec Inv"))) + (if (not (with-current-buffer elisp (derived-mode-p 'emacs-lisp-mode))) + (progn + (unless (eq (current-buffer) elisp) + (display-buffer elisp)) + (message "Buffer %s is not in emacs-lisp-mode" (buffer-name elisp))) + (switch-to-buffer-other-window out-buf) + (let ((inhibit-read-only t)) + (erase-buffer) + (setq buffer-read-only t) + (web-vcs-button-mode 1) + (insert "A quick look for problems in ") + (if elisp-file + (progn + (insert "file\n ") + (insert-text-button elisp-file + 'action + `(lambda (button) + (interactive) + (find-file-other-window ,elisp-file)))) + (insert "buffer ") + (insert-text-button (buffer-name elisp) + 'action + `(lambda (button) + (interactive) + (switch-to-buffer-other-window ,elisp)))) + (insert "\n") + (let ((here (point))) + (insert + "\n" + (propertize + (concat "Note that this is just a quick look at the file." + " You have to investigate the file more carefully yourself" + " (or be sure someone else has done it for you)." + " The following are checked for here:" + "\n") + 'face font-lock-comment-face)) + (fill-region here (point))) + (insert + (propertize + (concat + "- Top level forms that might be executed when loading the file.\n" + "- Redefinition of functions.\n") + 'face font-lock-comment-face)) + (web-vcs-investigate-read elisp out-buf) + (when elisp-file + (insert "\n\n\n") + (let ((here (point))) + (insert "If you want to see what will actually be added to `load-history'" + " and which functions will be defined you can\n") + (insert-text-button "click here to try to eval the file" + 'action `(lambda (button) (interactive) + (if (y-or-n-p "Load the file in a batch Emacs session? ") + (web-vcs-investigate-eval ,elisp-file ,out-buf) + (message "Aborted")))) + (insert ".\n\nThis will load the file in a batch Emacs" + " which runs the same init files as you have run now" + (cond + ((not init-file-user) " (with -Q, ie no init files will run)") + ((not site-run-file) " (with -q, ie .emacs will not furn)") + (t " (your normal setup files will be run)" + )) + " and send back that information." + " The variable `load-path' is set to match the downloading" + " to make the loading possible before your setup is ready." + "\n\nYour current Emacs will not be affected by the loading," + " but please be aware that this does not mean your computer can not be." + " So please look at the file first.") + (fill-region here (point)) + (setq web-vcs-eval-output-start (point)) + )) + (set-buffer-modified-p nil) + (goto-char (point-min)))))) + +(make-variable-buffer-local 'web-vcs-eval-output-start) + +;;(web-vcs-investigate-eval "c:/emacsw32/nxhtml/nxhtml/nxhtml-autoload.el" "*Messages*") +;;(web-vcs-investigate-eval "c:/emacsw32/nxhtml/autostart.el" "*Messages*") +(defun web-vcs-investigate-eval (elisp-file out-buf) + "Get compile loads when evaling buffer. +For security reasons do this in a fresh Emacs and return the +resulting load-history entry." + (let* ((emacs-exe (locate-file invocation-name + (list invocation-directory) + exec-suffixes)) + ;; see custom-load-symbol + (get-lhe '(let ((lhe (or (assoc buffer-file-name load-history) + (assoc (concat (file-name-sans-extension buffer-file-name) ".elc") + load-history)))) + (prin1 "STARTHERE\n") + (prin1 lhe))) + (elisp-file-name (file-name-sans-extension (file-name-nondirectory elisp-file))) + (elisp-el-file (file-truename (concat (file-name-sans-extension elisp-file) ".el"))) + (temp-prefix web-autoload-temp-file-prefix) + (temp-prefix-len (length temp-prefix)) + (is-downloading (and (boundp 'web-autoload-paranoid) + web-autoload-paranoid)) + (is-temp-file (and is-downloading + (< (length temp-prefix) (length elisp-file-name)) + (string= temp-prefix + (substring elisp-file-name 0 temp-prefix-len)))) + (elisp-feature-name (if is-temp-file + (substring elisp-file-name temp-prefix-len) + elisp-file-name)) + (is-same-file (lambda (file) + (when file ;; self protecting + (setq file (concat (file-name-sans-extension file) ".el")) + (string= (file-truename file) elisp-el-file)))) + (active-sub-url (when (web-autoload-acvtive) + (file-name-sans-extension web-autoload-active-file-sub-url))) + whole-result + batch-error + result) + (with-current-buffer out-buf + (let ((here (point)) + (inhibit-read-only t)) + (save-restriction + (widen) + (goto-char (point-max)) + (delete-region web-vcs-eval-output-start (point))) + (goto-char here))) + ;; Fix-me: do not use temp buffer so we can check errors + (with-temp-buffer + (let ((old-loadpath (getenv "EMACSLOADPATH")) + ;;(new-loadpath (mapconcat 'identity load-path ";")) + (new-loadpath (mapconcat 'identity load-path path-separator)) + ret-val) + (setenv new-loadpath) + (message "Loading file in batch Emacs...") + (setq ret-val + (call-process emacs-exe nil + (current-buffer) + t "--batch" + ;; fix-me: "-Q" - should be run in the users current environment. + ;; init-file-user nil => -Q + ;; site-run-file nil => -q + (cond + ((not init-file-user) "-Q") + ((not site-run-file) "-q") + (t "--debug-init")) ;; have to have something here... + "-l" elisp-file + elisp-file + "-eval" (format "%S" get-lhe))) + (message "Loading file in batch Emacs... done, returned %S" ret-val) + (setenv old-loadpath)) + ;; Fix-me: how do you check the exit status on different platforms? + (setq whole-result (buffer-substring-no-properties (point-min) (point-max))) + (condition-case err + (progn + (goto-char (point-min)) + (search-forward "STARTHERE") + (search-forward "(") + (backward-char) + (setq result (read (current-buffer)))) + (error (message "") + ;; Process should probably have failed if we are here, + ;; but anyway... ;-) + (setq batch-error + (concat "Sorry, batch Emacs failed. It returned this message:\n\n" + whole-result + (if is-downloading + (concat + "\n--------\n" + "The error may depend on that not all needed files are yet downloaded.\n") + "\n"))) + ))) + (with-current-buffer out-buf + (let ((here (point)) + (inhibit-read-only t)) + (save-restriction + (widen) + (goto-char (point-max)) + (if batch-error + (progn + (insert "\n\n") + (insert (propertize batch-error 'face 'web-vcs-red))) + (insert (propertize "\n\nThis file added the following to `load-history':\n\n" + 'face '(:height 1.5))) + (insert " (\"" (car result) "\"\n") + (dolist (e (cdr result)) + (insert (format " %S" e)) + (cond ((stringp e)) ;; Should not happen... + ;; Variables + ((symbolp e) + (insert " - ") + (insert (if (not (boundp e)) + (propertize "New" 'face 'web-vcs-yellow) + (let ((e-file (symbol-file e))) + (if (funcall is-same-file e-file) + (propertize "Same file now" 'face 'web-vcs-green) + (let* ((fun-web-auto (get e 'web-autoload)) + (fun-sub-url (nth 2 fun-web-auto))) + (if (and fun-sub-url + (string= fun-sub-url active-sub-url)) + (propertize "Web download, matches current download" + 'face 'web-vcs-yellow) + (propertize (format "Loaded from %S now" e-file) + 'face 'web-vcs-red)))))))) + ;; provide + ((eq (car e) 'provide) + (insert " - ") + (let* ((feat (car e)) + (feat-name (symbol-name feat))) + (insert (cond + ((not (featurep feat)) + (if (or (string= elisp-feature-name + (symbol-name (cdr e)))) + (propertize "Web download, matches file name" 'face 'web-vcs-green) + (propertize "Does not match file name" 'face 'web-vcs-red))) + (t + ;; symbol-file will be where it is loaded + ;; so check load-path instead. + (let ((file (locate-library feat-name))) + (if (funcall is-same-file file) + (propertize "Probably loaded from same file now" 'face 'web-vcs-yellow) + (propertize (format "Probably loaded from %S now" file) + 'face 'web-vcs-yellow)))))))) + ;; require + ((eq (car e) 'require) + (if (featurep (cdr e)) + (insert " - " (propertize "Loaded now" 'face 'web-vcs-green)) + (insert " - " (propertize "Not loaded now" 'face 'web-vcs-yellow)))) + ;; Functions + ((memq (car e) '( defun macro)) + (insert " - ") + (let ((fun (cdr e))) + (insert (if (functionp fun) + (let ((e-file (symbol-file e))) + (if (funcall is-same-file e-file) + (propertize "Same file now" 'face 'web-vcs-green) + (let* ((fun-web-auto (get fun 'web-autoload)) + (fun-sub-url (nth 2 fun-web-auto))) + ;; Fix-me: check for temp download file. + (if (string= fun-sub-url active-sub-url) + (propertize "Web download, matches current download" + 'face 'web-vcs-yellow) + (propertize (format "Loaded from %S now" e-file) + 'face 'web-vcs-yellow))))) + ;; Note that web autoloaded functions are already defined. + (propertize "New" 'face 'web-vcs-yellow)))))) + (insert "\n")) + (insert " )\n") + (goto-char here)))) + (set-buffer-modified-p nil)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Specific for nXhtml + +(defvar nxhtml-web-vcs-base-url "http://bazaar.launchpad.net/%7Enxhtml/nxhtml/main/") + +;; Fix-me: make gen for 'lp etc +(defun nxhtml-download-root-url (revision) + (let* ((base-url nxhtml-web-vcs-base-url) + (files-url (concat base-url "files/")) + (rev-part (if revision (number-to-string revision) "head%3A/"))) + (concat files-url rev-part))) + +(defun web-vcs-nxhtml () + "Install nXhtml. +Download and install nXhtml." + (interactive) + (catch 'command-level + (setq debug-on-error t) + (let* ((this-dir (file-name-directory web-vcs-el-this)) + (root-url (nxhtml-download-root-url nil)) + ;;(files '("nxhtml-web-vcs.el" "nxhtml-base.el")) + (files '("nxhtml-web-vcs.el")) + (files2 (mapcar (lambda (file) + (cons file (expand-file-name file this-dir))) + files)) + need-dl) + (dolist (file files2) + (unless (file-exists-p (cdr file)) + (setq need-dl t))) + (when need-dl + (let ((prompt + (concat "Welcome to install nXhtml." + "\nFirst the nXhtml specific web install file must be downloaded." + "\nYou will get a chance to review it before it is used." + "\n\nDo you want to continue? "))) + (unless (y-or-n-p prompt) + (message "Aborted") + (throw 'command-level nil)))) + (message nil) + (unless (get-buffer-window "*Messages*") + (web-vcs-display-messages t) + (delete-other-windows)) + (dolist (file files2) + (unless (file-exists-p (cdr file)) + (web-vcs-get-missing-matching-files 'lp root-url this-dir (car file)))) + (load (cdr (car files2)))) + (call-interactively 'nxhtml-setup-install))) + + +(provide 'web-vcs) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; web-vcs.el ends here diff --git a/emacs/paredit.el b/emacs/paredit.el new file mode 100644 index 0000000..d0d4eb1 --- /dev/null +++ b/emacs/paredit.el @@ -0,0 +1,2149 @@ +;;; -*- Mode: Emacs-Lisp; outline-regexp: "\n;;;;+" -*- + +;;;;;; Paredit: Parenthesis-Editing Minor Mode +;;;;;; Version 21 + +;;; Copyright (c) 2008, Taylor R. Campbell +;;; +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: +;;; +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. +;;; +;;; * Redistributions in binary form must reproduce the above copyright +;;; notice, this list of conditions and the following disclaimer in +;;; the documentation and/or other materials provided with the +;;; distribution. +;;; +;;; * Neither the names of the authors nor the names of contributors +;;; may be used to endorse or promote products derived from this +;;; software without specific prior written permission. +;;; +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;; This file is permanently stored at +;;; <http://mumble.net/~campbell/emacs/paredit-21.el>. +;;; +;;; The currently released version of paredit is available at +;;; <http://mumble.net/~campbell/emacs/paredit.el>. +;;; +;;; The latest beta version of paredit is available at +;;; <http://mumble.net/~campbell/emacs/paredit-beta.el>. +;;; +;;; Release notes are available at +;;; <http://mumble.net/~campbell/emacs/paredit.release>. + +;;; Install paredit by placing `paredit.el' in `/path/to/elisp', a +;;; directory of your choice, and adding to your .emacs file: +;;; +;;; (add-to-list 'load-path "/path/to/elisp") +;;; (autoload 'paredit-mode "paredit" +;;; "Minor mode for pseudo-structurally editing Lisp code." +;;; t) +;;; +;;; Toggle Paredit Mode with `M-x paredit-mode RET', or enable it +;;; always in a major mode `M' (e.g., `lisp' or `scheme') with: +;;; +;;; (add-hook M-mode-hook (lambda () (paredit-mode +1))) +;;; +;;; Customize paredit using `eval-after-load': +;;; +;;; (eval-after-load 'paredit +;;; '(progn ...redefine keys, &c....)) +;;; +;;; Paredit should run in GNU Emacs 21 or later and XEmacs 21.5 or +;;; later. Paredit is highly unlikely to work in earlier versions of +;;; GNU Emacs, and it may have obscure problems in earlier versions of +;;; XEmacs due to the way its syntax parser reports conditions, as a +;;; result of which the code that uses the syntax parser must mask all +;;; error conditions, not just those generated by the syntax parser. +;;; +;;; Questions, bug reports, comments, feature suggestions, &c., may be +;;; addressed via email to the author's surname at mumble.net or via +;;; IRC to the user named Riastradh on irc.freenode.net in the #paredit +;;; channel. +;;; +;;; Please contact the author rather than forking your own versions, to +;;; prevent the dissemination of random variants floating about the +;;; internet unbeknownst to the author. Laziness is not an excuse: +;;; your laziness costs me confusion and time trying to support +;;; paredit, so if you fork paredit, you make the world a worse place. +;;; +;;; *** WARNING *** IMPORTANT *** DO NOT SUBMIT BUGS BEFORE READING *** +;;; +;;; If you plan to submit a bug report, where some sequence of keys in +;;; Paredit Mode, or some sequence of paredit commands, doesn't do what +;;; you wanted, then it is helpful to isolate an example in a very +;;; small buffer, and it is **ABSOLUTELY**ESSENTIAL** that you supply, +;;; along with the sequence of keys or commands, +;;; +;;; (1) the version of Emacs, +;;; (2) the version of paredit.el[*], and +;;; (3) the **COMPLETE** state of the buffer used to reproduce the +;;; problem, including major mode, minor modes, local key +;;; bindings, entire contents of the buffer, leading line breaks +;;; or spaces, &c. +;;; +;;; It is often extremely difficult to reproduce problems, especially +;;; with commands like `paredit-kill'. If you do not supply **ALL** of +;;; this information, then it is highly probable that I cannot +;;; reproduce your problem no matter how hard I try, and the effect of +;;; submitting a bug without this information is only to waste your +;;; time and mine. So, please, include all of the above information. +;;; +;;; [*] If you are using a beta version of paredit, be sure that you +;;; are using the *latest* edition of the beta version, available +;;; at <http://mumble.net/~campbell/emacs/paredit-beta.el>. If you +;;; are not using a beta version, then upgrade either to that or to +;;; the latest release version; I cannot support older versions, +;;; and I can't fathom any reason why you might be using them. So +;;; the answer to item (2) should be either `release' or `beta'. + +;;; The paredit minor mode, Paredit Mode, binds a number of simple +;;; keys, notably `(', `)', `"', and `\', to commands that more +;;; carefully insert S-expression structures in the buffer. The +;;; parenthesis delimiter keys (round or square) are defined to insert +;;; parenthesis pairs and move past the closing delimiter, +;;; respectively; the double-quote key is multiplexed to do both, and +;;; also to insert an escape if within a string; and backslashes prompt +;;; the user for the next character to input, because a lone backslash +;;; can break structure inadvertently. These all have their ordinary +;;; behaviour when inside comments, and, outside comments, if truly +;;; necessary, you can insert them literally with `C-q'. +;;; +;;; The key bindings are designed so that when typing new code in +;;; Paredit Mode, you can generally use exactly the same keystrokes as +;;; you would have used without Paredit Mode. Earlier versions of +;;; paredit.el did not conform to this, because Paredit Mode bound `)' +;;; to a command that would insert a newline. Now `)' is bound to a +;;; command that does not insert a newline, and `M-)' is bound to the +;;; command that inserts a newline. To revert to the former behaviour, +;;; add the following forms to an `eval-after-load' form for paredit.el +;;; in your .emacs file: +;;; +;;; (define-key paredit-mode-map (kbd ")") +;;; 'paredit-close-round-and-newline) +;;; (define-key paredit-mode-map (kbd "M-)") +;;; 'paredit-close-round) +;;; +;;; Paredit Mode also binds the usual keys for deleting and killing, so +;;; that they will not destroy any S-expression structure by killing or +;;; deleting only one side of a parenthesis or quote pair. If the +;;; point is on a closing delimiter, `DEL' will move left over it; if +;;; it is on an opening delimiter, `C-d' will move right over it. Only +;;; if the point is between a pair of delimiters will `C-d' or `DEL' +;;; delete them, and in that case it will delete both simultaneously. +;;; `M-d' and `M-DEL' kill words, but skip over any S-expression +;;; structure. `C-k' kills from the start of the line, either to the +;;; line's end, if it contains only balanced expressions; to the first +;;; closing delimiter, if the point is within a form that ends on the +;;; line; or up to the end of the last expression that starts on the +;;; line after the point. +;;; +;;; The behaviour of the commands for deleting and killing can be +;;; overridden by passing a `C-u' prefix argument: `C-u DEL' will +;;; delete a character backward, `C-u C-d' will delete a character +;;; forward, and `C-u C-k' will kill text from the point to the end of +;;; the line, irrespective of the S-expression structure in the buffer. +;;; This can be used to fix mistakes in a buffer, but should generally +;;; be avoided. +;;; +;;; Paredit performs automatic reindentation as locally as possible, to +;;; avoid interfering with custom indentation used elsewhere in some +;;; S-expression. Only the advanced S-expression manipulation commands +;;; automatically reindent, and only the forms that were immediately +;;; operated upon (and their subforms). +;;; +;;; This code is written for clarity, not efficiency. It frequently +;;; walks over S-expressions redundantly. If you have problems with +;;; the time it takes to execute some of the commands, let me know, but +;;; first be sure that what you're doing is reasonable: it is +;;; preferable to avoid immense S-expressions in code anyway. + +;;; This assumes Unix-style LF line endings. + +(defconst paredit-version 21) +(defconst paredit-beta-p nil) + +(eval-and-compile + + (defun paredit-xemacs-p () + ;; No idea where I got this definition from. Edward O'Connor + ;; (hober in #emacs) suggested the current definition. + ;; (and (boundp 'running-xemacs) + ;; running-xemacs) + (featurep 'xemacs)) + + (defun paredit-gnu-emacs-p () + ;++ This could probably be improved. + (not (paredit-xemacs-p))) + + (defmacro xcond (&rest clauses) + "Exhaustive COND. +Signal an error if no clause matches." + `(cond ,@clauses + (t (error "XCOND lost.")))) + + (defalias 'paredit-warn (if (fboundp 'warn) 'warn 'message)) + + (defvar paredit-sexp-error-type + (with-temp-buffer + (insert "(") + (condition-case condition + (backward-sexp) + (error (if (eq (car condition) 'error) + (paredit-warn "%s%s%s%s%s" + "Paredit is unable to discriminate" + " S-expression parse errors from" + " other errors. " + " This may cause obscure problems. " + " Please upgrade Emacs.")) + (car condition))))) + + (defmacro paredit-handle-sexp-errors (body &rest handler) + `(condition-case () + ,body + (,paredit-sexp-error-type ,@handler))) + + (put 'paredit-handle-sexp-errors 'lisp-indent-function 1) + + (defmacro paredit-ignore-sexp-errors (&rest body) + `(paredit-handle-sexp-errors (progn ,@body) + nil)) + + (put 'paredit-ignore-sexp-errors 'lisp-indent-function 0) + + nil) + +;;;; Minor Mode Definition + +(defvar paredit-mode-map (make-sparse-keymap) + "Keymap for the paredit minor mode.") + +(define-minor-mode paredit-mode + "Minor mode for pseudo-structurally editing Lisp code. +\\<paredit-mode-map>" + :lighter " Paredit" + ;; If we're enabling paredit-mode, the prefix to this code that + ;; DEFINE-MINOR-MODE inserts will have already set PAREDIT-MODE to + ;; true. If this is the case, then first check the parentheses, and + ;; if there are any imbalanced ones we must inhibit the activation of + ;; paredit mode. We skip the check, though, if the user supplied a + ;; prefix argument interactively. + (if (and paredit-mode + (not current-prefix-arg)) + (if (not (fboundp 'check-parens)) + (paredit-warn "`check-parens' is not defined; %s" + "be careful of malformed S-expressions.") + (condition-case condition + (check-parens) + (error (setq paredit-mode nil) + (signal (car condition) (cdr condition))))))) + +;;; Old functions from when there was a different mode for emacs -nw. + +(defun enable-paredit-mode () + "Turn on pseudo-structural editing of Lisp code. + +Deprecated: use `paredit-mode' instead." + (interactive) + (paredit-mode +1)) + +(defun disable-paredit-mode () + "Turn off pseudo-structural editing of Lisp code. + +Deprecated: use `paredit-mode' instead." + (interactive) + (paredit-mode -1)) + +(defvar paredit-backward-delete-key + (xcond ((paredit-xemacs-p) "BS") + ((paredit-gnu-emacs-p) "DEL"))) + +(defvar paredit-forward-delete-keys + (xcond ((paredit-xemacs-p) '("DEL")) + ((paredit-gnu-emacs-p) '("<delete>" "<deletechar>")))) + +;;;; Paredit Keys + +;;; Separating the definition and initialization of this variable +;;; simplifies the development of paredit, since re-evaluating DEFVAR +;;; forms doesn't actually do anything. + +(defvar paredit-commands nil + "List of paredit commands with their keys and examples.") + +;;; Each specifier is of the form: +;;; (key[s] function (example-input example-output) ...) +;;; where key[s] is either a single string suitable for passing to KBD +;;; or a list of such strings. Entries in this list may also just be +;;; strings, in which case they are headings for the next entries. + +(progn (setq paredit-commands + `( + "Basic Insertion Commands" + ("(" paredit-open-round + ("(a b |c d)" + "(a b (|) c d)") + ("(foo \"bar |baz\" quux)" + "(foo \"bar (|baz\" quux)")) + (")" paredit-close-round + ("(a b |c )" "(a b c)|") + ("; Hello,| world!" + "; Hello,)| world!")) + ("M-)" paredit-close-round-and-newline + ("(defun f (x| ))" + "(defun f (x)\n |)") + ("; (Foo.|" + "; (Foo.)|")) + ("[" paredit-open-square + ("(a b |c d)" + "(a b [|] c d)") + ("(foo \"bar |baz\" quux)" + "(foo \"bar [baz\" quux)")) + ("]" paredit-close-square + ("(define-key keymap [frob| ] 'frobnicate)" + "(define-key keymap [frob]| 'frobnicate)") + ("; [Bar.|" + "; [Bar.]|")) + ("\"" paredit-doublequote + ("(frob grovel |full lexical)" + "(frob grovel \"|\" full lexical)") + ("(foo \"bar |baz\" quux)" + "(foo \"bar \\\"|baz\" quux)")) + ("M-\"" paredit-meta-doublequote + ("(foo \"bar |baz\" quux)" + "(foo \"bar baz\"\n |quux)") + ("(foo |(bar #\\x \"baz \\\\ quux\") zot)" + ,(concat "(foo \"|(bar #\\\\x \\\"baz \\\\" + "\\\\ quux\\\")\" zot)"))) + ("\\" paredit-backslash + ("(string #|)\n ; Escaping character... (x)" + "(string #\\x|)") + ("\"foo|bar\"\n ; Escaping character... (\")" + "\"foo\\\"|bar\"")) + ("M-;" paredit-comment-dwim + ("(foo |bar) ; baz" + "(foo bar) ; |baz") + ("(frob grovel)|" + "(frob grovel) ;|") + (" (foo bar)\n|\n (baz quux)" + " (foo bar)\n ;; |\n (baz quux)") + (" (foo bar) |(baz quux)" + " (foo bar)\n ;; |\n (baz quux)") + ("|(defun hello-world ...)" + ";;; |\n(defun hello-world ...)")) + + ("C-j" paredit-newline + ("(let ((n (frobbotz))) |(display (+ n 1)\nport))" + ,(concat "(let ((n (frobbotz)))" + "\n |(display (+ n 1)" + "\n port))"))) + + "Deleting & Killing" + (("C-d" ,@paredit-forward-delete-keys) + paredit-forward-delete + ("(quu|x \"zot\")" "(quu| \"zot\")") + ("(quux |\"zot\")" + "(quux \"|zot\")" + "(quux \"|ot\")") + ("(foo (|) bar)" "(foo | bar)") + ("|(foo bar)" "(|foo bar)")) + (,paredit-backward-delete-key + paredit-backward-delete + ("(\"zot\" q|uux)" "(\"zot\" |uux)") + ("(\"zot\"| quux)" + "(\"zot|\" quux)" + "(\"zo|\" quux)") + ("(foo (|) bar)" "(foo | bar)") + ("(foo bar)|" "(foo bar|)")) + ("C-k" paredit-kill + ("(foo bar)| ; Useless comment!" + "(foo bar)|") + ("(|foo bar) ; Useful comment!" + "(|) ; Useful comment!") + ("|(foo bar) ; Useless line!" + "|") + ("(foo \"|bar baz\"\n quux)" + "(foo \"|\"\n quux)")) + ("M-d" paredit-forward-kill-word + ("|(foo bar) ; baz" + "(| bar) ; baz" + "(|) ; baz" + "() ;|") + (";;;| Frobnicate\n(defun frobnicate ...)" + ";;;|\n(defun frobnicate ...)" + ";;;\n(| frobnicate ...)")) + (,(concat "M-" paredit-backward-delete-key) + paredit-backward-kill-word + ("(foo bar) ; baz\n(quux)|" + "(foo bar) ; baz\n(|)" + "(foo bar) ; |\n()" + "(foo |) ; \n()" + "(|) ; \n()")) + + "Movement & Navigation" + ("C-M-f" paredit-forward + ("(foo |(bar baz) quux)" + "(foo (bar baz)| quux)") + ("(foo (bar)|)" + "(foo (bar))|")) + ("C-M-b" paredit-backward + ("(foo (bar baz)| quux)" + "(foo |(bar baz) quux)") + ("(|(foo) bar)" + "|((foo) bar)")) +;;;("C-M-u" backward-up-list) ; These two are built-in. +;;;("C-M-d" down-list) + ("C-M-p" backward-down-list) ; Built-in, these are FORWARD- + ("C-M-n" up-list) ; & BACKWARD-LIST, which have + ; no need given C-M-f & C-M-b. + + "Depth-Changing Commands" + ("M-(" paredit-wrap-round + ("(foo |bar baz)" + "(foo (|bar) baz)")) + ("M-s" paredit-splice-sexp + ("(foo (bar| baz) quux)" + "(foo bar| baz quux)")) + (("M-<up>" "ESC <up>") + paredit-splice-sexp-killing-backward + ("(foo (let ((x 5)) |(sqrt n)) bar)" + "(foo (sqrt n) bar)")) + (("M-<down>" "ESC <down>") + paredit-splice-sexp-killing-forward + ("(a (b c| d e) f)" + "(a b c f)")) + ("M-r" paredit-raise-sexp + ("(dynamic-wind in (lambda () |body) out)" + "(dynamic-wind in |body out)" + "|body")) + + "Barfage & Slurpage" + (("C-)" "C-<right>") + paredit-forward-slurp-sexp + ("(foo (bar |baz) quux zot)" + "(foo (bar |baz quux) zot)") + ("(a b ((c| d)) e f)" + "(a b ((c| d) e) f)")) + (("C-}" "C-<left>") + paredit-forward-barf-sexp + ("(foo (bar |baz quux) zot)" + "(foo (bar |baz) quux zot)")) + (("C-(" "C-M-<left>" "ESC C-<left>") + paredit-backward-slurp-sexp + ("(foo bar (baz| quux) zot)" + "(foo (bar baz| quux) zot)") + ("(a b ((c| d)) e f)" + "(a (b (c| d)) e f)")) + (("C-{" "C-M-<right>" "ESC C-<right>") + paredit-backward-barf-sexp + ("(foo (bar baz |quux) zot)" + "(foo bar (baz |quux) zot)")) + + "Miscellaneous Commands" + ("M-S" paredit-split-sexp + ("(hello| world)" + "(hello)| (world)") + ("\"Hello, |world!\"" + "\"Hello, \"| \"world!\"")) + ("M-J" paredit-join-sexps + ("(hello)| (world)" + "(hello| world)") + ("\"Hello, \"| \"world!\"" + "\"Hello, |world!\"") + ("hello-\n| world" + "hello-|world")) + ("C-c C-M-l" paredit-recentre-on-sexp) + ("M-q" paredit-reindent-defun) + )) + nil) ; end of PROGN + +;;;;; Command Examples + +(eval-and-compile + (defmacro paredit-do-commands (vars string-case &rest body) + (let ((spec (nth 0 vars)) + (keys (nth 1 vars)) + (fn (nth 2 vars)) + (examples (nth 3 vars))) + `(dolist (,spec paredit-commands) + (if (stringp ,spec) + ,string-case + (let ((,keys (let ((k (car ,spec))) + (cond ((stringp k) (list k)) + ((listp k) k) + (t (error "Invalid paredit command %s." + ,spec))))) + (,fn (cadr ,spec)) + (,examples (cddr ,spec))) + ,@body))))) + + (put 'paredit-do-commands 'lisp-indent-function 2)) + +(defun paredit-define-keys () + (paredit-do-commands (spec keys fn examples) + nil ; string case + (dolist (key keys) + (define-key paredit-mode-map (read-kbd-macro key) fn)))) + +(defun paredit-function-documentation (fn) + (let ((original-doc (get fn 'paredit-original-documentation)) + (doc (documentation fn 'function-documentation))) + (or original-doc + (progn (put fn 'paredit-original-documentation doc) + doc)))) + +(defun paredit-annotate-mode-with-examples () + (let ((contents + (list (paredit-function-documentation 'paredit-mode)))) + (paredit-do-commands (spec keys fn examples) + (push (concat "\n\n" spec "\n") + contents) + (let ((name (symbol-name fn))) + (if (string-match (symbol-name 'paredit-) name) + (push (concat "\n\n\\[" name "]\t" name + (if examples + (mapconcat (lambda (example) + (concat + "\n" + (mapconcat 'identity + example + "\n --->\n") + "\n")) + examples + "") + "\n (no examples)\n")) + contents)))) + (put 'paredit-mode 'function-documentation + (apply 'concat (reverse contents)))) + ;; PUT returns the huge string we just constructed, which we don't + ;; want it to return. + nil) + +(defun paredit-annotate-functions-with-examples () + (paredit-do-commands (spec keys fn examples) + nil ; string case + (put fn 'function-documentation + (concat (paredit-function-documentation fn) + "\n\n\\<paredit-mode-map>\\[" (symbol-name fn) "]\n" + (mapconcat (lambda (example) + (concat "\n" + (mapconcat 'identity + example + "\n ->\n") + "\n")) + examples + ""))))) + +;;;;; HTML Examples + +(defun paredit-insert-html-examples () + "Insert HTML for a paredit quick reference table." + (interactive) + (let ((insert-lines + (lambda (&rest lines) + (mapc (lambda (line) (insert line) (newline)) + lines))) + (html-keys + (lambda (keys) + (mapconcat 'paredit-html-quote keys ", "))) + (html-example + (lambda (example) + (concat "<table><tr><td><pre>" + (mapconcat 'paredit-html-quote + example + (concat "</pre></td></tr><tr><td>" + " --->" + "</td></tr><tr><td><pre>")) + "</pre></td></tr></table>"))) + (firstp t)) + (paredit-do-commands (spec keys fn examples) + (progn (if (not firstp) + (insert "</table>\n") + (setq firstp nil)) + (funcall insert-lines + (concat "<h3>" spec "</h3>") + "<table border=\"1\" cellpadding=\"1\">" + " <tr>" + " <th>Command</th>" + " <th>Keys</th>" + " <th>Examples</th>" + " </tr>")) + (let ((name (symbol-name fn))) + (if (string-match (symbol-name 'paredit-) name) + (funcall insert-lines + " <tr>" + (concat " <td><tt>" name "</tt></td>") + (concat " <td align=\"center\">" + (funcall html-keys keys) + "</td>") + (concat " <td>" + (if examples + (mapconcat html-example examples + "<hr>") + "(no examples)") + "</td>") + " </tr>"))))) + (insert "</table>\n")) + +(defun paredit-html-quote (string) + (with-temp-buffer + (dotimes (i (length string)) + (insert (let ((c (elt string i))) + (cond ((eq c ?\<) "<") + ((eq c ?\>) ">") + ((eq c ?\&) "&") + ((eq c ?\') "'") + ((eq c ?\") """) + (t c))))) + (buffer-string))) + +;;;; Delimiter Insertion + +(eval-and-compile + (defun paredit-conc-name (&rest strings) + (intern (apply 'concat strings))) + + (defmacro define-paredit-pair (open close name) + `(progn + (defun ,(paredit-conc-name "paredit-open-" name) (&optional n) + ,(concat "Insert a balanced " name " pair. +With a prefix argument N, put the closing " name " after N + S-expressions forward. +If the region is active, `transient-mark-mode' is enabled, and the + region's start and end fall in the same parenthesis depth, insert a + " name " pair around the region. +If in a string or a comment, insert a single " name ". +If in a character literal, do nothing. This prevents changing what was + in the character literal to a meaningful delimiter unintentionally.") + (interactive "P") + (cond ((or (paredit-in-string-p) + (paredit-in-comment-p)) + (insert ,open)) + ((not (paredit-in-char-p)) + (paredit-insert-pair n ,open ,close 'goto-char)))) + (defun ,(paredit-conc-name "paredit-close-" name) () + ,(concat "Move past one closing delimiter and reindent. +\(Agnostic to the specific closing delimiter.) +If in a string or comment, insert a single closing " name ". +If in a character literal, do nothing. This prevents changing what was + in the character literal to a meaningful delimiter unintentionally.") + (interactive) + (paredit-move-past-close ,close)) + (defun ,(paredit-conc-name "paredit-close-" name "-and-newline") () + ,(concat "Move past one closing delimiter, add a newline," + " and reindent. +If there was a margin comment after the closing delimiter, preserve it + on the same line.") + (interactive) + (paredit-move-past-close-and-newline ,close)) + (defun ,(paredit-conc-name "paredit-wrap-" name) + (&optional argument) + ,(concat "Wrap the following S-expression. +See `paredit-wrap-sexp' for more details.") + (interactive "P") + (paredit-wrap-sexp argument ,open ,close)) + (add-to-list 'paredit-wrap-commands + ',(paredit-conc-name "paredit-wrap-" name))))) + +(defvar paredit-wrap-commands '(paredit-wrap-sexp) + "List of paredit commands that wrap S-expressions. +Used by `paredit-yank-pop'; for internal paredit use only.") + +(define-paredit-pair ?\( ?\) "round") +(define-paredit-pair ?\[ ?\] "square") +(define-paredit-pair ?\{ ?\} "curly") +(define-paredit-pair ?\< ?\> "angled") + +;;; Aliases for the old names. + +(defalias 'paredit-open-parenthesis 'paredit-open-round) +(defalias 'paredit-close-parenthesis 'paredit-close-round) +(defalias 'paredit-close-parenthesis-and-newline + 'paredit-close-round-and-newline) + +(defalias 'paredit-open-bracket 'paredit-open-square) +(defalias 'paredit-close-bracket 'paredit-close-square) +(defalias 'paredit-close-bracket-and-newline + 'paredit-close-square-and-newline) + +(defun paredit-move-past-close (close) + (cond ((or (paredit-in-string-p) + (paredit-in-comment-p)) + (insert close)) + ((not (paredit-in-char-p)) + (paredit-move-past-close-and-reindent close) + (paredit-blink-paren-match nil)))) + +(defun paredit-move-past-close-and-newline (close) + (if (or (paredit-in-string-p) + (paredit-in-comment-p)) + (insert close) + (if (paredit-in-char-p) (forward-char)) + (paredit-move-past-close-and-reindent close) + (let ((comment.point (paredit-find-comment-on-line))) + (newline) + (if comment.point + (save-excursion + (forward-line -1) + (end-of-line) + (indent-to (cdr comment.point)) + (insert (car comment.point))))) + (lisp-indent-line) + (paredit-ignore-sexp-errors (indent-sexp)) + (paredit-blink-paren-match t))) + +(defun paredit-find-comment-on-line () + "Find a margin comment on the current line. +Return nil if there is no such comment or if there is anything but + whitespace until such a comment. +If such a comment exists, delete the comment (including all leading + whitespace) and return a cons whose car is the comment as a string + and whose cdr is the point of the comment's initial semicolon, + relative to the start of the line." + (save-excursion + (paredit-skip-whitespace t (point-at-eol)) + (and (eq ?\; (char-after)) + (not (eq ?\; (char-after (1+ (point))))) + (not (or (paredit-in-string-p) + (paredit-in-char-p))) + (let* ((start ;Move to before the semicolon. + (progn (backward-char) (point))) + (comment + (buffer-substring start (point-at-eol)))) + (paredit-skip-whitespace nil (point-at-bol)) + (delete-region (point) (point-at-eol)) + (cons comment (- start (point-at-bol))))))) + +(defun paredit-insert-pair (n open close forward) + (let* ((regionp + (and (paredit-region-active-p) + (paredit-region-safe-for-insert-p))) + (end + (and regionp + (not n) + (prog1 (region-end) (goto-char (region-beginning)))))) + (let ((spacep (paredit-space-for-delimiter-p nil open))) + (if spacep (insert " ")) + (insert open) + (save-excursion + ;; Move past the desired region. + (cond (n (funcall forward + (save-excursion + (forward-sexp (prefix-numeric-value n)) + (point)))) + (regionp (funcall forward (+ end (if spacep 2 1))))) + (insert close) + (if (paredit-space-for-delimiter-p t close) + (insert " ")))))) + +(defun paredit-region-safe-for-insert-p () + (save-excursion + (let ((beginning (region-beginning)) + (end (region-end))) + (goto-char beginning) + (let* ((beginning-state (paredit-current-parse-state)) + (end-state + (parse-partial-sexp beginning end nil nil beginning-state))) + (and (= (nth 0 beginning-state) ; 0. depth in parens + (nth 0 end-state)) + (eq (nth 3 beginning-state) ; 3. non-nil if inside a + (nth 3 end-state)) ; string + (eq (nth 4 beginning-state) ; 4. comment status, yada + (nth 4 end-state)) + (eq (nth 5 beginning-state) ; 5. t if following char + (nth 5 end-state))))))) ; quote + +(defun paredit-space-for-delimiter-p (endp delimiter) + ;; If at the buffer limit, don't insert a space. If there is a word, + ;; symbol, other quote, or non-matching parenthesis delimiter (i.e. a + ;; close when want an open the string or an open when we want to + ;; close the string), do insert a space. + (and (not (if endp (eobp) (bobp))) + (memq (char-syntax (if endp (char-after) (char-before))) + (list ?w ?_ ?\" + (let ((matching (matching-paren delimiter))) + (and matching (char-syntax matching))))))) + +(defun paredit-move-past-close-and-reindent (close) + (let ((open (paredit-missing-close))) + (if open + (if (eq close (matching-paren open)) + (save-excursion + (message "Missing closing delimiter: %c" close) + (insert close)) + (error "Mismatched missing closing delimiter: %c ... %c" + open close)))) + (let ((orig (point))) + (up-list) + (if (catch 'return ; This CATCH returns T if it + (while t ; should delete leading spaces + (save-excursion ; and NIL if not. + (let ((before-paren (1- (point)))) + (back-to-indentation) + (cond ((not (eq (point) before-paren)) + ;; Can't call PAREDIT-DELETE-LEADING-WHITESPACE + ;; here -- we must return from SAVE-EXCURSION + ;; first. + (throw 'return t)) + ((save-excursion (forward-line -1) + (end-of-line) + (paredit-in-comment-p)) + ;; Moving the closing delimiter any further + ;; would put it into a comment, so we just + ;; indent the closing delimiter where it is and + ;; abort the loop, telling its continuation that + ;; no leading whitespace should be deleted. + (lisp-indent-line) + (throw 'return nil)) + (t (delete-indentation))))))) + (paredit-delete-leading-whitespace)))) + +(defun paredit-missing-close () + (save-excursion + (paredit-handle-sexp-errors (backward-up-list) + (error "Not inside a list.")) + (let ((open (char-after))) + (paredit-handle-sexp-errors (progn (forward-sexp) nil) + open)))) + +(defun paredit-delete-leading-whitespace () + ;; This assumes that we're on the closing delimiter already. + (save-excursion + (backward-char) + (while (let ((syn (char-syntax (char-before)))) + (and (or (eq syn ?\ ) (eq syn ?-)) ; whitespace syntax + ;; The above line is a perfect example of why the + ;; following test is necessary. + (not (paredit-in-char-p (1- (point)))))) + (backward-delete-char 1)))) + +(defun paredit-blink-paren-match (another-line-p) + (if (and blink-matching-paren + (or (not show-paren-mode) another-line-p)) + (paredit-ignore-sexp-errors + (save-excursion + (backward-sexp) + (forward-sexp) + ;; SHOW-PAREN-MODE inhibits any blinking, so we disable it + ;; locally here. + (let ((show-paren-mode nil)) + (blink-matching-open)))))) + +(defun paredit-doublequote (&optional n) + "Insert a pair of double-quotes. +With a prefix argument N, wrap the following N S-expressions in + double-quotes, escaping intermediate characters if necessary. +If the region is active, `transient-mark-mode' is enabled, and the + region's start and end fall in the same parenthesis depth, insert a + pair of double-quotes around the region, again escaping intermediate + characters if necessary. +Inside a comment, insert a literal double-quote. +At the end of a string, move past the closing double-quote. +In the middle of a string, insert a backslash-escaped double-quote. +If in a character literal, do nothing. This prevents accidentally + changing a what was in the character literal to become a meaningful + delimiter unintentionally." + (interactive "P") + (cond ((paredit-in-string-p) + (if (eq (cdr (paredit-string-start+end-points)) + (point)) + (forward-char) ; We're on the closing quote. + (insert ?\\ ?\" ))) + ((paredit-in-comment-p) + (insert ?\" )) + ((not (paredit-in-char-p)) + (paredit-insert-pair n ?\" ?\" 'paredit-forward-for-quote)))) + +(defun paredit-meta-doublequote (&optional n) + "Move to the end of the string, insert a newline, and indent. +If not in a string, act as `paredit-doublequote'; if no prefix argument + is specified and the region is not active or `transient-mark-mode' is + disabled, the default is to wrap one S-expression, however, not + zero." + (interactive "P") + (if (not (paredit-in-string-p)) + (paredit-doublequote (or n + (and (not (paredit-region-active-p)) + 1))) + (let ((start+end (paredit-string-start+end-points))) + (goto-char (1+ (cdr start+end))) + (newline) + (lisp-indent-line) + (paredit-ignore-sexp-errors (indent-sexp))))) + +(defun paredit-forward-for-quote (end) + (let ((state (paredit-current-parse-state))) + (while (< (point) end) + (let ((new-state (parse-partial-sexp (point) (1+ (point)) + nil nil state))) + (if (paredit-in-string-p new-state) + (if (not (paredit-in-string-escape-p)) + (setq state new-state) + ;; Escape character: turn it into an escaped escape + ;; character by appending another backslash. + (insert ?\\ ) + ;; Now the point is after both escapes, and we want to + ;; rescan from before the first one to after the second + ;; one. + (setq state + (parse-partial-sexp (- (point) 2) (point) + nil nil state)) + ;; Advance the end point, since we just inserted a new + ;; character. + (setq end (1+ end))) + ;; String: escape by inserting a backslash before the quote. + (backward-char) + (insert ?\\ ) + ;; The point is now between the escape and the quote, and we + ;; want to rescan from before the escape to after the quote. + (setq state + (parse-partial-sexp (1- (point)) (1+ (point)) + nil nil state)) + ;; Advance the end point for the same reason as above. + (setq end (1+ end))))))) + +;;;; Escape Insertion + +(defun paredit-backslash () + "Insert a backslash followed by a character to escape." + (interactive) + (insert ?\\ ) + ;; This funny conditional is necessary because PAREDIT-IN-COMMENT-P + ;; assumes that PAREDIT-IN-STRING-P already returned false; otherwise + ;; it may give erroneous answers. + (if (or (paredit-in-string-p) + (not (paredit-in-comment-p))) + (let ((delp t)) + (unwind-protect (setq delp + (call-interactively 'paredit-escape)) + ;; We need this in an UNWIND-PROTECT so that the backlash is + ;; left in there *only* if PAREDIT-ESCAPE return NIL normally + ;; -- in any other case, such as the user hitting C-g or an + ;; error occurring, we must delete the backslash to avoid + ;; leaving a dangling escape. (This control structure is a + ;; crock.) + (if delp (backward-delete-char 1)))))) + +;;; This auxiliary interactive function returns true if the backslash +;;; should be deleted and false if not. + +(defun paredit-escape (char) + ;; I'm too lazy to figure out how to do this without a separate + ;; interactive function. + (interactive "cEscaping character...") + (if (eq char 127) ; The backslash was a typo, so + t ; the luser wants to delete it. + (insert char) ; (Is there a better way to + nil)) ; express the rubout char? + ; ?\^? works, but ugh...) + +;;; The placement of these functions in this file is totally random. + +(defun paredit-newline () + "Insert a newline and indent it. +This is like `newline-and-indent', but it not only indents the line + that the point is on but also the S-expression following the point, + if there is one. +Move forward one character first if on an escaped character. +If in a string, just insert a literal newline." + (interactive) + (if (paredit-in-string-p) + (newline) + (if (and (not (paredit-in-comment-p)) (paredit-in-char-p)) + (forward-char)) + (newline-and-indent) + ;; Indent the following S-expression, but don't signal an error if + ;; there's only a closing delimiter after the point. + (paredit-ignore-sexp-errors (indent-sexp)))) + +(defun paredit-reindent-defun (&optional argument) + "Reindent the definition that the point is on. +If the point is in a string or a comment, fill the paragraph instead, + and with a prefix argument, justify as well." + (interactive "P") + (if (or (paredit-in-string-p) + (paredit-in-comment-p)) + (fill-paragraph argument) + (save-excursion + (beginning-of-defun) + (indent-sexp)))) + +;;;; Comment Insertion + +(defun paredit-comment-dwim (&optional argument) + "Call the Lisp comment command you want (Do What I Mean). +This is like `comment-dwim', but it is specialized for Lisp editing. +If transient mark mode is enabled and the mark is active, comment or + uncomment the selected region, depending on whether it was entirely + commented not not already. +If there is already a comment on the current line, with no prefix + argument, indent to that comment; with a prefix argument, kill that + comment. +Otherwise, insert a comment appropriate for the context and ensure that + any code following the comment is moved to the next line. +At the top level, where indentation is calculated to be at column 0, + insert a triple-semicolon comment; within code, where the indentation + is calculated to be non-zero, and on the line there is either no code + at all or code after the point, insert a double-semicolon comment; + and if the point is after all code on the line, insert a single- + semicolon margin comment at `comment-column'." + (interactive "*P") + (paredit-initialize-comment-dwim) + (cond ((paredit-region-active-p) + (comment-or-uncomment-region (region-beginning) + (region-end) + argument)) + ((paredit-comment-on-line-p) + (if argument + (comment-kill (if (integerp argument) argument nil)) + (comment-indent))) + (t (paredit-insert-comment)))) + +;;; This is all a horrible, horrible hack, primarily for GNU Emacs 21, +;;; in which there is no `comment-or-uncomment-region'. + +(defun paredit-initialize-comment-dwim () + (require 'newcomment) + (if (not (fboundp 'comment-or-uncomment-region)) + (defalias 'comment-or-uncomment-region + (lambda (beginning end &optional argument) + (interactive "*r\nP") + (funcall (if (save-excursion (goto-char beginning) + (comment-forward (point-max)) + (<= end (point))) + 'uncomment-region + 'comment-region) + beginning end argument)))) + (defalias 'paredit-initialize-comment-dwim 'comment-normalize-vars) + (comment-normalize-vars)) + +(defun paredit-comment-on-line-p () + (save-excursion + (beginning-of-line) + (let ((comment-p nil)) + ;; Search forward for a comment beginning. If there is one, set + ;; COMMENT-P to true; if not, it will be nil. + (while (progn (setq comment-p + (search-forward ";" (point-at-eol) + ;; t -> no error + t)) + (and comment-p + (or (paredit-in-string-p) + (paredit-in-char-p (1- (point)))))) + (forward-char)) + comment-p))) + +(defun paredit-insert-comment () + (let ((code-after-p + (save-excursion (paredit-skip-whitespace t (point-at-eol)) + (not (eolp)))) + (code-before-p + (save-excursion (paredit-skip-whitespace nil (point-at-bol)) + (not (bolp))))) + (if (and (bolp) + ;; We have to use EQ 0 here and not ZEROP because ZEROP + ;; signals an error if its argument is non-numeric, but + ;; CALCULATE-LISP-INDENT may return nil. + (eq (let ((indent (calculate-lisp-indent))) + (if (consp indent) + (car indent) + indent)) + 0)) + ;; Top-level comment + (progn (if code-after-p (save-excursion (newline))) + (insert ";;; ")) + (if code-after-p + ;; Code comment + (progn (if code-before-p + ;++ Why NEWLINE-AND-INDENT here and not just + ;++ NEWLINE, or PAREDIT-NEWLINE? + (newline-and-indent)) + (lisp-indent-line) + (insert ";; ") + ;; Move the following code. (NEWLINE-AND-INDENT will + ;; delete whitespace after the comment, though, so use + ;; NEWLINE & LISP-INDENT-LINE manually here.) + (save-excursion (newline) + (lisp-indent-line))) + ;; Margin comment + (progn (indent-to comment-column + 1) ; 1 -> force one leading space + (insert ?\; )))))) + +;;;; Character Deletion + +(defun paredit-forward-delete (&optional argument) + "Delete a character forward or move forward over a delimiter. +If on an opening S-expression delimiter, move forward into the + S-expression. +If on a closing S-expression delimiter, refuse to delete unless the + S-expression is empty, in which case delete the whole S-expression. +With a numeric prefix argument N, delete N characters forward. +With a `C-u' prefix argument, simply delete a character forward, + without regard for delimiter balancing." + (interactive "P") + (cond ((or (consp argument) (eobp)) + (delete-char 1)) + ((integerp argument) + (if (< argument 0) + (paredit-backward-delete argument) + (while (> argument 0) + (paredit-forward-delete) + (setq argument (- argument 1))))) + ((paredit-in-string-p) + (paredit-forward-delete-in-string)) + ((paredit-in-comment-p) + ;++ What to do here? This could move a partial S-expression + ;++ into a comment and thereby invalidate the file's form, + ;++ or move random text out of a comment. + (delete-char 1)) + ((paredit-in-char-p) ; Escape -- delete both chars. + (backward-delete-char 1) + (delete-char 1)) + ((eq (char-after) ?\\ ) ; ditto + (delete-char 2)) + ((let ((syn (char-syntax (char-after)))) + (or (eq syn ?\( ) + (eq syn ?\" ))) + (if (save-excursion + (paredit-handle-sexp-errors (progn (forward-sexp) t) + nil)) + (forward-char) + (message "Deleting spurious opening delimiter.") + (delete-char 1))) + ((and (not (paredit-in-char-p (1- (point)))) + (eq (char-syntax (char-after)) ?\) ) + (eq (char-before) (matching-paren (char-after)))) + (backward-delete-char 1) ; Empty list -- delete both + (delete-char 1)) ; delimiters. + ;; Just delete a single character, if it's not a closing + ;; delimiter. (The character literal case is already handled + ;; by now.) + ((not (eq (char-syntax (char-after)) ?\) )) + (delete-char 1)))) + +(defun paredit-forward-delete-in-string () + (let ((start+end (paredit-string-start+end-points))) + (cond ((not (eq (point) (cdr start+end))) + ;; If it's not the close-quote, it's safe to delete. But + ;; first handle the case that we're in a string escape. + (cond ((paredit-in-string-escape-p) + ;; We're right after the backslash, so backward + ;; delete it before deleting the escaped character. + (backward-delete-char 1)) + ((eq (char-after) ?\\ ) + ;; If we're not in a string escape, but we are on a + ;; backslash, it must start the escape for the next + ;; character, so delete the backslash before deleting + ;; the next character. + (delete-char 1))) + (delete-char 1)) + ((eq (1- (point)) (car start+end)) + ;; If it is the close-quote, delete only if we're also right + ;; past the open-quote (i.e. it's empty), and then delete + ;; both quotes. Otherwise we refuse to delete it. + (backward-delete-char 1) + (delete-char 1))))) + +(defun paredit-backward-delete (&optional argument) + "Delete a character backward or move backward over a delimiter. +If on a closing S-expression delimiter, move backward into the + S-expression. +If on an opening S-expression delimiter, refuse to delete unless the + S-expression is empty, in which case delete the whole S-expression. +With a numeric prefix argument N, delete N characters backward. +With a `C-u' prefix argument, simply delete a character backward, + without regard for delimiter balancing." + (interactive "P") + (cond ((or (consp argument) (bobp)) + ;++ Should this untabify? + (backward-delete-char 1)) + ((integerp argument) + (if (< argument 0) + (paredit-forward-delete (- 0 argument)) + (while (> argument 0) + (paredit-backward-delete) + (setq argument (- argument 1))))) + ((paredit-in-string-p) + (paredit-backward-delete-in-string)) + ((paredit-in-comment-p) + (backward-delete-char 1)) + ((paredit-in-char-p) ; Escape -- delete both chars. + (backward-delete-char 1) + (delete-char 1)) + ((paredit-in-char-p (1- (point))) + (backward-delete-char 2)) ; ditto + ((let ((syn (char-syntax (char-before)))) + (or (eq syn ?\) ) + (eq syn ?\" ))) + (if (save-excursion + (paredit-handle-sexp-errors (progn (backward-sexp) t) + nil)) + (backward-char) + (message "Deleting spurious closing delimiter.") + (backward-delete-char 1))) + ((and (eq (char-syntax (char-before)) ?\( ) + (eq (char-after) (matching-paren (char-before)))) + (backward-delete-char 1) ; Empty list -- delete both + (delete-char 1)) ; delimiters. + ;; Delete it, unless it's an opening delimiter. The case of + ;; character literals is already handled by now. + ((not (eq (char-syntax (char-before)) ?\( )) + (backward-delete-char-untabify 1)))) + +(defun paredit-backward-delete-in-string () + (let ((start+end (paredit-string-start+end-points))) + (cond ((not (eq (1- (point)) (car start+end))) + ;; If it's not the open-quote, it's safe to delete. + (if (paredit-in-string-escape-p) + ;; If we're on a string escape, since we're about to + ;; delete the backslash, we must first delete the + ;; escaped char. + (delete-char 1)) + (backward-delete-char 1) + (if (paredit-in-string-escape-p) + ;; If, after deleting a character, we find ourselves in + ;; a string escape, we must have deleted the escaped + ;; character, and the backslash is behind the point, so + ;; backward delete it. + (backward-delete-char 1))) + ((eq (point) (cdr start+end)) + ;; If it is the open-quote, delete only if we're also right + ;; past the close-quote (i.e. it's empty), and then delete + ;; both quotes. Otherwise we refuse to delete it. + (backward-delete-char 1) + (delete-char 1))))) + +;;;; Killing + +(defun paredit-kill (&optional argument) + "Kill a line as if with `kill-line', but respecting delimiters. +In a string, act exactly as `kill-line' but do not kill past the + closing string delimiter. +On a line with no S-expressions on it starting after the point or + within a comment, act exactly as `kill-line'. +Otherwise, kill all S-expressions that start after the point. +With a `C-u' prefix argument, just do the standard `kill-line'. +With a numeric prefix argument N, do `kill-line' that many times." + (interactive "P") + (cond (argument + (kill-line (if (integerp argument) argument 1))) + ((paredit-in-string-p) + (paredit-kill-line-in-string)) + ((or (paredit-in-comment-p) + (save-excursion + (paredit-skip-whitespace t (point-at-eol)) + (or (eq (char-after) ?\; ) + (eolp)))) + ;** Be careful about trailing backslashes. + (kill-line)) + (t (paredit-kill-sexps-on-line)))) + +(defun paredit-kill-line-in-string () + (if (save-excursion (paredit-skip-whitespace t (point-at-eol)) + (eolp)) + (kill-line) + (save-excursion + ;; Be careful not to split an escape sequence. + (if (paredit-in-string-escape-p) + (backward-char)) + (let ((beginning (point))) + (while (not (or (eolp) + (eq (char-after) ?\" ))) + (forward-char) + ;; Skip past escaped characters. + (if (eq (char-before) ?\\ ) + (forward-char))) + (kill-region beginning (point)))))) + +(defun paredit-kill-sexps-on-line () + (if (paredit-in-char-p) ; Move past the \ and prefix. + (backward-char 2)) ; (# in Scheme/CL, ? in elisp) + (let ((beginning (point)) + (eol (point-at-eol))) + (let ((end-of-list-p (paredit-forward-sexps-to-kill beginning eol))) + ;; If we got to the end of the list and it's on the same line, + ;; move backward past the closing delimiter before killing. (This + ;; allows something like killing the whitespace in ( ).) + (if end-of-list-p (progn (up-list) (backward-char))) + (if kill-whole-line + (paredit-kill-sexps-on-whole-line beginning) + (kill-region beginning + ;; If all of the S-expressions were on one line, + ;; i.e. we're still on that line after moving past + ;; the last one, kill the whole line, including + ;; any comments; otherwise just kill to the end of + ;; the last S-expression we found. Be sure, + ;; though, not to kill any closing parentheses. + (if (and (not end-of-list-p) + (eq (point-at-eol) eol)) + eol + (point))))))) + +;;; Please do not try to understand this code unless you have a VERY +;;; good reason to do so. I gave up trying to figure it out well +;;; enough to explain it, long ago. + +(defun paredit-forward-sexps-to-kill (beginning eol) + (let ((end-of-list-p nil) + (firstp t)) + ;; Move to the end of the last S-expression that started on this + ;; line, or to the closing delimiter if the last S-expression in + ;; this list is on the line. + (catch 'return + (while t + ;; This and the `kill-whole-line' business below fix a bug that + ;; inhibited any S-expression at the very end of the buffer + ;; (with no trailing newline) from being deleted. It's a + ;; bizarre fix that I ought to document at some point, but I am + ;; too busy at the moment to do so. + (if (and kill-whole-line (eobp)) (throw 'return nil)) + (save-excursion + (paredit-handle-sexp-errors (forward-sexp) + (up-list) + (setq end-of-list-p (eq (point-at-eol) eol)) + (throw 'return nil)) + (if (or (and (not firstp) + (not kill-whole-line) + (eobp)) + (paredit-handle-sexp-errors + (progn (backward-sexp) nil) + t) + (not (eq (point-at-eol) eol))) + (throw 'return nil))) + (forward-sexp) + (if (and firstp + (not kill-whole-line) + (eobp)) + (throw 'return nil)) + (setq firstp nil))) + end-of-list-p)) + +(defun paredit-kill-sexps-on-whole-line (beginning) + (kill-region beginning + (or (save-excursion ; Delete trailing indentation... + (paredit-skip-whitespace t) + (and (not (eq (char-after) ?\; )) + (point))) + ;; ...or just use the point past the newline, if + ;; we encounter a comment. + (point-at-eol))) + (cond ((save-excursion (paredit-skip-whitespace nil (point-at-bol)) + (bolp)) + ;; Nothing but indentation before the point, so indent it. + (lisp-indent-line)) + ((eobp) nil) ; Protect the CHAR-SYNTAX below against NIL. + ;; Insert a space to avoid invalid joining if necessary. + ((let ((syn-before (char-syntax (char-before))) + (syn-after (char-syntax (char-after)))) + (or (and (eq syn-before ?\) ) ; Separate opposing + (eq syn-after ?\( )) ; parentheses, + (and (eq syn-before ?\" ) ; string delimiter + (eq syn-after ?\" )) ; pairs, + (and (memq syn-before '(?_ ?w)) ; or word or symbol + (memq syn-after '(?_ ?w))))) ; constituents. + (insert " ")))) + +;;;;; Killing Words + +;;; This is tricky and asymmetrical because backward parsing is +;;; extraordinarily difficult or impossible, so we have to implement +;;; killing in both directions by parsing forward. + +(defun paredit-forward-kill-word () + "Kill a word forward, skipping over intervening delimiters." + (interactive) + (let ((beginning (point))) + (skip-syntax-forward " -") + (let* ((parse-state (paredit-current-parse-state)) + (state (paredit-kill-word-state parse-state 'char-after))) + (while (not (or (eobp) + (eq ?w (char-syntax (char-after))))) + (setq parse-state + (progn (forward-char 1) (paredit-current-parse-state)) +;; (parse-partial-sexp (point) (1+ (point)) +;; nil nil parse-state) + ) + (let* ((old-state state) + (new-state + (paredit-kill-word-state parse-state 'char-after))) + (cond ((not (eq old-state new-state)) + (setq parse-state + (paredit-kill-word-hack old-state + new-state + parse-state)) + (setq state + (paredit-kill-word-state parse-state + 'char-after)) + (setq beginning (point))))))) + (goto-char beginning) + (kill-word 1))) + +(defun paredit-backward-kill-word () + "Kill a word backward, skipping over any intervening delimiters." + (interactive) + (if (not (or (bobp) + (eq (char-syntax (char-before)) ?w))) + (let ((end (point))) + (backward-word 1) + (forward-word 1) + (goto-char (min end (point))) + (let* ((parse-state (paredit-current-parse-state)) + (state + (paredit-kill-word-state parse-state 'char-before))) + (while (and (< (point) end) + (progn + (setq parse-state + (parse-partial-sexp (point) (1+ (point)) + nil nil parse-state)) + (or (eq state + (paredit-kill-word-state parse-state + 'char-before)) + (progn (backward-char 1) nil))))) + (if (and (eq state 'comment) + (eq ?\# (char-after (point))) + (eq ?\| (char-before (point)))) + (backward-char 1))))) + (backward-kill-word 1)) + +;;;;;; Word-Killing Auxiliaries + +(defun paredit-kill-word-state (parse-state adjacent-char-fn) + (cond ((paredit-in-comment-p parse-state) 'comment) + ((paredit-in-string-p parse-state) 'string) + ((memq (char-syntax (funcall adjacent-char-fn)) + '(?\( ?\) )) + 'delimiter) + (t 'other))) + +;;; This optionally advances the point past any comment delimiters that +;;; should probably not be touched, based on the last state change and +;;; the characters around the point. It returns a new parse state, +;;; starting from the PARSE-STATE parameter. + +(defun paredit-kill-word-hack (old-state new-state parse-state) + (cond ((and (not (eq old-state 'comment)) + (not (eq new-state 'comment)) + (not (paredit-in-string-escape-p)) + (eq ?\# (char-before)) + (eq ?\| (char-after))) + (forward-char 1) + (paredit-current-parse-state) +;; (parse-partial-sexp (point) (1+ (point)) +;; nil nil parse-state) + ) + ((and (not (eq old-state 'comment)) + (eq new-state 'comment) + (eq ?\; (char-before))) + (skip-chars-forward ";") + (paredit-current-parse-state) +;; (parse-partial-sexp (point) (save-excursion +;; (skip-chars-forward ";")) +;; nil nil parse-state) + ) + (t parse-state))) + +;;;; Cursor and Screen Movement + +(eval-and-compile + (defmacro defun-saving-mark (name bvl doc &rest body) + `(defun ,name ,bvl + ,doc + ,(xcond ((paredit-xemacs-p) + '(interactive "_")) + ((paredit-gnu-emacs-p) + '(interactive))) + ,@body))) + +(defun-saving-mark paredit-forward () + "Move forward an S-expression, or up an S-expression forward. +If there are no more S-expressions in this one before the closing + delimiter, move past that closing delimiter; otherwise, move forward + past the S-expression following the point." + (paredit-handle-sexp-errors + (forward-sexp) + ;++ Is it necessary to use UP-LIST and not just FORWARD-CHAR? + (if (paredit-in-string-p) (forward-char) (up-list)))) + +(defun-saving-mark paredit-backward () + "Move backward an S-expression, or up an S-expression backward. +If there are no more S-expressions in this one before the opening + delimiter, move past that opening delimiter backward; otherwise, move + move backward past the S-expression preceding the point." + (paredit-handle-sexp-errors + (backward-sexp) + (if (paredit-in-string-p) (backward-char) (backward-up-list)))) + +;;; Why is this not in lisp.el? + +(defun backward-down-list (&optional arg) + "Move backward and descend into one level of parentheses. +With ARG, do this that many times. +A negative argument means move forward but still descend a level." + (interactive "p") + (down-list (- (or arg 1)))) + +;;; Thanks to Marco Baringer for suggesting & writing this function. + +(defun paredit-recentre-on-sexp (&optional n) + "Recentre the screen on the S-expression following the point. +With a prefix argument N, encompass all N S-expressions forward." + (interactive "P") + (save-excursion + (forward-sexp n) + (let ((end-point (point))) + (backward-sexp n) + (let* ((start-point (point)) + (start-line (count-lines (point-min) (point))) + (lines-on-sexps (count-lines start-point end-point))) + (goto-line (+ start-line (/ lines-on-sexps 2))) + (recenter))))) + +(defun paredit-focus-on-defun () + "Moves display to the top of the definition at point." + (interactive) + (beginning-of-defun) + (recenter 0)) + +;;;; Depth-Changing Commands: Wrapping, Splicing, & Raising + +(defun paredit-wrap-sexp (&optional argument open close) + "Wrap the following S-expression. +If a `C-u' prefix argument is given, wrap all S-expressions following + the point until the end of the buffer or of the enclosing list. +If a numeric prefix argument N is given, wrap N S-expressions. +Automatically indent the newly wrapped S-expression. +As a special case, if the point is at the end of a list, simply insert + a parenthesis pair, rather than inserting a lone opening delimiter + and then signalling an error, in the interest of preserving + structure. +By default OPEN and CLOSE are round delimiters." + (interactive "P") + (paredit-lose-if-not-in-sexp 'paredit-wrap-sexp) + (let ((open (or open ?\( )) + (close (or close ?\) ))) + (paredit-handle-sexp-errors + ((lambda (n) (paredit-insert-pair n open close 'goto-char)) + (cond ((integerp argument) argument) + ((consp argument) (paredit-count-sexps-forward)) + ((paredit-region-active-p) nil) + (t 1))) + (insert close) + (backward-char))) + (save-excursion (backward-up-list) (indent-sexp))) + +(defun paredit-count-sexps-forward () + (save-excursion + (let ((n 0)) + (paredit-ignore-sexp-errors + (while (not (eobp)) + (forward-sexp) + (setq n (+ n 1)))) + n))) + +(defun paredit-yank-pop (&optional argument) + "Replace just-yanked text with the next item in the kill ring. +If this command follows a `yank', just run `yank-pop'. +If this command follows a `paredit-wrap-sexp', or any other paredit + wrapping command (see `paredit-wrap-commands'), run `yank' and + reindent the enclosing S-expression. +If this command is repeated, run `yank-pop' and reindent the enclosing + S-expression. + +The argument is passed on to `yank' or `yank-pop'; see their + documentation for details." + (interactive "*p") + (cond ((eq last-command 'yank) + (yank-pop argument)) + ((memq last-command paredit-wrap-commands) + (yank argument) + ;; `yank' futzes with `this-command'. + (setq this-command 'paredit-yank-pop) + (save-excursion (backward-up-list) (indent-sexp))) + ((eq last-command 'paredit-yank-pop) + ;; Pretend we just did a `yank', so that we can use + ;; `yank-pop' without duplicating its definition. + (setq last-command 'yank) + (yank-pop argument) + ;; Return to our original state. + (setq last-command 'paredit-yank-pop) + (setq this-command 'paredit-yank-pop) + (save-excursion (backward-up-list) (indent-sexp))) + (t (error "Last command was not a yank or a wrap: %s" last-command)))) + +;;; Thanks to Marco Baringer for the suggestion of a prefix argument +;;; for PAREDIT-SPLICE-SEXP. (I, Taylor R. Campbell, however, still +;;; implemented it, in case any of you lawyer-folk get confused by the +;;; remark in the top of the file about explicitly noting code written +;;; by other people.) + +(defun paredit-splice-sexp (&optional argument) + "Splice the list that the point is on by removing its delimiters. +With a prefix argument as in `C-u', kill all S-expressions backward in + the current list before splicing all S-expressions forward into the + enclosing list. +With two prefix arguments as in `C-u C-u', kill all S-expressions + forward in the current list before splicing all S-expressions + backward into the enclosing list. +With a numerical prefix argument N, kill N S-expressions backward in + the current list before splicing the remaining S-expressions into the + enclosing list. If N is negative, kill forward. +Inside a string, unescape all backslashes, or signal an error if doing + so would invalidate the buffer's structure." + (interactive "P") + (if (paredit-in-string-p) + (paredit-splice-string argument) + (save-excursion + (paredit-kill-surrounding-sexps-for-splice argument) + (backward-up-list) ; Go up to the beginning... + (save-excursion + (forward-sexp) ; Go forward an expression, to + (backward-delete-char 1)) ; delete the end delimiter. + (delete-char 1) ; ...to delete the open char. + (paredit-ignore-sexp-errors + (backward-up-list) ; Reindent, now that the + (indent-sexp))))) ; structure has changed. + +(defun paredit-kill-surrounding-sexps-for-splice (argument) + (cond ((or (paredit-in-string-p) + (paredit-in-comment-p)) + (error "Invalid context for splicing S-expressions.")) + ((or (not argument) (eq argument 0)) nil) + ((or (numberp argument) (eq argument '-)) + ;; Kill S-expressions before/after the point by saving the + ;; point, moving across them, and killing the region. + (let* ((argument (if (eq argument '-) -1 argument)) + (saved (paredit-point-at-sexp-boundary (- argument)))) + (goto-char saved) + (paredit-ignore-sexp-errors (backward-sexp argument)) + (paredit-hack-kill-region saved (point)))) + ((consp argument) + (let ((v (car argument))) + (if (= v 4) ;One `C-u'. + ;; Move backward until we hit the open paren; then + ;; kill that selected region. + (let ((end (point))) + (paredit-ignore-sexp-errors + (while (not (bobp)) + (backward-sexp))) + (paredit-hack-kill-region (point) end)) + ;; Move forward until we hit the close paren; then + ;; kill that selected region. + (let ((beginning (point))) + (paredit-ignore-sexp-errors + (while (not (eobp)) + (forward-sexp))) + (paredit-hack-kill-region beginning (point)))))) + (t (error "Bizarre prefix argument `%s'." argument)))) + +(defun paredit-splice-sexp-killing-backward (&optional n) + "Splice the list the point is on by removing its delimiters, and + also kill all S-expressions before the point in the current list. +With a prefix argument N, kill only the preceding N S-expressions." + (interactive "P") + (paredit-splice-sexp (if n + (prefix-numeric-value n) + '(4)))) + +(defun paredit-splice-sexp-killing-forward (&optional n) + "Splice the list the point is on by removing its delimiters, and + also kill all S-expressions after the point in the current list. +With a prefix argument N, kill only the following N S-expressions." + (interactive "P") + (paredit-splice-sexp (if n + (- (prefix-numeric-value n)) + '(16)))) + +(defun paredit-raise-sexp (&optional n) + "Raise the following S-expression in a tree, deleting its siblings. +With a prefix argument N, raise the following N S-expressions. If N + is negative, raise the preceding N S-expressions." + (interactive "p") + (paredit-lose-if-not-in-sexp 'paredit-raise-sexp) + ;; Select the S-expressions we want to raise in a buffer substring. + (let* ((bound (save-excursion (forward-sexp n) (point))) + (sexps (if (and n (< n 0)) + (buffer-substring bound + (paredit-point-at-sexp-end)) + (buffer-substring (paredit-point-at-sexp-start) + bound)))) + ;; Move up to the list we're raising those S-expressions out of and + ;; delete it. + (backward-up-list) + (delete-region (point) (save-excursion (forward-sexp) (point))) + (save-excursion (insert sexps)) ; Insert & reindent the sexps. + (save-excursion (let ((n (abs (or n 1)))) + (while (> n 0) + (paredit-forward-and-indent) + (setq n (1- n))))))) + +(defun paredit-convolute-sexp (&optional n) + "Convolute S-expressions. +Save the S-expressions preceding point and delete them. +Splice the S-expressions following point. +Wrap the enclosing list in a new list prefixed by the saved text. +With a prefix argument N, move up N lists before wrapping." + (interactive "p") + (paredit-lose-if-not-in-sexp 'paredit-convolute-sexp) + (let (open close) ;++ Is this a good idea? + (let ((prefix + (let ((end (point))) + (paredit-ignore-sexp-errors + (while (not (bobp)) (backward-sexp))) + (prog1 (buffer-substring (point) end) + (backward-up-list) + (save-excursion (forward-sexp) + (setq close (char-before)) + (backward-delete-char 1)) + (setq open (char-after)) + (delete-region (point) end))))) + (backward-up-list n) + (paredit-insert-pair 1 open close 'goto-char) + (insert prefix) + (backward-up-list) + (paredit-ignore-sexp-errors (indent-sexp))))) + +(defun paredit-splice-string (argument) + (let ((original-point (point)) + (start+end (paredit-string-start+end-points))) + (let ((start (car start+end)) + (end (cdr start+end))) + ;; START and END both lie before the respective quote + ;; characters, which we want to delete; thus we increment START + ;; by one to extract the string, and we increment END by one to + ;; delete the string. + (let* ((escaped-string + (cond ((not (consp argument)) + (buffer-substring (1+ start) end)) + ((= 4 (car argument)) + (buffer-substring original-point end)) + (t + (buffer-substring (1+ start) original-point)))) + (unescaped-string + (paredit-unescape-string escaped-string))) + (if (not unescaped-string) + (error "Unspliceable string.") + (save-excursion + (goto-char start) + (delete-region start (1+ end)) + (insert unescaped-string)) + (if (not (and (consp argument) + (= 4 (car argument)))) + (goto-char (- original-point 1)))))))) + +(defun paredit-unescape-string (string) + (with-temp-buffer + (insert string) + (goto-char (point-min)) + (while (and (not (eobp)) + ;; nil -> no bound; t -> no errors. + (search-forward "\\" nil t)) + (delete-char -1) + (forward-char)) + (condition-case condition + (progn (check-parens) (buffer-string)) + (error nil)))) + +;;;; Slurpage & Barfage + +(defun paredit-forward-slurp-sexp () + "Add the S-expression following the current list into that list + by moving the closing delimiter. +Automatically reindent the newly slurped S-expression with respect to + its new enclosing form. +If in a string, move the opening double-quote forward by one + S-expression and escape any intervening characters as necessary, + without altering any indentation or formatting." + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p)) + (error "Invalid context for slurping S-expressions.")) + ((paredit-in-string-p) + (paredit-forward-slurp-into-string)) + (t + (paredit-forward-slurp-into-list))))) + +(defun paredit-forward-slurp-into-list () + (up-list) ; Up to the end of the list to + (let ((close (char-before))) ; save and delete the closing + (backward-delete-char 1) ; delimiter. + (catch 'return ; Go to the end of the desired + (while t ; S-expression, going up a + (paredit-handle-sexp-errors ; list if it's not in this, + (progn (paredit-forward-and-indent) + (throw 'return nil)) + (up-list) + (setq close ; adjusting for mixed + (prog1 (char-before) ; delimiters as necessary, + (backward-delete-char 1) + (insert close)))))) + (insert close))) ; to insert that delimiter. + +(defun paredit-forward-slurp-into-string () + (goto-char (1+ (cdr (paredit-string-start+end-points)))) + ;; Signal any errors that we might get first, before mucking with the + ;; buffer's contents. + (save-excursion (forward-sexp)) + (let ((close (char-before))) + (backward-delete-char 1) + (paredit-forward-for-quote (save-excursion (forward-sexp) (point))) + (insert close))) + +(defun paredit-forward-barf-sexp () + "Remove the last S-expression in the current list from that list + by moving the closing delimiter. +Automatically reindent the newly barfed S-expression with respect to + its new enclosing form." + (interactive) + (paredit-lose-if-not-in-sexp 'paredit-forward-slurp-sexp) + (save-excursion + (up-list) ; Up to the end of the list to + (let ((close (char-before))) ; save and delete the closing + (backward-delete-char 1) ; delimiter. + (paredit-ignore-sexp-errors ; Go back to where we want to + (backward-sexp)) ; insert the delimiter. + (paredit-skip-whitespace nil) ; Skip leading whitespace. + (cond ((bobp) + (error "Barfing all subexpressions with no open-paren?")) + ((paredit-in-comment-p) ; Don't put the close-paren in + (newline-and-indent))) ; a comment. + (insert close)) + ;; Reindent all of the newly barfed S-expressions. + (paredit-forward-and-indent))) + +(defun paredit-backward-slurp-sexp () + "Add the S-expression preceding the current list into that list + by moving the closing delimiter. +Automatically reindent the whole form into which new S-expression was + slurped. +If in a string, move the opening double-quote backward by one + S-expression and escape any intervening characters as necessary, + without altering any indentation or formatting." + (interactive) + (save-excursion + (cond ((or (paredit-in-comment-p) + (paredit-in-char-p)) + (error "Invalid context for slurping S-expressions.")) + ((paredit-in-string-p) + (paredit-backward-slurp-into-string)) + (t + (paredit-backward-slurp-into-list))))) + +(defun paredit-backward-slurp-into-list () + (backward-up-list) + (let ((open (char-after))) + (delete-char 1) + (catch 'return + (while t + (paredit-handle-sexp-errors + (progn (backward-sexp) (throw 'return nil)) + (backward-up-list) + (setq open + (prog1 (char-after) + (save-excursion (insert open) (delete-char 1))))))) + (insert open)) + ;; Reindent the line at the beginning of wherever we inserted the + ;; opening delimiter, and then indent the whole S-expression. + (backward-up-list) + (lisp-indent-line) + (indent-sexp)) + +(defun paredit-backward-slurp-into-string () + (goto-char (car (paredit-string-start+end-points))) + ;; Signal any errors that we might get first, before mucking with the + ;; buffer's contents. + (save-excursion (backward-sexp)) + (let ((open (char-after)) + (target (point))) + (message "open = %S" open) + (delete-char 1) + (backward-sexp) + (insert open) + (paredit-forward-for-quote target))) + +(defun paredit-backward-barf-sexp () + "Remove the first S-expression in the current list from that list + by moving the closing delimiter. +Automatically reindent the barfed S-expression and the form from which + it was barfed." + (interactive) + (paredit-lose-if-not-in-sexp 'paredit-forward-slurp-sexp) + (save-excursion + (backward-up-list) + (let ((open (char-after))) + (delete-char 1) + (paredit-ignore-sexp-errors + (paredit-forward-and-indent)) + (while (progn (paredit-skip-whitespace t) + (eq (char-after) ?\; )) + (forward-line 1)) + (if (eobp) + (error "Barfing all subexpressions with no close-paren?")) + ;** Don't use `insert' here. Consider, e.g., barfing from + ;** (foo|) + ;** and how `save-excursion' works. + (insert-before-markers open)) + (backward-up-list) + (lisp-indent-line) + (indent-sexp))) + +;;;; Splitting & Joining + +(defun paredit-split-sexp () + "Split the list or string the point is on into two." + (interactive) + (cond ((paredit-in-string-p) + (insert "\"") + (save-excursion (insert " \""))) + ((or (paredit-in-comment-p) + (paredit-in-char-p)) + (error "Invalid context for splitting S-expression.")) + (t (let ((open (save-excursion (backward-up-list) + (char-after))) + (close (save-excursion (up-list) + (char-before)))) + (delete-horizontal-space) + (insert close) + (save-excursion (insert ?\ ) + (insert open) + (backward-char) + (indent-sexp)))))) + +(defun paredit-join-sexps () + "Join the S-expressions adjacent on either side of the point. +Both must be lists, strings, or atoms; error if there is a mismatch." + (interactive) + ;++ How ought this to handle comments intervening symbols or strings? + (save-excursion + (if (or (paredit-in-comment-p) + (paredit-in-string-p) + (paredit-in-char-p)) + (error "Invalid context for joining S-expressions.") + (let ((left-point (paredit-point-at-sexp-end)) + (right-point (paredit-point-at-sexp-start))) + (let ((left-char (char-before left-point)) + (right-char (char-after right-point))) + (let ((left-syntax (char-syntax left-char)) + (right-syntax (char-syntax right-char))) + (cond ((>= left-point right-point) + (error "Can't join a datum with itself.")) + ((and (eq left-syntax ?\) ) + (eq right-syntax ?\( ) + (eq left-char (matching-paren right-char)) + (eq right-char (matching-paren left-char))) + ;; Leave intermediate formatting alone. + (goto-char right-point) + (delete-char 1) + (goto-char left-point) + (backward-delete-char 1) + (backward-up-list) + (indent-sexp)) + ((and (eq left-syntax ?\" ) + (eq right-syntax ?\" )) + ;; Delete any intermediate formatting. + (delete-region (1- left-point) + (1+ right-point))) + ((and (memq left-syntax '(?w ?_)) ; Word or symbol + (memq right-syntax '(?w ?_))) + (delete-region left-point right-point)) + (t + (error "Mismatched S-expressions to join."))))))))) + +;;;; Variations on the Lurid Theme + +;;; I haven't the imagination to concoct clever names for these. + +(defun paredit-add-to-previous-list () + "Add the S-expression following point to the list preceding point." + (interactive) + (paredit-lose-if-not-in-sexp 'paredit-add-to-previous-list) + (save-excursion + (backward-down-list) + (paredit-forward-slurp-sexp))) + +(defun paredit-add-to-next-list () + "Add the S-expression preceding point to the list following point. +If no S-expression precedes point, move up the tree until one does." + (interactive) + (paredit-lose-if-not-in-sexp 'paredit-add-to-next-list) + (save-excursion + (down-list) + (paredit-backward-slurp-sexp))) + +(defun paredit-join-with-previous-list () + "Join the list the point is on with the previous list in the buffer." + (interactive) + (paredit-lose-if-not-in-sexp 'paredit-join-with-previous-list) + (save-excursion + (while (paredit-handle-sexp-errors (save-excursion (backward-sexp) nil) + (backward-up-list) + t)) + (paredit-join-sexps))) + +(defun paredit-join-with-next-list () + "Join the list the point is on with the next list in the buffer." + (interactive) + (paredit-lose-if-not-in-sexp 'paredit-join-with-next-list) + (save-excursion + (while (paredit-handle-sexp-errors (save-excursion (forward-sexp) nil) + (up-list) + t)) + (paredit-join-sexps))) + +;;;; Utilities + +(defun paredit-in-string-escape-p () + "True if the point is on a character escape of a string. +This is true only if the character is preceded by an odd number of + backslashes. +This assumes that `paredit-in-string-p' has already returned true." + (let ((oddp nil)) + (save-excursion + (while (eq (char-before) ?\\ ) + (setq oddp (not oddp)) + (backward-char))) + oddp)) + +(defun paredit-in-char-p (&optional argument) + "True if the point is immediately after a character literal. +A preceding escape character, not preceded by another escape character, + is considered a character literal prefix. (This works for elisp, + Common Lisp, and Scheme.) +Assumes that `paredit-in-string-p' is false, so that it need not handle + long sequences of preceding backslashes in string escapes. (This + assumes some other leading character token -- ? in elisp, # in Scheme + and Common Lisp.)" + (let ((argument (or argument (point)))) + (and (eq (char-before argument) ?\\ ) + (not (eq (char-before (1- argument)) ?\\ ))))) + +(defun paredit-forward-and-indent () + "Move forward an S-expression, indenting it fully. +Indent with `lisp-indent-line' and then `indent-sexp'." + (forward-sexp) ; Go forward, and then find the + (save-excursion ; beginning of this next + (backward-sexp) ; S-expression. + (lisp-indent-line) ; Indent its opening line, and + (indent-sexp))) ; the rest of it. + +(defun paredit-skip-whitespace (trailing-p &optional limit) + "Skip past any whitespace, or until the point LIMIT is reached. +If TRAILING-P is nil, skip leading whitespace; otherwise, skip trailing + whitespace." + (funcall (if trailing-p 'skip-chars-forward 'skip-chars-backward) + " \t\n" ; This should skip using the syntax table, but LF + limit)) ; is a comment end, not newline, in Lisp mode. + +(defalias 'paredit-region-active-p + (xcond ((paredit-xemacs-p) 'region-active-p) + ((paredit-gnu-emacs-p) + (lambda () + (and mark-active transient-mark-mode))))) + +(defun paredit-hack-kill-region (start end) + "Kill the region between START and END. +Do not append to any current kill, and + do not let the next kill append to this one." + (interactive "r") ;Eh, why not? + ;; KILL-REGION sets THIS-COMMAND to tell the next kill that the last + ;; command was a kill. It also checks LAST-COMMAND to see whether it + ;; should append. If we bind these locally, any modifications to + ;; THIS-COMMAND will be masked, and it will not see LAST-COMMAND to + ;; indicate that it should append. + (let ((this-command nil) + (last-command nil)) + (kill-region start end))) + +;;;;; S-expression Parsing Utilities + +;++ These routines redundantly traverse S-expressions a great deal. +;++ If performance issues arise, this whole section will probably have +;++ to be refactored to preserve the state longer, like paredit.scm +;++ does, rather than to traverse the definition N times for every key +;++ stroke as it presently does. + +(defun paredit-current-parse-state () + "Return parse state of point from beginning of defun." + (let ((point (point))) + (beginning-of-defun) + ;; Calling PARSE-PARTIAL-SEXP will advance the point to its second + ;; argument (unless parsing stops due to an error, but we assume it + ;; won't in paredit-mode). + (parse-partial-sexp (point) point))) + +(defun paredit-in-string-p (&optional state) + "True if the parse state is within a double-quote-delimited string. +If no parse state is supplied, compute one from the beginning of the + defun to the point." + ;; 3. non-nil if inside a string (the terminator character, really) + (and (nth 3 (or state (paredit-current-parse-state))) + t)) + +(defun paredit-string-start+end-points (&optional state) + "Return a cons of the points of open and close quotes of the string. +The string is determined from the parse state STATE, or the parse state + from the beginning of the defun to the point. +This assumes that `paredit-in-string-p' has already returned true, i.e. + that the point is already within a string." + (save-excursion + ;; 8. character address of start of comment or string; nil if not + ;; in one + (let ((start (nth 8 (or state (paredit-current-parse-state))))) + (goto-char start) + (forward-sexp 1) + (cons start (1- (point)))))) + +(defun paredit-in-comment-p (&optional state) + "True if parse state STATE is within a comment. +If no parse state is supplied, compute one from the beginning of the + defun to the point." + ;; 4. nil if outside a comment, t if inside a non-nestable comment, + ;; else an integer (the current comment nesting) + (and (nth 4 (or state (paredit-current-parse-state))) + t)) + +(defun paredit-point-at-sexp-boundary (n) + (cond ((< n 0) (paredit-point-at-sexp-start)) + ((= n 0) (point)) + ((> n 0) (paredit-point-at-sexp-end)))) + +(defun paredit-point-at-sexp-start () + (save-excursion + (forward-sexp) + (backward-sexp) + (point))) + +(defun paredit-point-at-sexp-end () + (save-excursion + (backward-sexp) + (forward-sexp) + (point))) + +(defun paredit-lose-if-not-in-sexp (command) + (if (or (paredit-in-string-p) + (paredit-in-comment-p) + (paredit-in-char-p)) + (error "Invalid context for command `%s'." command))) + +;;;; Initialization + +(paredit-define-keys) +(paredit-annotate-mode-with-examples) +(paredit-annotate-functions-with-examples) + +(provide 'paredit) diff --git a/emacs/pastebin.el b/emacs/pastebin.el new file mode 100644 index 0000000..587cc20 --- /dev/null +++ b/emacs/pastebin.el @@ -0,0 +1,190 @@ +;;; pastebin.el --- A simple interface to the www.pastebin.com webservice + +;;; Copyright (C) 2008 by Tapsell-Ferrier Limited +;;; Copyright (C) 2010 by Ivan Korotkov <twee@tweedle-dee.org> + +;;; 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: +;;; +;;; Load this file and run: +;;; +;;; M-x pastebin-buffer +;;; +;;; to send the whole buffer or select a region and run +;;; +;;; M-x pastebin +;;; +;;; to send just the region. +;;; +;;; In either case the url that pastebin generates is left on the kill +;;; ring and the paste buffer. + + +;;; Code: + +;;;###autoload +(defgroup pastebin nil + "Pastebin -- pastebin.com client" + :tag "Pastebin" + :group 'tools) + +(defcustom pastebin-default-subdomain "" + "Pastebin subdomain to use by default" + :type 'string + :group 'pastebin) + +(defcustom pastebin-type-assoc + '((actionscript-mode . " actionscript") + (ada-mode . "ada") + (asm-mode . "asm") + (autoconf-mode . "bash") + (bibtex-mode . "bibtex") + (cmake-mode . "cmake") + (c-mode . "c") + (c++-mode . "cpp") + (cobol-mode . "cobol") + (conf-colon-mode . "properties") + (conf-javaprop-mode . "properties") + (conf-mode . "ini") + (conf-space-mode . "properties") + (conf-unix-mode . "ini") + (conf-windows-mode . "ini") + (cperl-mode . "perl") + (csharp-mode . "csharp") + (css-mode . "css") + (delphi-mode . "delphi") + (diff-mode . "diff") + (ebuild-mode . "bash") + (eiffel-mode . "eiffel") + (emacs-lisp-mode . "lisp") + (erlang-mode . "erlang") + (erlang-shell-mode . "erlang") + (espresso-mode . "javascript") + (fortran-mode . "fortran") + (glsl-mode . "glsl") + (gnuplot-mode . "gnuplot") + (graphviz-dot-mode . "dot") + (haskell-mode . "haskell") + (html-mode . "html4strict") + (idl-mode . "idl") + (inferior-haskell-mode . "haskell") + (inferior-octave-mode . "octave") + (inferior-python-mode . "python") + (inferior-ruby-mode . "ruby") + (java-mode . "java") + (js2-mode . "javascript") + (jython-mode . "python") + (latex-mode . "latex") + (lisp-mode . "lisp") + (lua-mode . "lua") + (makefile-mode . "make") + (makefile-automake-mode . "make") + (makefile-gmake-mode . "make") + (makefile-makepp-mode . "make") + (makefile-bsdmake-mode . "make") + (makefile-imake-mode . "make") + (matlab-mode . "matlab") + (nxml-mode . "xml") + (oberon-mode . "oberon2") + (objc-mode . "objc") + (ocaml-mode . "ocaml") + (octave-mode . "matlab") + (pascal-mode . "pascal") + (perl-mode . "perl") + (php-mode . "php") + (plsql-mode . "plsql") + (po-mode . "gettext") + (prolog-mode . "prolog") + (python-2-mode . "python") + (python-3-mode . "python") + (python-basic-mode . "python") + (python-mode . "python") + (ruby-mode . "ruby") + (scheme-mode . "lisp") + (shell-mode . "bash") + (sh-mode . "bash") + (smalltalk-mode . "smalltalk") + (sql-mode . "sql") + (tcl-mode . "tcl") + (visual-basic-mode . "vb") + (xml-mode . "xml") + (yaml-mode . "properties")) + "Alist composed of major-mode names and corresponding pastebin highlight formats." + :type '(alist :key-type symbol :value-tupe string) + :group 'pastebin) + +(defvar pastebin-subdomain-history '()) + +;;;###autoload +(defun pastebin-buffer (&optional subdomain) + "Send the whole buffer to pastebin.com. +Optional argument subdomain will request the virtual host to use, + eg:'emacs' for 'emacs.pastebin.com'." + (interactive + (let ((pastebin-subdomain + (if current-prefix-arg + (read-string "pastebin subdomain:" nil 'pastebin-subdomain-history) pastebin-default-subdomain))) + (list pastebin-subdomain))) + (pastebin (point-min) (point-max) subdomain)) + +;;;###autoload +(defun pastebin (start end &optional subdomain) + "An interface to the pastebin code snippet www service. + +See pastebin.com for more information about pastebin. + +Called interactively pastebin uses the current region for +preference for sending... if the mark is NOT set then the entire +buffer is sent. + +Argument START is the start of region. +Argument END is the end of region. + +If subdomain is used pastebin prompts for a subdomain to be used as the +virtual host to use. For example use 'emacs' for 'emacs.pastebin.com'." + (interactive + (let ((pastebin-subdomain + (if current-prefix-arg + (read-string "pastebin subdomain:" nil 'pastebin-subdomain-history) pastebin-default-subdomain))) + (if (mark) + (list (region-beginning) (region-end) pastebin-subdomain) + (list (point-min) (point-max) pastebin-subdomain)))) + ;; Main function + (let* ((data (buffer-substring-no-properties start end)) + (pastebin-url "http://pastebin.com/api_public.php") + (url-request-method "POST") + (url-request-extra-headers + '(("Content-Type" . "application/x-www-form-urlencoded"))) + (url-request-data + + (concat (format "submit=submit&paste_private=0&paste_expire_date=N&paste_subdomain=%s&paste_format=%s&paste_name=%s&paste_code=%s" + subdomain + (or (assoc-default major-mode pastebin-type-assoc) "text") + (url-hexify-string (user-full-name)) + (url-hexify-string data)))) + (content-buf (url-retrieve pastebin-url + (lambda (arg) + (cond + ((equal :error (car arg)) + (signal 'pastebin-error (cdr arg))) + (t + (re-search-forward "\n\n") + (clipboard-kill-ring-save (point) (point-max)) + (message "Pastebin URL: %s" (buffer-substring (point) (point-max))))))))))) + +(provide 'pastebin) +;;; pastebin.el ends here diff --git a/emacs/pbook.el b/emacs/pbook.el new file mode 100644 index 0000000..0d076bd --- /dev/null +++ b/emacs/pbook.el @@ -0,0 +1,932 @@ +;;; pbook.el -- Format a program listing for LaTeX. +;;; +;;; More mangling by Paul Khuong on 2007-Jan-31 to typeset +;;; code in a more generic and customisable manner, including +;;; a rough xref (annotates definition sites). +;;; Mangled by Paul Khuong (pvk@pvk.ca) on 2007-Jan-20 to +;;; emit coloured/bold/italic \tt code instead of verbatim +;;; pbook.el,v 1.4 2007/01/20 +;;; Written by Luke Gorrie <luke@member.fsf.org> in May of 2004. +;;; $Id: pbook.el,v 1.3 2004/05/17 01:09:01 luke Exp luke $ +;;; +;;; TODO: +;;; +;;; X Remove FIXMEs, etc from index. +;;; +;;; X Replace pbook-latex-escape with pbook-escape-code-substring +;;; Find way to make space work. +;;; +;;; o Better xreferencing. Run a first pass to identify all +;;; the toplevel definitions [as fontified], then annotate +;;; the source correctly; either change the face, or use the +;;; escaping mechanism. Changing the face sounds more robust. +;;; This could run as advice over pbook-process-buffer. +;;; The face changing could be an advice on pbook-escape-code, +;;; or, since we ignore face info outside of code, over the +;;; whole buffer, w/ the definition identification. +;;; If want to avoid multiple passes (why?), can accumulate +;;; toplevel defn names while processing them. +;;; +;;; X Add a public variable for the current line number (for +;;; property -> latex, especially) +;;; +;;; _ Make all/most of the extras togglable. +;;; +;;; X Rewrite the code escaping functions to use regexes instead of +;;; searching ourselves. +;;; +;;; ? Allow escaped `raw' latex strings in comments +;;; +;;; o Improve (think) the interface for customising code output +;;; +;;; X Find some way to customise font-lock for paper automatically, +;;; or introduce alists for italic, bold & colour override (per face)? +;;; Currently: converts to yuv, flips the luminance and back to rgb. +;;; +;;;# Introduction +;;; +;;; Have you ever printed out a program and read it on paper? +;;; +;;; It is an interesting exercise to try with one of your own +;;; programs, one that you think is well-written. The first few times +;;; you will probably find that it's torture to try and read in a +;;; straight line. What seemed so nice in Emacs is riddled with +;;; glaring problems on paper. +;;; +;;; How a program reads on paper may not be very important in itself, +;;; but there is wonderful upside to this. If you go through the +;;; program with a red pen and fix all the mind-bendingly obvious +;;; problems you see, what happens is that the program greatly +;;; improves -- not just on paper, but also in Emacs! +;;; +;;; This is a marvellously effective way to make programs +;;; better. +;;; +;;; Let's explore the idea some more! +;;; +;;;# `pbook' +;;; +;;; This program, `pbook', is a tool for making readable programs by +;;; generating LaTeX'ified program listings. Its purpose is to help +;;; you improve your programs by making them read well on paper. It +;;; serves this end by generating pretty-looking PDF output for you to +;;; print out and attack with a red pen, and perhaps use the medium to +;;; trick your mind into seeking the clarity of a technical paper and +;;; bringing your prose-editing skills to bear on your source code. +;;; +;;; `pbook' is aware of three things: headings, top-level comments, +;;; and code. Headings become LaTeX sections, and have entries in a +;;; table of contents. Top-level comments become plain text in a nice +;;; variable-width font. Other source code is listed as-is in a +;;; fixed-width font. +;;; +;;; These different elements are distinguished in the source using +;;; maximally unobtrusive markup, which you can see at work in the +;;; `pbook.el' source code. +;;; +;;; Read on to see the program and how it works. +;;; +;;;# Prelude +;;; +;;; (I have successfully tested this program with GNU Emacs versions +;;; 20.7 and 21.3, and with XEmacs version 21.5.) +;;; +;;; This is actually not true anymore. I have tested this in GNU Emacs +;;; 22.??? and 21.???. While I don't expect there to be any portability +;;; problem, it has not been tested in XEmacs at all. +;;; +;;; For some tiny luxuries and portability help we use the Common Lisp +;;; compatibility library: +(require 'cl) + +;;;# Emacs commands +;;; +;;; A handful of Emacs commands make up the pbook user-interface. The +;;; most fundamental is to render a pbook-formatted Emacs buffer as +;;; LaTeX. + +(defun pbook-buffer () + "Generate LaTeX from the current (pbook-formatted) buffer. +The resulting source is displayed in a buffer called *pbook*." + (interactive) + (pbook-process-buffer)) + +;;; A very handy utility is to display a summary of the buffer's +;;; structure and use it to jump to an appropriate section. I've +;;; always enjoyed being able to do this in texinfo-mode. Happily, +;;; pbook gets this for free using the `occur' function, which lists +;;; all lines in the buffer that match some regular expression. + +(defun pbook-show-structure () + "Display the pbook heading structure of the current buffer." + (interactive) + (occur pbook-heading-regexp)) + +;;; To avoid a lot of mucking about in the shell there is also a +;;; command to generate and display a PDF file. This function is a +;;; quick hack to make experimentation easy. +;;; +;;; I should add a function to do the same with dvis, and to output +;;; to non-temporary files. + +(defun pbook-buffer-view-pdf () + "Generate and display PDF from the current buffer. +The intermediate files are created in the standard temporary +directory." + (interactive) + (save-window-excursion + (pbook-buffer)) + (with-current-buffer "*pbook*" + (let ((texfile (pbook-tmpfile "pbook" "tex")) + (pdffile (pbook-tmpfile "pbook" "pdf")) + (idxfile (pbook-tmpfile "pbook" "idx"))) + (write-region (point-min) (point-max) texfile) + ;; Possibly there is a better way to ensure that LaTeX generates + ;; the table of contents correctly than to run it more than + ;; once, but I don't know one. + (shell-command (format "\ + cd /tmp; latex %s && \ + makeindex %s && \ + pdflatex %s && acroread %s &" + texfile + idxfile + texfile pdffile))))) + +(defun pbook-buffer-view-dvi () + "Generate and display DVI from the current buffer. +The intermediate files are created in the standard temporary +directory." + (interactive) + (save-window-excursion + (pbook-buffer)) + (with-current-buffer "*pbook*" + (let ((texfile (pbook-tmpfile "pbook" "tex")) + (dvifile (pbook-tmpfile "pbook" "dvi")) + (idxfile (pbook-tmpfile "pbook" "idx"))) + (write-region (point-min) (point-max) texfile) + ;; Possibly there is a better way to ensure that LaTeX generates + ;; the table of contents correctly than to run it more than + ;; once, but I don't know one. + (shell-command (format "\ + cd /tmp; latex %s && \ + makeindex %s && \ + latex %s && xdvi %s &" + texfile + idxfile + texfile dvifile))))) + +(defun pbook-buffer-regenerate-dvi () + (interactive) + (save-window-excursion + (pbook-buffer)) + (with-current-buffer "*pbook*" + (let ((texfile (pbook-tmpfile "pbook" "tex")) + (idxfile (pbook-tmpfile "pbook" "idx"))) + (write-region (point-min) (point-max) texfile) + ;; Possibly there is a better way to ensure that LaTeX generates + ;; the table of contents correctly than to run it more than + ;; once, but I don't know one. + (shell-command (format "\ + cd /tmp; latex %s && \ + makeindex %s && \ + latex %s" + texfile + idxfile + texfile))))) + +(defun pbook-tmpfile (name extension) + "Return the full path to a temporary file called NAME and with EXTENSION. +An appropriate directory is chosen and the PID of Emacs is inserted +before the extension." + (format "%s%s-%S.%s" + (if (boundp 'temporary-file-directory) + temporary-file-directory + ;; XEmacs does it this way instead: + (temp-directory)) + name (emacs-pid) extension)) + +;;;# Configurable variables +;;; +;;; These are variables that can be customized to affect pbook's +;;; behaviour. The default regular expressions assume Lisp-style +;;; comment characters, but they can be overridden with buffer-local +;;; bindings from hooks for other programming modes. The other +;;; variables that control formatting are best configured with Emacs's +;;; magic "file variables" (see down the very bottom for an example). + +(defvar pbook-commentary-regexp "^;;;\\($\\|[^#]\\)" + "Regular expression matching lines of high-level commentary.") + +(defvar pbook-heading-regexp "^;;;\\(#+\\)" + "Regular expression matching heading lines of chapters/sections/headings.") + +(defvar pbook-heading-level-subexp 1 + "The subexpression of `pbook-heading-regexp' whose length indicates nesting.") + +(defvar pbook-include-toc t + "When true include a table of contents.") + +(defvar pbook-style 'article + "Style of output. Either article (small) or book (large).") + +(defvar pbook-author (user-full-name) + "The name to use in the \author LaTeX command.") + +;;;## Configuration variables for code formatting + +(defvar pbook-code-prologue "\ +\\vspace{1pc} +\\begin{adjustwidth}{0in}{-1.5in} +\\begin{flushleft} +" + "Tex string to prepend to code listings") + +(defvar pbook-code-epilogue "\ +\\end{flushleft} +\\end{adjustwidth} +\\vspace{1pc} +" + "Tex string to append to code listings") + +(defvar pbook-current-line nil + "Holds the line number being processed. Note that this +is reset for every new section of code. This variable +is only accessible while processing code lines, obviously.") + +(defvar pbook-current-total-lines nil + "Holds the total number of lines in the section of +code that's being processed.") + +(defun pbook-around-code-line (line-number total-lines) + "returns a list of Tex strings `(prepend append)' to +surround the line in a code listing. It may also append +any number of entries to put in `pbook-escaping-regexps'. +It receives, as its arguments, the line number and the +total number of lines in the code segment." + (labels ((repeat (string num) + (if (<= num 0) + "" + (concat string (repeat string (1- num)))))) + (if (looking-at "^ *$") + (list "~" "\\\\") + (let ((str (number-to-string (1+ line-number)))) + (list (concat "\\hspace{-.4in}{\\small\\texttt{" + (repeat "\\ " (max 1 (- 4 (length str)))) + str + "\\ \\ " + "}}") + (if (= line-number (- total-lines 1)) + "\\\\" + "\\nopagebreak[4]\\\\")))))) + +(defvar pbook-dark-colors '("black") + "List of dark colours. Used by the coloring property +to detect when to flip luminances.") + +(defvar pbook-face-latex-properties '() + "plist of latex properties for current face + (only active while calling functions in `pbook-properties')") + +(defvar pbook-monochrome t + "Force every color to be the specified color (list of rgb components) +or t for standard black. nil for normal colors.") + +(defvar pbook-font-lock-override '(("\\(\\.\\|\\w\\)\\{2,\\}" + 0 (string-to-syntax "word") ;; was `pbook-identifier' + keep t)) + "Appended to `font-lock-syntactic-keywords' while fontifying.") + +;;;## configuration for the translation of properties to Latex +;;; +;;; The code formatting engine is composed of two parts: +;;; a system of properties that link font-lock faces and syntactic +;;; markup with latex environments, and a string escaping function. +;;; These variables let us easily customise both of these systems. + +(defvar pbook-current-text-properties nil + "text-properties of the current region of text. Maybe be used +by the property transformation functions to fine-tune their +output.") + +;;; The most common customisation will be to change the way faces +;;; are shown on paper. By default, they are translated faithfully: +;;; color, slantedness and boldness are directly translated. +;;; While a value of `nil' means don't care (and defers to other +;;; faces properties or default property values), `:no', by default, +;;; disables the associated property. + +(defvar pbook-face-override '((font-lock-keyword-face :bold t :index :no) + (font-lock-builtin-face :bold t :index :no) + (font-lock-function-name-face + :sc t :tt :no + :index function) + (font-lock-variable-name-face + :sc t :tt :no + :index variable) + (font-lock-warning-face :bold t :index :no) + (font-lock-comment-face :italic t :tt :no :index :no) + (font-lock-doc-face :italic t :tt :no :index :no) + (font-lock-constant-face :italic :no :index :no) + (font-lock-string-face :index :no) + (paren-face :intensity .5) + (default :italic :no)) + "Alist that associates a face with a set of default properties.") + +(defvar pbook-escaping-regexps '(("<" . "\\\\textless{}") + (">" . "\\\\textgreater{}") + ("\\\\" . "\\\\textbackslash{}") + ("~" . "\\\\textasciitilde{}") + ("\\^" . "\\\\textasciicircum{}") + ("[#%&$_{}]" . "\\\\\\&")) ;;space added as needed in pbook-latex-escape + "alist of regexp -> replacement (passed to re-search-forward and replace-match) +A simple way to index FIXMEs would be to add a regex for that in this list.") + +;;; `pbook-properties' defines pbook properties: their name, +;;; when they are applied (by default), and how they are translated +;;; into Latex. +;;; It is a list of triples `([name] [default-value] [translater])'. +;;; `[name]' is an unique identifier for the property. +;;; `[default-value]' is an unary function that, given the face, +;;; returns the value to associate with the property (or `nil' +;;; to defer). +;;; `[translater]' is either an unary function that, given +;;; the property's value, returns a list of a string to prepend +;;; to the formatted region, a string to append to it, and +;;; any number of pairs as in `pbook-escaping-regexps'. +;;; Latex code is spliced outside (for the first property) +;;; in (for the last property). + +(defvar pbook-properties + `((:color + pbook-face-color + (lambda (color) + (if (or (null color) + (eq pbook-monochrome t) + (every (lambda (component) + (< component 0.01)) + color)) + nil + (let ((components (mapcar (lambda (component) + (if (< component 0.01) + "0" + (number-to-string component))) + (or pbook-monochrome + color)))) + (list (format "\\textcolor[rgb]{%s, %s, %s}{" + (first components) + (second components) + (third components)) + "}"))))) + + (:intensity + (lambda (face) + nil) + (lambda (intensity) + (if (null intensity) + nil + (let* ((default-color (if (or (null pbook-monochrome) + (eq pbook-monochrome t)) + '(0.0 0.0 0.0) + pbook-monochrome)) + (yuv-default (apply 'pbook-rgb-yuv default-color)) + (yuv-intensity (list* (- 1 (* intensity (- 1 (car yuv-default)))) + (cdr yuv-default))) + (rgb-intensity (apply 'pbook-yuv-rgb yuv-intensity))) + (list (apply 'format + "\\textcolor[rgb]{%s, %s, %s}{" + rgb-intensity) + "}"))))) + + (:bold face-bold-p + (lambda (prop) + (and prop + (not (eq prop :no)) + (looking-at " *[^ ]") + '("\\textbf{" "}")))) + + (:italic face-italic-p + (lambda (prop) + (and prop + (not (eq prop :no)) + (looking-at " *[^ ]") + '("\\textit{" "}")))) + + (:tt (lambda (face) + t) + (lambda (prop) + (when (or (not (looking-at " *[^ ]")) ;; always \tt whitespace. + (and prop + (not (eq prop :no)))) + '("\\texttt{" "}")))) + + (:sc (lambda (face) + nil) + ("\\textsc{" "}")) + + (:index (lambda (face) + (and (eq face 'default) + (equal (plist-get pbook-current-text-properties + 'syntax-table) + (string-to-syntax "word")) + 'use)) + (lambda (index) + (when (and index + (not (eq index :no))) + (let* ((pbook-escaping-regexps (list* (cons "[!@|]" "\"\\&") + pbook-escaping-regexps)) + (word (pbook-latex-escape-string (buffer-string)))) + (list (format "\\index{%s%s}{" word (ecase index + ((function) "|bb") + ((variable) "|ii") + ((use) ""))) + "}"))))) + ) + "Complex system. See paragraph above.") + +(defun pbook-face-color (face) + "Given a face, return a triplet of rgb values. Flips the luminance +as needed (to adapt dark background colours to a light background)." + (let ((dark-bg-p (or (and (boundp 'face-background-mode) + (eq face-background-mode 'dark)) + (member (face-background face) + pbook-dark-colors)))) + (and (face-foreground face) + (let ((rgb-specs (mapcar (lambda (n) + (/ n 65535.0)) + (color-values (face-foreground face))))) + (and rgb-specs + (if dark-bg-p + (let ((yuv-specs (apply 'pbook-rgb-yuv rgb-specs))) + (pbook-yuv-rgb (* 0.25 (- 1 (first yuv-specs))) + (second yuv-specs) + (third yuv-specs))) + rgb-specs)))))) + +(defun pbook-rgb-yuv (r g b) + "As http://en.wikipedia.org/wiki/YUV -- Matrix fixed by mjp." + (let* ((y (+ (* 0.299 r) + (* 0.587 g) + (* 0.114 b))) + (u (+ (* -0.168740 r) + (* -0.331260 g) + (* 0.500000 b))) + (v (+ (* 0.500000 r) + (* -0.418690 g) + (* -0.081310 b)))) + (list y u v))) + +(defun pbook-yuv-rgb (y u v) + "As http://en.wikipedia.org/wiki/YUV -- Matrix fixed by mjp" + (let ((r (+ y + + (* 1.40200 v))) + (g (+ y + (* -0.34413 u) + (* -0.71414 v))) + (b (+ y + (* 1.77200 u)))) + (mapcar (lambda (x) + (cond ((< x 0) 0.0) ;; Need to clamp values for some reason + ((> x 1) 1.0) + (t x))) + (list r g b)))) +;;;# Top-level logic +;;; +;;; Here we have the top level of the program. Setting up, calling the +;;; formatting engine, piecing things together, and putting on the +;;; finishing touches. +;;; +;;; The real work is done in a new buffer called *pbook*. First the +;;; source is fontified, then copied into this buffer and from there +;;; it is massaged into shape. +;;; +;;; Most of this is mundane, but there is one tricky part: the source +;;; buffer may have buffer-local values for some pbook settings, and +;;; we have to be careful or we'd lose them when switching into the +;;; *pbook* buffer. This is taken care of by moving the correct values +;;; of all the relevant customizable settings into new dynamic +;;; bindings. + +(defun pbook-process-buffer () + "Generate pbook output for the current buffer +The output is put in the buffer *pbook* and displayed." + (interactive) + (let ((font-lock-syntactic-keywords + (append font-lock-syntactic-keywords + pbook-font-lock-override))) + (setq font-lock-fontified nil) ;; pretend buffer isn't fontified + (font-lock-default-fontify-buffer) ;; HACK!!! Looks like an internal... + ) + (let ((buffer (current-buffer)) + (beginning (pbook-tex-beginning)) + (ending (pbook-tex-ending)) + (text (buffer-string))) + (with-current-buffer (get-buffer-create "*pbook*") + ;; Setup, + (pbook-inherit-buffer-locals buffer + '(pbook-commentary-regexp + pbook-heading-regexp + pbook-style + pbook-heading-level-subexp + pbook-include-toc + pbook-monochrome + pbook-font-lock-override + pbook-face-override)) + (erase-buffer) + (insert text) + ;; Reformat as LaTeX, + (pbook-preprocess) + (pbook-format-buffer) + ;; Insert header & footer. + (goto-char (point-min)) + (insert beginning) + (goto-char (point-max)) + (insert ending) + (display-buffer (current-buffer))))) + +(defun pbook-inherit-buffer-locals (buffer variables) + "Make buffer-local bindings of VARIABLES using the values in BUFFER." + (dolist (v variables) + (set (make-local-variable v) + (with-current-buffer buffer (symbol-value v))))) + +(defun pbook-preprocess () + "Cleanup the buffer to prepare for formatting." + (goto-char (point-min)) + ;; FIXME: Currently we just zap all pagebreak characters. + (save-excursion + (while (re-search-forward "\C-l" nil t) + (replace-match ""))) + (unless (re-search-forward pbook-heading-regexp nil t) + (error "File must have at least one heading.")) + (beginning-of-line) + ;; Delete everything before the first heading. + (delete-region (point-min) (point))) + +(defun pbook-tex-beginning () + "Return the beginning prelude for the LaTeX output." + (format "\ +\\documentclass[notitlepage,a4paper]{%s} +\\usepackage[nohead,nofoot]{geometry} +\\usepackage{color} +\\usepackage{bold-extra} +\\usepackage{chngpage} +\\usepackage{index} +\\newcommand{\\ii}[1]{{\\it #1}} +\\newcommand{\\bb}[1]{{\\bf #1}} +\\makeindex +\\title{%s} +\\author{%s} +\\begin{document} +\\maketitle +%s\n" + (symbol-name pbook-style) + (pbook-latex-escape-string (buffer-name)) + (pbook-latex-escape-string pbook-author) + (if pbook-include-toc "\\tableofcontents" ""))) + +(defun pbook-tex-ending () + "Return the ending of the LaTeX output." + "\ +\\printindex + +\\end{document}\n") + +;;;# Escaping special characters +;;; +;;; We have to escape characters that LaTeX treats specially. This is +;;; done based on `pbook-escaping-regexps', whicn is defined according +;;; to the rules in the `Special Characters' node of the +;;; LaTeX2e info manual. (CHECKME) + +(defun pbook-latex-escape-string (string &optional space) + (with-temp-buffer + (insert string) + (pbook-latex-escape (point-min) (point-max) space) + (buffer-string))) + +(defun pbook-latex-escape (start end &optional space) + "LaTeX-escape special characters in the region from START to END." + (when (or space + pbook-escaping-regexps) + (let* ((pbook-escaping-regexps (if space + (append pbook-escaping-regexps + (list (cons " " "\\\\\\&"))) + pbook-escaping-regexps)) + (scan-regexp (apply 'concat + (car (first pbook-escaping-regexps)) + (mapcan (lambda (entry) + (list "\\|" + (car entry))) + (rest pbook-escaping-regexps))))) + (save-excursion + (save-restriction + (narrow-to-region start end) + (goto-char start) + (while (re-search-forward scan-regexp + nil t) + (goto-char (match-beginning 0)) + (catch 'out + (dolist (entry pbook-escaping-regexps) + (let ((test (car entry)) + (replace (cdr entry))) + (when (looking-at test) + (replace-match replace) + (throw 'out nil))))))))))) + +;;;# Processing engine +;;; +;;; The main loop scans through the source buffer piece by piece and +;;; converts each one to LaTeX as it goes. There are three sorts of +;;; pieces: headings, top-level commentary, and code. +;;; +;;; This loop recognises what type of piece is at the point and then +;;; calls the appropriate subroutine. The subroutines are responsible +;;; for determining where their piece finishes and for advancing the +;;; point beyond the region they have formatted. + +(defun pbook-format-buffer () + (while (not (eobp)) + (if (looking-at "^\\s *$") + ;; Skip blank lines. + (forward-line) + (cond ((looking-at pbook-heading-regexp) + (pbook-do-heading)) + ((looking-at pbook-commentary-regexp) + (pbook-do-commentary)) + (t + (pbook-do-code)))))) + +;;;## Heading formatting +;;; +;;; Each heading line is converted to a LaTeX sectioning command. The +;;; heading text is escaped. + +(defun pbook-do-heading () + ;; NB: `looking-at' sets the Emacs match data (for match-string, etc) + (assert (looking-at pbook-heading-regexp)) + (let ((depth (length (match-string-no-properties pbook-heading-level-subexp)))) + ;; Strip off the comment characters and whitespace. + (replace-match "") + (when (looking-at "\\s +") + (replace-match "")) + (pbook-latex-escape (line-beginning-position) (line-end-position)) + (wrap-line (format "\\%s{" (pbook-nth-sectioning-command depth)) + "}")) + (forward-line)) + +(defun wrap-line (prefix suffix) + "Insert PREFIX at the start of the current line and SUFFIX at the end." + (save-excursion + (goto-char (line-beginning-position)) + (insert prefix) + (goto-char (line-end-position)) + (insert suffix))) + +;;; LaTeX has different sectioning commands for articles and books, so +;;; we have to choose from the right set. These variables define the +;;; sets in order of nesting -- the first element is top-level, etc. + +(defconst pbook-article-sectioning-commands + '("section" "subsection" "subsubsection") + "LaTeX commands for sectioning articles.") + +(defconst pbook-book-sectioning-commands + (cons "chapter" pbook-article-sectioning-commands) + "LaTeX commands for sectioning books.") + +(defun pbook-nth-sectioning-command (n) + "Return the sectioning command for nesting level N (top-level is 1)." + (let ((commands (ecase pbook-style + (article pbook-article-sectioning-commands) + (book pbook-book-sectioning-commands)))) + (nth (min (1- n) (1- (length commands))) commands))) + +;;;## Commentary formatting +;;; +;;; Top-level commentary is stripped of its comment characters and we +;;; escape all characters that LaTeX treats specially. + +(defun pbook-do-commentary () + "Format one or more lines of commentary into LaTeX." + (assert (looking-at pbook-commentary-regexp)) + (let ((start (point))) + ;; Strip off comment characters line-by-line until end of section. + (while (or (looking-at pbook-commentary-regexp) + (and (looking-at "^\\s *$") + (not (eobp)))) + (replace-match "") + (delete-horizontal-space) + (forward-line)) + (save-excursion + (pbook-latex-escape start (point)) + (pbook-pretty-commentary start (point))))) + +;;; These functions define a simple Wiki-like markup language for +;;; basic formatting. + +(defun pbook-pretty-commentary (start end) + "Make commentary prettier." + (save-restriction + (narrow-to-region start end) + (goto-char (point-min)) + (save-excursion (pbook-pretty-tt)) + (save-excursion (pbook-pretty-doublequotes)))) + +(defun pbook-pretty-tt () + "Format `single quoted' text with a typewriter font." + (while (re-search-forward "`\\([^`']*\\)'" nil t) + (replace-match "{\\\\tt \\1}" t))) + +(defun pbook-pretty-doublequotes () + "Format \"double quoted\" text with ``double single quotes''." + (while (re-search-forward "\"\\([^\"]*\\)\"" nil t) + (replace-match "``\\1''"))) + +;;;## Source code formatting +;;; +;;; Source text is rendered as defined in pbook-properties. + +(defun pbook-do-code () + (assert (and (not (looking-at pbook-commentary-regexp)) + (not (looking-at pbook-heading-regexp)))) + (let ((start (point)) + (end (progn + (pbook-goto-end-of-code) + (point)))) + (save-restriction + (narrow-to-region start end) + (pbook-convert-tabs-to-spaces start end) + ;;delete trailing newlines and spaces + (goto-char (point-max)) + (while (or (equal (char-syntax (char-before)) " ") + (bolp)) + (delete-char -1)) + (pbook-format-code start (point-max) + (count-lines start (point-max))) + (goto-char (point-min)) + (insert pbook-code-prologue) + (goto-char (point-max)) + (insert "\n" pbook-code-epilogue "\n")))) + +(defun pbook-goto-end-of-code () + "Goto the end of the current section of code." + (if (re-search-forward (format "\\(%s\\)\\|\\(%s\\)" + pbook-heading-regexp + pbook-commentary-regexp) + nil t) + (beginning-of-line) + (goto-char (point-max)))) + +(defun pbook-convert-tabs-to-spaces (start end) + "Replace tab characters with spaces." + (save-excursion + (save-restriction + (narrow-to-region start end) + (untabify start end)))) + + +(defun pbook-format-code (start end num-lines) + "Format the section of code. The third argument is +the total number of line in the section." + (save-excursion + (save-restriction + (narrow-to-region start end) + (goto-char (point-min)) + (let ((cur-line 0)) + (while (< cur-line num-lines) + (pbook-format-line (line-beginning-position) (line-end-position) + cur-line num-lines) + (incf cur-line) + (beginning-of-line 2)))))) + +(defun pbook-get-inherits (face) + "Flattens a face's inheritance list, in order." + (let ((faces (cond ((eq face 'unspecified) nil) + ((listp face) face) + (t (list face))))) + (mapcan (lambda (face) + (let ((inherits (face-attribute face :inherit))) + (if (and inherits + (not (eq inherits 'unspecified))) + (cons face (pbook-get-inherits inherits)) + (list face)))) + faces))) + +(defun pbook-translate-face-properties (face props) + "Updates the list of properties `props' with those +associates with `face'. `pbook-face-override' has priority" + (setq props (append props + (copy-list (cdr (assoc face pbook-face-override))))) + (dolist (defn pbook-properties) + (let ((prop-name (first defn)) + (predicate (second defn))) + (unless (plist-get props prop-name) + (let ((value (funcall predicate face))) + (when value + (setq props (plist-put props prop-name value))))))) + props) + +(defun pbook-face-properties (face) + "Finds a face's (and those from which it inherits) pbook +properties. Earlier faces in the inheritance list (preorder +depth-first) have priority." + (let ((faces (append (pbook-get-inherits face) + '(default))) + (props nil)) + (dolist (face faces props) + (setq props (pbook-translate-face-properties face props))))) + +(defun pbook-properties-latex-strings (plist) + "Given a plist of pbook properties, finds the latex +strings with which to wrap the text that is being formatted, +and the additional regexps with which to escape it." + (let* ((pbook-face-latex-properties plist) ;;special var + (prepend nil) + (append nil) + (regexps nil) ;;escaping-regexp entry + ) + (dolist (property pbook-properties (list (apply 'concat + (reverse prepend)) + (apply 'concat append) + regexps)) + (let* ((name (first property)) + (transformer (third property)) + (foundp (plist-member plist name)) + (prop (plist-get plist name))) + (when foundp + (let ((wrap (if (and (listp transformer) + (not (eq (first transformer) + 'lambda))) + (and prop + (not (eq prop :no)) + transformer) + (funcall transformer prop)))) + (when wrap + (push (first wrap) prepend) + (push (second wrap) append) + (setq regexps (append (cddr wrap) + regexps))))))))) + +(defun pbook-format-line (start end line-number total-lines) + "Format a complete line of code, by spans of constant text property. +Also wraps it as per `pbook-around-code-line'. Each span is only escaped +at the very end to facilitate examination of the buffer." + (save-excursion + (save-restriction + (narrow-to-region start end) + (goto-char start) + (let* ((pbook-current-line line-number) + (pbook-current-total-lines total-lines) + (substr-beg (point-marker)) + (substr-end (point-marker)) + (wrap (pbook-around-code-line line-number total-lines)) + (pbook-escaping-regexps (append (cddr wrap) + pbook-escaping-regexps))) + (move-marker substr-end + (next-char-property-change (marker-position substr-beg))) + (set-marker-insertion-type substr-beg t) + (set-marker-insertion-type substr-end t) + ;; Main loop: find spans of constant text properties + ;; then get the latex trings to wrap around it. + (while (not (equal substr-beg substr-end)) + (goto-char (marker-position substr-beg)) + (let ((wrap (save-excursion ;;DOCUMENT ME + (save-restriction + (narrow-to-region (marker-position substr-beg) + (marker-position substr-end)) + (let ((pbook-current-text-properties + (text-properties-at (marker-position substr-beg)))) + (pbook-properties-latex-strings + (pbook-face-properties + (get-char-property (marker-position substr-beg) + 'face)))))))) + (insert (first wrap)) + (let ((pbook-escaping-regexps (append (third wrap) + pbook-escaping-regexps))) + (pbook-latex-escape (marker-position substr-beg) + (marker-position substr-end) + t)) + (goto-char (marker-position substr-end)) + (insert (second wrap)) + + (move-marker substr-beg (marker-position substr-end)) + (move-marker substr-end + (next-char-property-change + (marker-position substr-beg))))) + (wrap-line (first wrap) + (second wrap)))))) + +;;;# Prologue and file variables + +(provide 'pbook) + +;;; We use Emacs's magic `file variables' to make sure pbook is +;;; formatted how it should be: + +;; Local Variables: +;; pbook-author: "Luke Gorrie, with modifications by Paul Khuong" +;; pbook-use-toc: t +;; pbook-style: article +;; pbook-monochrome: t +;; End: diff --git a/emacs/quack.el b/emacs/quack.el new file mode 100644 index 0000000..447b463 --- /dev/null +++ b/emacs/quack.el @@ -0,0 +1,4742 @@ +;;; quack.el --- enhanced support for editing and running Scheme code + +(defconst quack-copyright "Copyright (C) 2002-2012 Neil Van Dyke") +(defconst quack-copyright-2 "Portions Copyright (C) Free Software Foundation") +;; Emacs-style font-lock specs adapted from GNU Emacs 21.2 scheme.el. +;; Scheme Mode menu adapted from GNU Emacs 21.2 cmuscheme.el. + +(defconst quack-version "0.44") +(defconst quack-author-name "Neil Van Dyke") +(defconst quack-author-email "neil@neilvandyke.org") +(defconst quack-web-page "http://www.neilvandyke.org/quack/") + +(defconst quack-legal-notice + "This is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. This is +distributed in the hope that it will be useful, but without any warranty; +without even the implied warranty of merchantability or fitness for a +particular purpose. See the GNU General Public License for more details. See +http://www.gnu.org/licenses/ for details. For other licenses and consulting, +please contact Neil Van Dyke.") + +(defconst quack-cvsid "$Id: quack.el,v 1.481 2012-04-11 17:42:25 user Exp $") + +;;; Commentary: + +;; INTRODUCTION: +;; +;; Quack enhances Emacs support for Scheme programming. +;; +;; Install Quack rather than following non-Quack-based tutorials on how to +;; set up Emacs for Scheme. +;; +;; The name "Quack" was a play on "DrScheme". +;; +;; Quack is dedicated to Yosh, naturally. + +;; COMPATIBILITY: +;; +;; GNU Emacs 23 and 22 -- Yes. Quack is now developed under GNU Emacs 23 +;; on a GNU/Linux system, which is the preferred platform for Quacksmokers. +;; Quack should work under GNU Emacs 23 on any Un*x-like OS. Reportedly, +;; Quack also works with GNU Emacs 22 on Apple Mac OS X and Microsoft +;; Windows (NT, 2000, XP), but the author has no means of testing on those +;; platforms. +;; +;; GNU Emacs 21 -- Probably, but no longer tested. +;; +;; GNU Emacs 20 -- Probably mostly. When last tested. Some of the menus do +;; not work properly, due to a bug in easymenu.el (which the FSF will not +;; fix, since they no longer support Emacs 20). Nested block comments are +;; not fontified correctly. Pretty-lambda does not work. Quack runs less +;; efficiently in 20 than 21, due to the lack of standard hash tables. +;; +;; XEmacs 21 -- Probably mostly, but no longer tested. Block comment +;; fontification is not yet supported under XEmacs 21, due to what appears +;; to be a bug in 21.4 font-lock. Pretty-lambda does not work. XEmacs +;; Quacksmokers who always want the latest and greatest Quack should +;; consider GNU Emacs 21 -- Quack treats XEmacs like a high-maintenance +;; redheaded stepchild. + +;; INSTALLATION: +;; +;; To install, put this file (`quack.el') somewhere in your Emacs load +;; path, and add the following line to your `.emacs' file: +;; +;; (require 'quack) +;; +;; If you don't know what your Emacs load path is, try invoking the command +;; "C-h v load-path RET" or consulting the Emacs manual. +;; +;; Note to advanced Emacsers: Byte-compiled `quack.elc' files generally are +;; *not* portable between Emacs implementations, nor between different +;; versions of the same implementation. +;; +;; You will also need the GNU `wget' program, which Quack uses for +;; downloading SRFI indexes. This popular program is included in most +;; GNU/Linux distributions and is available for most other platforms. +;; +;; Note to PLT Scheme users: If you do not already have the PLT manuals +;; installed, they can be downloaded from +;; `http://download.plt-scheme.org/doc/' and installed in your PLT `doc' +;; collection. If Quack is not finding installed PLT manuals, then be sure +;; that the `quack-pltcollect-dirs' variable contains the appropriate +;; collection directory (if it does not, then either set the `PLTHOME' +;; and/or `PLTCOLLECTS' environment variables appropriately, or set +;; `quack-pltcollect-dirs'). + +;; KEY BINDINGS: +;; +;; The key bindings that Quack adds to `scheme-mode' include: +;; +;; C-c C-q m View a manual in your Web browser. +;; C-c C-q k View the manual documentation for a keyword +;; (currently only works for PLT manuals). +;; C-c C-q s View an SRFI. +;; C-c C-q r Run an inferior Scheme process. +;; C-c C-q f Find a file using context of point for default. +;; C-c C-q l Toggle `lambda' syntax of `define'-like form. +;; C-c C-q t Tidy the formatting of the buffer. +;; +;; One additional command that does not currently have a standard binding +;; is `quack-dired-pltcollect', which prompts for a PLT collection name and +;; creates a Dired buffer on the collection's directory. (A future version +;; of Quack may integrate this functionality into a more generalized +;; documentation navigation interface.) + +;; RELEASE ANNOUNCEMENTS EMAIL: +;; +;; To receive email notification when a new Quack version is released, ask +;; neil@neilvandyke.org to add you to the moderated `scheme-announce' list. + +;; HISTORY: +;; +;; Version 0.44 (2012-04-11): +;; * Added indent and fontify for `struct', `module+', `module*'. +;; * Changed intent for `module' from `defun' to 2. +;; * Added fontify for `define-syntax-class', +;; `define-splicing-syntax-class', `begin-for-syntax'. +;; * Changed `define-struct' fontify. +;; +;; Version 0.43 (2011-08-23): +;; * Add indent and fontify for "syntax-parse". +;; * Added another compile error regexp for Racket backtraces. +;; +;; Version 0.42 (2011-07-30): +;; * Added compile error regexp for "raco". +;; +;; Version 0.41 (2011-06-04) +;; * Added `sxml-match' to `scheme-indent-function'. +;; +;; Version 0.40 (2010-12-22) +;; * Added indent rules for Racket `let:', `let*:', and `match'. And +;; a provisional rule for `define:'. +;; +;; Version 0.39 (2010-10-18) +;; * Renamed "typed/scheme" to "typed/racket". +;; +;; Version 0.38 (2010-10-14) +;; * Replaced old PLT Scheme programs in `quack-programs' with Racket. +;; * Added Racket ".rkt" and ".rktd" filename extensions. +;; * Added some Racket keywords for fontifying. +;; +;; Version 0.37 (2009-06-29) +;; * Disabled highlighting of "Compilation started at" lines. +;; +;; Version 0.36 (2009-05-27) +;; * Made `#:' ``colon keywords'' fontify in PLT-ish mode. +;; * Added PLT `r6rs' and `typed-scheme' languages to `quack-programs'. +;; +;; Version 0.35 (2009-02-24) +;; * Added `interpreter-mode-alist' support, so Scheme scripts with "#!" +;; start in `scheme-mode'. +;; * Added PLT `parameterize-break'. +;; * Improved `compile' mode for PLT 4.x tracebacks when there is only +;; file, line, and column, but no additional information. +;; +;; Version 0.34 (2009-02-19) +;; * Added fontify and indent support for PLT `define/kw', `lambda/kw', +;; `parameterize*'. +;; * Fontify Unix "#!" cookie in PLT-ish font-lock. +;; * Changed reference to `quack-announce' email list to +;; `scheme-announce'. +;; * Added PLT `default-load-handler' to +;; `quack-compilation-error-regexp-alist-additions' +;; * Changed some face ":height" attributes. +;; +;; Version 0.33 (2008-07-31) +;; * Added handlers for some PLT 4.0.1 "setup-plt" messages. +;; +;; Version 0.32 (2008-06-19) +;; * Added to `quack-programs'. +;; * Updated compatibility comments. +;; * Added indent rule for `for/fold'. +;; +;; Version 0.31 (2008-05-03) +;; * Added `defvar' for `quack-pltish-font-lock-keywords', so that the +;; GNU Emacs 22.1 compiler doesn't complain about assignment to a free +;; variable. +;; * Changed banner regexp for MzScheme for v3.99.x. +;; * Set `dynamic-wind' `scheme-indent-function to 0, when the default +;; is 3. It was just taking up too much space. DrScheme's +;; indentation seems to be equivalent -1, so there is precedent for +;; something different. We generally respect Emacs indentation +;; convention. +;; * Added fontifying and indent for PLT `define-for-syntax', +;; `define-values-for-syntax', `quasisyntax', `quasisyntax/loc', +;; `syntax', `syntax/loc', `define-parameters'. +;; * Advise `scheme-interactively-start-process' for GNU Emacs 22. +;; * Removed TODO comment that mentioned using `(current-eventspace +;; (make-eventspace))' under `mred', as Robby Findler has indicated +;; that is not good advice. +;; +;; Version 0.30 (2007-06-27) +;; * Emacs 22 compatibility change: `string-to-number' instead of +;; `string-to-int'. Thanks to Charles Comstock. +;; +;; Version 0.29 (2006-11-12) +;; * Fixed `quack-bar-syntax-string', which caused vertical bar +;; characters to be treated as whitespace. Thanks to Eric Hanchrow +;; for reporting. +;; +;; Version 0.28 (2005-05-14) +;; * Added `quack-smart-open-paren-p'. +;; * Changed `scheme-indent-function' for `parameterize' from `defun' +;; to `1'. +;; * In `quack-pltish-keywords-to-fontify': added `quasiquote', +;; `unquote', and `unquote-splicing'. +;; * Added ".mzschemerc" to `auto-mode-alist'. +;; * Added a little extra threesemi fontification for Funcelit and +;; similar Texinfo markup formats. +;; +;; Version 0.27 (2004-12-19) +;; * For Gambit-C, added REPL banner fontifying, `quack-manuals' entry, +;; and "gsi ~~/syntax-case.scm -" `quack-programs' entry. +;; * Changed "[PLT]" prefix on PLT manuals to "PLT", to make it easier +;; to type. +;; * Minor changes to reflect "MIT Scheme" becoming "MIT/GNU Scheme". +;; +;; Version 0.26 (2004-07-14) +;; * Added fontifying of a bunch of "define-"* syntax from Chicken. +;; +;; Version 0.25 (2004-07-09) +;; * Added `define-record-type' to `quack-pltish-keywords-to-fontify'. +;; * Added "csi -hygienic" to `quack-programs'. +;; * In `quack-manuals', replaced PLT-specific `r5rs' and `t-y-scheme' +;; with generic ones. +;; * Updated URL in `quack-manuals' for 3rd ed. of `tspl'. +;; * `quack-view-manual' completions no longer include symbols. +;; * `quack-view-manual' completion default is now "R5RS". +;; +;; Version 0.24 (2004-05-09) +;; * Made `quack-pltish-keywords-to-fontify' and +;; `quack-emacs-keywords-to-fontify' custom changes update +;; immediately. Bug reported by Taylor Campbell. +;; * Removed some non-syntax names from +;; `quack-pltish-keywords-to-fontify'. +;; * Documentation changes. +;; +;; Version 0.23 (2003-11-11) +;; * `quack-local-keywords-for-remote-manuals-p' can now have the value +;; of the symbol `always', to work around a defect in some versions +;; of Microsoft Windows. Thanks to Bill Clementson. +;; * `quack-w3m-browse-url-other-window' no longer splits a `*w3m*' +;; buffer. +;; * Added indent and `quack-pltish-keywords-to-fontify' rules for +;; `c-lambda' and `c-declare'. +;; +;; Version 0.22 (2003-07-03) +;; * `quack-newline-behavior' controls the RET key behavior in Scheme +;; buffers. +;; * In `quack-manuals', added Chez Scheme, and updated Chicken. +;; * Added error message navigation to `compile' for PLT `setup-plt'. +;; * Partial fix for Quack global menu disappearing from the main menu +;; bar in XEmacs. Thought it used to work, but it doesn't in XEmacs +;; 21.4.12. +;; +;; Version 0.21 (2003-05-28) +;; * `quack-find-file' is faster in many cases due to fix to +;; `quack-backward-sexp'. +;; * Added auto-mode-alist for `.ccl', `.stk', and `.stklos' files. +;; * Indent rule additions/changes for `chicken-setup' and `unit/sig'. +;; +;; Version 0.20 (2003-05-04) +;; * Added indent and fontify for SRFI-8 "receive". +;; * Added indent and fontify for additional PLT syntax. +;; * Added `quack-fontify-threesemi-p'. +;; * `quack-tidy-buffer' sets `fill-prefix' to nil when running. +;; * Added messages to `run-scheme', if only to get rid of annoying +;; "Mark set" message. +;; * Added "mzscheme -M errortrace" to `quack-programs'. +;; * `quack-dired-pltcollect' prompt defaults to `mzlib'. +;; * "Update SRFI Index" menu item has moved to top of menu, mainly to +;; avoid usability issue in a particular Emacs menu implementation. +;; * Several code quality improvements sent by Stefan Monnier will be +;; in the next release. +;; +;; Version 0.19 (2003-03-04) +;; * Commands such as `scheme-load-file' now start a Scheme process if +;; none is found. +;; * Bugfix for using `match-string-no-properties' when we meant +;; `quack-match-string-no-properties'. (Thanks to Noel Welsh.) +;; +;; Version 0.18 (2003-05-02) +;; * Removed uses of `(regexp-opt LIST t)', since XEmacs21 does not +;; create match data. (Thanks to Garrett Mitchener for debugging.) +;; * Added to `quack-programs' and `quack-manuals'. +;; * Added pretty-case-lambda. +;; * Changed PLT documentation URL function. +;; +;; Version 0.17 (2003-01-03) +;; * Pretty-lambda is supported well under GNU Emacs 21, when using PLT +;; Style fontification. Enable via the Options menu. (Based on +;; approach by Stefan Monnier; suggested by Ray Racine.) +;; * Various faces now have separate defaults for `light' and `dark' +;; backgrounds, so may now look better on dark backgrounds. +;; (Suggested by Eli Barzilay.) +;; * `quack-find-file' now respects `insert-default-directory' when +;; there is no default file. (Thanks to Eli Barzilay.) +;; * Most of the special w3m support has been moved to a separate +;; package, `w3mnav' (`http://www.neilvandyke.org/w3mnav/'). +;; `quack-w3m-browse-url-other-window' has been added. +;; +;; Version 0.16 (2002-12-16) +;; * `quack-insert-closing' now calls `blink-paren-function'. (Thanks +;; to Guillaume Marceau and Steve Elkins for reporting this.) +;; * Now uses PLT 202 manuals. Added "PLT Framework" manual. +;; * Added `quack-pltish-module-defn-face'. +;; * Added some PLTish font-lock keywords. +;; +;; Version 0.15 (2002-11-21) +;; * "Keywords" are now fontified in PLT Style fontification mode. +;; * Definition names are now blue by default in PLT Style. +;; * Symbol literals with vertical bars are now fontified in PLT Style. +;; * New `quack-manuals-webjump-sites' function for people who prefer +;; to use the `webjump' package for invoking manuals. +;; * New `quack-quiet-warnings-p' option. +;; * New `quack-pltish-class-defn-face' face. +;; +;; Version 0.14 (2002-10-18) +;; * Fix for `quack-view-manual' interactive prompting (thanks to Marko +;; Slyz for reporting this). +;; * `quack-emacsw3m-go-next' and `quack-emacsw3m-go-prev' now work +;; with GTK reference documentation (not that this has anything to do +;; with Scheme). +;; * Added SLIB to `quack-manuals'. +;; * Added comment about installing PLT manuals (thanks to Marko). +;; * We now call the canonical version of Emacs "GNU Emacs," instead of +;; "FSF Emacs". +;; +;; Version 0.13 (2002-09-21) +;; * Bugfix: No longer drop SRFI index entries on the floor. +;; +;; Version 0.12 (2002-09-20) +;; * New "View SRFI" menu. Select "Update SRFI Index" if the submenus +;; "Draft", "Final", and "Withdrawn" are disabled. +;; * Most options are now settable via "Options" menu. +;; * PLT collections are no longer scanned when building "View Manuals" +;; menu. +;; * "View Keyword Docs..." back on Scheme Mode menu in addition to +;; Quack menu. +;; * Various `defcustom' variables have been made to dynamically update +;; relevant program state when changed. +;; * Under GNU Emacs 20, dynamic menus still do not work -- they now +;; display, but do not perform the selected action. Will do more +;; debugging after this release. +;; * '[' and ']' keys work in emacs-w3m of MIT Scheme manuals. +;; +;; Version 0.11 (2002-09-17) +;; * Menus now work under XEmacs. Also now partly broken for Emacs 20. +;; * New global "Quack" menu. Disable with `quack-global-menu-p'. +;; * New "View Manual" submenu under GNU Emacs 21 and XEmacs (GNU Emacs +;; 20 is stuck with the old "View Manual..." menu item). +;; * Fix for `quack-pltcollects-alist' to include PLT `doc' collection, +;; which was preventing local manuals from being used. +;; * `quack-manuals' now includes `t-y-scheme'. +;; * `quack-view-in-different-browser' command that spawns alternative +;; Web browser from the special emacs-w3m support, bound to `B'. For +;; when you normally view manuals in an Emacs window, but +;; occasionally want to view a particular page in normal Web browser. +;; * More `scheme-indent-function' properties set. +;; * `quack-about' command. +;; * Fix to `quack-keyword-at-point'. +;; +;; Version 0.10 (2002-09-11) +;; * `quack-view-srfi' now prompts with completion, including titles +;; for all SRFIs. The SRFI titles are fetched from the official SRFI +;; Web site using the GNU Wget program, and cached locally. +;; * `quack-view-srfi' also now defaults to the SRFI number at or near +;; the point. +;; * `quack-dir' variable specifies a directory where Quack should +;; store its persistent data files (e.g., cached SRFI indexes), and +;; defaults to "~/.quack/". +;; * New `quack-tidy-buffer' command. [C-c C-q t] is now bound to +;; this; [C-c C-q l] ("l" as in "lambda) is now the official binding +;; for `quack-toggle-lambda'. +;; * `quack-find-file' now recognizes PLT `dynamic-require' form. +;; * Fix to make `quack-looking-at-backward' preserve match data. +;; * Fix for benign bug in `quack-parent-sexp-search'. +;; +;; Version 0.9 (2002-09-04) +;; * Quack now works under XEmacs 21, except no menus are currently +;; defined (that will come in a later version) and block comments +;; aren't fontified. +;; * `quack-toggle-lambda' command toggles a `define' form between +;; explicit and implicit `lambda' syntax. +;; * `quack-dired-pltcollect' feature prompts for a PLT collection name +;; and creates a Dired on the collection. +;; * `)' and `]' keys are bound to insert a closing character that +;; agrees with the opening character of the sexp. +;; * Nested `#|' comment blocks are now fontified mostly correctly +;; under GNU Emacs 21. +;; * Fix to `quack-parent-sexp-search'. +;; * Fix for PLT manual keywords lookup under Emacs 20. +;; * `quack-manuals' URLs for assorted implementation manuals now point +;; to canonical Web copies. +;; * No longer warns about PLT manual keywords file found without HTML. +;; * `find-file' key bindings are automatically remapped to +;; `quack-find-file' in Scheme buffers. +;; * Both PLT-style and Emacs-style fontification now work with the +;; `noweb-mode' package. Tested under GNU Emacs 21 with +;; Debian `nowebm' package version 2.10c-1. +;; * Added to `quack-emacsish-keywords-to-fontify'. +;; * Disabled fontification of named `let'. +;; * Renamed "collect" in PLT identifiers to "pltcollect". +;; * `auto-mode-alist' set more aggressively. +;; +;; Version 0.8 (2002-08-25) +;; * PLT package file viewing mode. This is mainly used to easily +;; inspect a ".plt" package before installing it via DrScheme or +;; "setup-plt". +;; * No longer warns about `font-lock-keywords' when `noweb-mode' +;; package is installed. +;; +;; Version 0.7 (2002-08-22) +;; * Now works on GNU Emacs 20 (though people are still encouraged to +;; upgrade to GNU Emacs 21 if they are able). +;; * `quack-manuals' now includes MIT Scheme and Chicken manuals +;; (currently where Debian GNU/Linux puts them). +;; * `quack-view-srfi' command. +;; * Named-`let' name is fontified like a PLTish definition name. +;; * `define-record' and `define-opt' fontified. +;; * Scheme Mode is forced in `auto-mode-alist' for ".sch" files. +;; * Fix to `quack-backward-sexp'. +;; * `quack-warning' messages get your attention. +;; * `quack-pltrequire-at-point-data-1' search depth limited. +;; +;; Version 0.6 (2002-08-20) +;; * `quack-find-file' now supports multi-line PLT `require' forms. +;; * When `emacs-w3m' is used, the keys "[", "]", and "t" are bound to +;; navigate through PLT manuals like in Info mode. +;; * Names highlighted in PLT-style fontification of `defmacro', +;; `defmacro-public', `defsyntax'. +;; * Advised `run-scheme' no longer prompts when there is already a +;; running Scheme. +;; * "csi" (Chicken interpreter) added to `quack-programs' default. +;; * Forces `auto-mode-alist' for ".scm" files to `scheme-mode' +;; (two can play at that game, `bee-mode'!). +;; * To-do comments moved from the top of the file to throughout code. +;; +;; Version 0.5 (2002-08-15) +;; * New `quack-find-file' permits quick navigation to files indicated +;; by a PLT Scheme `require' form under the point. Currently only +;; works when the "(require" string is on the same line as point. +;; * Improved PLT-style fontification. Most noticeable difference is +;; that names in many definition forms are boldfaced. See +;; `quack-pltish-fontify-definition-names-p' option. +;; * `quack-collects-alist' added. +;; * "~/plt/" has been removed from `quack-collect-dirs' default. +;; * Unnecessary syntax table settings have been removed. +;; * Reduced memory usage in some cases, via explicit GC calls. +;; +;; Version 0.4 (2002-08-07) +;; * Functionality adapted from author's `giguile.el' package: +;; - Enhanced `run-scheme' behavior. `quack-run-mzscheme', +;; `quack-run-mred', and `quack-remove-run-scheme-menu-item-p' +;; are obsolete. +;; - Enhanced `switch-to-scheme' behavior. +;; - Options menu. +;; - Indent rules for a few Guile-isms. +;; * Inferior Scheme Mode now uses the preferred fontification method. +;; * Now uses the PLT-bundled version of R5RS manual, which permits +;; keyword searching. +;; * `quack-banner-face' for the MzScheme/MrEd banner in REPL buffer. +;; * This code includes a start on toolbars and XEmacs21 portability, +;; but neither feature is yet functional. +;; +;; Version 0.3 (2002-08-01) +;; * PLT-style fontification added, except for quoted lists. Emacs- +;; style fontification still available; see `quack-fontify-style'. +;; * `emacs-w3m' package support for lightweight viewing of PLT manuals +;; in Emacs window. If you install the `emacs-w3m' package, then you +;; can change the new `quack-browse-url-browser-function' option to +;; use it. +;; * Quack menu items added to Scheme Mode menu. "Run Scheme" item +;; is removed by default; see `quack-remove-run-scheme-menu-item-p'. +;; * MrEd REPL supported with `quack-run-mred'. +;; * Better default for `quack-collect-dirs'. +;; * More `scheme-indent-function' settings. +;; * Bugfix for `quack-prompt-for-kwmatch-choice'. +;; * Bugfix for font-lock keywords getting set too early. +;; * Now byte-compiles without warnings/errors. +;; +;; Version 0.2 (2002-07-28) +;; * Manual keywords lookup. +;; * Other minor changes. +;; +;; Version 0.1 (2002-07-18) +;; * Initial release. + +;; ADMONISHMENT TO IMPRESSIONABLE YOUNG SCHEME STUDENTS: +;; +;; Quack should by no means be construed as a model of good programming, +;; much less of good software engineering. Emacs is by nature a complex +;; system of interacting kludges. To get Emacs to do useful new things is +;; to artfully weave one's extensions into a rich tapestry of sticky duct +;; tape. Also, Quack usually only got hacked on when I was stuck in a busy +;; lobby for an hour with a laptop and unable to do real work. + +;;; Code: + +;; Dependencies: + +(require 'advice) +(require 'cmuscheme) +(require 'compile) +(require 'custom) +(require 'easymenu) +(require 'font-lock) +(require 'scheme) +(require 'thingatpt) + +(unless (fboundp 'customize-save-variable) + (autoload 'customize-save-variable "cus-edit")) + +;; Custom Variables: + +(defgroup quack nil + "Enhanced support for editing and running Scheme code." + :group 'scheme + :prefix "quack-" + :link '(url-link "http://www.neilvandyke.org/quack/")) + +(defcustom quack-dir "~/.quack" + "*Directory where Quack stores various persistent data in file format." + :type 'string + :group 'quack) + +(defcustom quack-scheme-mode-keymap-prefix "\C-c\C-q" + "*Keymap prefix string for `quack-scheme-mode-keymap'. + +One of the nice things about having C-q in the prefix is that it is unlikely to +be already be in use, due to the historical reality of software flow control +\(and the fact that it is hard to type). If your C-q doesn't seem to be going +through, then you have several options: disable flow control (if it is safe to +do so), change the value of this variable, or see the Emacs documentation for +`enable-flow-control-on'." + :type 'string + :group 'quack) + +(defcustom quack-remap-find-file-bindings-p t + "Whether to remap `find-file' key bindings to `quack-find-file'. +The local map in Scheme Mode and Inferior Scheme Mode buffers is used." + :type 'boolean + :group 'quack) + +(defcustom quack-global-menu-p t + "*Whether to have a \"Quack\" menu always on the menu bar." + :type 'boolean :group 'quack) + +(defcustom quack-tabs-are-evil-p t + "*Whether Quack should avoid use of Tab characters in indentation." + :type 'boolean + :group 'quack) + +(defcustom quack-browse-url-browser-function nil + "*Optional override for `browse-url-browser-function'. + +If non-nil, overrides that variable for URLs viewed by `quack-browse-url'." + :type '(choice (const :tag "Do Not Override" nil) + (function :tag "Function") + (alist :tag "Regexp/Function Association List" + :key-type regexp :value-type function)) + :group 'quack) + +(defcustom quack-manuals ; TODO: Options menu. + + ;; TODO: If we make this so users are likely to want to override parts of it, + ;; then introduce `quack-manuals-defaults' variable with this in it, + ;; and let users edit `quack-manuals-overrides' which are keyed on the + ;; ID symbol. + + ;; TODO: Have a way for finding docs on the local filesystem, and/or + ;; permitting a user to easily specify location. + + ;; TODO: Provide a way of specifying alternative access means so that, for + ;; example, we can look for R5RS first in locally-installed PLT + ;; collection, then in one of various non-PLT directories it might be + ;; mirrored, then remote PLT copy using local PLT keywords file, then + ;; the canonical HTML copy on the Web... Maybe even permit Info + ;; format. Let's just reinvent the Web, while we're at it. + + '( + + (r5rs "R5RS" + "http://www.schemers.org/Documents/Standards/R5RS/HTML/" + nil) + + (bigloo + "Bigloo" + "http://www-sop.inria.fr/mimosa/fp/Bigloo/doc/bigloo.html" + ;;"file:///usr/share/doc/bigloo/manuals/bigloo.html" + nil) + + (chez + "Chez Scheme User's Guide" + "http://www.scheme.com/csug/index.html" + nil) + + (chicken + "Chicken User's Manual" + "http://www.call-with-current-continuation.org/manual/manual.html" + ;;"file:///usr/share/doc/chicken/manual.html" + nil) + + (gambit + "Gambit-C home page" + "http://www.iro.umontreal.ca/~gambit/") + + (gauche + "Gauche Reference Manual" + "http://www.shiro.dreamhost.com/scheme/gauche/man/gauche-refe.html" + nil) + + (mitgnu-ref + "MIT/GNU Scheme Reference" + "http://www.gnu.org/software/mit-scheme/documentation/scheme.html" + ;;"http://www.swiss.ai.mit.edu/projects/scheme/documentation/scheme.html" + + ;;"file:///usr/share/doc/mit-scheme/html/scheme.html" + nil) + + (mitgnu-user + "MIT/GNU Scheme User's Manual" + "http://www.gnu.org/software/mit-scheme/documentation/user.html" + ;;"http://www.swiss.ai.mit.edu/projects/scheme/documentation/user.html" + ;;"file:///usr/share/doc/mit-scheme/html/user.html" + nil) + + (mitgnu-sos + "MIT/GNU Scheme SOS Reference Manual" + "http://www.gnu.org/software/mit-scheme/documentation/sos.html" + ;;"http://www.swiss.ai.mit.edu/projects/scheme/documentation/sos.html" + ;;"file:///usr/share/doc/mit-scheme/html/sos.html" + nil) + + (plt-mzscheme "PLT MzScheme: Language Manual" plt t) + (plt-mzlib "PLT MzLib: Libraries Manual" plt t) + (plt-mred "PLT MrEd: Graphical Toolbox Manual" plt t) + (plt-framework "PLT Framework: GUI Application Framework" plt t) + (plt-drscheme "PLT DrScheme: Programming Environment Manual" plt nil) + (plt-insidemz "PLT Inside PLT MzScheme" plt nil) + (plt-tools "PLT Tools: DrScheme Extension Manual" plt nil) + (plt-mzc "PLT mzc: MzScheme Compiler Manual" plt t) + (plt-r5rs "PLT R5RS" plt t) + + (scsh + "Scsh Reference Manual" + "http://www.scsh.net/docu/html/man-Z-H-1.html" + ;;"file:///usr/share/doc/scsh-doc/scsh-manual/man-Z-H-1.html" + nil) + + (sisc + "SISC for Seasoned Schemers" + "http://sisc.sourceforge.net/manual/html/" + nil) + + (htdp "How to Design Programs" + "http://www.htdp.org/" + nil) + (htus "How to Use Scheme" + "http://www.htus.org/" + nil) + (t-y-scheme "Teach Yourself Scheme in Fixnum Days" + "http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html" + nil) + (tspl "Scheme Programming Language (Dybvig)" + "http://www.scheme.com/tspl/" + nil) + (sicp "Structure and Interpretation of Computer Programs" + "http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-4.html" + nil) + (slib "SLIB" + "http://swissnet.ai.mit.edu/~jaffer/SLIB.html" + nil) + (faq "Scheme Frequently Asked Questions" + "http://www.schemers.org/Documents/FAQ/" + nil)) + "*List of specifications of manuals that can be viewed. + +Each manual specification is a list of four elements: + + (SYMBOL TITLE LOCATION USE-KEYWORDS-P) + +where SYMBOL is a short symbol that identifies the manual, TITLE is a string, +LOCATION is either a string with the URL of the manual or the symbol `plt', +and USE-KEYWORDS-P is `t' or `nil'. + +If LOCATION is `plt', then Quack treats it as a PLT bundled manual, looking for +the HTML and keyword files in `quack-pltcollect-dirs', and optionally providing +keyword lookup if USE-KEYWORDS-P is `t'. Remote canonical copies of the +manuals will be used if local copies cannot be found. + +If LOCATION is a URL, then USE-KEYWORDS-P must be `nil'." + :type '(repeat (list (symbol :tag "Identifying Symbol") + (string :tag "Title String") + (choice :tag "Location" + (string :tag "URL") + (const :tag "PLT Bundled Manual" plt)) + (boolean :tag "Use Keywords?"))) + :group 'quack) + +(defcustom quack-local-keywords-for-remote-manuals-p t + "*If non-nil, Quack will use canonical remote Web URLs when there is a local +keyword file for a PLT manual but no local HTML files. (This feature was +prompted by the Debian 200.2-3 package for MzScheme, which includes keyword +files but not HTML files.) If the symbol `always', then Quack will always use +remote Web manuals for keywords lookup, even if local HTML files exist, as a +workaround for how some versions of Emacs interact with some versions of +Microsoft Windows \(inexplicably discarding the fragment identifier from `file' +scheme URI\)." + :type '(choice (const :tag "Permit" t) + (const :tag "Forbid" nil) + (const :tag "Always" always)) + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-srfi-master-base-url "http://srfi.schemers.org/" + ;; Note: Intentionally not letting user change this through the options menu. + "*The base URL for the master SRFI Web pages. +The SRFI index files should be immediately beneath this." + :type 'string + :group 'quack) + +(defcustom quack-pltcollect-dirs + (let ((good '())) + (mapcar (function (lambda (dir) + (and dir + (not (assoc dir good)) + (file-directory-p dir) + (setq good (nconc good (list dir)))))) + `(,@(let ((v (getenv "PLTCOLLECTS"))) + (and v (split-string v ":"))) + ,(let ((v (getenv "PLTHOME"))) + (and v (expand-file-name "collects" v))) + ,@(mapcar 'expand-file-name + '("/usr/lib/plt/collects" + "/usr/local/lib/plt/collects")))) + good) + "*PLT collection directories. +Listed in order of priority." + :type '(repeat directory) + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-fontify-style 'plt + "*Which font-lock fontification style to use. + +If symbol `plt', an approximation of PLT DrScheme 200 Check Syntax +fontification will be used. If symbol `emacs', then fontification in the style +of GNU Emacs' Scheme Mode with extensions will be used. If nil, then Quack +will not override the default Scheme Mode fontification." + :type '(choice (const :tag "PLT Style" plt) + (const :tag "Extended GNU Emacs Style" emacs) + (const :tag "Emacs Default" nil)) + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-pltish-fontify-definition-names-p t + "*If non-nil, fontify names in definition forms for PLT-style fontification. + +This only has effect when `quack-fontify-style' is `plt'." + :type 'boolean + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-pltish-fontify-keywords-p t + ;; TODO: Rename this from "keywords" to "syntax-keywords", here, and in for + ;; face names. + "*If non-nil, fontify keywords in PLT-style fontification. + +This only has effect when `quack-fontify-style' is `plt'." + :type 'boolean + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-pltish-keywords-to-fontify + ;; TODO: These are currently R5RS and some SRFI special syntax plus a bunch + ;; of PLT, especially PLT 200 class.ss, and some "define-"* variants from + ;; various dialects, plus some Racket 5.0.2... The dumbness of this kind of + ;; highlighting without regard to context is not really satisfactory. + '( + + "and" "begin" "begin-for-syntax" + "begin0" "c-declare" "c-lambda" "case" "case-lambda" "class" + "class*" "class*/names" "class100" "class100*" "compound-unit/sig" "cond" + "cond-expand" "define" "define-class" "define-compound-unit" + "define-const-structure" + "define-constant" "define-embedded" "define-entry-point" "define-external" + "define-for-syntax" "define-foreign-record" "define-foreign-type" + "define-foreign-variable" "define-generic" "define-generic-procedure" + "define-inline" "define-location" "define-macro" "define-method" + "define-module" "define-opt" "define-public" "define-reader-ctor" + "define-record" "define-record-printer" "define-record-type" + "define-signature" + "define-splicing-syntax-class" + "define-struct" + "define-structure" + "define-syntax" + "define-syntax-class" + "define-syntax-set" "define-values" "define-values-for-syntax" + "define-values/invoke-unit/infer" + "define-values/invoke-unit/sig" "define/contract" "define/override" + "define/private" "define/public" "define/kw" + "delay" "do" "else" "exit-handler" "field" + "if" "import" "inherit" "inherit-field" "init" "init-field" "init-rest" + "instantiate" "interface" "lambda" "lambda/kw" "let" "let*" "let*-values" + "let+" + "let-syntax" "let-values" "let/ec" "letrec" "letrec-values" "letrec-syntax" + "match-lambda" "match-lambda*" "match-let" "match-let*" "match-letrec" + "match-define" "mixin" "module" "module*" "module+" "opt-lambda" "or" "override" "override*" + "namespace-variable-bind/invoke-unit/sig" "parameterize" "parameterize*" + "parameterize-break" "private" + "private*" "protect" "provide" "provide-signature-elements" + "provide/contract" "public" "public*" "quasiquote" + "quasisyntax" "quasisyntax/loc" "quote" "receive" + "rename" "require" "require-for-syntax" "send" "send*" "set!" "set!-values" + "signature->symbols" "super-instantiate" "syntax" "syntax/loc" + "syntax-case" "syntax-case*" "syntax-error" "syntax-parse" "syntax-rules" + "unit/sig" + "unless" "unquote" "unquote-splicing" "when" "with-handlers" "with-method" + "with-syntax" + "define-type-alias" + "define-struct:" + "define:" + "let:" + "letrec:" + "let*:" + "lambda:" + "plambda:" + "case-lambda:" + "pcase-lambda:" + "require/typed" + "require/opaque-type" + "require-typed-struct" + "struct" + "inst" + "ann" + + ) + "*Scheme keywords to fontify when `quack-fontify-style' is `plt'." + :type '(repeat string) + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-emacsish-keywords-to-fontify + '("and" "begin" "begin0" "call-with-current-continuation" + "call-with-input-file" "call-with-output-file" "call/cc" "case" + "case-lambda" "class" "cond" "delay" "do" "else" "exit-handler" "field" + "for-each" "if" "import" "inherit" "init-field" "interface" "lambda" "let" + "let*" "let*-values" "let-values" "let-syntax" "let/ec" "letrec" + "letrec-syntax" "map" "mixin" "opt-lambda" "or" "override" "protect" + "provide" "public" "rename" "require" "require-for-syntax" "syntax" + "syntax-case" "syntax-error" "syntax-rules" "unit/sig" "unless" "when" + "with-syntax") + "*Scheme keywords to fontify when `quack-fontify-style' is `emacs'." + :type '(repeat string) + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-fontify-threesemi-p t + "*Whether three-semicolon comments should be fontified differently." + :type 'boolean + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-pretty-lambda-p nil + "*Whether Quack should display \"lambda\" as the lambda character. + +`quack-fontify-style' must be `plt'. Only supported under GNU Emacs version +21\; not under XEmacs or older GNU Emacs. + +Note: Pretty lambda requires that suitable iso8859-7 fonts be available. Under +Debian/GNU Linux, for example, these can be downloaded and installed with the +shell command \"apt-get install 'xfonts-greek-*'\". If iso8859-7 fonts are +unavailable for your system, please notify the Quack author." + :type 'boolean + :group 'quack + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-programs + '("bigloo" "csi" "csi -hygienic" "gosh" "gracket" "gsi" + "gsi ~~/syntax-case.scm -" "guile" "kawa" "mit-scheme" "racket" + "racket -il typed/racket" "rs" "scheme" "scheme48" "scsh" "sisc" "stklos" + "sxi") + "List of Scheme interpreter programs that can be used with `run-scheme'. + +These names will be accessible via completion when `run-scheme' prompts for +which program to run." + :group 'quack + :type '(repeat string) + :set 'quack-custom-set + :initialize 'custom-initialize-default) + +(defcustom quack-default-program "mzscheme" + "Default Scheme interpreter program to use with `run-scheme'." + :group 'quack + :type 'string) + +(defcustom quack-run-scheme-always-prompts-p t + "`run-scheme' should always prompt for which program to run. + +If nil, `run-scheme' will always use `quack-default-program' when invoked +interactively without a prefix argument; this is closest to the behavior of the +`cmuscheme' package." + :group 'quack + :type 'boolean) + +(defcustom quack-run-scheme-prompt-defaults-to-last-p t + "If non-nil, `run-scheme' prompt should default to the last program run." + :group 'quack + :type 'boolean) + +(defcustom quack-remember-new-programs-p t + "Programs are added to `quack-programs' automatically." + :group 'gigule + :type 'boolean) + +(defcustom quack-switch-to-scheme-method 'other-window + "Method to use for choosing a window and frame for the process buffer. + +One of three symbols: +`other-window' will split display in a different window in the current frame, +splitting the current window if necessary. +`own-frame' will display the process buffer in its own frame. +`cmuscheme' will use the normal behavior of the `cmuscheme' package." + :group 'quack + :type '(choice (const :tag "Other Window" other-window) + (const :tag "Own Frame" own-frame) + (const :tag "Cmuscheme Behavior" cmuscheme))) + +(defcustom quack-warp-pointer-to-frame-p t + "Warp mouse pointer to frame with Scheme process buffer. + +When `quack-switch-to-scheme-method' is `own-frame', `switch-to-scheme' will +warp the mouse pointer to the frame displaying the Scheme process buffer." + :group 'quack + :type 'boolean) + +(defcustom quack-newline-behavior 'newline-indent + "*Behavior of the RET key in Scheme-Mode buffers. The value is one of three +symbols: `newline' inserts a normal newline, `newline-indent' \(the default\) +inserts a newline and leaves the point properly indented on the new line, and +`indent-newline-indent' indents the current line before inserting a newline and +indenting the new one." + :type '(choice (const 'newline) + (const 'newline-indent) + (const 'indent-newline-indent)) + :group 'quack) + +(defcustom quack-smart-open-paren-p nil + "The `[' can be used to insert `(' characters. +Actually, this just makes the `(' and '[' keys both insert `(', unless given a +prefix argument. This makes typing parens easier on typical keyboards for +which `(' requires a shift modifier but `[' does not. A later version of Quack +might add actual \"smart\" support for automatic PLT-esque insertion of `[' +instead of `(' in some syntactic contexts." + :group 'quack + :type 'boolean) + +(defcustom quack-options-persist-p t + "Option menu settings and programs persist using the `custom' facility. + +Note that the value of this option itself cannot be set persistently via the +option menu -- you must use the `customize' interface or set it manually in an +Emacs startup file. This is by design, to avoid the risk of users accidentally +disabling their ability to set persistent options via the option menu." + :group 'quack + :type 'boolean) + +(defcustom quack-quiet-warnings-p t ; TODO: Options menu. + "Warning messages are quiet and subtle." + :group 'quack + :type 'boolean) + +(defconst quack-pltish-comment-face 'quack-pltish-comment-face) +(defface quack-pltish-comment-face + '((((class color) (background light)) (:foreground "cyan4")) + (((class color) (background dark)) (:foreground "cyan1")) + (t (:slant italic))) + "Face used for comments when `quack-fontify-style' is `plt'." + :group 'quack) + +(defconst quack-pltish-selfeval-face 'quack-pltish-selfeval-face) +(defface quack-pltish-selfeval-face + '((((class color) (background light)) (:foreground "green4")) + (((class color) (background dark)) (:foreground "green2")) + (t ())) + "Face used for self-evaluating forms when `quack-fontify-style' is `plt'." + :group 'quack) + +(defconst quack-pltish-paren-face 'quack-pltish-paren-face) +(defface quack-pltish-paren-face + '((((class color) (background light)) (:foreground "red3")) + (((class color) (background dark)) (:foreground "red1")) + (((class grayscale)) (:foreground "gray")) + (t ())) + "Face used for parentheses when `quack-fontify-style' is `plt'." + :group 'quack) + +(defconst quack-pltish-colon-keyword-face 'quack-pltish-colon-keyword-face) +(defface quack-pltish-colon-keyword-face + '((t (:bold t :foreground "gray50"))) + "Face used for `#:' keywords when `quack-fontify-style' is `plt'. +Note that this isn't based on anything in PLT." + :group 'quack) + +(defconst quack-pltish-paren-face 'quack-pltish-paren-face) +(defface quack-pltish-paren-face + '((((class color) (background light)) (:foreground "red3")) + (((class color) (background dark)) (:foreground "red1")) + (((class grayscale)) (:foreground "gray")) + (t ())) + "Face used for parentheses when `quack-fontify-style' is `plt'." + :group 'quack) + +(defconst quack-banner-face 'quack-banner-face) +(defface quack-banner-face + '((t (:family "Helvetica"))) + "Face used in the inferior process buffer for the MzScheme banner. + +Currently only takes effect when `quack-fontify-style' is `plt'." + :group 'quack) + +(defconst quack-pltish-defn-face 'quack-pltish-defn-face) +(defface quack-pltish-defn-face + '((((class color) (background light)) (:bold t :foreground "blue3")) + (((class color) (background dark)) (:bold t :foreground "blue1")) + (t (:bold t :underline t))) + "Face used for names in toplevel definitions. + +For PLT-style when `quack-pltish-fontify-definition-names-p' is non-nil." + :group 'quack) + +(defconst quack-pltish-class-defn-face 'quack-pltish-class-defn-face) +(defface quack-pltish-class-defn-face + '((((class color) (background light)) + (:foreground "purple3" :inherit quack-pltish-defn-face)) + (((class color) (background dark)) + (:foreground "purple1" :inherit quack-pltish-defn-face)) + (t (:inherit quack-pltish-defn-face))) + "Face used for class names in toplevel definitions. + +For PLT-style when `quack-pltish-fontify-definition-names-p' is non-nil." + :group 'quack) + +(defconst quack-pltish-module-defn-face 'quack-pltish-module-defn-face) +(defface quack-pltish-module-defn-face + '((((class color) (background light)) + (:foreground "purple3" :inherit quack-pltish-defn-face)) + (((class color) (background dark)) + (:foreground "purple1" :inherit quack-pltish-defn-face)) + (t (:inherit quack-pltish-defn-face))) + "Face used for module names in toplevel definitions. + +For PLT-style when `quack-pltish-fontify-definition-names-p' is non-nil." + :group 'quack) + +(defconst quack-pltish-keyword-face 'quack-pltish-keyword-face) +(defface quack-pltish-keyword-face + '((t (:bold t))) + "Face used for keywords in PLT Style fontification. + +For PLT-style when `quack-pltish-fontify-keywords-p' is non-nil." + :group 'quack) + +(defconst quack-threesemi-semi-face 'quack-threesemi-semi-face) +(defface quack-threesemi-semi-face + '((((class color) (background light)) + (:foreground "#a0ffff":background "#c0ffff")) + (((class color) (background dark)) + (:foreground "cyan2" :background "cyan4")) + (t (:slant italic))) + "Face used for `;;;' semicolons when `quack-fontify-threesemi-p' is non-nil." + :group 'quack) + +(defconst quack-threesemi-text-face 'quack-threesemi-text-face) +(defface quack-threesemi-text-face + '((((class color) (background light)) + (:foreground "cyan4" :background "#c0ffff")) + (((class color) (background dark)) + (:foreground "white" :background "cyan4")) + (t (:slant italic))) + "Face used for `;;;' text when `quack-fontify-threesemi-p' is non-nil." + :group 'quack) + +(defconst quack-threesemi-h1-face 'quack-threesemi-h1-face) +(defface quack-threesemi-h1-face + '((t (:bold t :family "Helvetica" :height 1.4 :size "20pt"))) + "Face used for H1 headings in `;;;' text." + :group 'quack) + +(defconst quack-threesemi-h2-face 'quack-threesemi-h2-face) +(defface quack-threesemi-h2-face + '((t (:bold t :family "Helvetica" :height 1.2 :size "16pt"))) + "Face used for H2 headings in `;;;' text." + :group 'quack) + +(defconst quack-threesemi-h3-face 'quack-threesemi-h3-face) +(defface quack-threesemi-h3-face + '((t (:bold t :family "Helvetica"))) + "Face used for H3 headings in `;;;' text." + :group 'quack) + +(defconst quack-pltfile-prologue-face 'quack-pltfile-prologue-face) +(defface quack-pltfile-prologue-face + '((((class color)) (:foreground "black" :background "gray66")) + (((class grayscale)) (:foreground "black" :background "gray66")) + (t ())) + "Face used for the prologue in a decoded PLT package buffer." + :group 'quack) + +(defconst quack-pltfile-dir-face 'quack-pltfile-dir-face) +(defface quack-pltfile-dir-face + '((((class color)) (:bold t :foreground "white" :background "gray33" + :family "Helvetica" :height 1.2 :size "20pt")) + (((class grayscale)) (:bold t :foreground "white" :background "gray33" + :family "Helvetica" :height 1.2 :size "20pt")) + (t (:bold t :inverse-video t))) + "Face used for directory headers in a decoded PLT package buffer." + :group 'quack) + +(defconst quack-pltfile-file-face 'quack-pltfile-file-face) +(defface quack-pltfile-file-face + '((((class color)) (:bold t :foreground "black" :background "gray66" + :family "Helvetica" :height 1.2 :size "20pt")) + (((class grayscale)) (:bold t :foreground "black" :background "gray66" + :family "Helvetica" :height 1.2 :size "20pt")) + (t (:bold t :inverse-video t))) + "Face used for file headers in a decoded PLT package buffer." + :group 'quack) + +(defconst quack-about-title-face 'quack-about-title-face) +(defface quack-about-title-face + '((((class color) (background light)) + (:bold t :family "Helvetica" :foreground "#008000" + :height 2.0 :size "24pt")) + (((class color) (background dark)) + (:bold t :family "Helvetica" :foreground "#00f000" + :height 2.0 :size "24pt")) + (t (:bold t :family "Helvetica" + :height 2.0 :size "24pt"))) + "Face used for Quack name in About Quack." + :group 'quack) + +(defconst quack-about-face 'quack-about-face) +(defface quack-about-face + '((t (:family "Helvetica"))) + "Face used for the body text in About Quack." + :group 'quack) + +(defconst quack-smallprint-face 'quack-smallprint-face) +(defface quack-smallprint-face + '((t (:family "Courier" :height 0.8 :size "8pt"))) + "Face used for the \"small print\" in About Quack." + :group 'quack) + +;; Compatibility/Portability Misc. Kludges: + +;; Note: Some compatibility gotchas found while porting Quack that aren't +;; addressed by macros and functions: +;; +;; * `defface' in Emacs 21 supports ":weight bold", but this is silently +;; ignored under older Emacsen, so ":bold t" must be used instead. +;; +;; * Third argument of `detect-coding-region' is different in Emacs 21 and +;; XEmacs 21, so only use the first two args. +;; +;; * Under XEmacs 21, characters are `equal' but not `eq' to their integer +;; ASCII values +;; +;; * GNU Emacs 21 faces have `:height' property that is either absolute +;; decipoints or relative scaling factor. XEmacs 21 faces instead have +;; `:size' property, which appears to be absolute point or mm size. +;; +;; * XEmacs 21 text properties appear to be front-sticky, and there did not +;; seem to be any documentation references to stickiness. +;; +;; * XEmacs 21 `local-variable-p' has second argument mandatory. +;; +;; * XEmacs 21 does not display submenu labels at all unless the submenu has +;; content. For inactive submenus, an empty string suffices for content. +;; +;; * XEmacs 21 doesn't support composite characters (which we use for very +;; nice pretty lambda under GNU Emacs). + +(eval-and-compile + (defvar quack-xemacs-p (eval '(and (boundp 'running-xemacs) running-xemacs))) + (defvar quack-gnuemacs-p (not quack-xemacs-p))) + +(defmacro quack-when-xemacs (&rest args) + (if quack-xemacs-p (cons 'progn args) 'nil)) + +(defmacro quack-when-gnuemacs (&rest args) + (if quack-gnuemacs-p (cons 'progn args) 'nil)) + +(defmacro quack-define-key-after (keymap key definition &optional after) + (if quack-gnuemacs-p + `(define-key-after ,keymap ,key ,definition ,after) + `(define-key ,keymap ,key (prog1 ,definition ,after)))) + +(defmacro quack-delete-horizontal-space (&rest args) + (if (and quack-gnuemacs-p (>= emacs-major-version 21)) + `(delete-horizontal-space ,@args) + `(delete-horizontal-space))) + +(defmacro quack-match-string-no-properties (&rest args) + `(,(if quack-xemacs-p 'match-string 'match-string-no-properties) ,@args)) + +(defmacro quack-menufilter-return (name form) + (if (= emacs-major-version 20) + ;; Note: This isn't working in Emacs 20. Menu displays now but actions + ;; are not executed. No answer to test case posted to comp.emacs + ;; and then to gnu.emacs.help. In response to my subsequent bug + ;; report against Emacs, RMS says that, if this is indeed a bug, + ;; then nothing will be done, since 20 is no longer supported. I'm + ;; going to let this quietly not work unless someone emails me that + ;; they're actually using Emacs 20. + `(easy-menu-filter-return (easy-menu-create-menu ,name ,form)) + form)) + +(defmacro quack-propertize (obj &rest props) + (if (and quack-gnuemacs-p (>= emacs-major-version 21)) + `(propertize ,obj ,@props) + (let ((obj-var 'quack-propertize-G-obj)) + `(let ((,obj-var ,obj)) + (add-text-properties 0 (length ,obj-var) (list ,@props) ,obj-var) + ,obj-var)))) + +(eval-when-compile + (when quack-xemacs-p + (defvar inhibit-eol-conversion) + (defvar minibuffer-allow-text-properties))) + +;; Compatibility/Portability Hash Table: + +(eval-and-compile + (defmacro quack-make-hash-table (&rest args) + `(,(if (>= emacs-major-version 21) + 'make-hash-table + 'quack-fake-make-hash-table) + ,@args))) + +(defmacro quack-puthash (key value table) + (list (if (>= emacs-major-version 21) 'puthash 'quack-fake-puthash) + key value table)) + +(defmacro quack-gethash (key table &optional dflt) + (list (if (>= emacs-major-version 21) 'gethash 'quack-fake-gethash) + key table dflt)) + +(defun quack-fake-make-hash-table (&rest args) + ;; TODO: Parse the keyword args and make this do 'assoc or 'assq, as + ;; appropriate. Currently, this package only needs 'assoc. + (vector 'assoc '())) + +(defun quack-fake-puthash (key value table) + (let ((pair (funcall (aref table 0) key (aref table 1)))) + (if pair + (setcdr pair value) + (aset table 1 (cons (cons key value) (aref table 1)))))) + +(defun quack-fake-gethash (key table &optional dflt) + (let ((pair (funcall (aref table 0) key (aref table 1)))) + (if pair (cdr pair) dflt))) + +;; Compatibility/Portability Overlays/Extents: + +;; TODO: Maybe get rid of overlays (and the XEmacs extent kludge), and just use +;; text properties instead. + +(defmacro quack-make-face-ovlext (beg end face) + (if quack-xemacs-p + `(set-extent-property (make-extent ,beg ,end) 'face ,face) + `(overlay-put (make-overlay ,beg ,end) 'face ,face))) + +(defmacro quack-make-hiding-ovlext (beg end) + (if quack-xemacs-p + `(set-extent-property (make-extent ,beg ,end) 'invisible t) + `(overlay-put (make-overlay ,beg ,end) 'category 'quack-hiding-ovlcat))) + +;; Messages, Errors, Warnings: + +(defmacro quack-activity (what &rest body) + (let ((var-what (make-symbol "quack-activity-G-what"))) + `(let ((,var-what ,what)) + (message (concat ,var-what "...")) + (prog1 (progn ,@body) + (message (concat ,var-what "...done")))))) + +(defun quack-internal-error (&optional format &rest args) + (if format + (apply 'error (concat "Quack Internal Error: " format) args) + (error "Quack Internal Error."))) + +(defun quack-warning (format &rest args) + (apply 'message (concat "Quack Warning: " format) args) + (unless quack-quiet-warnings-p + (beep) + (sleep-for 1))) + +;; Regular Expressions: + +(defun quack-re-alt (&rest regexps) + (concat "\\(" (mapconcat 'identity regexps "\\|") "\\)")) + +(defun quack-re-optional (&rest regexps) + (concat "\\(" + (apply 'concat regexps) + "\\)?")) + +;; Misc.: + +;; (defun quack-abbreviate-file-name (file-name) +;; (let ((directory-abbrev-alist '())) +;; (abbreviate-file-name file-name))) + +(defun quack-delete-file-if-can (file) + (condition-case nil (delete-file file) (error nil))) + +(defun quack-expand-file-name (name-or-names &optional directory) + ;; Note: This only works for systems with Unix-like filenames. + (expand-file-name (if (listp name-or-names) + (mapconcat 'identity name-or-names "/") + name-or-names) + directory)) + +(defun quack-kill-current-buffer () + (interactive) + (kill-buffer (current-buffer))) + +(defun quack-line-at-point () + (save-excursion + (buffer-substring-no-properties + (progn (beginning-of-line) (point)) + (progn (end-of-line) (point))))) + +(defun quack-looking-at-backward (re &optional limit) + (save-excursion + (save-restriction + (let ((start-pt (point))) + (narrow-to-region (point-min) (point)) + (and (re-search-backward re limit t) + (= (match-end 0) start-pt) + (match-beginning 0)))))) + +(defun quack-looking-at-close-paren-backward () + (save-match-data + (quack-looking-at-backward "[])][ \t\r\n\f]*"))) + +(defun quack-looking-at-open-paren-backward () + (save-match-data + (quack-looking-at-backward "[[(][ \t\r\n\f]*"))) + +(defun quack-make-directory (dir) + (setq dir (file-name-as-directory dir)) + (unless (file-directory-p dir) + (make-directory dir t))) + +(defun quack-make-directory-for-file (file) + (let ((dir (file-name-directory file))) + (when dir (quack-make-directory dir)))) + +(defun quack-propertize-bold (str) + (quack-propertize str 'face 'bold)) + +(defun quack-propertize-face (str face) + (quack-propertize str 'face face)) + +(defun quack-propertize-italic (str) + (quack-propertize str 'face 'italic)) + +(defun quack-sort-string-list-copy (lst) + (sort (copy-sequence lst) 'string<)) + +(defun quack-uncomment-region (beg end) + ;; TODO: Make a quack-toggle-commentout-region. + (interactive "r") + (comment-region beg end '(4))) + +(defun quack-without-side-whitespace (str) + ;; Copied from `padr-str-trim-ws' by author. + ;; + ;; TODO: Don't make an intermediate string. Use regexp match start position. + (save-match-data + (if (string-match "^[ \t\n\r]+" str) + (setq str (substring str (match-end 0)))) + (if (string-match "[ \t\n\r]+$" str) + (setq str (substring str 0 (match-beginning 0)))) + str)) + +;; Kludgey Sexp Buffer Operations: + +(defconst quack-backward-sexp-re + (concat "\\`" + (quack-re-alt "[^\";\\\\]" + "\\\\\\." + (concat "\"" + (quack-re-alt "[^\"\\\\]" + "\\\\\\.") + "*\"")) + "*\\([\"\\\\]\\)?")) + +(defun quack-backward-sexp () + ;; Returns non-nil iff point was in a string literal or comment. + (interactive) + (when (bobp) + (error "beginning of buffer")) + (save-match-data + (let* ((orig (point)) + (bol (progn (beginning-of-line) (point)))) + (if (string-match quack-backward-sexp-re + (buffer-substring-no-properties bol orig)) + (if (match-beginning 3) + ;; We're in what appears to be a comment or unterminated string + ;; literal (though might not be, due to multi-line string + ;; literals and block comments), so move point to the beginning. + (progn (goto-char (+ bol (match-beginning 3))) + t) + ;; We don't appear to be in a comment or string literal, so just + ;; let `backward-sexp' do its thing. + (goto-char orig) + (backward-sexp) + nil))))) + +(defun quack-parent-sexp-search (name-regexp &optional max-depth max-breadth) + (save-match-data + (save-excursion + (let ((max-depth (or max-depth 100)) + (max-breadth (or max-breadth 100)) + (orig-point (point)) + (found 'looking) + (depth 0) + (child-start nil)) + (while (and (eq found 'looking) (< depth max-depth)) + (condition-case nil + (let ((breadth 0)) + ;; Loop until we hit max breadth or error. + (while (< breadth max-breadth) + (when (and (quack-backward-sexp) (not child-start)) + (setq child-start (point))) + (setq breadth (1+ breadth))) + ;; We hit our max breadth without erroring, so set the found + ;; flag to indicate failure and then fall out of our loop. + (setq found nil)) + (error ; scan-error + ;; We probably hit the beginning of the enclosing sexp, and point + ;; should be on the first sexp, which will most often be the form + ;; name, so first check that there really is an open paren to our + ;; left, and then check if it matches our regexp. + (let ((paren-start (quack-looking-at-open-paren-backward))) + (if paren-start + ;; There is a paren, so check the name of the form. + (if (and (looking-at name-regexp) + (quack-not-symbol-char-at-point-p (match-end 0))) + ;; Found it, so set the result to a list (lexeme, lexeme + ;; end point, last nested child sexp start point, parent + ;; paren start point) and then fall out of our loop. + ;; Note that we return the original point if no child + ;; point was found, on the assumption that point was at + ;; the beginning of the child sexp (unless it was within + ;; the found form name, in which case child sexp start + ;; is nil). + (setq found (list (quack-match-string-no-properties 0) + (match-end 0) + (or child-start + (if (> orig-point (match-end 0)) + orig-point)) + paren-start)) + ;; This form name didn't match, so try to move up in the + ;; paren syntax (which will usually mean moving left one + ;; character). + (condition-case nil + (progn (up-list -1) + (setq child-start (point)) + (setq depth (1+ depth))) + (error ; scan-error + ;; We can't go up here, so set found flag to indicate + ;; failure and then fall out of the loop. + (setq found nil)))) + ;; There wasn't a paren, which means we hit a scan error for + ;; some reason other than being at the beginning of the sexp, + ;; so consider the search a failure + (setq found nil)))))) + (if (eq found 'looking) + nil + found))))) + +;; TODO: We really need a global definition of what are Scheme symbol +;; constituent characters (or a whole-symbol regexp)! + +(defun quack-not-symbol-char-at-point-p (pt) + ;; This is used to check for a symbol boundary point. + (save-match-data + (or (= pt (point-max)) + (if (string-match "[^-a-zA-Z0-9!+<=>$%&*./:@^_~]" + (buffer-substring-no-properties pt (1+ pt))) + t)))) + +;; String Constant Hashtable: + +(eval-and-compile + (if (< emacs-major-version 21) + + (defun quack-strconst (str) str) + + (defvar quack-strconst-hashtable + (if (>= emacs-major-version 21) + (quack-make-hash-table :test 'equal :size 1000))) + + (defun quack-strconst (str) + (unless (stringp str) + (error "Non-string object passed to quack-strconst: %s" str)) + (or (quack-gethash str quack-strconst-hashtable nil) + (quack-puthash str str quack-strconst-hashtable) + str)))) + +;; Web URLs: + +(defun quack-quote-url-substring (str &optional quote-slash-p always-new-p) + (save-match-data + (let ((regexp (if quote-slash-p "[^-_.A-Za-z0-9]" "[^-_.A-Za-z0-9/]")) + (subs '()) + (len (length str)) + (start 0)) + (while (and (> len start) + (string-match regexp str start)) + (let ((beg (match-beginning 0)) + (end (match-end 0))) + (when (> beg start) + (setq subs (cons (substring str start beg) subs))) + (setq subs (cons (format "%%%X" (aref str beg)) subs)) + (setq start end))) + (if subs + (apply 'concat (reverse (if (> len start) + (cons (substring str start len) subs) + subs))) + (if always-new-p (copy-sequence str) str))))) + +(defun quack-file-url (dir file) + ;; TODO: This is Unix-centric and a little fragile. Rewrite eventually. + (concat "file:" + (quack-quote-url-substring dir) + "/" + (or (quack-quote-url-substring file) ""))) + +(defun quack-build-url (base path) + (let ((base-slash-p (= (aref base (1- (length base))) ?\/))) + (if path + (mapconcat 'identity + (cons (if base-slash-p + (substring base 0 -1) + base) + path) + "/") + (if base-slash-p + base + (concat base "/"))))) + +;; Web Browsing: + +(defun quack-browse-url (url) + (require 'browse-url) + (message "Quack viewing URL: %s" url) + (let ((browse-url-browser-function (or quack-browse-url-browser-function + browse-url-browser-function))) + (browse-url url))) + +(defun quack-browse-quack-web-page () + (interactive) + (quack-browse-url quack-web-page)) + +(defun quack-w3m-browse-url-other-window (url &optional new-window) + (interactive (eval '(browse-url-interactive-arg "URL: "))) + (unless (string= (buffer-name) "*w3m*") + (switch-to-buffer-other-window (current-buffer))) + ;; TODO: If `*w3m*' buffer is visible in current frame or other frame, + ;; switch to that, for Emacsen that don't do that by default. + (eval '(w3m-browse-url url nil))) + +;; Web Getting: + +(defconst quack-web-get-log-buffer-name "*quack-web-get*") + +(defun quack-web-get-to-file (url out-file) + ;; TODO: Support other getting tools, such as "lynx -source", "links + ;; -source", "w3m -dump_source", and the Emacs w3 package. Most of + ;; these send the Web content to stdout, so, unlike for wget, it will + ;; be easier to insert directly to a buffer and send stderr to a temp + ;; file. We should have *-to-file-* and *-insert-via-* functions for + ;; each external downloader program anyway. + (quack-make-directory-for-file out-file) + (quack-web-get-to-file-via-wget url out-file)) + +;;(defun quack-web-get-to-temp-file (url) +;; (let ((temp-file (quack-make-temp-file "web-get"))) +;; (quack-web-get-to-file url temp-file) +;; temp-file)) + +(defun quack-web-get-to-file-via-wget (url out-file) + ;; TODO: Make this initially download to a temp file; replace any + ;; pre-existing out-file after successful download. Do this for any + ;; external downloader programs that write to the specified output file + ;; before the download is complete. + (let ((window (selected-window)) + (saved-buf (current-buffer)) + (log-buf (get-buffer-create quack-web-get-log-buffer-name))) + (unwind-protect + (progn + ;; Prepare the log buffer. + (set-buffer log-buf) + (widen) + (buffer-disable-undo) + (goto-char (point-min)) + (delete-region (point-min) (point-max)) + (set-window-buffer window log-buf) + ;; Do the wget. + (quack-activity + (format "Getting %S via wget" url) + (let ((status (call-process "wget" nil t t + "-O" out-file "-t" "1" "--" url))) + (unless (= status 0) + (quack-delete-file-if-can out-file) + (error "Could not get %S via wget." url)) + (kill-buffer log-buf) + out-file))) + ;; unwind-protect cleanup + (set-window-buffer window saved-buf) + (set-buffer saved-buf)))) + +;; HTML Kludges: + +(defun quack-strip-limited-html-tags (str) + (save-match-data + (let ((case-fold-search t) + (str-len (length str)) + (frags '()) + (start 0)) + (while (string-match "</?[a-z]+[ \r\n]*>" str start) + (when (> (match-beginning 0) start) + (setq frags (cons (substring str start (match-beginning 0)) frags))) + (setq start (match-end 0))) + (if frags + (progn (when (< start str-len) + (setq frags (cons (substring str start) frags))) + (apply 'concat (reverse frags))) + str)))) + +;; Temp Files: + +(defun quack-temp-dir () + (file-name-as-directory (expand-file-name "tmp" quack-dir))) + +;; TODO: Make sure this gets executed in load phase even if byte-compiled. + +(random t) + +(defun quack-make-temp-file (purpose-str) + ;; Note: There is an obvious race condition here. But we're trying to do + ;; this in portable Elisp, and if user's `quack-dir' is writable by + ;; someone other than user, then user has bigger problems. + (save-excursion + (let* ((buf (generate-new-buffer "*quack-make-temp-file*")) + (dir (quack-temp-dir)) + file) + (set-buffer buf) + (quack-make-directory dir) + (while (progn (setq file (expand-file-name (format "%d-%s-%d" + (emacs-pid) + purpose-str + (random 10000)) + dir)) + (file-exists-p file))) + (set-visited-file-name file) + (save-buffer 0) + (kill-buffer buf) + file))) + +;; About: + +(defun quack-about () + (interactive) + (let* ((buf-name "*About Quack*") + (buf (get-buffer buf-name))) + (when buf (kill-buffer buf)) + (setq buf (get-buffer-create buf-name)) + (switch-to-buffer buf) + (setq buffer-read-only nil) + (widen) + (fundamental-mode) + (when font-lock-mode + ;;(quack-warning "Font-lock mode mysteriously on in fundamental-mode.") + (font-lock-mode -1)) + (buffer-disable-undo) + ;;(delete-region (point-min) (point-max)) + (erase-buffer) + (insert + "\n" + (quack-propertize-face (copy-sequence "Quack") 'quack-about-title-face) + " Version " + (quack-propertize-bold (copy-sequence quack-version)) + "\n" + (quack-propertize-italic + (copy-sequence "Enhanced Emacs support for Scheme programming")) + "\n\n" + "You can email bug reports and feature requests to the author,\n" + quack-author-name + " <" + quack-author-email + ">. Mention that\n" + "you are using " + (quack-propertize-bold + (copy-sequence + (cond (quack-gnuemacs-p "GNU Emacs") + (quack-xemacs-p "XEmacs") + (t "*an unrecognized Emacs kind*")))) + " " + (quack-propertize-bold + (format "%d.%d" emacs-major-version emacs-minor-version)) + " on " + (quack-propertize-bold (copy-sequence system-configuration)) + ".\n\n" + "To be notified via email when new Quack versions are released,\n" + "ask Neil to add you to the moderated " + (quack-propertize-bold "scheme-announce") + " list.\n\n" + "Visit the Web page: " + quack-web-page + "\n") + (insert "\n\n" + (quack-propertize-face (copy-sequence quack-copyright) + 'quack-smallprint-face) + "\n" + (quack-propertize-face (copy-sequence quack-copyright-2) + 'quack-smallprint-face) + "\n\n" + (quack-propertize-face (concat quack-legal-notice "\n") + 'quack-smallprint-face)) + (goto-char (point-min)) + (set-buffer-modified-p nil) + (setq buffer-read-only t) + (local-set-key "q" 'quack-kill-current-buffer) + (local-set-key "w" 'quack-browse-quack-web-page) + (message + "Press `q' to quit *About Quack*, `w' to visit the Quack Web page."))) + +;; PLT Collections: + +(defvar quack-pltcollects-alist-cache nil) + +(defun quack-invalidate-pltcollects-caches () + (setq quack-pltcollects-alist-cache nil) + (quack-invalidate-manuals-caches)) + +(defun quack-pltcollects-alist () + (or quack-pltcollects-alist-cache + (quack-activity + "Scanning PLT collection directories" + (let ((result '())) + (mapcar (function + (lambda (dir) + (mapcar (function + (lambda (subdir) + (unless (member subdir '("." ".." "CVS" "RCS")) + (let ((subdir-path (expand-file-name subdir + dir))) + (when (file-directory-p subdir-path) + (setq result + (cons (cons subdir subdir-path) + result))))))) + (condition-case nil + (directory-files dir) + (file-error nil))))) + quack-pltcollect-dirs) + (setq quack-pltcollects-alist-cache (reverse result)))))) + +(defun quack-dir-for-pltcollect (name) + (cdr (assoc name (quack-pltcollects-alist)))) + +(defun quack-dired-pltcollect () + (interactive) + (let* ((alist (quack-pltcollects-alist)) + (default (if (assoc "mzlib" alist) "mzlib" nil)) + (dir (cdr (assoc + (completing-read + (if default + (format "Dired for PLT collection (default %S): " + default) + "Dired for PLT collection: ") + alist nil t nil nil default) + alist)))) + (and dir (dired dir)))) + +;; Find File: + +(defun quack-shorter-file-relative-name (filename &optional directory) + (let ((absolute (expand-file-name filename directory)) + (relative (file-relative-name filename directory))) + (if (< (length relative) (length absolute)) + relative + absolute))) + +;; TODO: Also write `quack-find-file-other-window' and +;; `quack-find-file-other-frame' and steal appropriate key bindings. + +(defun quack-find-file () + ;; TODO: Hangup/delay problems in mega-huge files. + ;; + ;; TODO: Handle `(load <filename>)' + (interactive) + (let* ((default (quack-find-file-default)) + (entry (let ((insert-default-directory (if default + nil + insert-default-directory))) + (read-file-name + (if default + (format "Quack find file (default %S): " + (quack-shorter-file-relative-name + default + default-directory)) + "Quack find file: ") + default-directory + default)))) + (find-file (if (string= entry "") + (or default "") + entry)))) + +(defun quack-find-file-default () + (or (quack-pltrequire-at-point-filename) + ;; TODO: Add support for syntax from Guile, SLIB, Chicken, etc. + )) + +;; TODO: Guile `:use-module' support. Forget about 1.4, and do 1.6. +;; +;; (defun quack-guilecolonusemodule-at-point-data () +;; (save-match-data +;; (when (thing-at-point-looking-at +;; ":use-module[ \t]+\\(([^][()\"#'`,]+)\\)") +;; (condition-case nil +;; (car (read-from-string (buffer-substring-no-properties +;; (match-beginning 1) (match-end 1)))) +;; (error nil))))) +;; +;; ;; (define-module (ice-9 expect) :use-module (ice-9 regex)) + +;; TODO: Guile 1.6 `use-modules' and `use-syntax' support. +;; +;; (use-modules (ice-9 regex)) +;; +;; (use-modules ((ice-9 popen) +;; :select ((open-pipe . pipe-open) close-pipe) +;; :renamer (symbol-prefix-proc 'unixy:))) +;; +;; (use-modules { SPEC }+ ) +;; +;; SPEC ::= MODULE-NAME | (MODULE-NAME [:select SELECTION] [:renamer RENAMER]) +;; +;; (use-syntax MODULE-NAME) + +;; TODO: Support SLIB-style `require' forms: +;; +;; (require 'foo) + +;; TODO: Bigloo `import' and maybe `extern' support. +;; +;; ;; /usr/share/doc/bigloo-examples/examples/Foreign/ +;; (module example +;; (import (bis foreign2 "foreign2.scm")) +;; ...) +;; +;; ;; /usr/share/doc/bigloo-examples/examples/Fork/ +;; (module sys-example +;; (extern (include "sys/types.h") +;; (include "wait.h") +;; (include "unistd.h") +;; ...)) + +;; TODO: PLT module language syntax: (module info (lib "infotab.ss" "setup") + +(defconst quack-pltrequire-at-point-data-re + (quack-re-alt "dynamic-require" + (concat "require" + (quack-re-alt "-for-syntax" + "")))) + +(defconst quack-pltrequire-at-point-data-1-re + (concat quack-pltrequire-at-point-data-re + "\\>")) + +(defconst quack-pltrequire-at-point-data-2-re + (concat "[^\r\n]*[[(]" + quack-pltrequire-at-point-data-re + "[ \t]+\\([^\r\n]+\\)")) + +(defun quack-pltrequire-at-point-data-1 () + (save-match-data + (let ((qpss (quack-parent-sexp-search quack-pltrequire-at-point-data-1-re + 4))) + (when qpss + (let ((child-start (nth 2 qpss))) + (when child-start + (save-excursion + (goto-char child-start) + (condition-case nil + ;; Note: It is normally OK to use the Elisp reader here. + (read (current-buffer)) + (error nil))))))))) + +(defun quack-pltrequire-at-point-data-2 () + (save-match-data + (when (thing-at-point-looking-at quack-pltrequire-at-point-data-2-re) + (let* ((read-start (match-beginning 2)) + (parts-pt (- (point) read-start)) + (parts (buffer-substring-no-properties read-start + (match-end 2))) + (parts-len (length parts)) + (start 0) + (result '())) + (condition-case nil + (while (< start parts-len) + ;; Note: It is normally OK to use the Elisp reader here. + (let ((r (read-from-string parts start))) + (when (or (not result) (> parts-pt start)) + (setq result (car r))) + (setq start (cdr r)))) + (error nil)) + result)))) + +(defun quack-pltrequire-at-point-filename (&optional silent) + (let* ((d (or (quack-pltrequire-at-point-data-1) + (quack-pltrequire-at-point-data-2))) + (m (cond + ((not d) nil) + ((stringp d) d) + ((listp d) + (let ((f (car d))) + (when (symbolp f) + (cond ((memq f '(file lib)) d) + ((memq f '(all-except rename)) (nth 1 d)) + ((memq f '(prefix prefix-all-except)) (nth 2 d))))))))) + (cond + ((stringp m) m) + ((listp m) + (let ((f (car m))) + (when (symbolp f) + (cond ((eq f 'file) (nth 1 f)) + ((eq f 'lib) + (let* ((file (nth 1 m)) + (collect (or (nth 2 m) "mzlib")) + (collect-dir (quack-dir-for-pltcollect collect)) + (subs (nthcdr 3 m))) + (when file + (if collect-dir + (quack-expand-file-name (nconc subs (list file)) + collect-dir) + (unless silent + (quack-warning "Cannot find collection %S" collect)) + nil))))))))))) + +;; Indenting Newline: + +(defun quack-newline (&optional arg) + (interactive "*P") + (if (eq quack-newline-behavior 'newline) + (newline arg) + (if (eq quack-newline-behavior 'indent-newline-indent) + (lisp-indent-line) + (unless (eq quack-newline-behavior 'newline-indent) + (error "invalid quack-newline-behavior value: %s" + quack-newline-behavior))) + (let ((n (prefix-numeric-value arg))) + (when (> n 0) + (while (> n 0) + (setq n (1- n)) + (quack-delete-horizontal-space t) + (newline)) + (lisp-indent-line))))) + +;; Agreeing-Paren Insert: + +;; TODO: Make paren-matching within comments limit seaching to within comments, +;; not skip back and try to match code. One workaround is to prefix +;; parents/brackets in comments with backslash. + +(defun quack-insert-closing (prefix default-close other-open other-close) + (insert default-close) + (unless prefix + (let ((open-pt (condition-case nil + (scan-sexps (point) -1) + (error (beep) nil)))) + (when open-pt + (let ((open-char (aref (buffer-substring-no-properties + open-pt (1+ open-pt)) + 0))) + (when (= open-char other-open) + (delete-backward-char 1) + (insert other-close)))))) + (when blink-paren-function (funcall blink-paren-function))) + +(defun quack-insert-closing-paren (&optional prefix) + (interactive "P") + (quack-insert-closing prefix ?\) ?\[ ?\])) + +(defun quack-insert-closing-bracket (&optional prefix) + (interactive "P") + (quack-insert-closing prefix ?\] ?\( ?\))) + +;; Opening-Paren Insert: + +(defun quack-insert-opening (prefix char) + (insert (if (or prefix (not quack-smart-open-paren-p)) char ?\()) + (when blink-paren-function (funcall blink-paren-function))) + +(defun quack-insert-opening-paren (&optional prefix) + (interactive "P") + (quack-insert-opening prefix ?\()) + +(defun quack-insert-opening-bracket (&optional prefix) + (interactive "P") + (quack-insert-opening prefix ?\[)) + +;; Definition Lambda Syntax Toggling: + +(defconst quack-toggle-lambda-re-1 + (concat "define\\*?" + (quack-re-alt "-for-syntax" + "-public" + "/override" + "/private" + "/public" + ""))) + +(defconst quack-toggle-lambda-re-2 + (let ((ws-opt "[ \t\r\n\f]*") + (symbol "[^][() \t\r\n\f]+") + (open-paren "[[(]") + (close-paren "[])]")) + (concat ws-opt + (quack-re-alt ; #=1 + (concat "\\(" ; #<2 `NAME (lambda (' + "\\(" ; #<3 name + symbol + "\\)" ; #>3 + ws-opt + open-paren + ws-opt + "lambda" + ws-opt + open-paren + ws-opt + "\\)") + (concat "\\(" ; #<4 `(NAME' + open-paren + ws-opt + "\\(" ; #<5 name + symbol + "\\)" ; #>5 + ws-opt + "\\)")) + "\\(" ; #<6 optional close paren + close-paren + "\\)?" ; #>6 + ))) + +(defun quack-toggle-lambda () + (interactive) + (save-match-data + (let ((found (quack-parent-sexp-search quack-toggle-lambda-re-1)) + last-paren-marker + leave-point-marker) + (unless found + (error "Sorry, this does not appear to be a definition form.")) + (unwind-protect + (let ((lexeme-end (nth 1 found)) + (define-beg (nth 3 found))) + + ;; Make the markers. + (setq last-paren-marker (make-marker)) + (setq leave-point-marker (point-marker)) + + ;; Move to right after the define form keyword, and match the + ;; pattern of the two possible syntaxes. Error if no match. + (goto-char lexeme-end) + (unless (looking-at quack-toggle-lambda-re-2) + (error "Sorry, we can't grok this definition syntax.")) + + ;; Pattern matched, so find the closing paren of the define form. + (let ((pt (condition-case nil + (scan-sexps define-beg 1) + (error ; scan-error + nil)))) + (if pt + (set-marker last-paren-marker (1- pt)) + (quack-warning + "This definition form sexp is unclosed. Consider undo."))) + + ;; Now act based on which syntax we saw. + (cond + + ((match-beginning 2) + ;; We saw the syntax `NAME (lambda ('. + (let ((name (quack-match-string-no-properties 3))) + (when (marker-position last-paren-marker) + (goto-char last-paren-marker) + (let ((victim-beg (quack-looking-at-close-paren-backward))) + (unless victim-beg + (error "This definition form should end with `))'.")) + (delete-region victim-beg (point)))) + (goto-char lexeme-end) + (delete-region lexeme-end (match-end 2)) + (insert " (" name (if (match-beginning 6) "" " ")))) + + ((match-beginning 4) + ;; We saw the syntax `(NAME'. + (let ((name (quack-match-string-no-properties 5))) + (when (marker-position last-paren-marker) + (goto-char last-paren-marker) + (insert ")")) + (goto-char lexeme-end) + (delete-region lexeme-end (match-end 4)) + (insert " " name "\n") + (set-marker leave-point-marker (point)) + (insert "(lambda (") + (set-marker-insertion-type leave-point-marker t))) + + (t (quack-internal-error))) + + ;; Reindent, which also takes care of font-lock updating of deleted + ;; and inserted text. + (indent-region define-beg + (or (marker-position last-paren-marker) + (max (marker-position leave-point-marker) + (point))) + nil)) + + ;; unwind-protect cleanup + (goto-char (marker-position leave-point-marker)) + (set-marker leave-point-marker nil))))) + +;; Buffer Tidying: + +;; TODO: Maybe have an option to automatically tidy the buffer on save. Make +;; default off. This can be slow for larger buffers on older computers, +;; especially if font-lock is activated. It can also annoy people who +;; have a CM system full of improperly formatted files, or who like +;; things like formfeed characters in their files. + +(defun quack-delete-all-in-buffer (regexp &optional subexp) + (unless subexp (setq subexp 0)) + ;; Note: This moves the point and changes the match data. + (goto-char (point-min)) + (while (re-search-forward regexp nil t) + (goto-char (match-end subexp)) + (delete-region (match-beginning subexp) (point)))) + +(defun quack-tidy-buffer () + + ;; TODO: Make sure this works with odd eol conventions and the various + ;; codeset representations in various versions of Emacs. + + ;; TODO: Maybe detect DrScheme ASCII-art "big letters" and protect them from + ;; reindenting. + + "Tidy the formatting of the current Scheme buffer. + +This reindents, converts tabs to spaces, removes trailing whitespace on lines, +removes formfeed characters, removes extraneous blank lines, and makes sure +the buffer ends with a newline. + +This can conceivably corrupt multi-line string literals, but not in any way +they wouldn't be corrupted by Usenet, various mailers, typesetting for print, +etc. + +This may also result in large diffs when the tidied file is commited back to a +version control or configuration management system. Consider making a VC or CM +delta that consists only of changes made by `quack-tidy-buffer'." + (interactive) + (if (= (point-min) (point-max)) + (message "Buffer is empty; no tidying necessary.") + (let ((marker (point-marker)) + (fill-prefix nil)) + (unwind-protect + (save-excursion + (save-match-data + (quack-activity + "Tidying buffer" + + ;; Make sure last character is a newline. + (unless (string= "\n" (buffer-substring-no-properties + (1- (point-max)) + (point-max))) + (goto-char (point-max)) + (insert "\n")) + + ;; Remove form-feed characters. + (quack-delete-all-in-buffer "\f") + + ;; Reindent buffer (without inserting any new tabs). + ;; Note: This is the time-consuming pass. + (let ((saved-indent-tabs-mode indent-tabs-mode)) + (unwind-protect + (progn (setq indent-tabs-mode nil) + (indent-region (point-min) (point-max) nil)) + ;; unwind-protect cleanup + (setq indent-tabs-mode saved-indent-tabs-mode))) + + ;; Expand any remaining tabs. + (untabify (point-min) (point-max)) + + ;; Remove trailing whitespace on each line. + (quack-delete-all-in-buffer "\\([ \t\r]+\\)\n" 1) + + ;; Remove blank lines from top. + (goto-char (point-min)) + (when (looking-at "[ \t\r\n]+") + (delete-region (match-beginning 0) (match-end 0))) + + ;; Remove excess adjacent blank lines. + (quack-delete-all-in-buffer "\n\n\\(\n+\\)" 1) + + ;; Remove blank lines from bottom. + (goto-char (point-max)) + (when (quack-looking-at-backward + "\n\\(\n\\)" + (max (point-min) (- (point-max) 3))) + (delete-region (match-beginning 1) (match-end 1)))))) + + ;; unwind-protect cleanup + (goto-char (marker-position marker)) + (set-marker marker nil))))) + +;; SRFIs: + +;; TODO: Archive local copies of SRFIs? Have to update them when modified, but +;; without unnecessarily downloading from the master site. This is +;; doable with wget mirroring, but not with things like "lynx -source". + +(defconst quack-srfi-subindex-kinds '(draft final withdrawn) + "List of symbols representing the three possible states of an SRFI (`draft', +`final', and `withdrawn'), in order of increasing precedence (e.g., final +follows draft,since a final version supercedes a draft version).") + +(defvar quack-srfi-completes-cache 'invalid) +(defvar quack-srfi-menu-cache 'invalid) + +(defun quack-srfi-completes () + (when (eq quack-srfi-completes-cache 'invalid) + (quack-process-srfi-subindex-files)) + quack-srfi-completes-cache) + +(defun quack-srfi-menu (&optional noninteractive) + (when (eq quack-srfi-menu-cache 'invalid) + (quack-process-srfi-subindex-files noninteractive)) + quack-srfi-menu-cache) + +(defun quack-srfi-master-url (path) + (quack-build-url quack-srfi-master-base-url path)) + +(defun quack-srfi-subindex-master-url (kind) + (quack-srfi-master-url (list (quack-srfi-subindex-basename kind)))) + +(defun quack-srfi-dir () + (file-name-as-directory (expand-file-name "srfi" quack-dir))) + +(defun quack-srfi-subindex-file (kind) + (expand-file-name (quack-srfi-subindex-basename kind) (quack-srfi-dir))) + +(defun quack-srfi-subindex-basename (kind) + (format "%S-srfis.html" kind)) + +(defun quack-invalidate-srfi-index-caches () + (setq quack-srfi-completes-cache 'invalid) + (setq quack-srfi-menu-cache 'invalid)) + +(defun quack-update-srfi-index () + (interactive) + (quack-activity + "Updating SRFI index" + (quack-download-srfi-subindex-files))) + +(defun quack-download-srfi-subindex-files () + (quack-invalidate-srfi-index-caches) + (mapcar (function + (lambda (kind) + (quack-activity + (format "Downloading %s SRFI subindex" kind) + (quack-web-get-to-file (quack-srfi-subindex-master-url kind) + (quack-srfi-subindex-file kind))))) + quack-srfi-subindex-kinds)) + +(defun quack-download-srfi-subindex-files-if-missing () + (let ((missing '())) + (mapcar (function + (lambda (kind) + (unless (file-exists-p (quack-srfi-subindex-file kind)) + (setq missing (nconc missing (list kind)))))) + quack-srfi-subindex-kinds) + (when (and missing + (y-or-n-p "Some cached SRFI subindexes are missing. Update? ")) + (quack-update-srfi-index)))) + +(defun quack-process-srfi-subindex-files (&optional noninteractive) + (let ((index '()) + (completes '()) + (menu (mapcar (function (lambda (kind) (cons kind nil))) + quack-srfi-subindex-kinds))) + + ;; Invalidate dependent caches. + (quack-invalidate-srfi-index-caches) + + ;; Give user a chance to download any missing cache files all at once, + ;; instead of prompting individually later. + (unless noninteractive + (quack-download-srfi-subindex-files-if-missing)) + + ;; Parse the index files, letting entries for successive states supercede. + (mapcar (function + (lambda (kind) + (mapcar (function + (lambda (new) + (let (old) + (if (setq old (assq (car new) index)) + (setcdr old (cdr new)) + (setq index (cons new index)))))) + (quack-parse-srfi-subindex-file kind noninteractive)))) + quack-srfi-subindex-kinds) + + ;; Sort the parse form in reverse order, since the cache-building functions + ;; will reverse this. + (setq index (sort index (function (lambda (a b) (>= (car a) (car b)))))) + + ;; Build the completions and menu caches. + (let ((fmt (concat "%" + (if index + (number-to-string + (length (number-to-string (car (car index))))) + "") + "d %s"))) + (mapcar (function + (lambda (n) + (let ((num (nth 0 n)) + (kind (nth 1 n)) + (title (nth 2 n))) + (unless kind (quack-internal-error)) + (setq completes + (cons (cons (if (eq kind 'final) + (format "%d %s" num title) + (format "%d [%s] %s" num kind title)) + num) + completes)) + (let ((pair (or (assq kind menu) + (quack-internal-error)))) + (setcdr pair (cons `[,(format fmt num title) + (quack-view-srfi ,num)] + (cdr pair))))))) + index)) + + ;; Finish the menu. + (mapcar (function (lambda (n) + (setcar n (cdr (assoc (car n) + '((draft . "Draft") + (final . "Final") + (withdrawn . "Withdrawn"))))) + ;; Add dummy content so that XEmacs 21 will display + ;; the submenu label. + (unless (cdr n) + (setcdr n (cons "(None)" nil))))) + menu) + (setq menu `(["Update SRFI Index" quack-update-srfi-index] + "---" + ,@menu + ["Other SRFI..." quack-view-srfi])) + + ;; Store the results. + (setq quack-srfi-menu-cache menu) + (setq quack-srfi-completes-cache completes))) + +(defun quack-parse-srfi-subindex-file (kind &optional noninteractive) + (save-excursion + (let ((file (quack-srfi-subindex-file kind))) + (unless (file-exists-p file) + (error "No SRFI index file %S" file)) + (let* ((buf (get-file-buffer file)) + (already-visiting-p buf)) + (unless buf + (setq buf (find-file-noselect file t t))) + (unwind-protect + (progn (set-buffer buf) + (quack-parse-srfi-subindex-buffer kind)) + ;; unwind-protect-cleanup + (unless already-visiting-p + (kill-buffer buf))))))) + +(defconst quack-parse-srfi-index-buffer-re-1 + (concat + "<LI><A HREF=\"?srfi-[0-9]+/?\"?>SRFI[ \t]+" + "\\([0-9]+\\)" ; #=1 srfi number + "</A>:?[ \t]*" + "\\(" ; #<2 srfi title + ; #=3 + (quack-re-alt "[^\r\n<>]" "</?[a-z]+>") + "+" + "\\)")) + +(defun quack-parse-srfi-subindex-buffer (kind) + (save-excursion + (let ((case-fold-search t) + (alist '())) + (goto-char (point-min)) + (while (re-search-forward quack-parse-srfi-index-buffer-re-1 nil t) + (let ((number (string-to-number (quack-match-string-no-properties 1))) + (title (quack-without-side-whitespace + (quack-strip-limited-html-tags + (quack-match-string-no-properties 2))))) + (setq alist (cons + + ;;(cons number + ;; (if (and kind (not (eq kind 'final))) + ;; (format "[%s] %s" kind title) + ;; title)) + (list number kind title) + + alist)))) + (setq alist (reverse alist))))) + +(defun quack-srfi-num-url (num) + (quack-srfi-master-url (list (format "srfi-%d" num) + (format "srfi-%d.html" num)))) + +(defconst quack-srfi-num-at-point-re-1 + "srfi[-: \t]*\\([0-9]+\\)") + +(defconst quack-srfi-num-at-point-re-2 + ;; Note: We can't have "[^\r\n]*" as a prefix, since it's too slow. + (concat quack-srfi-num-at-point-re-1 "[^\r\n]*")) + +(defun quack-srfi-num-at-point () + ;; TODO: Make this get the nearest SRFI number in all cases. + (save-match-data + (let ((case-fold-search t)) + (cond ((thing-at-point-looking-at quack-srfi-num-at-point-re-1) + (string-to-number (quack-match-string-no-properties 1))) + ((thing-at-point-looking-at "[0-9]+") + (string-to-number (quack-match-string-no-properties 0))) + ((thing-at-point-looking-at quack-srfi-num-at-point-re-2) + (string-to-number (quack-match-string-no-properties 1))) + ((let ((str (quack-line-at-point))) + (when (string-match quack-srfi-num-at-point-re-1 str) + (string-to-number + (quack-match-string-no-properties 1 str))))))))) + +(defun quack-view-srfi (num) + (interactive (list (quack-srfi-num-prompt "View SRFI number"))) + (when num + (unless (and (integerp num) (>= num 0)) + (error "Not a valid SRFI number: %S" num)) + (quack-browse-url (quack-srfi-num-url num)))) + +(defun quack-srfi-num-prompt (prompt) + (let* ((completes (quack-srfi-completes)) + (default (quack-srfi-num-at-point)) + (input (quack-without-side-whitespace + (completing-read + (if default + (format "%s (default %d): " prompt default) + (concat prompt ": ")) + completes))) + v) + (cond ((or (not input) (string= "" input)) default) + ((setq v (assoc input completes)) (cdr v)) + ((and (setq v (condition-case nil + (string-to-number input) + (error nil))) + (integerp v) + (>= v 0)) + v) + (t (error "Invalid SRFI number: %s" input))))) + +;; Doc Keyword Value Object: + +(defmacro quack-kw-get-syntax (o) `(aref ,o 0)) +(defmacro quack-kw-get-file (o) `(aref ,o 1)) +(defmacro quack-kw-get-fragment (o) `(aref ,o 2)) + +(defmacro quack-kw-set-syntax (o v) `(aset ,o 0 ,v)) +(defmacro quack-kw-set-file (o v) `(aset ,o 1 ,v)) +(defmacro quack-kw-set-fragment (o v) `(aset ,o 2 ,v)) + +;; Documentation Object: + +;; TODO: Rework these document representations once we know the different kinds +;; of documents with which we'll be dealing. + +(defmacro quack-doc-get-type (o) `(aref ,o 0)) +(defmacro quack-doc-get-sym (o) `(aref ,o 1)) +(defmacro quack-doc-get-title (o) `(aref ,o 2)) +(defmacro quack-doc-get-loc (o) `(aref ,o 3)) +(defmacro quack-doc-get-kw-p (o) `(aref ,o 4)) +(defmacro quack-doc-get-start-url (o) `(aref ,o 5)) +(defmacro quack-doc-get-kw-base-url (o) `(aref ,o 6)) +(defmacro quack-doc-get-kw-file (o) `(aref ,o 7)) +(defmacro quack-doc-get-kw-hashtable (o) `(aref ,o 8)) + +(defmacro quack-doc-set-type (o v) `(aset ,o 0 ,v)) +(defmacro quack-doc-set-sym (o v) `(aset ,o 1 ,v)) +(defmacro quack-doc-set-title (o v) `(aset ,o 2 ,v)) +(defmacro quack-doc-set-loc (o v) `(aset ,o 3 ,v)) +(defmacro quack-doc-set-kw-p (o v) `(aset ,o 4 ,v)) +(defmacro quack-doc-set-start-url (o v) `(aset ,o 5 ,v)) +(defmacro quack-doc-set-kw-base-url (o v) `(aset ,o 6 ,v)) +(defmacro quack-doc-set-kw-file (o v) `(aset ,o 7 ,v)) +(defmacro quack-doc-set-kw-hashtable (o v) `(aset ,o 8 ,v)) + +(defun quack-manual-to-doc (manual) + ;; Accepts a user's manual preference object of the list form: + ;; + ;; (SYM TITLE LOC KW-P) + ;; + ;; and creates a manual doc object of the vector form: + ;; + ;; [manual SYM TITLE LOC KW-P START-URL KW-BASE-URL KW-FILE KW-P + ;; KEYWORDS] + ;; + ;; KEYWORDS is not populated here -- keywords importing for a manual happens + ;; the first time keyword searching is done for the manual." + (let ((sym (nth 0 manual)) + (title (nth 1 manual)) + (loc (nth 2 manual)) + (kw-p (nth 3 manual)) + (start-url nil) + (kw-file nil) + (kw-base nil)) + (cond + ;; If the location is a string, then handle manual as simple URL. + ((stringp loc) + (setq start-url loc) + (when kw-p + (quack-warning "Quack can only use keywords for PLT manuals.") + (setq kw-p nil))) + ;; If the location is a symbol, handle manual as special. + ((symbolp loc) + (cond + ;; If the location is symbol `plt', handle manual as PLT bundled. + ((eq loc 'plt) + (let* ((plt-name (let ((s (symbol-name sym))) + (if (string-match "\\`plt-\\(.+\\)\\'" s) + (match-string 1 s) + s))) + (web-base (concat + "http://download.plt-scheme.org/doc/" + plt-name + "/")) + (index-name "index.htm") + (col-dirs quack-pltcollect-dirs)) + ;; Search from the collection directories for keywords and index + ;; files. Note that we currently look for keywords files even if + ;; `kw-p' is false since we want to allow the user to dynamically + ;; enable and disable keywords searching for a particular manual + ;; without us having to change `quack-docs'. + (while (and col-dirs (not (and kw-file kw-base start-url))) + (let ((dir (expand-file-name plt-name + (expand-file-name "doc" + (car col-dirs))))) + (setq col-dirs (cdr col-dirs)) + (when (file-directory-p dir) + (let* ((k-f (expand-file-name "keywords" dir)) + (i-f (expand-file-name index-name dir)) + (i-r (file-readable-p i-f))) + (if (file-readable-p k-f) + ;; Keywords file. + (if i-r + ;; Keywords file and index file. So, unless we + ;; already found a keywords base URL, set everything + ;; based on this directory. Note that we override + ;; any existing start URL because we prefer to use + ;; the same manual version for both keywords and + ;; non-keywords access. + (unless kw-base + (setq kw-file k-f) + (setq kw-base (quack-file-url dir nil)) + (setq start-url (quack-file-url dir index-name))) + ;; Keywords file, but no index file. So, unless we + ;; already have a keywords file, set it to this one. + (unless kw-file + (setq kw-file k-f))) + ;; No keywords file. So, if there is an index file, and we + ;; don't already have one, then use this one. + (when (and i-r (not start-url)) + (setq start-url (quack-file-url dir index-name)))))))) + ;; If we didn't find a start URL, use the Web one. + (unless start-url + (setq start-url (concat web-base index-name))) + ;; Do we have a keywords file? + (if kw-file + ;; We have a keywords file, so set the keywords base to the Web + ;; if needed and desired. Note that we never use the keywords + ;; file from one directory with the HTML files from a different + ;; directory, on the assumption that a local copy of HTML missing + ;; a keywords file is suspect, and that the Web version is + ;; therefore preferable. + (when (or (eq quack-local-keywords-for-remote-manuals-p 'always) + (and (not kw-base) + quack-local-keywords-for-remote-manuals-p)) + (setq kw-base web-base)) + ;; We don't have a keywords file, so warn if the user wanted + ;; keywords for this manual. + (when kw-p + (quack-warning "Could not find keywords file for manual %S." + plt-name))))) + ;; The location is an unrecognized symbol, so just barf. + (t (quack-internal-error)))) + ;; The location is something other than a string or symbol, so just barf. + (t (quack-internal-error))) + ;; We've populated all the variables for the location type, so return the + ;; representation. + (vector 'manual sym title loc kw-p start-url kw-base kw-file nil))) + +(defun quack-doc-keyword-lookup (doc keyword) + (let ((ht (or (quack-doc-get-kw-hashtable doc) + (progn (quack-doc-import-keywords doc) + (quack-doc-get-kw-hashtable doc))))) + (if ht + (quack-gethash keyword ht nil) + (quack-warning "No keywords for document \"%S\"." + (quack-doc-get-sym doc)) + nil))) + +(defun quack-doc-import-keywords (doc) + (if (eq (quack-doc-get-loc doc) 'plt) + (quack-doc-import-plt-manual-keywords doc) + (quack-internal-error))) + +(defun quack-doc-import-plt-manual-keywords (doc) + ;; Reads in the predetermined keywords file for PLT manual `doc' object, + ;; populating the `kw-hashtable' field of the `doc' object. The format of + ;; each entry in the PLT keywords file is a list of 5 strings: + ;; + ;; (KEYWORD SYNTAX FILE FRAGMENT SECTION) + ;; + ;; The hashtable is keyed on the KEYWORD string, for which the value is + ;; usually a vector: + ;; + ;; [SYNTAX FILE-CONST FRAGMENT] + ;; + ;; where FILE-CONST is the FILE string registered with the `quack-strconst' + ;; to save memory on redundant strings. + ;; + ;; When more there is more than one entry for a given keyword, then the value + ;; of the hashtable entry for that keyword is a list of vectors, in the order + ;; in which they were derived from the original keywords file. + ;; + ;; These duplicate values may be duplicated or conflicting, as in: + ;; + ;; (["(regexp-match pattern input-port [start-k end-k output-port])" + ;; "mzscheme-Z-H-10.html" "%_kw_definitionregexp-match"] + ;; ["(regexp-match pattern string [start-k end-k output-port])" + ;; "mzscheme-Z-H-10.html" "%_kw_definitionregexp-match"]) + ;; + ;; No attempt is made here to weed out any duplicate/conflicting entries -- + ;; that behavior left up to the code that accesses the hashtable. For the + ;; example above, a command to display the syntax for the keyword would need + ;; to display both values. However, a command to view the documentation for + ;; the keyword would need only to display one Web page without querying the + ;; user, since both entries above point to the same page and fragment. + (quack-activity + (format "Importing keywords for manual %S" (quack-doc-get-sym doc)) + (let (sexp) + (garbage-collect) + (condition-case err + (setq sexp (quack-read-sexp-file + (or (quack-doc-get-kw-file doc) + (quack-warning "Manual %S has no keywords file." + (quack-doc-get-sym doc))))) + (error (quack-warning "Problem importing keywords for manual %S: %s" + (quack-doc-get-sym doc) err))) + (when sexp + (garbage-collect) + (let ((ht (quack-make-hash-table :test 'equal + :size (length sexp) + :rehash-threshold 1.0))) + ;; Note: We make the hashtable equal to the length of the read list of + ;; keyword forms so that it will be at least large enough for all the + ;; keywords without being excessively overlarge, and without having to + ;; do resizes or a counting pass or intermediate representation. The + ;; hashtable will be a little larger than necessary when there are + ;; multiple keyword forms for the same keyword. In a test with + ;; MzScheme 200.2, the hashtable used/size for "mzscheme" manual was + ;; 489/502; for "mzlib", 245/257. + (quack-doc-set-kw-hashtable doc ht) + (mapcar (function + (lambda (raw-entry) + (let* ((kw (nth 0 raw-entry)) + (new (vector (nth 1 raw-entry) + (quack-strconst (nth 2 raw-entry)) + (nth 3 raw-entry))) + (old (quack-gethash kw ht nil))) + (quack-puthash + kw + (cond ((not old) new) + ((vectorp old) (list old new)) + ((listp old) (nconc old (list new)))) + ht)))) + sexp)))))) + +(defun quack-read-sexp-file (filename) + (save-excursion + (let* ((buf (generate-new-buffer "*quack-read-sexp-file*"))) + (set-buffer buf) + (unwind-protect + (progn (insert-file-contents-literally filename) + (goto-char (point-min)) + (read buf)) + ;; unwind-protect cleanup + (kill-buffer buf))))) + +;; Documentation Database: + +(defvar quack-docs 'invalid) + +(defun quack-docs () + (when (eq quack-docs 'invalid) + (quack-docs-build)) + quack-docs) + +(defun quack-docs-build () + (quack-activity + "Building Quack docs database" + (quack-invalidate-manuals-caches) + (setq quack-docs (mapcar 'quack-manual-to-doc quack-manuals)))) + +(defun quack-docs-manual-lookup (sym) + (let ((docs (quack-docs)) + (found nil)) + (while (and docs (not found)) + (let ((doc (car docs))) + (setq docs (cdr docs)) + (when (eq (quack-doc-get-sym doc) sym) + (setq found doc)))) + found)) + +(defun quack-docs-manual-keyword-lookup (keyword) + (let ((results '())) + (mapcar (function + (lambda (doc) + (cond + ((not (quack-doc-get-kw-p doc)) nil) + ((not (quack-doc-get-kw-base-url doc)) + (quack-warning "Manual %S has no HTML." + (quack-doc-get-sym doc))) + (t (let ((match (quack-doc-keyword-lookup doc keyword))) + (cond + ((not match) nil) + ((vectorp match) + (setq results (cons (cons doc match) results))) + ((listp match) + (mapcar (function + (lambda (m) + (setq results (cons (cons doc m) results)))) + match)) + (t (quack-internal-error)))))))) + (quack-docs)) + (reverse results))) + +;; Keyword Lookup Match Object: + +(defmacro quack-kwmatch-get-doc (o) `(car ,o)) +(defmacro quack-kwmatch-get-kw (o) `(cdr ,o)) + +(defun quack-kwmatch-url (kwmatch) + (let ((doc (car kwmatch)) + (kw (cdr kwmatch))) + (concat (quack-doc-get-kw-base-url doc) + (quack-quote-url-substring (quack-kw-get-file kw)) + "#" + (quack-quote-url-substring (quack-kw-get-fragment kw) t)))) + +;; Manual Viewing: + +(defun quack-view-manual (&optional sym) + "View a manual." + (interactive + (list + (let* ((completes (or (quack-manuals-completes) + (error + "Sorry, variable \"quack-manuals\" is empty."))) + (default "R5RS") + (input (let ((completion-ignore-case t)) + (completing-read + (format "Quack Manual (default %S): " default) + completes nil t nil nil default)))) + (cdr (or (assoc input completes) + (error "No manual %S." input)))))) + (quack-activity + (format "Viewing manual \"%S\"" sym) + (quack-browse-url (or (quack-doc-get-start-url + (or (quack-docs-manual-lookup sym) + (error "Manual \"%S\" not found." sym))) + (error "Don't know a URL for manual \"%S\"." sym))))) + +(defvar quack-manuals-menu-cache 'invalid) +(defvar quack-manuals-completes-cache 'invalid) + +(defun quack-invalidate-manuals-caches () + (setq quack-docs 'invalid) + (setq quack-manuals-completes-cache 'invalid) + (setq quack-manuals-menu-cache 'invalid)) + +;;(quack-invalidate-manuals-caches) + +;; This version maps completion strings to URLs. +;; (defun quack-manuals-completes () +;; (when (eq quack-manuals-completes-cache 'invalid) +;; (let ((completes '())) +;; (mapcar (function +;; (lambda (doc) +;; (let ((sym (quack-doc-get-sym doc)) +;; (url (quack-doc-get-start-url doc))) +;; (setq completes +;; (cons (cons (quack-doc-get-title doc) url) +;; (cons (cons (symbol-name sym) url) +;; completes)))))) +;; (quack-docs)) +;; (setq quack-manuals-completes-cache (reverse completes)))) +;; quack-manuals-completes-cache) + +(defun quack-manuals-completes () + (when (eq quack-manuals-completes-cache 'invalid) + (let ((completes '())) + (mapcar (function + (lambda (doc) + (let ((sym (quack-doc-get-sym doc)) + ;;(url (quack-doc-get-start-url doc)) + ) + (setq completes + (cons (cons (quack-doc-get-title doc) sym) + ;;(cons (cons (symbol-name sym) sym) + completes + ;;) + ))))) + (quack-docs)) + (setq quack-manuals-completes-cache (reverse completes)))) + quack-manuals-completes-cache) + +(defun quack-manuals-menu () + (when (eq quack-manuals-menu-cache 'invalid) + (setq quack-manuals-menu-cache + (mapcar (function + (lambda (manual) + (let ((sym (nth 0 manual)) + (title (nth 1 manual))) + `[,title (quack-view-manual (quote ,sym))]))) + quack-manuals))) + quack-manuals-menu-cache) + +(defun quack-manuals-webjump-sites () + "Returns `webjump' entries for manuals in `quack-manuals'. + +Can be used in your `~/.emacs' file something like this: + + (require 'quack) + (require 'webjump) + (require 'webjump-plus) + (setq webjump-sites + (append my-own-manually-maintained-webjump-sites + (quack-manuals-webjump-sites) + webjump-plus-sites + webjump-sample-sites))" + ;; TODO: Note what they should do if they are adding to plt collectsion dirs + ;; via custom settings but quack-manuals-webjump-sites is getting + ;; called before then. + (let ((result '()) + (quack-quiet-warnings-p t)) + (mapcar (function + (lambda (doc) + (let ((url (quack-doc-get-start-url doc))) + (when url + (setq result (cons (cons (quack-doc-get-title doc) url) + result)))))) + (quack-docs)) + result)) + +;; Keyword Docs Viewing: + +;; TODO: Add doc lookup in PLT "doc.txt" files. A little tricky. Maybe make +;; sure doc.txt is a long-term format first. + +(defun quack-view-keyword-docs (keyword) + ;; TODO: Don't prompt if all choices would result in the same URL. + (interactive (list (quack-prompt-for-keyword "View docs for keyword"))) + (when (and keyword (stringp keyword) (not (string= keyword ""))) + (let ((matches (quack-docs-manual-keyword-lookup keyword))) + (if (not matches) + (message "Sorry, no documentation found for keyword %S." keyword) + (quack-browse-url + (quack-kwmatch-url + (if (cdr matches) + (quack-prompt-for-kwmatch-choice "Which" matches) + (car matches)))))))) + +(defun quack-keyword-at-point () + ;; TODO: Make sure this reads all Scheme symbols -- it may currently only + ;; read valid Elisp symbols. + (let ((bounds (bounds-of-thing-at-point 'symbol))) + ;; In some cases (point at beginning of empty buffer?), `bounds' will be + ;; the bounds of an empty string, so check this. + (when bounds + (let ((beg (car bounds)) + (end (cdr bounds))) + (when (/= beg end) + (buffer-substring-no-properties beg end)))))) + +(defun quack-prompt-for-keyword (prompt) + (let* ((default (quack-keyword-at-point)) + (history (list default))) + (read-string (if default + (format "%s (default %S): " prompt default) + (concat prompt ": ")) + nil + ;; Note: Gratuitous reference to `history' eliminates warning + ;; from XEmacs 21 byte-compiler. + (if (and default history) 'history nil) + default))) + +(defun quack-prompt-for-kwmatch-choice (prompt kwmatch-list) + (let ((completes '())) + ;; Build the completion alist, ensure each key is unique. + (mapcar + (function + (lambda (kwmatch) + (let* ((kw (quack-kwmatch-get-kw kwmatch)) + (orig-name (or (quack-kw-get-syntax kw) + (progn (quack-warning "No keyword syntax: %s" + kw) + "???"))) + (name orig-name) + (name-tries 1)) + ;; Ensure the name is unique within the completion list thus far. + (while (assoc name completes) + (setq name-tries (1+ name-tries)) + (setq name (format "%s #%d" orig-name name-tries))) + ;; Prepend to the completion list (we'll reverse the list later). + (setq completes (cons (cons name kwmatch) completes))))) + kwmatch-list) + (setq completes (reverse completes)) + ;; Prompt user and return selection. + (let* ((default (car (car completes))) + (read (let ((completion-ignore-case t)) + (completing-read + (format "%s (default %S): " prompt default) + completes nil t nil nil default)))) + (cdr (assoc read completes))))) + +;; Inferior Process: + +(defvar quack-run-scheme-prompt-history '()) + +(defun quack-remember-program-maybe (program) + (when (and quack-remember-new-programs-p + (not (member program quack-programs))) + (quack-option-set 'quack-programs (cons program quack-programs) t) + (message "Remembering program %S." program))) + +(defun quack-run-scheme-prompt () + (let* ((last (car quack-run-scheme-prompt-history)) + (default (or (and quack-run-scheme-prompt-defaults-to-last-p + last) + quack-default-program + scheme-program-name + last + "mzscheme")) + (program (let ((minibuffer-allow-text-properties nil)) + (completing-read + (concat "Run Scheme" + (if default + (format " (default %S)" default) + "") + ": ") + (quack-run-scheme-prompt-completion-collection) + nil nil nil + 'quack-run-scheme-prompt-history + default)))) + (quack-remember-program-maybe program) + program)) + +(defun quack-run-scheme-prompt-completion-collection () + (let ((program-list quack-programs)) + (mapcar (function (lambda (program) + (and program + (not (member program program-list)) + (setq program-list (cons program program-list))))) + (list quack-default-program + scheme-program-name)) + (mapcar (function (lambda (program) (cons program nil))) + program-list))) + +(defadvice run-scheme (around quack-ad-run first nil activate) + "Adds prompting for which Scheme interpreter program to run." + ;; We don't want to prompt if there's already a Scheme running, but it's + ;; possible for process to die between the comint check in `interactive' form + ;; of this advice and the comint check in the `run-scheme' function. We + ;; should override `run-scheme' altogether, but for now let's only call the + ;; original in the case that we do not detect a running Scheme. + (interactive (list (cond ((comint-check-proc "*scheme*") nil) + ((or current-prefix-arg + quack-run-scheme-always-prompts-p) + (quack-run-scheme-prompt)) + (t quack-default-program)))) + (if cmd + ;; We will assume there is no running Scheme, so... Since `run-scheme' + ;; calls `pop-to-buffer' rather than `switch-to-scheme', our options for + ;; Scheme process window management, such as putting the process buffer + ;; window in its own frame, do not take effect when the process buffer is + ;; displayed by `run-scheme'. So, unless we are using the `cmuscheme' + ;; window management behavior, we attempt to undo whatever window changes + ;; and buffer changes `run-scheme' makes, then just call + ;; `switch-to-scheme'. (This code will be revisited once we decide how + ;; to handle multiple Schemes, if not before then.) + (let ((buf (current-buffer)) + (wg (current-window-configuration))) + ad-do-it + (unless (or (not quack-switch-to-scheme-method) + (eq quack-switch-to-scheme-method 'cmuscheme)) + (set-window-configuration wg) + (set-buffer buf) + (switch-to-scheme t)) + (message "Started Scheme: %s" scheme-program-name)) + ;; There is a running Scheme, so don't call the `run-scheme' function at + ;; all -- just call `switch-to-scheme' or duplicate the `cmuscheme' + ;; package's `pop-to-buffer' behavior. + (if (or (not quack-switch-to-scheme-method) + (eq quack-switch-to-scheme-method 'cmuscheme)) + (pop-to-buffer "*scheme*") + (switch-to-scheme t)) + (message "Switched to running Scheme: %s" scheme-program-name))) + +(defadvice scheme-interactively-start-process (around + quack-ad-sisp + first + (&optional cmd) + activate) + ;; (save-window-excursion + (call-interactively 'run-scheme) + ;; ) + ) + +(defadvice scheme-proc (around quack-ad-scheme-proc first nil activate) + (condition-case nil + ad-do-it + (error (message "Oops, we must start a Scheme process!") + (call-interactively 'run-scheme) + (setq ad-return-value (scheme-proc))))) + +;; Switch-to-Scheme: + +(defun quack-force-frame-switch-to-window (win) + (let ((frame (window-frame win))) + (unless (eq frame (selected-frame)) + (and window-system + quack-warp-pointer-to-frame-p + (set-mouse-position frame 0 0)) + (select-frame frame)) + (select-window win))) + +(defadvice switch-to-scheme (before quack-ad-switch last nil activate) + "Adds support for the `quack-switch-to-scheme-method' option." + ;; This can be done as before-advice since the `pop-to-buffer' that + ;; `switch-to-scheme' is using appears to always be a no-op when the target + ;; buffer is already the current buffer. + (require 'cmuscheme) + ;; The `eval' below is to avoid problems with the byte-compiler and advising. + ;; It doesn't seem to like: (and (boundp 'SYM) SYM) + (let ((repl-buf (eval '(and (boundp 'scheme-buffer) + scheme-buffer + (get-buffer scheme-buffer))))) + (cond ((not repl-buf) + (error (concat "No process current buffer." + " Set `scheme-buffer' or execute `run-scheme'"))) + + ((or (not quack-switch-to-scheme-method) + (eq quack-switch-to-scheme-method 'cmuscheme)) + nil) + + ((eq (current-buffer) repl-buf) nil) + + ((eq quack-switch-to-scheme-method 'other-window) + (switch-to-buffer-other-window repl-buf)) + + ;; The following code may be revived if anyone reports problems with + ;; the use of `special-display-popup-frame'. + ;; + ;; ((eq quack-switch-to-scheme-method 'own-frame) + ;; (let ((pop-up-frames t) + ;; (same-window-buffer-names nil) + ;; (same-window-regexps nil) + ;; (special-display-buffer-names nil) + ;; (special-display-regexps nil)) + ;; (switch-to-buffer (pop-to-buffer repl-buf)))) + + ((eq quack-switch-to-scheme-method 'own-frame) + (quack-force-frame-switch-to-window + (special-display-popup-frame repl-buf))) + + (t (error "Invalid quack-switch-to-scheme-method: %S" + quack-switch-to-scheme-method))))) + +;; Customize: + +(defun quack-customize () + "Customize the Quack package." + (interactive) + (customize-group 'quack)) + +;; Auto Modes: + +(defun quack-add-auto-mode-alist (alist) + (setq auto-mode-alist + (append alist + (let ((retained '())) + (mapcar (function (lambda (pair) + (unless (assoc (car pair) alist) + (setq retained (cons pair retained))))) + auto-mode-alist) + (reverse retained))))) + +(quack-add-auto-mode-alist '(("\\.ccl\\'" . scheme-mode) + ("\\.rkt\\'" . scheme-mode) + ("\\.rktd\\'" . scheme-mode) + ("\\.sch\\'" . scheme-mode) + ("\\.scm\\'" . scheme-mode) + ("\\.ss\\'" . scheme-mode) + ("\\.stk\\'" . scheme-mode) + ("\\.stklos\\'" . scheme-mode) + ;; + ("/\\.mzschemerc\\'" . scheme-mode) + ;; Non-Scheme: + ("\\.plt\\'" . quack-pltfile-mode))) + +;; Syntax Table: + +(defmacro quack-str-syntax (str) + `(,(if (and quack-gnuemacs-p (>= emacs-major-version 21)) + 'string-to-syntax + 'quack-kludged-string-to-syntax) + ,str)) + +(defun quack-kludged-string-to-syntax (str) + (let* ((str-len (length str)) + (code (aref str 0)) + (matches (if (> str-len 1) (aref str 1))) + (result (cond ((= code 32) 0) + ((= code ?_) 3) + (t (quack-internal-error)))) + (i 2)) + (while (< i str-len) + (let ((c (aref str i))) + (setq i (1+ i)) + (setq result (logior result + (lsh 1 (cond ((= c ?1) 16) + ((= c ?2) 17) + ((= c ?3) 18) + ((= c ?4) 19) + ((= c ?p) 20) + ((= c ?b) 21) + ((= c ?n) 21) + (t (quack-internal-error)))))))) + (cons result (if (= matches 32) nil matches)))) + +;; Note: We are assuming that it is better to endeavor to fontify all "#|" +;; block comments as nestable rather than as unnestable, regardless of +;; whether or not a user's target Scheme dialect supports nested. + +(defconst quack-pound-syntax-string (if quack-gnuemacs-p "_ p14bn" "_ p14b")) +;; (defconst quack-bar-syntax-string (if quack-gnuemacs-p " 23bn" " 23b")) +(defconst quack-bar-syntax-string (if quack-gnuemacs-p "_ 23bn" "_ 23b")) + +(defconst quack-pound-syntax (quack-str-syntax quack-pound-syntax-string)) +(defconst quack-bar-syntax (quack-str-syntax quack-bar-syntax-string)) + +(modify-syntax-entry ?# quack-pound-syntax-string scheme-mode-syntax-table) +(modify-syntax-entry ?| quack-bar-syntax-string scheme-mode-syntax-table) + +;; Note: Unclear why, but `scheme.el' in GNU Emacs 21.2 is doing +;; `(set-syntax-table scheme-mode-syntax-table)' in whatever buffer is +;; active at the time the Elisp package is loaded. + +;; Indent Properties: + +(put 'begin0 'scheme-indent-function 1) +(put 'c-declare 'scheme-indent-function 0) +(put 'c-lambda 'scheme-indent-function 2) +(put 'case-lambda 'scheme-indent-function 0) +(put 'catch 'scheme-indent-function 1) +(put 'chicken-setup 'scheme-indent-function 1) +(put 'class 'scheme-indent-function 'defun) +(put 'class* 'scheme-indent-function 'defun) +(put 'compound-unit/sig 'scheme-indent-function 0) +(put 'define: 'scheme-indent-function 3) +(put 'dynamic-wind 'scheme-indent-function 0) +(put 'for/fold 'scheme-indent-function 2) +(put 'instantiate 'scheme-indent-function 2) +(put 'interface 'scheme-indent-function 1) +(put 'lambda/kw 'scheme-indent-function 1) +(put 'let*-values 'scheme-indent-function 1) +(put 'let*: 'scheme-indent-function 'quack-let-colon-indent) +(put 'let+ 'scheme-indent-function 1) +(put 'let-values 'scheme-indent-function 1) +(put 'let/ec 'scheme-indent-function 1) +(put 'let: 'scheme-indent-function 'quack-let-colon-indent) +(put 'match 'scheme-indent-function 1) +(put 'mixin 'scheme-indent-function 2) +(put 'module 'scheme-indent-function 'defun) +(put 'module 'scheme-indent-function 2) +(put 'module* 'scheme-indent-function 2) +(put 'module+ 'scheme-indent-function 1) +(put 'opt-lambda 'scheme-indent-function 1) +(put 'parameterize 'scheme-indent-function 1) +(put 'parameterize* 'scheme-indent-function 1) +(put 'parameterize-break 'scheme-indent-function 1) +(put 'quasisyntax/loc 'scheme-indent-function 1) +(put 'receive 'scheme-indent-function 2) +(put 'send* 'scheme-indent-function 1) +(put 'sigaction 'scheme-indent-function 1) +(put 'struct 'scheme-indent-function 1) +(put 'sxml-match 'scheme-indent-function 1) +(put 'syntax-case 'scheme-indent-function 2) +(put 'syntax-parse 'scheme-indent-function 1) +(put 'syntax/loc 'scheme-indent-function 1) +(put 'unit 'scheme-indent-function 'defun) +(put 'unit/sig 'scheme-indent-function 2) +(put 'unless 'scheme-indent-function 1) +(put 'when 'scheme-indent-function 1) +(put 'while 'scheme-indent-function 1) +(put 'with-handlers 'scheme-indent-function 1) +(put 'with-method 'scheme-indent-function 1) +(put 'with-syntax 'scheme-indent-function 1) + +(defun quack-let-colon-indent (state indent-point normal-indent) + ;; Note: This was adapted from "scheme.el" "scheme-let-indent". + (skip-chars-forward " \t") + (if (looking-at "[-a-zA-Z0-9+*/?!@$%^&_:~]") + (lisp-indent-specform 4 state indent-point normal-indent) + (lisp-indent-specform 1 state indent-point normal-indent))) + +;; Keymaps: + +(defvar quack-scheme-mode-keymap nil) + +(setq quack-scheme-mode-keymap (make-sparse-keymap)) + +;; TODO: Maybe have an option to also map the Ctrl variants of each of these +;; keys to their respective bindings. As Eli pointed out, `C-c C-q C-x' +;; is arguably easier to type than `C-c C-q x'. Actually, though, I +;; don't like the `C-c C-q' prefix at all -- it signifies everything that +;; is wrong with traditional modifier-happy Emacs keybindings. Maybe we +;; should encourage users to set the prefix to some other key, like an +;; unmodified function key. + +(define-key quack-scheme-mode-keymap "f" 'quack-find-file) +(define-key quack-scheme-mode-keymap "k" 'quack-view-keyword-docs) +(define-key quack-scheme-mode-keymap "m" 'quack-view-manual) +(define-key quack-scheme-mode-keymap "r" 'run-scheme) +(define-key quack-scheme-mode-keymap "s" 'quack-view-srfi) +(define-key quack-scheme-mode-keymap "l" 'quack-toggle-lambda) +(define-key quack-scheme-mode-keymap "t" 'quack-tidy-buffer) + +;; Menus: + +(defmacro quack-bool-menuitem (title var &rest rest) + (unless (stringp title) (quack-internal-error)) + (unless (symbolp var) (quack-internal-error)) + `[,title (quack-option-toggle (quote ,var)) :style toggle :selected ,var + ,@rest]) + +(defmacro quack-radio-menuitems (var alist) + (unless (symbolp var) (quack-internal-error)) + (unless (listp alist) (quack-internal-error)) + `(quote ,(mapcar + (function (lambda (pair) + (let ((title (car pair)) + (value (cdr pair))) + (unless (stringp title) (quack-internal-error)) + (unless (symbolp value) (quack-internal-error)) + `[,title + (quack-option-set (quote ,var) (quote ,value)) + :style radio + :selected (eq ,var (quote ,value))]))) + alist))) + +(defconst quack-browser-radio-alist + '((nil . "(Browse-URL Default)") + (browse-url-galeon . "Galeon") + (browse-url-mozilla . "Mozilla") + (browse-url-kde . "KDE Konqueror") + (browse-url-netscape . "Netscape Navigator") + (browse-url-w3 . "Emacs W3") + (w3m-browse-url . "W3M") + (quack-w3m-browse-url-other-window . "W3M (in other window)") + (browse-url-lynx-xterm . "Lynx in Xterm") + (browse-url-lynx-emacs . "Lynx in Emacs") + (browse-url-default-windows-browser . "MS Windows Default"))) + +(defconst quack-global-menuspec + `("Quack" + ["About Quack..." quack-about] + ("Options" + ("Startup Options" + "These settings take full effect" + "once Emacs is restarted." + "---" + ,(quack-bool-menuitem "Put Quack on Global Menu Bar" quack-global-menu-p) + ,(quack-bool-menuitem "Remap Find-File Bindings" + quack-remap-find-file-bindings-p) + "---" + ["Quack Directory..." (customize-option 'quack-dir)] + ["Quack Scheme Mode Keymap Prefix..." + (customize-option 'quack-scheme-mode-keymap-prefix)]) + "---" + ("Default Program" :filter quack-defaultprogram-menufilter) + ,(quack-bool-menuitem "Always Prompt for Program" + quack-run-scheme-always-prompts-p) + ,(quack-bool-menuitem "Program Prompt Defaults to Last" + quack-run-scheme-prompt-defaults-to-last-p) + ,(quack-bool-menuitem "Remember New Programs" + quack-remember-new-programs-p) + "---" + ("Newline Behavior" + ,@(quack-radio-menuitems + quack-newline-behavior + (("Newline" . newline) + ("Newline-Indent" . newline-indent) + ("Indent-Newline-Indent" . indent-newline-indent)))) + ,(quack-bool-menuitem "Smart Open-Paren" + quack-smart-open-paren-p) + ("Switch-to-Scheme Method" + ,@(quack-radio-menuitems quack-switch-to-scheme-method + (("Other Window" . other-window) + ("Own Frame" . own-frame) + ("Cmuscheme Behavior" . cmuscheme))) + "---" + ,(quack-bool-menuitem + "Warp Pointer to Frame" + quack-warp-pointer-to-frame-p + :active (eq quack-switch-to-scheme-method 'own-frame))) + ("Fontification" + ,@(quack-radio-menuitems quack-fontify-style + (("PLT Style" . plt) + ("Extended GNU Emacs Style" . emacs) + ("Emacs Default" . nil))) + "---" + ,(quack-bool-menuitem "Pretty Lambda \(in PLT Style\)" + quack-pretty-lambda-p + :active (and quack-pretty-lambda-supported-p + (memq quack-fontify-style '(plt)))) + ,(quack-bool-menuitem "Fontify Definition Names \(in PLT Style\)" + quack-pltish-fontify-definition-names-p + :active (eq quack-fontify-style 'plt)) + ,(quack-bool-menuitem "Fontify Syntax Keywords \(in PLT Style\)" + quack-pltish-fontify-keywords-p + :active (eq quack-fontify-style 'plt)) + ;; TODO: Add menuitem here for "Fontify #: Keywords \(in PLT Style\)" + ,(quack-bool-menuitem "Fontify 3-Semicolon Comments \(in PLT Style\)" + quack-fontify-threesemi-p + :active (memq quack-fontify-style '(plt))) + ) + ("Web Browser" + ,@(mapcar (function + (lambda (n) + (let ((func (car n)) + (title (cdr n))) + `[,title + (quack-option-set 'quack-browse-url-browser-function + (quote ,func)) + :style radio + :selected ,(if (not func) + '(not quack-browse-url-browser-function) + `(eq quack-browse-url-browser-function + (quote ,func)))]))) + quack-browser-radio-alist) + ["(Other)..." + (customize-option 'quack-browse-url-browser-function) + :style radio + :selected (not (assq quack-browse-url-browser-function + quack-browser-radio-alist))]) + ,(quack-bool-menuitem "Tab Characters are Evil" quack-tabs-are-evil-p) + ("Local Keywords for Remote Manuals" + ,@(quack-radio-menuitems + quack-local-keywords-for-remote-manuals-p + (("Permit" . t) + ("Forbid" . nil) + ("Always" . always)))) + ["PLT Collection Directories..." + (customize-option 'quack-pltcollect-dirs)] + "---" + ["Customize..." quack-customize]) + "---" + ["Run Scheme" run-scheme] + ["Switch to Scheme Buffer" switch-to-scheme] + "---" + ("View Manual" :filter quack-view-manual-menufilter) + ("View SRFI" :filter quack-view-srfi-menufilter) + ["View Keyword Docs..." quack-view-keyword-docs] + ["Dired on PLT Collection..." quack-dired-pltcollect])) + +(defun quack-install-global-menu () + (when quack-global-menu-p + (quack-when-gnuemacs + (unless (assq 'Quack menu-bar-final-items) + (setq menu-bar-final-items (cons 'Quack menu-bar-final-items))) + (easy-menu-define quack-global-menu global-map "" + quack-global-menuspec)) + (quack-when-xemacs + ;; Die! Die! Die! + ;;(mapcar (function (lambda (n) + ;;(delete-menu-item '("Quack") n) + ;;(add-submenu nil quack-global-menuspec "Help" n))) + ;;(list + ;;;;current-menubar + ;;default-menubar + ;;)) + (delete-menu-item '("Quack") current-menubar) + (add-submenu nil quack-global-menuspec "Help" current-menubar) + (set-menubar-dirty-flag)))) + +;; TODO: We should make sure the user's custom settings have been loaded +;; before we do this. +(quack-install-global-menu) + +;; And die some more! +;;(quack-when-xemacs (add-hook 'after-init-hook 'quack-install-global-menu)) + +(defconst quack-scheme-mode-menuspec + `("Scheme" + ("Quack Global" ,@(cdr quack-global-menuspec)) + "---" + ["Toggle Lambda Syntax" quack-toggle-lambda] + ["Tidy Buffer Formatting" quack-tidy-buffer] + ["Comment-Out Region" comment-region] + ["Un-Comment-Out Region" quack-uncomment-region] + "---" + ["Evaluate Last S-expression" scheme-send-last-sexp] + ["Evaluate Region" scheme-send-region] + ["Evaluate Region & Go" scheme-send-region-and-go] + ["Evaluate Last Definition" scheme-send-definition] + ["Evaluate Last Definition & Go" scheme-send-definition-and-go] + ["Compile Definition" scheme-compile-definition] + ["Compile Definition & Go" scheme-compile-definition-and-go] + ["Load Scheme File" scheme-load-file] + ["Compile Scheme File" scheme-compile-file] + "---" + ["View Keyword Docs..." quack-view-keyword-docs] + ["Quack Find File" quack-find-file])) + +(defvar quack-scheme-mode-menu) +(quack-when-gnuemacs + (let ((map (make-sparse-keymap))) + (setq quack-scheme-mode-menu nil) + (easy-menu-define quack-scheme-mode-menu map "" + quack-scheme-mode-menuspec) + (define-key scheme-mode-map [menu-bar scheme] + (cons "Scheme" + (or (lookup-key map [menu-bar Scheme]) + (lookup-key map [menu-bar scheme])))))) + +(defun quack-view-manual-menufilter (arg) + (quack-menufilter-return "quack-view-manual-menufilter-menu" + (quack-manuals-menu))) + +(defun quack-view-srfi-menufilter (arg) + (quack-menufilter-return + "quack-view-srfi-menufilter-menu" + (condition-case nil + (quack-srfi-menu t) + ;; TODO: Move the generation of this fallback menu down to + ;; quack-srfi-menu. + (error '(["Update SRFI Index" quack-update-srfi-index] + "---" + ("Draft" :active nil "") + ("Final" :active nil "") + ("Withdrawn" :active nil "") + ["Other SRFI..." quack-view-srfi]))))) + +(defun quack-defaultprogram-menufilter (arg) + (quack-menufilter-return + "quack-defaultprogram-menufilter-menu" + `(,@(quack-optionmenu-items-setdefaultprogram) + "---" + ["Other Program..." quack-set-other-default-program] + "---" + ("Forget Program" + ,@(mapcar + (function + (lambda (program) + `[,(format "Forget %s" program) + (quack-forget-program ,program)])) + quack-programs))))) + +(defun quack-optionmenu-items-setdefaultprogram () + (let* ((programs (quack-sort-string-list-copy quack-programs)) + (add-default-p (and quack-default-program + (not (member quack-default-program programs))))) + (and add-default-p + (setq programs (cons quack-default-program programs))) + (mapcar + (function + (lambda (program) + (let* ((selected-p (and quack-default-program + (equal program quack-default-program)))) + `[,(format "%s%s" + program + (if (and add-default-p + (equal program quack-default-program)) + " (temporary)" + "")) + (quack-option-set 'quack-default-program ,program) + :style radio :selected ,selected-p]))) + programs))) + +(mapcar (function (lambda (sym) (put sym 'menu-enable 'mark-active))) + '(comment-region + indent-region + quack-uncomment-region + scheme-send-region + scheme-send-region-and-go)) + +;; Option Menu Callbacks: + +(defun quack-set-other-default-program () + (interactive) + (let* ((minibuffer-allow-text-properties nil) + (program (quack-without-side-whitespace + (read-string "Other Default Program: ")))) + (if (string= program "") + (message "Default program unchanged.") + (quack-remember-program-maybe program) + (quack-option-set 'quack-default-program + program)))) + +(defun quack-forget-program (program) + (setq quack-programs (delete program quack-programs)) + (quack-option-set 'quack-programs quack-programs t) + (message "Forgot program %S." program)) + +(defun quack-custom-set (sym value) + ;; Clean up the value based on the variable symbol. + (cond ((eq sym 'quack-programs) + (setq value (quack-sort-string-list-copy value)))) + + ;; Set default binding. Set local binding just for the halibut, although if + ;; there are local bindings, then other things will likely break. \(We used + ;; to have a check here, but removed it while porting to XEmacs.\) + (set sym value) + (set-default sym value) + + ;; TODO: Probably don't do this during Emacs initialization time, to avoid + ;; unnecessary behavior like: + ;; + ;; Loading ~/emacs/my-custom.el (source)... + ;; Updating Scheme Mode buffers...done + ;; Updating Scheme Mode buffers...done + ;; Updating Scheme Mode buffers...done + ;; Updating Scheme Mode buffers...done + ;; Updating Scheme Mode buffers...done + ;; Loading ~/emacs/my-custom.el (source)...done + + ;; Update dependent program state. + (cond ((memq sym '(quack-emacsish-keywords-to-fontify + quack-fontify-style + quack-fontify-threesemi-p + quack-pltish-fontify-definition-names-p + quack-pltish-fontify-keywords-p + quack-pltish-keywords-to-fontify + quack-pretty-lambda-p)) + (quack-update-scheme-mode-buffers)) + + ((eq sym 'quack-local-keywords-for-remote-manuals-p) + (quack-invalidate-manuals-caches)) + + ((eq sym 'quack-pltcollect-dirs) + (quack-invalidate-pltcollects-caches)))) + +(defun quack-option-set (sym value &optional silently) + (if quack-options-persist-p + (customize-save-variable sym value) + (quack-custom-set sym value)) + (or silently + (message "Set %s%s to: %S" + sym + (if quack-options-persist-p "" " (non-persistently)") + value))) + +(defun quack-option-toggle (sym &optional silently) + (quack-option-set sym (not (symbol-value sym)) t) + (or silently + (message "Set %s%s %s." + sym + (if quack-options-persist-p "" " (non-persistently)") + (if (symbol-value sym) "ON" "OFF")))) + +(defun quack-update-scheme-mode-buffers () + (save-excursion + (quack-activity + "Updating Scheme Mode buffers" + (mapcar (function + (lambda (buf) + (set-buffer buf) + (when (eq major-mode 'scheme-mode) + (quack-activity (format "Updating buffer %S" (buffer-name)) + (scheme-mode))))) + (buffer-list))))) + +;; Pretty Lambda: + +(defconst quack-lambda-char (make-char 'greek-iso8859-7 107)) + +(defconst quack-pretty-lambda-supported-p + (and quack-gnuemacs-p (>= emacs-major-version 21))) + +;; Font Lock: + +(defconst quack-emacsish1-font-lock-keywords + `((,(concat "[[(]" + "\\(" ; #<1 + "define\\*?" + ; #=2 #=3 + (quack-re-alt (quack-re-alt "" + "-generic" + "-generic-procedure" + "-method" + "-public" + "/kw" + "/override" + "/private" + "/public") + ; #=4 + (quack-re-alt "-macro" + "-syntax") + "-class" + "-module" + "-signature" + "-struct") + "\\)" ; #>1 + "\\>" + "[ \t]*[[(]?" + ; #=5 + "\\(\\sw+\\)?") + (1 font-lock-keyword-face) + (5 (cond ((match-beginning 3) font-lock-function-name-face) + ((match-beginning 4) font-lock-variable-name-face) + (t font-lock-type-face)) + nil t)) + + ;; PLT module definitions. + ("[[(]\\(module\\)\\>[ \t]+\\(\\sw+\\)?" + (1 font-lock-keyword-face) + (2 font-lock-type-face nil t)))) + +(defconst quack-emacsish2-font-lock-keywords + (append quack-emacsish1-font-lock-keywords + `( + ;; Misc. keywords. + (,(concat + "[[(]\\(" + (regexp-opt quack-emacsish-keywords-to-fontify) + "\\)\\>") + . 1) + ;; Class specifiers in SOS, Stklos, Goops. + ("\\<<\\sw+>\\>" . font-lock-type-face) + ;; Colon keywords. + ("\\<:\\sw+\\>" . font-lock-builtin-face)))) + +(defvar quack-pltish-font-lock-keywords nil) + +(defun quack-pltish-num-re (radix digit base16-p) + ;; These regexps started as a transliteration of the R5RS BNF to regular + ;; expressions, adapted for PLTisms, and with a few optimizations. + ;; + ;; PLTisms are that 'e' is not permitted as an exponent marker in base-16 + ;; literals, and that "decimal-point" forms are permitted in any radix. + ;; + ;; There's obvious opportunity for further optimization, especially if we + ;; relax the accepted syntax a little. These regexps have not been tested + ;; much, but, since this is only Emacs syntax fontification, false-positives + ;; and false-negatives will be obvious yet benign. + (let* ((uint (concat digit "+#*")) + (sign "[-+]?") + (suffix (quack-re-optional (if base16-p "[sSfFdDlL]" "[eEsSfFdDlL]") + sign + "[0-9]+")) + (decimal (quack-re-alt + (concat uint suffix) + (concat "\\." digit "+#*" suffix) + (concat digit + "+" + (quack-re-alt (concat "\\." digit "*") + "#+\\.") + "#*"))) + (ureal (quack-re-alt uint + (concat uint "/" uint) + decimal)) + (real (concat sign ureal)) + (complex (quack-re-alt + (concat real + (quack-re-alt (concat "@" real) + (quack-re-optional + "[-+]" + (quack-re-optional ureal) + "i") + "")) + (concat "[-+]" (quack-re-optional ureal) "i"))) + (exact (quack-re-optional "#[eEiI]")) + (prefix (quack-re-alt (concat radix exact) + (concat exact radix)))) + (concat "\\<" prefix complex "\\>"))) + +(defconst quack-pltish-fls-base + `( + ("\\`\\(MrEd\\|Welcome to MzScheme\\) v[^\n]+" . quack-banner-face) + ("\\`Gambit Version 4\\.0[^\n]*" . quack-banner-face) + ("\\`Welcome to scsh [0-9][^\n]+\nType ,\\? for help[^\n]+" + . quack-banner-face) + ("\\`MIT/GNU Scheme running under [^\n]+" . quack-banner-face) + ;;("\\`; This is the CHICKEN interpreter - Version [^\n]+\n; (c)[^\n]+" + ;; . quack-banner-face) + ;;("\\`Scheme Microcode Version[^\n]+\nMIT Scheme[^\n]+\n\\([^\n]+\n\\)+" . + ;;quack-banner-face) + ;; Unix cookie line. + ("\\`#![^\r\n]*" . quack-pltish-comment-face) + ;; Colon keywords: + ("\\<#:\\sw+\\>" . quack-pltish-colon-keyword-face) + ;; Self-evals: + ("'\\sw+\\>" . quack-pltish-selfeval-face) + ("'|\\(\\sw\\| \\)+|" . quack-pltish-selfeval-face) + ;; Note: The first alternative in the following rule will misleadingly + ;; fontify some invalid syntax, such as "#\(x". + ("\\<#\\\\\\([][-`~!@#$%&*()_+=^{}\;:'\"<>,.?/|\\\\]\\|\\sw+\\>\\)" + . quack-pltish-selfeval-face) + ("[][()]" . quack-pltish-paren-face) + ("\\<#\\(t\\|f\\)\\>" . quack-pltish-selfeval-face) + ("\\<+\\(inf.0\\|nan\\)\\>" . quack-pltish-selfeval-face) + ("\\<-inf.0\\>" . quack-pltish-selfeval-face) + ,@(mapcar (function (lambda (args) + (cons (apply 'quack-pltish-num-re args) + 'quack-pltish-selfeval-face))) + '(("#b" "[01]" nil) + ("#o" "[0-7]" nil) + ("\\(#d\\)?" "[0-9]" nil) + ("#x" "[0-9a-fA-F]" t))))) + +(defconst quack-pltish-fls-defnames + ;; TODO: Optimize these once they're fairly complete and correct. + + ;; TODO: Would be nice to fontify binding names everywhere they are + ;; introduced, such as in `let' and `lambda' forms. That may require + ;; real parsing to do reasonably well -- the kludges get too bad and + ;; slow, and font-lock gets in the way more than it helps. + + `( + ;,@quack-pltish-font-lock-keywords + + ;; Lots of definition forms that start with "define". + (,(concat "[[(]" + "define\\*?" + ;; TODO: make this into regexp-opt + (quack-re-alt "" + ":" + "-class" + "-class" + "-const-structure" + "-constant" + "-embedded" + "-entry-point" + "-external" + "-for-syntax" + "-foreign-record" + "-foreign-type" + "-foreign-variable" + "-generic" + "-generic-procedure" + "-inline" + "-location" + "-macro" + "-method" + "-opt" + "-parameters" + "-public" + "-reader-ctor" + "-record" + "-record-printer" + "-record-type" + "-signature" + "-structure" + "-syntax" + "-values" + "-values-for-syntax" + "/contract" + "/override" + "/private" + "/public") + "\\>" + "[ \t]*[[(]?" + "\\(\\sw+\\)") + (2 (let ((name (quack-match-string-no-properties 2))) + (if (= (aref name (1- (length name))) ?%) + quack-pltish-class-defn-face + quack-pltish-defn-face)) + nil t)) + + ;; Racket "struct" and "define-struct" forms: + (,(concat "[[(]" + "\\(?:define-\\)?" + "struct" + "\\>" + "[ \t]*[[(]?" + "\\(\\sw+\\)") + ;; TODO: Use a struct face rather than the class face. + (1 quack-pltish-class-defn-face nil t)) + + ;; `defmacro' and related SCM forms. + (,(concat "[[(]def" + (quack-re-alt (concat "macro" + (quack-re-alt "" "-public")) + "syntax") + "\\>[ \t]+\\(\\sw+\\)") + 3 quack-pltish-defn-face nil t) + + ;; `defmac' from SIOD. + ("[[(]defmac[ \t]+[[(][ \t]*\\(\\sw+\\)" + 1 quack-pltish-defn-face nil t) + + ;; `defvar' and `defun' from SIOD. + (,(concat "[[(]def" + (quack-re-alt "un" + "var") + "[ \t]+\\(\\sw+\\)") + 2 quack-pltish-defn-face nil t) + + ;; Guile and Chicken `define-module'. + ("[[(]define-module\\>[ \t]+[[(][ \t]*\\(\\sw+\\([ \t]+\\sw+\\)*\\)" + 1 quack-pltish-module-defn-face nil t) + + ;; PLT `define-values', `define-syntaxes', and `define-syntax-set'. + (,(concat "[[(]define-" + (quack-re-alt "values" "syntax-set" "syntaxes") + "\\>[ \t]+[[(][ \t]*\\(\\sw+\\([ \t]+\\sw+\\)*\\)") + 2 quack-pltish-defn-face nil t) + + ;; PLT `module'. + ("[[(]module\\>[ \t]+\\(\\sw+\\)" + 1 quack-pltish-module-defn-face nil t) + + ;; Named `let'. (Note: This is disabled because it's too incongruous.) + ;;("[[(]let\\>[ \t]+\\(\\sw+\\)" + ;; 1 quack-pltish-defn-face nil t) + )) + +;; TODO: Adding PLT-style (quasi)quoted list fontifying is obviously not doable +;; with just regexps. Probably requires either cloning +;; `font-lock-default-fontify-region' just to get it to call our +;; replacement syntactic pass fontification function, *or* +;; before-advising `font-lock-fontify-keywords-region' to perform our +;; syntactic pass when in scheme-mode, and around-advising +;; `font-lock-fontify-syntactically-region' to not do anything for +;; scheme-mode (or maybe setting `font-lock-keywords-only' to non-nil, +;; unless that breaks something else). Or just ditch font-lock. See +;; `font-lock-fontify-region-function' variable in font-lock specs. + +;; (defconst quack-pltish-fls-keywords +;; `((,(concat +;; "[[(]\\(" +;; (regexp-opt quack-pltish-keywords-to-fontify) +;; "\\)\\>") +;; (1 quack-pltish-keyword-face)))) + +(defun quack-install-fontification () + + (when (eq quack-fontify-style 'plt) + (set (make-local-variable 'font-lock-comment-face) + 'quack-pltish-comment-face) + (set (make-local-variable 'font-lock-string-face) + 'quack-pltish-selfeval-face)) + + (let* ((sk `(("\\(#\\)\\(|\\)" + (1 ,quack-pound-syntax) + (2 ,quack-bar-syntax)) + ("\\(|\\)\\(#\\)" + (1 ,quack-bar-syntax) + (2 ,quack-pound-syntax)))) + (pl (if (and quack-pretty-lambda-supported-p quack-pretty-lambda-p) + '(("[[(]\\(case-\\|match-\\|opt-\\)?\\(lambda\\)\\>" + 2 + (progn (compose-region (match-beginning 2) + (match-end 2) + quack-lambda-char) + nil))) + '())) + (threesemi + (if quack-fontify-threesemi-p + `( + (,(concat "^\\(\;\;\;\\)" + ;; TODO: Make this enforce space or newline after the + ;; three semicolons. + "\\(" + "[ \t]*" + "\\(" + "[^\r\n]*" + "\\)" + "\r?\n?\\)") + (1 quack-threesemi-semi-face prepend) + (2 quack-threesemi-text-face prepend) + ;;(4 quack-threesemi-h1-face prepend) + ;;(5 quack-threesemi-h2-face prepend) + ) + + ;; Funcelit: + ("^\;\;\; @\\(Package\\|section\\|unnumberedsec\\)[ \t]+\\([^\r\n]*\\)" + (2 quack-threesemi-h1-face prepend)) + ("^\;\;\; @subsection[ \t]+\\([^\r\n]*\\)" + (1 quack-threesemi-h2-face prepend)) + + ;; semiscribble: + ("^\;\;\; package +\"\\([^\r\n\"]*\\)\" *" + (1 quack-threesemi-h1-face prepend)) + ("^\;\;\; @section\\(?:\\[[^]]*\\]\\)?{\\([^\r\n]*\\)}" + (1 quack-threesemi-h1-face prepend)) + ("^\;\;\; @subsection\\(?:\\[[^]]*\\]\\)?{\\([^\r\n]*\\)}" + (1 quack-threesemi-h2-face prepend)) + + + ) + '())) + (fld `(,(cond + ((eq quack-fontify-style 'plt) + (set (make-local-variable + 'quack-pltish-font-lock-keywords) + `(,@quack-pltish-fls-base + ,@(if quack-pltish-fontify-definition-names-p + quack-pltish-fls-defnames + '()) + ,@pl + ,@(if quack-pltish-fontify-keywords-p + ;; quack-pltish-fls-keywords + `((,(concat + "[[(]\\(" + (regexp-opt + quack-pltish-keywords-to-fontify) + "\\)\\>") + (1 quack-pltish-keyword-face))) + '()) + ,@threesemi + )) + 'quack-pltish-font-lock-keywords) + ((eq quack-fontify-style 'emacs) + ;; TODO: Do pretty-lambda here too. But first get rid of + ;; this font-lock style "degrees of general gaudiness" + ;; and switch to separate options for each property of + ;; fontification. + '(quack-emacsish1-font-lock-keywords + quack-emacsish1-font-lock-keywords + quack-emacsish2-font-lock-keywords)) + (t (quack-internal-error))) + nil + t + ((?! . "w") (?$ . "w") (?% . "w") (?& . "w") (?* . "w") + (?+ . "w") (?- . "w") (?. . "w") (?/ . "w") (?: . "w") + (?< . "w") (?= . "w") (?> . "w") (?? . "w") (?@ . "w") + (?^ . "w") (?_ . "w") (?~ . "w") + ,@(if (eq quack-fontify-style 'plt) + '((?# . "w")) + '())) + ;; TODO: Using `beginning-of-defun' here could be very slow, + ;; say, when you have a large buffer that is wrapped in a + ;; `module' form. Look into whether this is a problem. + beginning-of-defun + ,@(if t ; quack-gnuemacs-p + `((font-lock-mark-block-function . mark-defun) + (font-lock-syntactic-keywords . ,sk)) + '())))) + + ;; TODO: Figure out why `font-lock-syntactic-keywords' just doesn't work in + ;; XEmacs 21, even though the syntax text properties seem to get set. + ;; We have already beaten it like an egg-sucking dog. + + ;;(if quack-xemacs-p + ;;(put 'scheme-mode 'font-lock-defaults fld) + (set (make-local-variable 'font-lock-defaults) fld) + ;;) + + ;;(when quack-xemacs-p + ;; (set (make-local-variable 'font-lock-syntactic-keywords) + ;; syntactic-keywords)) + )) + +;; Scheme Mode Startup Hook: + +(defun quack-locally-steal-key-bindings (old-func new-func) + (mapcar (function (lambda (key) + (unless (and (vectorp key) + (eq (aref key 0) 'menu-bar)) + (local-set-key key new-func)))) + (where-is-internal old-func))) + +(defun quack-shared-mode-hookfunc-stuff () + + ;; Install the Quack keymap and menu items. + (local-set-key quack-scheme-mode-keymap-prefix quack-scheme-mode-keymap) + (quack-when-xemacs + (when (featurep 'menubar) + ;;(set-buffer-menubar current-menubar) + ;; TODO: For XEmacs, we could have two versions of this menu -- the popup + ;; one would have the Global submenu, but the menubar one would have + ;; the Global submenu only if quack-global-menu-p were nil. + (add-submenu nil quack-scheme-mode-menuspec) + (set-menubar-dirty-flag) + (setq mode-popup-menu quack-scheme-mode-menuspec))) + + ;; Bind the paren-matching keys. + (local-set-key ")" 'quack-insert-closing-paren) + (local-set-key "]" 'quack-insert-closing-bracket) + + (local-set-key "(" 'quack-insert-opening-paren) + (local-set-key "[" 'quack-insert-opening-bracket) + + ;; Steal any find-file bindings. + (when quack-remap-find-file-bindings-p + (quack-locally-steal-key-bindings 'find-file 'quack-find-file) + (quack-locally-steal-key-bindings 'ido-find-file 'quack-find-file)) + + ;; Fight against tabs. + (when quack-tabs-are-evil-p + (setq indent-tabs-mode nil)) + + ;; Remove character compositions, to get rid of any pretty-lambda. (Note: + ;; This is bad, if it turns out compositions are used for other purposes in + ;; buffers that are edited with Scheme Mode.) + (when quack-pretty-lambda-supported-p + (eval '(decompose-region (point-min) (point-max)))) + + ;; Install fontification + (when quack-fontify-style + (when (and (boundp 'font-lock-keywords) + (symbol-value 'font-lock-keywords) + (not (featurep 'noweb-mode))) + ;; This warning is not given if the `noweb-mode' package is installed. + (quack-warning "`font-lock-keywords' already set when hook ran.")) + (quack-install-fontification)) + + ;; Die! Die! Die! + (quack-when-xemacs + (quack-install-global-menu))) + +(defun quack-inferior-scheme-mode-hookfunc () + (quack-shared-mode-hookfunc-stuff)) + +(defun quack-scheme-mode-hookfunc () + (quack-shared-mode-hookfunc-stuff) + + ;; Bind Return/Enter key. + (local-set-key "\r" 'quack-newline) + + ;; Install toolbar. + ;;(unless quack-xemacs-p + ;;(when (display-graphic-p) + ;;(quack-install-tool-bar))) + ) + +(add-hook 'scheme-mode-hook 'quack-scheme-mode-hookfunc) +(add-hook 'inferior-scheme-mode-hook 'quack-inferior-scheme-mode-hookfunc) + +;; Compilation Mode: + +;; TODO: Add compilation-directory-matcher support for "setup-plt: in". + +(defvar quack-saved-compilation-error-regexp-alist nil) + +(defconst quack-compilation-error-regexp-alist-additions + (let ((no-line (if quack-xemacs-p + (let ((m (make-marker))) (set-marker m 0) m) + 'quack-compile-no-line-number))) + `( + + ;; Racket 5.1.1 "raco" compile error (which can have multiple spaces): + ("^raco\\(?:cgc\\)?: +\\([^: ][^:]*\\):\\([0-9]+\\):\\([0-9]+\\):" + 1 2 3) + + ;; Racket 5.1.1 entries without line number info in "=== context ===": + ("^\\(/[^:]+\\): \\[running body\\]$" 1 nil nil 0) + + ;; PLT MzScheme 4.1.4 "=== context ===" traceback when there is only file, + ;; line, and column info, but potentially no following ":" and additional + ;; info like procedure name. + ("^\\([^:\n\" ]+\\):\\([0-9]+\\):\\([0-9]+\\)" 1 2 3) + + ;; PLT MzScheme 205 "setup-plt" + ;; load-handler: expected a `module' declaration for `bar-unit' in + ;; "/u/collects/bar/bar-unit.ss", but found something else + (,(concat "load-handler: expected a `module' declaration for `[^']+' in " + "\"\\([^:\n\"]+\\)\", but found something else") + 1 ,no-line) + + ;; PLT MzScheme 205 "setup-plt". + ;; setup-plt: Error during Compiling .zos for Foo Bar (/u/collects/fb) + ("setup-plt: Error during Compiling .zos for [^\n]+ \(\\([^\n\)]+\\)\)" + 1 ,no-line) + + ;; PLT MzScheme 4.0.1 "setup-plt". + ("setup-plt: +\\(?:WARNING: +\\)\\([^:\n]+\\)::" + 1 ,no-line) + + ;; PLT MzScheme 4.0.1 "setup-plt". + ("setup-plt: +\\(?:WARNING: +\\)\\([^:\n ][^:\n]*\\):\\([0-9]+\\):\\([0-9]+\\)" + 1 2 3) + + ;; PLT MzScheme 4.0.1 "setup-plt": + ("load-handler: expected a `module' declaration for `[^'\n]+' in #<path:\\([^>\n]+\\)>[^\n]+" + 1 ,no-line) + + ;; PLT Scheme 4.1.2 "default-load-handler" error without useful filename: + ("default-load-handler: cannot open input-file: " + nil ,no-line) + + ))) + +(defun quack-compile-no-line-number (filename column) + (list (point-marker) filename 1 (and column (string-to-number column)))) + +(defun quack-install-compilation-mode-stuff () + (unless quack-saved-compilation-error-regexp-alist + (setq quack-saved-compilation-error-regexp-alist + compilation-error-regexp-alist)) + (setq compilation-error-regexp-alist + (append quack-compilation-error-regexp-alist-additions + quack-saved-compilation-error-regexp-alist))) + +(quack-install-compilation-mode-stuff) + +;; Interpreter-mode-alist: + +(defvar quack-saved-interpreter-mode-alist nil) + +(defvar quack-interpreter-mode-alist-additions + (mapcar (function (lambda (x) + (cons x 'scheme-mode))) + '("bigloo" + "csi" + "gosh" + "gsi" + "guile" + "kawa" + "mit-scheme" + "mred" + "mred3m" + "mredcgc" + "mzscheme" + "mzscheme3m" + "mzschemecgc" + "r5rs" + "r6rs" + "rs" + "rs" + "scheme" + "scheme48" + "scsh" + "sisc" + "stklos" + "sxi"))) + +(defun quack-install-interpreter-mode-alist () + (unless quack-saved-interpreter-mode-alist + (setq quack-saved-interpreter-mode-alist + interpreter-mode-alist)) + (setq interpreter-mode-alist + (append quack-interpreter-mode-alist-additions + quack-saved-interpreter-mode-alist))) + +(quack-install-interpreter-mode-alist) + +;; PLT Package Mode: + +;; TODO: Do some simple checking and summarize what directories and files are +;; getting modified by this package. + +;; TODO: Maybe don't worry about preserving the decompressed text verbatim in +;; the buffer -- set markers and generate headings, and be able to +;; construct valid package. + +;; TODO: Command to install package from original file using "setup-plt". + +;; TODO: Fontify Scheme code file contents. + +(defvar quack-pltfile-mode-hook nil) + +(defvar quack-hiding-ovlcat) +(put 'quack-hiding-ovlcat 'face 'default) +(put 'quack-hiding-ovlcat 'intangible t) +(put 'quack-hiding-ovlcat 'invisible t) + +(defvar quack-pltfile-mode-map (make-sparse-keymap)) +(define-key quack-pltfile-mode-map "q" 'quack-pltfile-quit) +(define-key quack-pltfile-mode-map "r" 'quack-pltfile-raw) +(define-key quack-pltfile-mode-map " " 'scroll-up) + +;; TODO: Make a menu map for pltfile-mode. + +(defun quack-pltfile-mode () + (interactive) + "Major mode for viewing PLT Scheme `.plt' package files. + +\\{quack-pltfile-mode-map} + +Provided by Quack: http://www.neilvandyke.org/quack/" + (kill-all-local-variables) + (put 'quack-pltfile-mode 'mode-class 'special) + (setq major-mode 'quack-pltfile-mode) + (setq mode-name "PLT Package") + (use-local-map quack-pltfile-mode-map) + ;; Note: Currently, the `font-lock' feature is always defined, since we + ;; require it. + (when (featurep 'font-lock) + (setq font-lock-defaults nil)) + (buffer-disable-undo) + (let ((saved-bmp (buffer-modified-p))) + (quack-activity "Decoding PLT package" (quack-pltfile-decode-buffer)) + (setq buffer-read-only t) + (set-buffer-modified-p saved-bmp)) + (quack-when-xemacs + (make-variable-buffer-local 'write-contents-hooks)) + (add-hook 'write-contents-hooks 'quack-prevent-pltfile-write) + (run-hooks 'quack-pltfile-mode-hook) + (message "Decoded PLT package. %s" + (substitute-command-keys + (concat "`\\[quack-pltfile-quit]' to quit" + ", `\\[quack-pltfile-raw]' for raw format.")))) + +(defun quack-prevent-pltfile-write () + (unless (yes-or-no-p + "Write a decoded PLT package buffer?! Are you *sure*?!") + (error "Aborted write of decoded PLT package buffer."))) + +(defun quack-pltfile-raw () + (interactive) + (let ((auto-mode-alist '())) + (setq buffer-read-only nil) + (widen) + (delete-region (point-min) (point-max)) + (fundamental-mode) + (revert-buffer t t))) + +(defun quack-pltfile-quit () + (interactive) + (kill-buffer (current-buffer))) + +(defun quack-skip-whitespace-to-nonblank-line-beginning () + (save-match-data + (while (looking-at "[ \t\r\f]*\n") + (goto-char (match-end 0))))) + +(defun quack-pltfile-decode-buffer () + + ;; MIME Base-64 decode. (Note: an error is signaled if this fails.) + (base64-decode-region (point-min) (point-max)) + + ;; Gzip decompress. + (let ((coding-system-for-write (if quack-xemacs-p 'binary 'raw-text-unix)) + (coding-system-for-read (if quack-xemacs-p 'binary 'raw-text-unix)) + (inhibit-eol-conversion t) + status) + (unless (= (setq status (call-process-region (point-min) (point-max) + "gzip" t t nil "-d")) 0) + (error "Could not decompress PLT package: gzip process status %s" + status))) + + ;; Move past the "PLT" cookie, and the two sexp forms. + (goto-char (point-min)) + (unless (looking-at "PLT") + (error "This does not appear to be a PLT package file.")) + (goto-char (match-end 0)) + (forward-list 2) + (quack-skip-whitespace-to-nonblank-line-beginning) + (quack-make-face-ovlext (point-min) (point) 'quack-pltfile-prologue-face) + + ;; Process the buffer contents. + (let ((standard-input (current-buffer))) + + (while (not (eobp)) + (let ((step-beg (point))) + ;; TODO: This read will fail if we just had whitespace at the end of + ;; the file, which it shouldn't, but maybe we should check, just + ;; in case. + (let ((sym (read))) + (unless (symbolp sym) + (error "Expected a symbol, but saw: %S" sym)) + (cond + + ((eq sym 'dir) + (forward-list) + (quack-skip-whitespace-to-nonblank-line-beginning) + (quack-make-face-ovlext step-beg + (point) + 'quack-pltfile-dir-face)) + + ((memq sym '(file file-replace)) + (forward-list) + (let ((size (read))) + (unless (and (integerp size) (>= size 0)) + (error "Expected a file size, but saw: %S" size)) + (unless (looking-at "[ \t\r\n\f]*\\*") + (error "Expected a `*' after file size.")) + (goto-char (match-end 0)) + + ;; Fontify the file header. + (quack-make-face-ovlext step-beg + (1- (point)) + 'quack-pltfile-file-face) + + ;; Hide the file contents asterisk. + (quack-make-hiding-ovlext (1- (point)) (point)) + + ;; Set the coding region for the content. + (let* ((content-beg (point)) + (content-end (+ content-beg size)) + (cs (detect-coding-region content-beg + content-end))) + (goto-char content-end) + (when (listp cs) + (setq cs (car cs))) + (unless (eq cs 'undecided) + (cond ((eq cs 'undecided-dos) (setq cs 'raw-text-dos)) + ((eq cs 'undecided-mac) (setq cs 'raw-text-mac)) + ((eq cs 'undecided-unix) (setq cs 'raw-text-unix))) + (decode-coding-region content-beg content-end cs)) + ;; TODO: XEmacs 21 `decode-coding-region' seems to lose the + ;; point position. This is disconcerting, since the + ;; point semantics under coding system changes do not + ;; currently seem to be well-specified, so resetting the + ;; point here *might* not always be the right thing to + ;; do. Verify. + (quack-when-xemacs + (goto-char content-end))))) + + (t (error "Expected `dir', `file', or `file-replace', but saw: %S" + sym))))))) + + ;; Return point to top of buffer. + (goto-char (point-min))) + +;; The rest of this file except for the `provide' form is TODO comments. + +;; TODO: Add tool bar support later. +;; +;; (defvar quack-toolbarimage-width 24) +;; (defvar quack-toolbarimage-height 24) +;; +;; (defun quack-create-image (&rest args) +;; (if (and quack-gnuemacs-p (>= emacs-major-version 21)) +;; (apply 'create-image args) +;; nil)) +;; +;; (defun quack-make-toolbarimage (&rest lines) +;; ;; TODO: We really should make an efficient function to print N spaces +;; ;; or to return a string of N spaces. Or at least keep 1-2 +;; ;; strings for the left and right padding here, which will +;; ;; usually be the same for the duration of this function. +;; (quack-create-image +;; (let* ((lines-count (length lines)) +;; (blank-line (make-string quack-toolbarimage-width 32))) +;; (and (> lines-count quack-toolbarimage-height) (quack-internal-error)) +;; (with-output-to-string +;; (princ "/* XPM */\nstatic char *magick[] = {\n") +;; ;;(princ "/* columns rows colors chars-per-pixel */\n") +;; (princ (format "\"%d %d 5 1\",\n" +;; quack-toolbarimage-width quack-toolbarimage-height)) +;; (princ "\". c #f0f0f0\",\n") +;; (princ "\"@ c #0f0f0f\",\n") +;; (princ "\"g c #00b000\",\n") +;; (princ "\"r c #d00000\",\n") +;; (princ "\" c None\",\n") +;; ;;(princ "/* pixels */\n") +;; (let ((line-num 0)) +;; (mapcar (function +;; (lambda (line) +;; (princ "\"") +;; (if line +;; (let* ((c (length line)) +;; (l (/ (- quack-toolbarimage-width c) 2))) +;; (and (> c quack-toolbarimage-width) +;; (quack-internal-error)) +;; (princ (make-string l 32)) +;; (princ line) +;; (princ (make-string (- quack-toolbarimage-width +;; c l) +;; 32))) +;; (princ blank-line)) +;; (if (< (setq line-num (1+ line-num)) +;; quack-toolbarimage-height) +;; (princ "\",\n") +;; (princ "\"\n")))) +;; (let ((rows-before (/ (- quack-toolbarimage-width +;; lines-count) +;; 2))) +;; `(,@(make-list rows-before nil) +;; ,@lines +;; ,@(make-list (- quack-toolbarimage-height +;; lines-count rows-before) +;; nil))))) +;; (princ "};\n"))) +;; 'xpm t)) +;; +;; (defvar quack-tbi-evalbuf +;; (quack-make-toolbarimage +;; "@@@@@@@@@@ " +;; "@........@@ " +;; "@........@.@ ggg " +;; "@........@..@ ggg " +;; "@........@@@@@ ggg " +;; "@............@ ggg " +;; "@..@@........@ ggg " +;; "@...@@.......@ ggg " +;; "@....@@......@ ggg " +;; "@.....@@.....@ ggg " +;; "@....@@@@....@ ggg " +;; "@...@@..@@...@ ggg " +;; "@..@@....@@..@ ggg " +;; "@............@ ggg " +;; "@@@@@@@@@@@@@@ ggg " +;; " ggg " +;; " ggggggg" +;; " ggggg " +;; " ggg " +;; " g ")) +;; +;; (defvar quack-tbi-adoc +;; (quack-make-toolbarimage +;; "@@@@@@@@@@ " +;; "@........@@ " +;; "@........@.@ " +;; "@........@..@ " +;; "@........@@@@@" +;; "@...@@@......@" +;; "@..@@@@@@....@" +;; "@..@....@@...@" +;; "@...@@@.@@...@" +;; "@..@@@@@@@...@" +;; "@..@@...@@...@" +;; "@..@@..@@@...@" +;; "@...@@@@.@@..@" +;; "@............@" +;; "@@@@@@@@@@@@@@")) +;; +;; (defvar quack-tbi-manual +;; (quack-make-toolbarimage +;; "@@@@@@@@@@ " +;; "@........@@ " +;; "@........@.@ " +;; "@........@..@ " +;; "@........@@@@@" +;; "@............@" +;; "@..@@.@.@@...@" +;; "@..@@@@@@@@..@" +;; "@..@@.@@.@@..@" +;; "@..@@.@@.@@..@" +;; "@..@@.@@.@@..@" +;; "@..@@.@@.@@..@" +;; "@..@@.@@.@@..@" +;; "@............@" +;; "@@@@@@@@@@@@@@")) +;; +;; (defvar quack-tbi-manuallookup +;; (quack-make-toolbarimage +;; "@@@@@@@@@@ " +;; "@........@@ " +;; "@........@.@ " +;; "@........@..@ " +;; "@........@@@@@ " +;; "@............@ " +;; "@..@@.@@@@@@@@@@ " +;; "@...@@@........@@ " +;; "@....@@........@.@ " +;; "@.....@........@..@ " +;; "@....@@........@@@@@" +;; "@...@@@............@" +;; "@..@@.@..@@.@.@@...@" +;; "@.....@..@@@@@@@@..@" +;; "@@@@@@@..@@.@@.@@..@" +;; " @..@@.@@.@@..@" +;; " @..@@.@@.@@..@" +;; " @..@@.@@.@@..@" +;; " @..@@.@@.@@..@" +;; " @............@" +;; " @@@@@@@@@@@@@@")) +;; +;; (defvar quack-tbi-stop +;; (quack-make-toolbarimage +;; " @@@@@ " +;; " @@rrrrr@@ " +;; " @rrrrrrrrr@ " +;; " @rrrrrrrrr@ " +;; "@rr@@rrr@@rr@" +;; "@rrr@@r@@rrr@" +;; "@rrrr@@@rrrr@" +;; "@rrr@@r@@rrr@" +;; "@rr@@rrr@@rr@" +;; " @rrrrrrrrr@ " +;; " @rrrrrrrrr@ " +;; " @@rrrrr@@ " +;; " @@@@@ ")) +;; +;; (defun quack-install-tool-bar () +;; (require 'tool-bar) +;; (let ((map (make-sparse-keymap))) +;; +;; (quack-define-key-after map [quack-load-file] +;; `(menu-item "quack-evalbuffer" scheme-load-file +;; :image ,quack-tbi-evalbuf +;; :help "Load File")) +;; +;; (quack-define-key-after map [quack-alpha] +;; `(menu-item "quack-alpha" quack-alpha +;; :image ,quack-tbi-adoc +;; :help "alpha")) +;; +;; (quack-define-key-after map [quack-manual] +;; `(menu-item "quack-manual" quack-manual +;; :image ,quack-tbi-manual +;; :help "View Manual")) +;; +;; (quack-define-key-after map [quack-view-keyword-docs] +;; `(menu-item "quack-view-keyword-docs" +;; quack-view-keyword-docs +;; :image ,quack-tbi-manuallookup +;; :help "View Keyword Docs")) +;; +;; (quack-define-key-after map [quack-stop] +;; `(menu-item "quack-stop" quack-stop +;; :image ,quack-tbi-stop +;; :help "Stop")) +;; +;; (set (make-local-variable 'tool-bar-map) map))) + +;; TODO: Extend `scheme-imenu-generic-expression' for PLT-specific definition +;; forms and for definitions within modules. + +;; TODO: Clickable URLs +;; +;; (defvar quack-url-keymap) +;; +;; (setq quack-url-keymap (make-sparse-keymap)) +;; (define-key quack-url-keymap "\r" 'quack-browse-overlaid-url) +;; (define-key quack-url-keymap "q" 'quack-browse-overlaid-url) +;; +;; (defun quack-make-url-overlay (beg end &optional url) +;; (let ((ovl (make-overlay beg end nil t))) +;; (overlay-put ovl 'face 'underline) +;; (overlay-put ovl 'local-map 'quack-url-keymap) +;; (overlay-put ovl 'help-echo "Press RET to browse this URL.") +;; (overlay-put ovl 'quack-url +;; (or url (buffer-substring-no-properties beg end))) +;; ovl)) +;; +;; (defun quack-insert-url (url) +;; (let* ((beg (point))) +;; (insert url) +;; (quack-make-url-overlay beg (point)))) +;; +;; (defun quack-overlaid-url-at-point (&optional pt) +;; (let ((overlays (overlays-at (or pt (point)))) +;; (url nil)) +;; (while overlays +;; (setq overlays (if (setq url (overlay-get (car overlays) 'quack-url)) +;; (cdr overlays) +;; '()))) +;; url)) +;; +;; (defun quack-browse-overlaid-url (pt) +;; ;; Dehydration. +;; (interactive "d") +;; (quack-browse-url (quack-overlaid-url-at-point pt))) + +;; TODO: Possible Future Inferior Process I/O Stuff. Make encoding with +;; inferior process disambiguate REPL values, port output, error info, +;; etc. Start of code commented out below. This may require rewriting +;; chunks of `cmuscheme' and `comint'. +;; +;; Try to use ELI protocol first. http://www.cliki.net/ELI +;; +;; (defface quack-output-face +;; '((((class color)) (:foreground "purple4" :background "lavender")) +;; (t (:inverse-video t))) +;; "Face used for..." +;; :group 'quack) +;; +;; (defface quack-value-face +;; '((((class color)) (:foreground "blue4" :background "light sky blue")) +;; (t (:inverse-video t))) +;; "Face used for..." +;; :group 'quack) +;; +;; Escape Codes: +;; REPL State: +;; R repl read begin +;; r repl read end +;; E repl eval begin +;; e repl eval end +;; P repl print begin +;; p repl print end +;; Stream Change: +;; O output stream +;; E error stream +;; Error Info? +;; +;; (defconst quack-mzscheme-init-string +;; (let ((print-length nil) +;; (print-level nil)) +;; (prin1-to-string +;; '(let ((o (current-output-port)) +;; (i (current-input-port)) +;; (e (current-eval))) +;; ;; TODO: Define custom escaping output and error ports here. +;; (current-prompt-read +;; (lambda () +;; (display "\eR" o) +;; (begin0 (read-syntax "quack-repl" i) +;; (display "\er" o)))) +;; (current-eval +;; (lambda (n) +;; (display "\eE" o) +;; (begin0 (e n) +;; (display "\ee" o)))) +;; (current-print +;; (lambda (n) +;; (display "\eP" o) +;; (begin0 (print n o) +;; (display "\ep" o)))))))) +;; +;; In `quack' function, after call to `run-scheme': +;; +;; (add-hook 'comint-preoutput-filter-functions +;; 'quack-comint-preoutput-filter-func) +;; (comint-send-string (scheme-proc) quack-mzscheme-init-string) +;; (comint-send-string (scheme-proc) "\n") + +;; TODO: If we do that, then add pretty-printing of REPL results. + +;; TODO: Maybe provide utilities for converting to/from PLT-style +;; square-bracket paren conventions. + +;; TODO: Populate abbrevs table from keywords extracted from manuals, and from +;; definitions in current buffer. Or maybe query running MzScheme +;; process for bound symbols. + +;; TODO: Maybe use `compile-zos' to do error-checking for PLT (look up person +;; to credit with idea of using that to get more warnings). Need to know +;; more about a particular Scheme implementation than just the command +;; line to start its REPL, though. + +;; TODO: Perhaps put some initialization code that depends on user's custom +;; settings into after-init-hook. See if this works in XEmacs. + +;; TODO: Set `interpreter-mode-alist' based on interpreter list. + +;; TODO: "I think it would be good if the quack menu showed up only when emacs +;; was in Scheme mode." + +;; TODO: Support this: +;; +;; * Added 'addon-dir for `find-system-path': +;; Unix: "~/.plt-scheme" +;; Windows: "PLT Scheme" in the user's Application Data folder. +;; Mac OS X: "~/Library/PLT Scheme" +;; Mac OS Classic: "PLT Scheme" in the preferences folder. +;; +;; The version string for "~/.plt-scheme/<version>/collects/" might be: +;; mzscheme -mqe '(begin (display (version)) (exit))' +;; Double-check PLT source first. + +;; TODO: Add autoindenting to inferior Scheme buffer when pressing RET on an +;; incomplete sexp -- iff we can do this reliably enough. + +;; TODO: When tidying and point is within a series of multiple blank lines that +;; are reduced to a single blank line, leave point at the beginning of +;; the single blank line. + +;; TODO: Riastradh says: Do you suppose you could add a feature to Quack that +;; indents lists beginning with symbols of the form WITH-... & +;; CALL-WITH-... as if their SCHEME-INDENT-FUNCTION property were DEFUN? + +;; TODO: Matt Dickerson asks " Also, the command history appears to be based on +;; newlines -- I work with blocks of code in the REPL and would like C-p +;; to give me the last block, not the last line of the previous block." + +;; TODO: Maybe get appropriate PLT collection path from the default for +;; whatever "mzscheme" executable is picked up. +;; +;; mzscheme -emq '(begin (write (current-library-collection-paths)) (exit 0))' +;; ("/home/neil/collects" "/home/neil/.plt-scheme/208/collects" +;; "/usr/lib/plt/collects") + +;; TODO: Bind M-[ to quack-insert-parentheses + +;; TODO: Peter Barabas reports that `quack-global-menu-p' set to nil doesn't +;; disable the menu. + +;; TODO: Way to get default collects directories. From Matthew Flatt, +;; 2006-04-22: +;; +;; env PLTCOLLECTS="" mzscheme -mvqe '(printf "~s\n" (map path->string +;; (current-library-collection-paths)))' + +;; TODO: Have key binding to insert "lambda" (for use with pretty-lambda). +;; Suggested by Olwe Bottorff on 2006-04-20. + +;; TODO: Jerry van Dijk writes: "I would like to try out quack, but I do not +;; like its menu constantly on the main menu bar (as I use emacs for a lot of +;; things). Unfortunately sofar quack has bravely defied all my attempts to +;; remove it. From desecting the customize option to adding (define-key +;; global-map [menu-bar quack] nil)" + +;; TODO: We could do this: +;; +;; mzscheme -m -e "(begin (display #\') (write (map path->string (current-library-collection-paths))) (newline) (exit))" +;; '("/home/neil/collects" +;; "/home/neil/.plt-scheme/360/collects" +;; "/usr/lib/plt/collects") + +;; emacs22 -batch -no-site-file -f batch-byte-compile quack.el ; rm quack.elc +;; emacs21 -batch -no-site-file -f batch-byte-compile quack.el ; rm quack.elc +;; emacs20 -batch -no-site-file -f batch-byte-compile quack.el ; rm quack.elc +;; xemacs21 -batch -no-site-file -f batch-byte-compile quack.el ; rm quack.elc + +;; End: + +(provide 'quack) + +;; quack.el ends here diff --git a/emacs/rainbow-mode.el b/emacs/rainbow-mode.el new file mode 100644 index 0000000..8207abc --- /dev/null +++ b/emacs/rainbow-mode.el @@ -0,0 +1,207 @@ +;;; rainbow-mode.el --- prints color strings with colored background + +;; Copyright (C) 2010 Julien Danjou + +;; Author: Julien Danjou <julien@danjou.info> +;; Keywords: strings, faces + +;; This file is NOT 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 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; This minor mode will add background to strings that matches color names. +;; i.e. +;; #0000ff +;; Will be printed in white with a blue background. +;; + +;;; Code: + +(eval-when-compile + (require 'cl)) + +(require 'regexp-opt) +(require 'faces) + +(defgroup rainbow nil + "Show color strings with a background color." + :tag "Rainbow" + :group 'help) + +;; Hexadecimal colors +(defvar rainbow-hexadecimal-colors-font-lock-keywords + '("#[0-9a-fA-F]\\{3\\}[0-9a-fA-F]\\{3\\}?" + (0 (rainbow-colorize-itself))) + "Font-lock keywords to add for hexadecimal colors.") + +;; rgb() colors +(defvar rainbow-html-rgb-colors-font-lock-keywords + '(("rgb(\s*\\([0-9]\\{1,3\\}\\(?:\s*%\\)?\\)\s*,\s*\\([0-9]\\{1,3\\}\\(?:\s*%\\)?\\)\s*,\s*\\([0-9]\\{1,3\\}\\(?:\s*%\\)?\\)\s*)" + (0 (rainbow-colorize-rgb))) + ("rgba(\s*\\([0-9]\\{1,3\\}\\(?:\s*%\\)?\\)\s*,\s*\\([0-9]\\{1,3\\}\\(?:\s*%\\)?\\)\s*,\s*\\([0-9]\\{1,3\\}\\(?:\s*%\\)?\\)\s*,\s*[0-9]\\{1,3\\}\s*%?\s*)" + (0 (rainbow-colorize-rgb)))) + "Font-lock keywords to add for RGB colors.") + +;; HTML colors name +(defvar rainbow-html-colors-font-lock-keywords nil + "Font-lock keywords to add for HTML colors.") +(make-variable-buffer-local 'rainbow-html-colors-font-lock-keywords) + +(defcustom rainbow-html-colors-alist + '(("black" . "#000000") + ("silver" . "#C0C0C0") + ("gray" . "#808080") + ("white" . "#FFFFFF") + ("maroon" . "#800000") + ("red" . "#FF0000") + ("purple" . "#800080") + ("fuchsia" . "#FF00FF") + ("green" . "#008000") + ("lime" . "#00FF00") + ("olive" . "#808000") + ("yellow" . "#FFFF00") + ("navy" . "#000080") + ("blue" . "#0000FF") + ("teal" . "#008080") + ("aqua" . "#00FFFF")) + "Alist of HTML colors. +Each entry should have the form (COLOR-NAME . HEXADECIMAL-COLOR)." + :group 'rainbow) + +(defcustom rainbow-html-colors-major-mode-list + '(html-mode css-mode php-mode nxml-mode xml-mode) + "List of major mode where HTML colors are enabled when +`rainbow-html-colors' is set to auto." + :group 'rainbow) + +(defcustom rainbow-html-colors 'auto + "When to enable HTML colors. +If set to t, the HTML colors will be enabled. If set to nil, the +HTML colors will not be enabled. If set to auto, the HTML colors +will be enabled if a major mode has been detected from the +`rainbow-html-colors-major-mode-list'." + :group 'rainbow) + +;; X colors +(defvar rainbow-x-colors-font-lock-keywords + `(,(regexp-opt (x-defined-colors) 'words) + (0 (rainbow-colorize-itself))) + "Font-lock keywords to add for X colors.") + +(defcustom rainbow-x-colors-major-mode-list + '(emacs-lisp-mode lisp-interaction-mode c-mode c++-mode java-mode) + "List of major mode where X colors are enabled when +`rainbow-x-colors' is set to auto." + :group 'rainbow) + +(defcustom rainbow-x-colors 'auto + "When to enable X colors. +If set to t, the X colors will be enabled. If set to nil, the +X colors will not be enabled. If set to auto, the X colors +will be enabled if a major mode has been detected from the +`rainbow-x-colors-major-mode-list'." + :group 'rainbow) + +;; Functions +(defun rainbow-colorize-match (color) + "Return a matched string propertized with a face whose +background is COLOR. The foreground is computed using +`rainbow-color-luminance', and is either white or black." + (put-text-property + (match-beginning 0) (match-end 0) + 'face `((:foreground ,(if (> 128.0 (rainbow-x-color-luminance color)) + "white" "black")) + (:background ,color)))) + +(defun rainbow-colorize-itself () + "Colorize a match with itself." + (rainbow-colorize-match (match-string-no-properties 0))) + +(defun rainbow-colorize-by-assoc (assoc-list) + "Colorize a match with its association from ASSOC-LIST." + (rainbow-colorize-match (cdr (assoc (match-string-no-properties 0) assoc-list)))) + +(defun rainbow-rgb-relative-to-absolute (number) + "Convert a relative NUMBER to absolute. If NUMBER is absolute, return NUMBER. +This will convert \"80 %\" to 204, \"100 %\" to 255 but \"123\" to \"123\"" + (let ((string-length (- (length number) 1))) + ;; Is this a number with %? + (if (eq (elt number string-length) ?%) + (/ (* (string-to-number (substring number 0 string-length)) 255) 100) + (string-to-number number)))) + +(defun rainbow-colorize-rgb () + "Colorize a match with itself." + (let ((r (rainbow-rgb-relative-to-absolute (match-string-no-properties 1))) + (g (rainbow-rgb-relative-to-absolute (match-string-no-properties 2))) + (b (rainbow-rgb-relative-to-absolute (match-string-no-properties 3)))) + (rainbow-colorize-match (format "#%02X%02X%02X" r g b)))) + +(defun rainbow-color-luminance (red green blue) + "Calculate the luminance of color composed of RED, BLUE and GREEN." + (floor (+ (* .2126 red) (* .7152 green) (* .0722 blue)) 256)) + +(defun rainbow-x-color-luminance (color) + "Calculate the luminance of a color string (e.g. \"#ffaa00\", \"blue\")." + (let* ((values (x-color-values color)) + (r (car values)) + (g (cadr values)) + (b (caddr values))) + (rainbow-color-luminance r g b))) + +(defun rainbow-turn-on () + "Turn on raibow-mode." + (font-lock-add-keywords nil + (list rainbow-hexadecimal-colors-font-lock-keywords)) + ;; Activate X colors? + (when (or (eq rainbow-x-colors t) + (and (eq rainbow-x-colors 'auto) + (memq major-mode rainbow-x-colors-major-mode-list))) + (font-lock-add-keywords nil + (list rainbow-x-colors-font-lock-keywords))) + ;; Activate HTML colors? + (when (or (eq rainbow-html-colors t) + (and (eq rainbow-html-colors 'auto) + (memq major-mode rainbow-html-colors-major-mode-list))) + (setq rainbow-html-colors-font-lock-keywords + `(,(regexp-opt (mapcar 'car rainbow-html-colors-alist) 'words) + (0 (rainbow-colorize-by-assoc rainbow-html-colors-alist)))) + (font-lock-add-keywords nil + `(,rainbow-html-colors-font-lock-keywords + ,@rainbow-html-rgb-colors-font-lock-keywords)))) + +(defun rainbow-turn-off () + "Turn off rainbow-mode." + (font-lock-remove-keywords + nil + (list + rainbow-hexadecimal-colors-font-lock-keywords + rainbow-html-colors-font-lock-keywords + rainbow-x-colors-font-lock-keywords + rainbow-html-rgb-colors-font-lock-keywords))) + +;;;###autoload +(define-minor-mode rainbow-mode + "Colorize strings that represent colors. +This will fontify with colors the string like \"#aabbcc\" or \"blue\"" + :lighter " Rbow" + (progn + (if rainbow-mode + (rainbow-turn-on) + (rainbow-turn-off)) + ;; Turn on font lock + (font-lock-mode 1))) + +(provide 'rainbow-mode) diff --git a/emacs/redo.el b/emacs/redo.el new file mode 100644 index 0000000..a0229d7 --- /dev/null +++ b/emacs/redo.el @@ -0,0 +1,203 @@ +;;; redo.el -- Redo/undo system for XEmacs + +;; Copyright (C) 1985, 1986, 1987, 1993-1995 Free Software Foundation, Inc. +;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp. +;; Copyright (C) 1997 Kyle E. Jones + +;; Author: Kyle E. Jones, February 1997 +;; Keywords: lisp, extensions + +;; 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: Not in FSF. + +;;; Commentary: + +;; Derived partly from lisp/prim/simple.el in XEmacs. + +;; 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. +;; +;; Installation: +;; +;; Save this file as redo.el, byte compile it and put the +;; resulting redo.elc file in a directory that is listed in +;; load-path. +;; +;; In your .emacs file, add +;; (require 'redo) +;; and the system will be enabled. + +;;; Code: + +(provide 'redo) + +(defvar redo-version "1.02" + "Version number for the Redo package.") + +(defvar last-buffer-undo-list nil + "The head of buffer-undo-list at the last time an undo or redo was done.") +(make-variable-buffer-local 'last-buffer-undo-list) + +(make-variable-buffer-local 'pending-undo-list) + +;; Emacs 20 variable +(defvar undo-in-progress) + +(defun redo (&optional count) + "Redo the the most recent undo. +Prefix arg COUNT means redo the COUNT most recent undos. +If you have modified the buffer since the last redo or undo, +then you cannot redo any undos before then." + (interactive "*p") + (if (eq buffer-undo-list t) + (error "No undo information in this buffer")) + (if (eq last-buffer-undo-list nil) + (error "No undos to redo")) + (or (eq last-buffer-undo-list buffer-undo-list) + ;; skip one undo boundary and all point setting commands up + ;; until the next undo boundary and try again. + (let ((p buffer-undo-list)) + (and (null (car-safe p)) (setq p (cdr-safe p))) + (while (and p (integerp (car-safe p))) + (setq p (cdr-safe p))) + (eq last-buffer-undo-list p)) + (error "Buffer modified since last undo/redo, cannot redo")) + (and (or (eq buffer-undo-list pending-undo-list) + (eq (cdr buffer-undo-list) pending-undo-list)) + (error "No further undos to redo in this buffer")) + (or (eq (selected-window) (minibuffer-window)) + (message "Redo...")) + (let ((modified (buffer-modified-p)) + (undo-in-progress t) + (recent-save (recent-auto-save-p)) + (old-undo-list buffer-undo-list) + (p (cdr buffer-undo-list)) + (records-between 0)) + ;; count the number of undo records between the head of the + ;; undo chain and the pointer to the next change. Note that + ;; by `record' we mean clumps of change records, not the + ;; boundary records. The number of records will always be a + ;; multiple of 2, because an undo moves the pending pointer + ;; forward one record and prepend a record to the head of the + ;; chain. Thus the separation always increases by two. When + ;; we decrease it we will decrease it by a multiple of 2 + ;; also. + (while p + (cond ((eq p pending-undo-list) + (setq p nil)) + ((null (car p)) + (setq records-between (1+ records-between)) + (setq p (cdr p))) + (t + (setq p (cdr p))))) + ;; we're off by one if pending pointer is nil, because there + ;; was no boundary record in front of it to count. + (and (null pending-undo-list) + (setq records-between (1+ records-between))) + ;; don't allow the user to redo more undos than exist. + ;; only half the records between the list head and the pending + ;; pointer are undos that are a part of this command chain. + (setq count (min (/ records-between 2) count) + p (primitive-undo (1+ count) buffer-undo-list)) + (if (eq p old-undo-list) + nil ;; nothing happened + ;; set buffer-undo-list to the new undo list. if has been + ;; shortened by `count' records. + (setq buffer-undo-list p) + ;; primitive-undo returns a list without a leading undo + ;; boundary. add one. + (undo-boundary) + ;; now move the pending pointer backward in the undo list + ;; to reflect the redo. sure would be nice if this list + ;; were doubly linked, but no... so we have to run down the + ;; list from the head and stop at the right place. + (let ((n (- records-between count))) + (setq p (cdr old-undo-list)) + (while (and p (> n 0)) + (if (null (car p)) + (setq n (1- n))) + (setq p (cdr p))) + (setq pending-undo-list p))) + (and modified (not (buffer-modified-p)) + (delete-auto-save-file-if-necessary recent-save)) + (or (eq (selected-window) (minibuffer-window)) + (message "Redo!")) + (setq last-buffer-undo-list buffer-undo-list))) + +(defun undo (&optional arg) + "Undo some previous changes. +Repeat this command to undo more changes. +A numeric argument serves as a repeat count." + (interactive "*p") + (let ((modified (buffer-modified-p)) + (recent-save (recent-auto-save-p))) + (or (eq (selected-window) (minibuffer-window)) + (message "Undo...")) + (or (eq last-buffer-undo-list buffer-undo-list) + ;; skip one undo boundary and all point setting commands up + ;; until the next undo boundary and try again. + (let ((p buffer-undo-list)) + (and (null (car-safe p)) (setq p (cdr-safe p))) + (while (and p (integerp (car-safe p))) + (setq p (cdr-safe p))) + (eq last-buffer-undo-list p)) + (progn (undo-start) + (undo-more 1))) + (undo-more (or arg 1)) + ;; Don't specify a position in the undo record for the undo command. + ;; Instead, undoing this should move point to where the change is. + ;; + ;;;; The old code for this was mad! It deleted all set-point + ;;;; references to the position from the whole undo list, + ;;;; instead of just the cells from the beginning to the next + ;;;; undo boundary. This does what I think the other code + ;;;; meant to do. + (let ((list buffer-undo-list) + (prev nil)) + (while (and list (not (null (car list)))) + (if (integerp (car list)) + (if prev + (setcdr prev (cdr list)) + ;; impossible now, but maybe not in the future + (setq buffer-undo-list (cdr list)))) + (setq prev list + list (cdr list)))) + (and modified (not (buffer-modified-p)) + (delete-auto-save-file-if-necessary recent-save))) + (or (eq (selected-window) (minibuffer-window)) + (message "Undo!")) + (setq last-buffer-undo-list buffer-undo-list)) + +;;; redo.el ends here diff --git a/emacs/scheme-complete.el b/emacs/scheme-complete.el new file mode 100644 index 0000000..214bbdb --- /dev/null +++ b/emacs/scheme-complete.el @@ -0,0 +1,4115 @@ +;;; scheme-complete.el --- Smart tab completion for Emacs + +;;; This code is written by Alex Shinn and placed in the Public +;;; Domain. All warranties are disclaimed. + +;;; Commentary: + +;; This file provides a single function, `scheme-smart-complete', +;; which you can use for intelligent, context-sensitive completion +;; for any Scheme implementation. To use it just load this file and +;; bind that function to a key in your preferred mode: +;; +;; (autoload 'scheme-smart-complete "scheme-complete" nil t) +;; (eval-after-load 'scheme +;; '(progn (define-key scheme-mode-map "\e\t" 'scheme-smart-complete))) +;; +;; Alternately, you may want to just bind TAB to the +;; `scheme-complete-or-indent' function, which indents at the start +;; of a line and otherwise performs the smart completion: +;; +;; (eval-after-load 'scheme +;; '(progn (define-key scheme-mode-map "\t" 'scheme-complete-or-indent))) +;; +;; If you use eldoc-mode (included in Emacs), you can also get live +;; scheme documentation with: +;; +;; (autoload 'scheme-get-current-symbol-info "scheme-complete" nil t) +;; (add-hook 'scheme-mode-hook +;; (lambda () +;; (make-local-variable 'eldoc-documentation-function) +;; (setq eldoc-documentation-function 'scheme-get-current-symbol-info) +;; (eldoc-mode))) +;; +;; There's a single custom variable, `scheme-default-implementation', +;; which you can use to specify your preferred implementation when we +;; can't infer it from the source code. +;; +;; That's all there is to it. + +;;; History: + +;; 0.8.2: 2008/07/04 - both TAB and M-TAB scroll results (thanks Peter Bex), +;; better MATCH handling, fixed SRFI-55, other bugfixes +;; 0.8.1: 2008/04/17 - great renaming, everthing starts with `scheme-' +;; also, don't scan imported modules multiple times +;; 0.8: 2008/02/08 - several parsing bugfixes on unclosed parenthesis +;; (thanks to Kazushi NODA) +;; filename completion works properly on absolute paths +;; eldoc works properly on dotted lambdas +;; 0.7: 2008/01/18 - handles higher-order types (for apply, map, etc.) +;; smarter string completion (hostname, username, etc.) +;; smarter type inference, various bugfixes +;; 0.6: 2008/01/06 - more bugfixes (merry christmas) +;; 0.5: 2008/01/03 - handling internal defines, records, smarter +;; parsing +;; 0.4: 2007/11/14 - silly bugfix plus better repo env support +;; for searching chicken and gauche modules +;; 0.3: 2007/11/13 - bugfixes, better inference, smart strings +;; 0.2: 2007/10/15 - basic type inference +;; 0.1: 2007/09/11 - initial release +;; +;; What is this talk of 'release'? Klingons do not make software +;; 'releases'. Our software 'escapes' leaving a bloody trail of +;; designers and quality assurance people in its wake. + +;;; Code: + +(require 'cl) + +;; this is just to eliminate some warnings when compiling - this file +;; should be loaded after 'scheme +(eval-when (compile) + (require 'scheme)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; info +;; +;; identifier type [doc-string no-type-display?] +;; +;; types: +;; +;; pair, number, symbol, etc. +;; (lambda (param-types) [return-type]) +;; (syntax (param-types) [return-type]) +;; (set name values ...) +;; (flags name values ...) +;; (list type) +;; (string expander) +;; (special type function [outer-function]) + +(defvar *scheme-r5rs-info* + '((define (syntax (identifier value) undefined) "define a new variable") + (set! (syntax (identifier value) undefined) "set the value of a variable") + (let (syntax (vars body \.\.\.)) "bind new local variables in parallel") + (let* (syntax (vars body \.\.\.)) "bind new local variables sequentially") + (letrec (syntax (vars body \.\.\.)) "bind new local variables recursively") + (lambda (syntax (params body \.\.\.)) "procedure syntax") + (if (syntax (cond then else)) "conditional evaluation") + (cond (syntax (clause \.\.\.)) "try each clause until one succeeds") + (case (syntax (expr clause \.\.\.)) "look for EXPR among literal lists") + (delay (syntax (expr)) "create a promise to evaluate EXPR") + (and (syntax (expr \.\.\.)) "evaluate EXPRs while true, return last") + (or (syntax (expr \.\.\.)) "return the first true EXPR") + (begin (syntax (expr \.\.\.)) "evaluate each EXPR in turn and return the last") + (do (syntax (vars finish body \.\.\.)) "simple iterator") + (quote (syntax (expr)) "represent EXPR literally without evaluating it") + (quasiquote (syntax (expr)) "quote literals allowing escapes") + (unquote (syntax (expr)) "escape an expression inside quasiquote") + (unquote-splicing (syntax (expr)) "escape and splice a list expression inside quasiquote") + (define-syntax (syntax (identifier body \.\.\.) undefined) "create a macro") + (let-syntax (syntax (syntaxes body \.\.\.)) "a local macro") + (letrec-syntax (syntax (syntaxes body \.\.\.)) "a local macro") + (syntax-rules (syntax (literals clauses \.\.\.) undefined) "simple macro language") + (eqv? (lambda (obj1 obj2) bool) "returns #t if OBJ1 and OBJ2 are the same object") + (eq? (lambda (obj1 obj2) bool) "finer grained version of EQV?") + (equal? (lambda (obj1 obj2) bool) "recursive equivalence") + (not (lambda (obj) bool) "returns #t iff OBJ is false") + (boolean? (lambda (obj) bool) "returns #t iff OBJ is #t or #f") + (number? (lambda (obj) bool) "returns #t iff OBJ is a number") + (complex? (lambda (obj) bool) "returns #t iff OBJ is a complex number") + (real? (lambda (obj) bool) "returns #t iff OBJ is a real number") + (rational? (lambda (obj) bool) "returns #t iff OBJ is a rational number") + (integer? (lambda (obj) bool) "returns #t iff OBJ is an integer") + (exact? (lambda (z) bool) "returns #t iff Z is exact") + (inexact? (lambda (z) bool) "returns #t iff Z is inexact") + (= (lambda (z1 z2 \.\.\.) bool) "returns #t iff the arguments are all equal") + (< (lambda (x1 x2 \.\.\.) bool) "returns #t iff the arguments are monotonically increasing") + (> (lambda (x1 x2 \.\.\.) bool) "returns #t iff the arguments are monotonically decreasing") + (<= (lambda (x1 x2 \.\.\.) bool) "returns #t iff the arguments are monotonically nondecreasing") + (>= (lambda (x1 x2 \.\.\.) bool) "returns #t iff the arguments are monotonically nonincreasing") + (zero? (lambda (z) bool)) + (positive? (lambda (x1) bool)) + (negative? (lambda (x1) bool)) + (odd? (lambda (n) bool)) + (even? (lambda (n) bool)) + (max (lambda (x1 x2 \.\.\.) x3) "returns the maximum of the arguments") + (min (lambda (x1 x2 \.\.\.) x3) "returns the minimum of the arguments") + (+ (lambda (z1 \.\.\.) z)) + (* (lambda (z1 \.\.\.) z)) + (- (lambda (z1 \.\.\.) z)) + (/ (lambda (z1 \.\.\.) z)) + (abs (lambda (x1) x2) "returns the absolute value of X") + (quotient (lambda (n1 n2) n) "integer division") + (remainder (lambda (n1 n2) n) "same sign as N1") + (modulo (lambda (n1 n2) n) "same sign as N2") + (gcd (lambda (n1 \.\.\.) n) "greatest common divisor") + (lcm (lambda (n2 \.\.\.) n) "least common multiple") + (numerator (lambda (rational) n)) + (denominator (lambda (rational) n)) + (floor (lambda (x1) n) "largest integer not larger than X") + (ceiling (lambda (x1) n) "smallest integer not smaller than X") + (truncate (lambda (x1) n) "drop fractional part") + (round (lambda (x1) n) "round to even (banker's rounding)") + (rationalize (lambda (x1 y) n) "rational number differing from X by at most Y") + (exp (lambda (z) z) "e^Z") + (log (lambda (z) z) "natural logarithm of Z") + (sin (lambda (z) z) "sine function") + (cos (lambda (z) z) "cosine function") + (tan (lambda (z) z) "tangent function") + (asin (lambda (z) z) "arcsine function") + (acos (lambda (z) z) "arccosine function") + (atan (lambda (z) z) "arctangent function") + (sqrt (lambda (z) z) "principal square root of Z") + (expt (lambda (z1 z2) z) "returns Z1 raised to the Z2 power") + (make-rectangular (lambda (x1 x2) z) "create a complex number") + (make-polar (lambda (x1 x2) z) "create a complex number") + (real-part (lambda (z) x1)) + (imag-part (lambda (z) x1)) + (magnitude (lambda (z) x1)) + (angle (lambda (z) x1)) + (exact->inexact (lambda (z) z)) + (inexact->exact (lambda (z) z)) + (number->string (lambda (z :optional radix) str)) + (string->number (lambda (str :optional radix) z)) + (pair? (lambda (obj) bool) "returns #t iff OBJ is a pair") + (cons (lambda (obj1 obj2) pair) "create a newly allocated pair") + (car (lambda (pair) obj)) + (cdr (lambda (pair) obj)) + (set-car! (lambda (pair obj) undefined)) + (set-cdr! (lambda (pair obj) undefined)) + (caar (lambda (pair) obj)) + (cadr (lambda (pair) obj)) + (cdar (lambda (pair) obj)) + (cddr (lambda (pair) obj)) + (caaar (lambda (pair) obj)) + (caadr (lambda (pair) obj)) + (cadar (lambda (pair) obj)) + (caddr (lambda (pair) obj)) + (cdaar (lambda (pair) obj)) + (cdadr (lambda (pair) obj)) + (cddar (lambda (pair) obj)) + (cdddr (lambda (pair) obj)) + (caaaar (lambda (pair) obj)) + (caaadr (lambda (pair) obj)) + (caadar (lambda (pair) obj)) + (caaddr (lambda (pair) obj)) + (cadaar (lambda (pair) obj)) + (cadadr (lambda (pair) obj)) + (caddar (lambda (pair) obj)) + (cadddr (lambda (pair) obj)) + (cdaaar (lambda (pair) obj)) + (cdaadr (lambda (pair) obj)) + (cdadar (lambda (pair) obj)) + (cdaddr (lambda (pair) obj)) + (cddaar (lambda (pair) obj)) + (cddadr (lambda (pair) obj)) + (cdddar (lambda (pair) obj)) + (cddddr (lambda (pair) obj)) + (null? (lambda (obj) bool) "returns #t iff OBJ is the empty list") + (list? (lambda (obj) bool) "returns #t iff OBJ is a proper list") + (list (lambda (obj \.\.\.) list) "returns a newly allocated list") + (length (lambda (list) n)) + (append (lambda (list \.\.\.) list) "concatenates the list arguments") + (reverse (lambda (list) list)) + (list-tail (lambda (list k) list) "returns the Kth cdr of LIST") + (list-ref (lambda (list k) obj) "returns the Kth element of LIST") + (memq (lambda (obj list)) "the sublist of LIST whose car is eq? to OBJ") + (memv (lambda (obj list)) "the sublist of LIST whose car is eqv? to OBJ") + (member (lambda (obj list)) "the sublist of LIST whose car is equal? to OBJ") + (assq (lambda (obj list)) "the element of LIST whose car is eq? to OBJ") + (assv (lambda (obj list)) "the element of LIST whose car is eqv? to OBJ") + (assoc (lambda (obj list)) "the element of LIST whose car is equal? to OBJ") + (symbol? (lambda (obj) bool) "returns #t iff OBJ is a symbol") + (symbol->string (lambda (symbol) str)) + (string->symbol (lambda (str) symbol)) + (char? (lambda (obj) bool) "returns #t iff OBJ is a character") + (char=? (lambda (ch1 ch2) bool)) + (char<? (lambda (ch1 ch2) bool)) + (char>? (lambda (ch1 ch2) bool)) + (char<=? (lambda (ch1 ch2) bool)) + (char>=? (lambda (ch1 ch2) bool)) + (char-ci=? (lambda (ch1 ch2) bool)) + (char-ci<? (lambda (ch1 ch2) bool)) + (char-ci>? (lambda (ch1 ch2) bool)) + (char-ci<=? (lambda (ch1 ch2) bool)) + (char-ci>=? (lambda (ch1 ch2) bool)) + (char-alphabetic? (lambda (ch) bool)) + (char-numeric? (lambda (ch) bool)) + (char-whitespace? (lambda (ch) bool)) + (char-upper-case? (lambda (ch) bool)) + (char-lower-case? (lambda (ch) bool)) + (char->integer (lambda (ch) int)) + (integer->char (lambda (int) ch)) + (char-upcase (lambda (ch) ch)) + (char-downcase (lambda (ch) ch)) + (string? (lambda (obj) bool) "returns #t iff OBJ is a string") + (make-string (lambda (k :optional ch) str) "a new string of length k") + (string (lambda (ch \.\.\.) str) "a new string made of the char arguments") + (string-length (lambda (str) n) "the number of characters in STR") + (string-ref (lambda (str i) ch) "the Ith character of STR") + (string-set! (lambda (str i ch) undefined) "set the Ith character of STR to CH") + (string=? (lambda (str1 str2) bool)) + (string-ci=? (lambda (str1 str2) bool)) + (string<? (lambda (str1 str2) bool)) + (string>? (lambda (str1 str2) bool)) + (string<=? (lambda (str1 str2) bool)) + (string>=? (lambda (str1 str2) bool)) + (string-ci<? (lambda (str1 str2) bool)) + (string-ci>? (lambda (str1 str2) bool)) + (string-ci<=? (lambda (str1 str2) bool)) + (string-ci>=? (lambda (str1 str2) bool)) + (substring (lambda (str start end) str)) + (string-append (lambda (str \.\.\.) str) "concatenate the string arguments") + (string->list (lambda (str) list)) + (list->string (lambda (list) str)) + (string-copy (lambda (str) str)) + (string-fill! (lambda (str ch) undefined) "set every char in STR to CH") + (vector? (lambda (obj) bool) "returns #t iff OBJ is a vector") + (make-vector (lambda (len :optional fill) vec) "a new vector of K elements") + (vector (lambda (obj \.\.\.) vec)) + (vector-length (lambda (vec) n) "the number of elements in VEC") + (vector-ref (lambda (vec i) obj) "the Ith element of VEC") + (vector-set! (lambda (vec i obj) undefined) "set the Ith element of VEC to OBJ") + (vector->list (lambda (vec) list)) + (list->vector (lambda (list) vec)) + (vector-fill! (lambda (vec obj) undefined) "set every element in VEC to OBJ") + (procedure? (lambda (obj) bool) "returns #t iff OBJ is a procedure") + (apply (lambda ((lambda obj a) obj \.\.\.) a) "procedure application") + (map (lambda ((lambda obj a) obj \.\.\.) (list a)) "a new list of PROC applied to every element of LIST") + (for-each (lambda ((lambda obj a) obj \.\.\.) undefined) "apply PROC to each element of LIST in order") + (force (lambda (promise) obj) "force the delayed value of PROMISE") + (call-with-current-continuation (lambda (proc) obj) "goto on steroids") + (values (lambda (obj \.\.\.)) "send multiple values to the calling continuation") + (call-with-values (lambda (producer consumer) obj)) + (dynamic-wind (lambda (before-thunk thunk after-thunk) obj)) + (scheme-report-environment (lambda (int) env) "INT should be 5") + (null-environment (lambda (int) env) "INT should be 5") + (call-with-input-file (lambda (path proc) input-port)) + (call-with-output-file (lambda (path proc) output-port)) + (input-port? (lambda (obj) bool) "returns #t iff OBJ is an input port") + (output-port? (lambda (obj) bool) "returns #t iff OBJ is an output port") + (current-input-port (lambda () input-port) "the default input for read procedures") + (current-output-port (lambda () output-port) "the default output for write procedures") + (with-input-from-file (lambda (path thunk) obj)) + (with-output-to-file (lambda (path thunk) obj)) + (open-input-file (lambda (path) input-port)) + (open-output-file (lambda (path) output-port)) + (close-input-port (lambda (input-port))) + (close-output-port (lambda (output-port))) + (read (lambda (:optional input-port) obj) "read a datum") + (read-char (lambda (:optional input-port) ch) "read a single character") + (peek-char (lambda (:optional input-port) ch)) + (eof-object? (lambda (obj) bool) "returns #t iff OBJ is the end-of-file object") + (char-ready? (lambda (:optional input-port) bool)) + (write (lambda (object :optional output-port) undefined) "write a datum") + (display (lambda (object :optional output-port) undefined) "display") + (newline (lambda (:optional output-port) undefined) "send a linefeed") + (write-char (lambda (char :optional output-port) undefined) "write a single character") + (load (lambda (filename) undefined) "evaluate expressions from a file") + (eval (lambda (expr env))) + )) + +(defvar *scheme-srfi-info* + [ + ;; SRFI 0 + ("Feature-based conditional expansion construct" + (cond-expand (syntax (clause \.\.\.)))) + + ;; SRFI 1 + ("List Library" + (xcons (lambda (object object) pair)) + (cons* (lambda (object \.\.\.) pair)) + (make-list (lambda (integer :optional object) list)) + (list-tabulate (lambda (integer procedure) list)) + (list-copy (lambda (list) list)) + (circular-list (lambda (object \.\.\.) list)) + (iota (lambda (integer :optional integer integer) list)) + (proper-list? (lambda (object) bool)) + (circular-list? (lambda (object) bool)) + (dotted-list? (lambda (object) bool)) + (not-pair? (lambda (object) bool)) + (null-list? (lambda (object) bool)) + (list= (lambda (procedure list \.\.\.) bool)) + (first (lambda (pair))) + (second (lambda (pair))) + (third (lambda (pair))) + (fourth (lambda (pair))) + (fifth (lambda (pair))) + (sixth (lambda (pair))) + (seventh (lambda (pair))) + (eighth (lambda (pair))) + (ninth (lambda (pair))) + (tenth (lambda (pair))) + (car+cdr (lambda (pair))) + (take (lambda (pair integer) list)) + (drop (lambda (pair integer) list)) + (take-right (lambda (pair integer) list)) + (drop-right (lambda (pair integer) list)) + (take! (lambda (pair integer) list)) + (drop-right! (lambda (pair integer) list)) + (split-at (lambda (pair integer) list)) + (split-at! (lambda (pair integer) list)) + (last (lambda (pair) obj)) + (last-pair (lambda (pair) pair)) + (length+ (lambda (object) n)) + (concatenate (lambda (list) list)) + (append! (lambda (list \.\.\.) list)) + (concatenate! (lambda (list) list)) + (reverse! (lambda (list) list)) + (append-reverse (lambda (list list) list)) + (append-reverse! (lambda (list list) list)) + (zip (lambda (list \.\.\.) list)) + (unzip1 (lambda (list) list)) + (unzip2 (lambda (list) list)) + (unzip3 (lambda (list) list)) + (unzip4 (lambda (list) list)) + (unzip5 (lambda (list) list)) + (count (lambda (procedure list \.\.\.) n)) + (fold (lambda ((lambda obj a) object list \.\.\.) a)) + (unfold (lambda (procedure procedure procedure object :optional procedure) obj)) + (pair-fold (lambda ((lambda obj a) object list \.\.\.) a)) + (reduce (lambda ((lambda obj a) object list \.\.\.) a)) + (fold-right (lambda ((lambda obj a) object list \.\.\.) a)) + (unfold-right (lambda (procedure procedure procedure object :optional object) obj)) + (pair-fold-right (lambda ((lambda obj a) object list \.\.\.) a)) + (reduce-right (lambda ((lambda obj a) object list \.\.\.) a)) + (append-map (lambda (procedure list \.\.\.) list)) + (append-map! (lambda (procedure list \.\.\.) list)) + (map! (lambda (procedure list \.\.\.) list)) + (pair-for-each (lambda (procedure list \.\.\.) undefined)) + (filter-map (lambda (procedure list \.\.\.) list)) + (map-in-order (lambda (procedure list \.\.\.) list)) + (filter (lambda (procedure list) list)) + (partition (lambda (procedure list) list)) + (remove (lambda (procedure list) list)) + (filter! (lambda (procedure list) list)) + (partition! (lambda (procedure list) list)) + (remove! (lambda (procedure list) list)) + (find (lambda (procedure list) obj)) + (find-tail (lambda (procedure list) obj)) + (any (lambda ((lambda obj a) list \.\.\.) a)) + (every (lambda ((lambda obj a) list \.\.\.) a)) + (list-index (lambda (procedure list \.\.\.) (or bool integer))) + (take-while (lambda (procedure list) list)) + (drop-while (lambda (procedure list) list)) + (take-while! (lambda (procedure list) list)) + (span (lambda (procedure list) list)) + (break (lambda (procedure list) list)) + (span! (lambda (procedure list) list)) + (break! (lambda (procedure list) list)) + (delete (lambda (object list :optional procedure) list)) + (delete-duplicates (lambda (list :optional procedure) list)) + (delete! (lambda (obj list :optional procedure) list)) + (delete-duplicates! (lambda (list :optional procedure) list)) + (alist-cons (lambda (obj1 obj2 alist) alist)) + (alist-copy (lambda (alist) alist)) + (alist-delete (lambda (obj alist) alist)) + (alist-delete! (lambda (obj alist) alist)) + (lset<= (lambda (procedure list \.\.\.) bool)) + (lset= (lambda (procedure list \.\.\.) bool)) + (lset-adjoin (lambda (procedure list object \.\.\.) list)) + (lset-union (lambda (procedure list \.\.\.) list)) + (lset-union! (lambda (procedure list \.\.\.) list)) + (lset-intersection (lambda (procedure list \.\.\.) list)) + (lset-intersection! (lambda (procedure list \.\.\.) list)) + (lset-difference (lambda (procedure list \.\.\.) list)) + (lset-difference! (lambda (procedure list \.\.\.) list)) + (lset-xor (lambda (procedure list \.\.\.) list)) + (lset-xor! (lambda (procedure list \.\.\.) list)) + (lset-diff+intersection (lambda (procedure list \.\.\.) list)) + (lset-diff+intersection! (lambda (procedure list \.\.\.) list)) + + ) + + ;; SRFI 2 + ("AND-LET*: an AND with local bindings, a guarded LET* special form" + (and-let* (syntax (bindings body \.\.\.)))) + + () + + ;; SRFI 4 + ("Homogeneous numeric vector datatypes" + + (u8vector? (lambda (obj) bool)) + (make-u8vector (lambda (size integer) u8vector)) + (u8vector (lambda (integer \.\.\.) u8vector)) + (u8vector-length (lambda (u8vector) n)) + (u8vector-ref (lambda (u8vector i) int)) + (u8vector-set! (lambda (u8vector i u8value) undefined)) + (u8vector->list (lambda (u8vector) list)) + (list->u8vector (lambda (list) u8vector)) + + (s8vector? (lambda (obj) bool)) + (make-s8vector (lambda (size integer) s8vector)) + (s8vector (lambda (integer \.\.\.) s8vector)) + (s8vector-length (lambda (s8vector) n)) + (s8vector-ref (lambda (s8vector i) int)) + (s8vector-set! (lambda (s8vector i s8value) undefined)) + (s8vector->list (lambda (s8vector) list)) + (list->s8vector (lambda (list) s8vector)) + + (u16vector? (lambda (obj) bool)) + (make-u16vector (lambda (size integer) u16vector)) + (u16vector (lambda (integer \.\.\.))) + (u16vector-length (lambda (u16vector) n)) + (u16vector-ref (lambda (u16vector i) int)) + (u16vector-set! (lambda (u16vector i u16value) undefined)) + (u16vector->list (lambda (u16vector) list)) + (list->u16vector (lambda (list) u16vector)) + + (s16vector? (lambda (obj) bool)) + (make-s16vector (lambda (size integer) s16vector)) + (s16vector (lambda (integer \.\.\.) s16vector)) + (s16vector-length (lambda (s16vector) n)) + (s16vector-ref (lambda (s16vector i) int)) + (s16vector-set! (lambda (s16vector i s16value) undefined)) + (s16vector->list (lambda (s16vector) list)) + (list->s16vector (lambda (list) s16vector)) + + (u32vector? (lambda (obj) bool)) + (make-u32vector (lambda (size integer) u32vector)) + (u32vector (lambda (integer \.\.\.) u32vector)) + (u32vector-length (lambda (u32vector) n)) + (u32vector-ref (lambda (u32vector i) int)) + (u32vector-set! (lambda (u32vector i u32value) undefined)) + (u32vector->list (lambda (u32vector) list)) + (list->u32vector (lambda (list) u32vector)) + + (s32vector? (lambda (obj) bool)) + (make-s32vector (lambda (size integer) s32vector)) + (s32vector (lambda (integer \.\.\.) s32vector)) + (s32vector-length (lambda (s32vector) n)) + (s32vector-ref (lambda (s32vector i) int)) + (s32vector-set! (lambda (s32vector i s32value) undefined)) + (s32vector->list (lambda (s32vector) list)) + (list->s32vector (lambda (list) s32vector)) + + (u64vector? (lambda (obj) bool)) + (make-u64vector (lambda (size integer) u64vector)) + (u64vector (lambda (integer \.\.\.) u64vector)) + (u64vector-length (lambda (u64vector) n)) + (u64vector-ref (lambda (u64vector i) int)) + (u64vector-set! (lambda (u64vector i u64value) undefined)) + (u64vector->list (lambda (u64vector) list)) + (list->u64vector (lambda (list) u64vector)) + + (s64vector? (lambda (obj) bool)) + (make-s64vector (lambda (size integer) s64vector)) + (s64vector (lambda (integer \.\.\.) s64vector)) + (s64vector-length (lambda (s64vector) n)) + (s64vector-ref (lambda (s64vector i) int)) + (s64vector-set! (lambda (s64vector i s64value) undefined)) + (s64vector->list (lambda (s64vector) list)) + (list->s64vector (lambda (list) s64vector)) + + (f32vector? (lambda (obj) bool)) + (make-f32vector (lambda (size integer) f32vector)) + (f32vector (lambda (number \.\.\.) f32vector)) + (f32vector-length (lambda (f32vector) n)) + (f32vector-ref (lambda (f32vector i) int)) + (f32vector-set! (lambda (f32vector i f32value) undefined)) + (f32vector->list (lambda (f32vector) list)) + (list->f32vector (lambda (list) f32vector)) + + (f64vector? (lambda (obj) bool)) + (make-f64vector (lambda (size integer) f64vector)) + (f64vector (lambda (number \.\.\.) f64vector)) + (f64vector-length (lambda (f64vector) n)) + (f64vector-ref (lambda (f64vector i) int)) + (f64vector-set! (lambda (f64vector i f64value) undefined)) + (f64vector->list (lambda (f64vector) list)) + (list->f64vector (lambda (list) f64vector)) + ) + + ;; SRFI 5 + ("A compatible let form with signatures and rest arguments" + (let (syntax (bindings body \.\.\.)))) + + ;; SRFI 6 + ("Basic String Ports" + (open-input-string (lambda (str) input-port)) + (open-output-string (lambda () output-port)) + (get-output-string (lambda (output-port) str))) + + ;; SRFI 7 + ("Feature-based program configuration language" + (program (syntax (clause \.\.\.))) + (feature-cond (syntax (clause)))) + + ;; SRFI 8 + ("receive: Binding to multiple values" + (receive (syntax (identifiers producer body \.\.\.)))) + + ;; SRFI 9 + ("Defining Record Types" + (define-record-type (syntax (name constructor-name pred-name fields \.\.\.)))) + + ;; SRFI 10 + ("Sharp-Comma External Form" + (define-reader-ctor (syntax (name proc) undefined))) + + ;; SRFI 11 + ("Syntax for receiving multiple values" + (let-values (syntax (bindings body \.\.\.))) + (let-values* (syntax (bindings body \.\.\.)))) + + () + + ;; SRFI 13 + ("String Library" + (string-map (lambda (proc str :optional start end) str)) + (string-map! (lambda (proc str :optional start end) undefined)) + (string-fold (lambda (kons knil str :optional start end) obj)) + (string-fold-right (lambda (kons knil str :optional start end) obj)) + (string-unfold (lambda (p f g seed :optional base make-final) str)) + (string-unfold-right (lambda (p f g seed :optional base make-final) str)) + (string-tabulate (lambda (proc len) str)) + (string-for-each (lambda (proc str :optional start end) undefined)) + (string-for-each-index (lambda (proc str :optional start end) undefined)) + (string-every (lambda (pred str :optional start end) obj)) + (string-any (lambda (pred str :optional start end) obj)) + (string-hash (lambda (str :optional bound start end) int)) + (string-hash-ci (lambda (str :optional bound start end) int)) + (string-compare (lambda (string1 string2 lt-proc eq-proc gt-proc :optional start end) obj)) + (string-compare-ci (lambda (string1 string2 lt-proc eq-proc gt-proc :optional start end) obj)) + (string= (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string<> (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string< (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string> (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string<= (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string>= (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-ci= (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-ci<> (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-ci< (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-ci> (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-ci<= (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-ci>= (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-titlecase (lambda (string :optional start end) str)) + (string-upcase (lambda (string :optional start end) str)) + (string-downcase (lambda (string :optional start end) str)) + (string-titlecase! (lambda (string :optional start end) undefined)) + (string-upcase! (lambda (string :optional start end) undefined)) + (string-downcase! (lambda (string :optional start end) undefined)) + (string-take (lambda (string nchars) str)) + (string-drop (lambda (string nchars) str)) + (string-take-right (lambda (string nchars) str)) + (string-drop-right (lambda (string nchars) str)) + (string-pad (lambda (string k :optional char start end) str)) + (string-pad-right (lambda (string k :optional char start end) str)) + (string-trim (lambda (string :optional char/char-set/pred start end) str)) + (string-trim-right (lambda (string :optional char/char-set/pred start end) str)) + (string-trim-both (lambda (string :optional char/char-set/pred start end) str)) + (string-filter (lambda (char/char-set/pred string :optional start end) str)) + (string-delete (lambda (char/char-set/pred string :optional start end) str)) + (string-index (lambda (string char/char-set/pred :optional start end) (or integer bool))) + (string-index-right (lambda (string char/char-set/pred :optional end start) (or integer bool))) + (string-skip (lambda (string char/char-set/pred :optional start end) (or integer bool))) + (string-skip-right (lambda (string char/char-set/pred :optional end start) (or integer bool))) + (string-count (lambda (string char/char-set/pred :optional start end) n)) + (string-prefix-length (lambda (string1 string2 :optional start1 end1 start2 end2) n)) + (string-suffix-length (lambda (string1 string2 :optional start1 end1 start2 end2) n)) + (string-prefix-length-ci (lambda (string1 string2 :optional start1 end1 start2 end2) n)) + (string-suffix-length-ci (lambda (string1 string2 :optional start1 end1 start2 end2) n)) + (string-prefix? (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-suffix? (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-prefix-ci? (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-suffix-ci? (lambda (string1 string2 :optional start1 end1 start2 end2) bool)) + (string-contains (lambda (string pattern :optional s-start s-end p-start p-end) obj)) + (string-contains-ci (lambda (string pattern :optional s-start s-end p-start p-end) obj)) + (string-fill! (lambda (string char :optional start end) undefined)) + (string-copy! (lambda (to tstart from :optional fstart fend) undefined)) + (string-copy (lambda (str :optional start end) str)) + (substring/shared (lambda (str start :optional end) str)) + (string-reverse (lambda (str :optional start end) str)) + (string-reverse! (lambda (str :optional start end) undefined)) + (reverse-list->string (lambda (char-list) str)) + (string->list (lambda (str :optional start end) list)) + (string-concatenate (lambda (string-list) str)) + (string-concatenate/shared (lambda (string-list) str)) + (string-append/shared (lambda (str \.\.\.) str)) + (string-concatenate-reverse (lambda (string-list :optional final-string end) str)) + (string-concatenate-reverse/shared (lambda (string-list :optional final-string end) str)) + (xsubstring (lambda (str from :optional to start end) str)) + (string-xcopy! (lambda (target tstart str from :optional to start end) undefined)) + (string-null? (lambda (str) bool)) + (string-join (lambda (string-list :optional delim grammar) str)) + (string-tokenize (lambda (string :optional token-chars start end) str)) + (string-replace (lambda (str1 str2 start1 end1 :optional start2 end2) str)) + (string-kmp-partial-search (lambda (pat rv str i :optional c= p-start s-start s-end) n)) + (make-kmp-restart-vector (lambda (str :optional c= start end) vec)) + (kmp-step (lambda (pat rv c i c= p-start) n)) + ) + + ;; SRFI 14 + ("Character-Set Library" + (char-set? (lambda (cset) bool)) + (char-set= (lambda (cset \.\.\.) bool)) + (char-set<= (lambda (cset \.\.\.) bool)) + (char-set-hash (lambda (cset :optional int) int)) + (char-set-cursor (lambda (cset) cursor)) + (char-set-ref (lambda (cset cursor) ch)) + (char-set-cursor-next (lambda (cset cursor) int)) + (end-of-char-set? (lambda (cursor) bool)) + (char-set-fold (lambda (proc obj cset) obj)) + (char-set-unfold (lambda (proc proc proc obj :optional obj) cset)) + (char-set-unfold! (lambda (proc proc proc obj obj) cset)) + (char-set-for-each (lambda (proc cset) undefined)) + (char-set-map (lambda (proc cset) cset)) + (char-set-copy (lambda (cset) cset)) + (char-set (lambda (ch \.\.\.) cset)) + (list->char-set (lambda (list :optional obj) cset)) + (list->char-set! (lambda (list cset) cset)) + (string->char-set (lambda (str :optional cset) cset)) + (string->char-set! (lambda (str cset) cset)) + (ucs-range->char-set (lambda (int int :optional bool cset) cset)) + (ucs-range->char-set! (lambda (int int bool cset) cset)) + (char-set-filter (lambda (proc cset :optional base-cset) cset)) + (char-set-filter! (lambda (proc cset base-cset) cset)) + (->char-set (lambda (obj) cset)) + (char-set-size (lambda (cset) n)) + (char-set-count (lambda (proc cset) n)) + (char-set-contains? (lambda (cset ch) bool)) + (char-set-every (lambda (proc cset) obj)) + (char-set-any (lambda (proc cset) obj)) + (char-set-adjoin (lambda (cset ch \.\.\.) cset)) + (char-set-delete (lambda (cset ch \.\.\.) cset)) + (char-set-adjoin! (lambda (cset ch \.\.\.) cset)) + (char-set-delete! (lambda (cset ch \.\.\.) cset)) + (char-set->list (lambda (cset) list)) + (char-set->string (lambda (cset) str)) + (char-set-complement (lambda (cset) cset)) + (char-set-union (lambda (cset \.\.\.) cset)) + (char-set-intersection (lambda (cset \.\.\.) cset)) + (char-set-xor (lambda (cset \.\.\.) cset)) + (char-set-difference (lambda (cset \.\.\.) cset)) + (char-set-diff+intersection (lambda (cset \.\.\.) cset)) + (char-set-complement! (lambda (cset) cset)) + (char-set-union! (lambda (cset \.\.\.) cset)) + (char-set-intersection! (lambda (cset \.\.\.) cset)) + (char-set-xor! (lambda (cset \.\.\.) cset)) + (char-set-difference! (lambda (cset \.\.\.) cset)) + (char-set-diff+intersection! (lambda (cset \.\.\.) cset)) + (char-set:lower-case char-set) + (char-set:upper-case char-set) + (char-set:letter char-set) + (char-set:digit char-set) + (char-set:letter+digit char-set) + (char-set:graphic char-set) + (char-set:printing char-set) + (char-set:whitespace char-set) + (char-set:blank char-set) + (char-set:iso-control char-set) + (char-set:punctuation char-set) + (char-set:symbol char-set) + (char-set:hex-digit char-set) + (char-set:ascii char-set) + (char-set:empty char-set) + (char-set:full char-set) + ) + + () + + ;; SRFI 16 + ("Syntax for procedures of variable arity" + (case-lambda (syntax (clauses \.\.\.) procedure))) + + ;; SRFI 17 + ("Generalized set!" + (set! (syntax (what value) undefined))) + + ;; SRFI 18 + ("Multithreading support" + (current-thread (lambda () thread)) + (thread? (lambda (obj) bool)) + (make-thread (lambda (thunk :optional name) thread)) + (thread-name (lambda (thread) name)) + (thread-specific (lambda (thread))) + (thread-specific-set! (lambda (thread obj))) + (thread-base-priority (lambda (thread))) + (thread-base-priority-set! (lambda (thread number))) + (thread-priority-boost (lambda (thread))) + (thread-priority-boost-set! (lambda (thread number))) + (thread-quantum (lambda (thread))) + (thread-quantum-set! (lambda (thread number))) + (thread-start! (lambda (thread))) + (thread-yield! (lambda ())) + (thread-sleep! (lambda (number))) + (thread-terminate! (lambda (thread))) + (thread-join! (lambda (thread :optional timeout timeout-val))) + (mutex? (lambda (obj) bool)) + (make-mutex (lambda (:optional name) mutex)) + (mutex-name (lambda (mutex) name)) + (mutex-specific (lambda (mutex))) + (mutex-specific-set! (lambda (mutex obj))) + (mutex-state (lambda (mutex))) + (mutex-lock! (lambda (mutex :optional timeout thread))) + (mutex-unlock! (lambda (mutex :optional condition-variable timeout))) + (condition-variable? (lambda (obj) bool)) + (make-condition-variable (lambda (:optional name) condition-variable)) + (condition-variable-name (lambda (condition-variable) name)) + (condition-variable-specific (lambda (condition-variable))) + (condition-variable-specific-set! (lambda (condition-variable obj))) + (condition-variable-signal! (lambda (condition-variable))) + (condition-variable-broadcast! (lambda (condition-variable))) + (current-time (lambda () time)) + (time? (lambda (obj) bool)) + (time->seconds (lambda (time) x1)) + (seconds->time (lambda (x1) time)) + (current-exception-handler (lambda () handler)) + (with-exception-handler (lambda (handler thunk))) + (raise (lambda (obj))) + (join-timeout-exception? (lambda (obj) bool)) + (abandoned-mutex-exception? (lambda (obj) bool)) + (terminated-thread-exception? (lambda (obj) bool)) + (uncaught-exception? (lambda (obj) bool)) + (uncaught-exception-reason (lambda (exc) obj)) + ) + + ;; SRFI 19 + ("Time Data Types and Procedures" + (current-date (lambda (:optional tz-offset)) date) + (current-julian-day (lambda ()) jdn) + (current-modified-julian-day (lambda ()) mjdn) + (current-time (lambda (:optional time-type)) time) + (time-resolution (lambda (:optional time-type)) nanoseconds) + (make-time (lambda (type nanosecond second))) + (time? (lambda (obj))) + (time-type (lambda (time))) + (time-nanosecond (lambda (time))) + (time-second (lambda (time))) + (set-time-type! (lambda (time))) + (set-time-nanosecond! (lambda (time))) + (set-time-second! (lambda (time))) + (copy-time (lambda (time))) + (time<=? (lambda (time1 time2))) + (time<? (lambda (time1 time2))) + (time=? (lambda (time1 time2))) + (time>=? (lambda (time1 time2))) + (time>? (lambda (time1 time2))) + (time-difference (lambda (time1 time2))) + (time-difference! (lambda (time1 time2))) + (add-duration (lambda (time duration))) + (add-duration! (lambda (time duration))) + (subtract-duration (lambda (time duration))) + (subtract-duration! (lambda (time duration))) + (make-date (lambda (nanosecond second minute hour day month year zone-offset))) + (date? (lambda (obj))) + (date-nanosecond (lambda (date))) + (date-second (lambda (date))) + (date-minute (lambda (date))) + (date-hour (lambda (date))) + (date-day (lambda (date))) + (date-month (lambda (date))) + (date-year (lambda (date))) + (date-zone-offset (lambda (date))) + (date-year-day (lambda (date))) + (date-week-day (lambda (date))) + (date-week-number (lambda (date))) + (date->julian-day (lambda (date))) + (date->modified-julian-day (lambda (date))) + (date->time-monotonic (lambda (date))) + (date->time-tai (lambda (date))) + (date->time-utc (lambda (date))) + (julian-day->date (lambda (date))) + (julian-day->time-monotonic (lambda (date))) + (julian-day->time-tai (lambda (date))) + (julian-day->time-utc (lambda (date))) + (modified-julian-day->date (lambda (date))) + (modified-julian-day->time-monotonic (lambda (date))) + (modified-julian-day->time-tai (lambda (date))) + (modified-julian-day->time-utc (lambda (date))) + (time-monotonic->date (lambda (date))) + (time-monotonic->julian-day (lambda (date))) + (time-monotonic->modified-julian-day (lambda (date))) + (time-monotonic->time-monotonic (lambda (date))) + (time-monotonic->time-tai (lambda (date))) + (time-monotonic->time-tai! (lambda (date))) + (time-monotonic->time-utc (lambda (date))) + (time-monotonic->time-utc! (lambda (date))) + (time-tai->date (lambda (date))) + (time-tai->julian-day (lambda (date))) + (time-tai->modified-julian-day (lambda (date))) + (time-tai->time-monotonic (lambda (date))) + (time-tai->time-monotonic! (lambda (date))) + (time-tai->time-utc (lambda (date))) + (time-tai->time-utc! (lambda (date))) + (time-utc->date (lambda (date))) + (time-utc->julian-day (lambda (date))) + (time-utc->modified-julian-day (lambda (date))) + (time-utc->time-monotonic (lambda (date))) + (time-utc->time-monotonic! (lambda (date))) + (time-utc->time-tai (lambda (date))) + (time-utc->time-tai! (lambda (date))) + (date->string (lambda (date :optional format-string))) + (string->date (lambda (input-string template-string))) + ) + + () + + ;; SRFI 21 + ("Real-time multithreading support" + srfi-18) ; same as srfi-18 + + ;; SRFI 22 + ("Running Scheme Scripts on Unix" + ) + + ;; SRFI 23 + ("Error reporting mechanism" + (error (lambda (reason-string arg \.\.\.)))) + + () + + ;; SRFI 25 + ("Multi-dimensional Array Primitives" + (array? (lambda (obj))) + (make-array (lambda (shape :optional init))) + (shape (lambda (bound \.\.\.))) + (array (lambda (shape obj \.\.\.))) + (array-rank (lambda (array))) + (array-start (lambda (array))) + (array-end (lambda (array))) + (array-shape (lambda (array))) + (array-ref (lambda (array i \.\.\.))) + (array-set! (lambda (array obj \.\.\.) undefined)) + (share-array (lambda (array shape proc))) + ) + + ;; SRFI 26 + ("Notation for Specializing Parameters without Currying" + (cut (syntax (obj \.\.\.))) + (cute (lambda (obj \.\.\.)))) + + ;; SRFI 27 + ("Sources of Random Bits" + (random-integer (lambda (n))) + (random-real (lambda ())) + (default-random-source (lambda ())) + (make-random-source (lambda ())) + (random-source? (lambda (obj))) + (random-source-state-ref (lambda (random-source))) + (random-source-state-set! (lambda (random-source state))) + (random-source-randomize! (lambda (random-source))) + (random-source-pseudo-randomize! (lambda (random-source i j))) + (random-source-make-integers (lambda (random-source))) + (random-source-make-reals (lambda (random-source))) + ) + + ;; SRFI 28 + ("Basic Format Strings" + (format (lambda (port-or-boolean format-string arg \.\.\.)))) + + ;; SRFI 29 + ("Localization" + (current-language (lambda (:optional symbol))) + (current-country (lambda (:optional symbol))) + (current-locale-details (lambda (:optional list))) + (declare-bundle! (lambda (bundle-name association-list))) + (store-bundle (lambda (bundle-name))) + (load-bundle! (lambda (bundle-name))) + (localized-template (lambda (package-name message-template-name))) + ) + + ;; SRFI 30 + ("Nested Multi-line Comments" + ) + + ;; SRFI 31 + ("A special form for recursive evaluation" + (rec (syntax (name body \.\.\.) procedure))) + + () + + () + + ;; SRFI 34 + ("Exception Handling for Programs" + (guard (syntax (clauses \.\.\.))) + (raise (lambda (obj))) + ) + + ;; SRFI 35 + ("Conditions" + (make-condition-type (lambda (id parent field-name-list))) + (condition-type? (lambda (obj))) + (make-condition (lambda (condition-type))) + (condition? (lambda (obj))) + (condition-has-type? (lambda (condition condition-type))) + (condition-ref (lambda (condition field-name))) + (make-compound-condition (lambda (condition \.\.\.))) + (extract-condition (lambda (condition condition-type))) + (define-condition-type (syntax (name parent pred-name fields \.\.\.))) + (condition (syntax (type-field-binding \.\.\.))) + ) + + ;; SRFI 36 + ("I/O Conditions" + (&error condition) + (&i/o-error condition) + (&i/o-port-error condition) + (&i/o-read-error condition) + (&i/o-write-error condition) + (&i/o-closed-error condition) + (&i/o-filename-error condition) + (&i/o-malformed-filename-error condition) + (&i/o-file-protection-error condition) + (&i/o-file-is-read-only-error condition) + (&i/o-file-already-exists-error condition) + (&i/o-no-such-file-error condition) + ) + + ;; SRFI 37 + ("args-fold: a program argument processor" + (args-fold + (arg-list option-list unrecognized-option-proc operand-proc seed \.\.\.)) + (option-processor (lambda (option name arg seeds \.\.\.))) + (operand-processor (lambda (operand seeds \.\.\.))) + (option (lambda (name-list required-arg? optional-arg? option-proc))) + (option-names (lambda (option))) + (option-required-arg? (lambda (option))) + (option-optional-arg? (lambda (option))) + (option-processor (lambda (option))) + ) + + ;; SRFI 38 + ("External Representation for Data With Shared Structure" + (write-with-shared-structure (lambda (obj :optional port optarg))) + (read-with-shared-structure (lambda (:optional port))) + ) + + ;; SRFI 39 + ("Parameter objects" + (make-parameter (lambda (init-value :optional converter))) + (parameterize (syntax (bindings body \.\.\.)))) + + ;; SRFI 40 + ("A Library of Streams" + (stream-null stream) + (stream-cons (syntax (obj stream))) + (stream? (lambda (obj))) + (stream-null? (lambda (obj))) + (stream-pair? (lambda (obj))) + (stream-car (lambda (stream))) + (stream-cdr (lambda (stream))) + (stream-delay (syntax (expr))) + (stream (lambda (obj \.\.\.))) + (stream-unfoldn (lambda (generator-proc seed n))) + (stream-map (lambda (proc stream \.\.\.))) + (stream-for-each (lambda (proc stream \.\.\.) undefined)) + (stream-filter (lambda (pred stream))) + ) + + () + + ;; SRFI 42 + ("Eager Comprehensions" + (list-ec (syntax)) + (append-ec (syntax)) + (sum-ec (syntax)) + (min-ec (syntax)) + (max-ec (syntax)) + (any?-ec (syntax)) + (every?-ec (syntax)) + (first-ec (syntax)) + (do-ec (syntax)) + (fold-ec (syntax)) + (fold3-ec (syntax)) + (:list (syntax () undefined)) + (:string (syntax () undefined)) + (:vector (syntax () undefined)) + (:integers (syntax () undefined)) + (:range (syntax () undefined)) + (:real-range (syntax () undefined)) + (:char-range (syntax () undefined)) + (:port (syntax () undefined)) + (:do (syntax () undefined)) + (:let (syntax () undefined)) + (:parallel (syntax () undefined)) + (:while (syntax () undefined)) + (:until (syntax () undefined)) + ) + + ;; SRFI 43 + ("Vector Library" + (vector-unfold (f length initial-seed \.\.\.)) + (vector-unfold-right (lambda (f length initial-seed \.\.\.))) + (vector-tabulate (lambda (f size))) + (vector-copy (lambda (vec :optional start end fill))) + (vector-reverse-copy (lambda (vec :optional start end))) + (vector-append (lambda (vec \.\.\.))) + (vector-concatenate (lambda (vector-list))) + (vector-empty? (lambda (obj))) + (vector= (lambda (eq-proc vec \.\.\.))) + (vector-fold (lambda (kons knil vec \.\.\.))) + (vector-fold-right (lambda (kons knil vec \.\.\.))) + (vector-map (lambda (f vec \.\.\.))) + (vector-map! (lambda (f vec \.\.\.))) + (vector-for-each (lambda (f vec \.\.\.) undefined)) + (vector-count (lambda (pred vec \.\.\.))) + (vector-index (lambda (pred vec \.\.\.))) + (vector-index-right (lambda (pred vec \.\.\.))) + (vector-skip (lambda (pred vec \.\.\.))) + (vector-skip-right (lambda (pred vec \.\.\.))) + (vector-binary-search (lambda (vec value cmp-proc))) + (vector-any (lambda (pred vec \.\.\.))) + (vector-every (lambda (pred vec \.\.\.))) + (vector-swap! (lambda (vec i j) undefined)) + (vector-reverse! (lambda (vec :optional start end) undefined)) + (vector-copy! (lambda (target-vec t-start source-vec :optional start end) undefined)) + (vector-reverse-copy! (lambda (target-vec t-start source-vec :optional start end) undefined)) + (reverse-vector-to-list (lambda (vec :optional start end))) + (reverse-list-to-vector (lambda (list))) + ) + + ;; SRFI 44 + ("Collections" + ) + + ;; SRFI 45 + ("Primitives for expressing iterative lazy algorithms" + (delay (syntax (expr))) + (lazy (syntax (expr))) + (force (lambda (promise))) + (eager (lambda (promise))) + ) + + ;; SRFI 46 + ("Basic Syntax-rules Extensions" + (syntax-rules (syntax () undefined))) + + ;; SRFI 47 + ("Array" + (make-array (lambda (prototype k \.\.\.))) + (ac64 (lambda (:optional z))) + (ac32 (lambda (:optional z))) + (ar64 (lambda (:optional x1))) + (ar32 (lambda (:optional x1))) + (as64 (lambda (:optional n))) + (as32 (lambda (:optional n))) + (as16 (lambda (:optional n))) + (as8 (lambda (:optional n))) + (au64 (lambda (:optional n))) + (au32 (lambda (:optional n))) + (au16 (lambda (:optional n))) + (au8 (lambda (:optional n))) + (at1 (lambda (:optional bool))) + (make-shared-array (lambda (array mapper k \.\.\.))) + (array-rank (lambda (obj))) + (array-dimensions (lambda (array))) + (array-in-bounds? (lambda (array k \.\.\.))) + (array-ref (lambda (array k \.\.\.))) + (array-set! (lambda (array obj k \.\.\.))) + ) + + ;; SRFI 48 + ("Intermediate Format Strings" + (format (lambda (port-or-boolean format-string arg \.\.\.)))) + + ;; SRFI 49 + ("Indentation-sensitive syntax" + ) + + () + + ;; SRFI 51 + ("Handling rest list" + (rest-values (lambda (caller rest-list :optional args-number-limit default))) + (arg-and (syntax)) + (arg-ands (syntax)) + (err-and (syntax)) + (err-ands (syntax)) + (arg-or (syntax)) + (arg-ors (syntax)) + (err-or (syntax)) + (err-ors (syntax)) + ) + + () + + () + + ;; SRFI 54 + ("Formatting" + (cat (lambda (obj \.\.\.)))) + + ;; SRFI 55 + ("require-extension" + (require-extension (syntax))) + + () + + ;; SRFI 57 + ("Records" + (define-record-type (syntax)) + (define-record-scheme (syntax)) + (record-update (syntax)) + (record-update! (syntax)) + (record-compose (syntax))) + + ;; SRFI 58 + ("Array Notation" + ) + + ;; SRFI 59 + ("Vicinity" + (program-vicinity (lambda ())) + (library-vicinity (lambda ())) + (implementation-vicinity (lambda ())) + (user-vicinity (lambda ())) + (home-vicinity (lambda ())) + (in-vicinity (lambda (vicinity filename))) + (sub-vicinity (lambda (vicinity name))) + (make-vicinity (lambda (dirname))) + (path-vicinity (lambda (path))) + (vicinity:suffix? (lambda (ch))) + ) + + ;; SRFI 60 + ("Integers as Bits" + (bitwise-and (lambda (n \.\.\.) int)) + (bitwise-ior (lambda (n \.\.\.) int)) + (bitwise-xor (lambda (n \.\.\.) int)) + (bitwise-not (lambda (n) int)) + (bitwise-if (lambda (mask n m) int)) + (any-bits-set? (lambda (n m) bool)) + (bit-count (lambda (n) int)) + (integer-length (lambda (n) int)) + (first-bit-set (lambda (n) int)) + (bit-set? (lambda (i n) bool)) + (copy-bit (lambda (index n bool) int)) + (bit-field (lambda (n start end) int)) + (copy-bit-field (lambda (to-int from-int start end) int)) + (arithmetic-shift (lambda (n count) int)) + (rotate-bit-field (lambda (n count start end) int)) + (reverse-bit-field (lambda (n start end) int)) + (integer->list (lambda (k :optional len) list)) + (list->integer (lambda (list) int)) + ) + + ;; SRFI 61 + ("A more general cond clause" + (cond (syntax))) + + ;; SRFI 62 + ("S-expression comments" + ) + + ;; SRFI 63 + ("Homogeneous and Heterogeneous Arrays" + ) + + ;; SRFI 64 + ("A Scheme API for test suites" + (test-assert (syntax)) + (test-eqv (syntax)) + (test-equal (syntax)) + (test-eq (syntax)) + (test-approximate (syntax)) + (test-error (syntax)) + (test-read-eval-string (lambda (string))) + (test-begin (syntax (suite-name :optional count))) + (test-end (syntax (suite-name))) + (test-group (syntax (suite-name decl-or-expr \.\.\.))) + (test-group-with-cleanup (syntax (suite-name decl-or-expr \.\.\.))) + (test-match-name (lambda (name))) + (test-match-nth (lambda (n :optional count))) + (test-match-any (lambda (specifier \.\.\.))) + (test-match-all (lambda (specifier \.\.\.))) + (test-skip (syntax (specifier))) + (test-expect-fail (syntax (specifier))) + (test-runner? (lambda (obj))) + (test-runner-current (lambda (:optional runner))) + (test-runner-get (lambda ())) + (test-runner-simple (lambda ())) + (test-runner-null (lambda ())) + (test-runner-create (lambda ())) + (test-runner-factory (lambda (:optional factory))) + (test-apply (syntax (runner specifier \.\.\.))) + (test-with-runner (syntax (runner decl-or-expr \.\.\.))) + (test-result-kind (lambda (:optional runner))) + (test-passed? (lambda (:optional runner))) + (test-result-ref (lambda (runner prop-name (:optional default)))) + (test-result-set! (lambda (runner prop-name value))) + (test-result-remove (lambda (runner prop-name))) + (test-result-clear (lambda (runner))) + (test-result-alist (lambda (runner))) + (test-runner-on-test-begin (lambda (runner :optional proc))) + (test-runner-on-test-begin! (lambda (runner :optional proc))) + (test-runner-on-test-end (lambda (runner :optional proc))) + (test-runner-on-test-end! (lambda (runner :optional proc))) + (test-runner-on-group-begin (lambda (runner :optional proc))) + (test-runner-on-group-begin! (lambda (runner :optional proc))) + (test-runner-on-group-end (lambda (runner :optional proc))) + (test-runner-on-group-end! (lambda (runner :optional proc))) + (test-runner-on-bad-count (lambda (runner :optional proc))) + (test-runner-on-bad-count! (lambda (runner :optional proc))) + (test-runner-on-bad-end-name (lambda (runner :optional proc))) + (test-runner-on-bad-end-name! (lambda (runner :optional proc))) + (test-runner-on-final (lambda (runner :optional proc))) + (test-runner-on-final! (lambda (runner :optional proc))) + (test-runner-pass-count (lambda (runner))) + (test-runner-fail-count (lambda (runner))) + (test-runner-xpass-count (lambda (runner))) + (test-runner-skip-count (lambda (runner))) + (test-runner-test-name (lambda (runner))) + (test-runner-group-path (lambda (runner))) + (test-runner-group-stack (lambda (runner))) + (test-runner-aux-value (lambda (runner))) + (test-runner-aux-value! (lambda (runner))) + (test-runner-reset (lambda (runner))) + ) + + () + + ;; SRFI 66 + ("Octet Vectors" + (make-u8vector (lambda (len n))) + (u8vector (lambda (n \.\.\.))) + (u8vector->list (lambda (u8vector))) + (list->u8vector (lambda (octet-list))) + (u8vector-length u8vector) + (u8vector-ref (lambda (u8vector k))) + (u8vector-set! (lambda (u8vector k n))) + (u8vector=? (lambda (u8vector-1 u8vector-2))) + (u8vector-compare (lambda (u8vector-1 u8vector-2))) + (u8vector-copy! (lambda (source source-start target target-start n))) + (u8vector-copy (lambda (u8vector))) + ) + + ;; SRFI 67 + ("Compare Procedures" + ) + + () + + ;; SRFI 69 + ("Basic hash tables" + ) + + ;; SRFI 70 + ("Numbers" + ) + + ;; SRFI 71 + ("LET-syntax for multiple values" + ) + + ;; SRFI 72 + ("Simple hygienic macros" + ) + + () + + ;; SRFI 74 + ("Octet-Addressed Binary Blocks" + ) + + ]) + +(defvar *scheme-chicken-modules* + '((extras + (->string (lambda (obj) str)) + (alist->hash-table (lambda (alist) hash-table)) + (alist-ref (lambda (alist key :optional eq-fn default))) + (alist-update! (lambda (key value alist :optional eq-fn) undefined)) + (atom? (lambda (obj) bool)) + (binary-search (lambda (vec proc))) + (butlast (lambda (list) list) "drops the last element of list") + (call-with-input-string (lambda (string proc))) + (call-with-output-string (lambda (proc) str)) + (chop (lambda (list k) list)) + (complement (lambda (f) f2)) + (compose (lambda (f1 f2 \.\.\.) f)) + (compress (lambda (boolean-list list))) + (conc (lambda (obj \.\.\.))) + (conjoin (lambda (pred \.\.\.) pred)) + (constantly (lambda (obj \.\.\.) f)) + (disjoin (lambda (pred \.\.\.) pred)) + (each (lambda (proc \.\.\.) proc)) + (flatten (lambda (list1 \.\.\.) list)) + (flip (lambda (proc) proc)) + (format (lambda (format-string arg \.\.\.))) + (fprintf (lambda (port format-string arg \.\.\.))) + (hash (lambda (obj :optional n) int)) + (hash-by-identity (lambda (obj :optional n) int)) + (hash-table->alist (lambda (hash-table) alist)) + (hash-table-copy (lambda (hash-table) hash-table)) + (hash-table-delete! (lambda (hash-table key) undefined)) + (hash-table-equivalence-function (lambda (hash-table) pred)) + (hash-table-exists? (lambda (hash-table key) bool)) + (hash-table-fold (lambda (hash-table f init-value))) + (hash-table-hash-function (lambda (hash-table) f)) + (hash-table-keys (lambda (hash-table) list)) + (hash-table-merge! (lambda (hash-table1 hash-table2) undefined)) + (hash-table-ref (lambda (hash-table key :optional thunk))) + (hash-table-ref/default (lambda (hash-table key default))) + (hash-table-remove! (lambda (hash-table proc) undefined)) + (hash-table-set! (lambda (hash-table key value) undefined)) + (hash-table-size (lambda (hash-table) n)) + (hash-table-update! (lambda (hash-table key proc :optional thunk) undefined)) + (hash-table-update!/default (lambda (hash-table key proc default) undefined)) + (hash-table-values (lambda (hash-table) list)) + (hash-table-walk (lambda (hash-table proc) undefined)) + (hash-table? (lambda (obj) bool)) + (identity (lambda (obj))) + (intersperse (lambda (list obj) list)) + (join (lambda (list-of-lists :optional list) list)) + (list->queue (lambda (list) queue)) + (list-of (lambda (pred))) + (make-hash-table (lambda (:optional eq-fn hash-fn size) hash-table)) + (make-input-port (lambda (read-proc ready?-pred close-proc :optional peek-proc) input-port)) + (make-output-port (lambda (write-proc close-proc :optional flush-proc) output-port)) + (make-queue (lambda () queue)) + (merge (lambda (list1 list2 less-fn) list)) + (merge! (lambda (list1 list2 less-fn) list)) + (noop (lambda (obj \.\.\.) undefined)) + (pp (lambda (obj :optional output-port) undefined)) + (pretty-print (lambda (obj :optional output-port) undefined)) + (pretty-print-width (lambda (:optional new-width) n)) + (printf (lambda (format-string arg \.\.\.) undefined)) + (project (lambda (n) proc)) + (queue->list (lambda (queue) list)) + (queue-add! (lambda (queue obj) undefined)) + (queue-empty? (lambda (queue) bool)) + (queue-first (lambda (queue))) + (queue-last (lambda (queue))) + (queue-push-back! (lambda (queue obj) undefined)) + (queue-push-back-list! (lambda (queue list) undefined)) + (queue-remove! (lambda (queue) undefined)) + (queue? (lambda (obj) bool)) + (random (lambda (n) n)) + (randomize (lambda (:optional x1) undefined)) + (rassoc (lambda (key list :optional eq-fn))) + (read-file (lambda (:optional file-or-port reader-fn max-count) str)) + (read-line (lambda (:optional port limit) str)) + (read-lines (lambda (:optional port max) list)) + (read-string (lambda (:optional n port) str)) + (read-string! (lambda (n dest :optional port start) undefined)) + (read-token (lambda (predicate :optional port) str)) + (shuffle (lambda (list) list)) + (sort (lambda (sequence less-fn) sequence)) + (sort! (lambda (sequence less-fn) sequence)) + (sorted? (lambda (sequence less-fn) bool)) + (sprintf (lambda (format-string arg \.\.\.) str)) + (string-chomp (lambda (str :optional suffix-str) str)) + (string-chop (lambda (str length) list)) + (string-ci-hash (lambda (str :optional n) n)) + (string-compare3 (lambda (str1 str2) n)) + (string-compare3-ci (lambda (str1 str2) n)) + (string-hash (lambda (str1 :optional n) n)) + (string-intersperse (lambda (list :optional seperator-string) str)) + (string-split (lambda (str :optional delimiter-str keep-empty?) list)) + (string-translate (lambda (str from-str :optional to-str) str)) + (string-translate* (lambda (str list) str)) + (substring-ci=? (lambda (str1 str2 :optional start1 start2 length) str)) + (substring-index (lambda (which-str where-str :optional start) i)) + (substring-index-ci (lambda (which-str where-str :optional start) i)) + (substring=? (lambda (str1 str2 :optional start1 start2 length) bool)) + (tail? (lambda (obj list) bool)) + (with-error-output-to-port (lambda (output-port thunk))) + (with-input-from-port (lambda (port thunk))) + (with-input-from-string (lambda (str thunk))) + (with-output-to-port (lambda (port thunk))) + (with-output-to-string (lambda (thunk) str)) + (write-line (lambda (str :optional port) undefined)) + (write-string (lambda (str :optional num port) undefined)) + ) + (lolevel + (address->pointer (lambda (n) ptr)) + (align-to-word (lambda (ptr-or-int) ptr)) + (allocate (lambda (size) block)) + (block-ref (lambda (block index) int)) + (block-set! (lambda (block index obj) undefined)) + (byte-vector (lambda (n \.\.\.) byte-vector)) + (byte-vector->list (lambda (byte-vector) list)) + (byte-vector->string (lambda (byte-vector) string)) + (byte-vector-fill! (lambda (byte-vector n) undefined)) + (byte-vector-length (lambda (byte-vector) n)) + (byte-vector-ref (lambda (byte-vector i) int)) + (byte-vector-set! (lambda (byte-vector i n) undefined)) + (byte-vector? (lambda (obj) bool)) + (extend-procedure (lambda (proc x1) proc)) + (extended-procedure? (lambda (proc) bool)) + (free (lambda (pointer) undefined)) + (global-bound? (lambda (sym) bool)) + (global-make-unbound! (lambda (sym) undefined)) + (global-ref (lambda (sym))) + (global-set! (lambda (sym val) undefined)) + (list->byte-vector (lambda (list) byte-vector)) + (locative->object (lambda (locative) obj)) + (locative-ref (lambda (locative))) + (locative-set! (lambda (locative val) undefined)) + (locative? (lambda (obj) bool)) + (make-byte-vector (lambda (size :optional init-n) byte-vector)) + (make-locative (lambda (obj :optional index) locative)) + (make-record-instance (lambda (sym arg \.\.\.))) + (make-static-byte-vector (lambda (size :optional init-n))) + (make-weak-locative (lambda (obj :optional index) locative)) + (move-memory! (lambda (from to :optional bytes from-offset to-offset) undefined)) + (mutate-procedure (lambda (proc proc) proc)) + (null-pointer (lambda () pointer)) + (null-pointer? (lambda (pointer) bool)) + (number-of-bytes (lambda (block) int)) + (number-of-slots (lambda (block) int)) + (object->pointer (lambda (obj) ptr)) + (object-become! (lambda (alist) undefined)) + (object-copy (lambda (obj))) + (object-evict (lambda (obj :optional allocator-proc))) + (object-evict-to-location (lambda (obj ptr :optional limit))) + (object-evicted? (lambda (obj) bool)) + (object-release (lambda (obj :optional releaser-proc))) + (object-size (lambda (obj) int)) + (object-unevict (lambda (obj :optional full))) + (pointer->address (lambda (ptr) n)) + (pointer->object (lambda (ptr))) + (pointer-f32-ref (lambda (ptr) real)) + (pointer-f32-set! (lambda (ptr x1) undefined)) + (pointer-f64-ref (lambda (ptr) real)) + (pointer-f64-set! (lambda (ptr x1) undefined)) + (pointer-offset (lambda (ptr n) n)) + (pointer-s16-ref (lambda (ptr) int)) + (pointer-s16-set! (lambda (ptr n) undefined)) + (pointer-s32-ref (lambda (ptr) int)) + (pointer-s32-set! (lambda (ptr n) undefined)) + (pointer-s8-ref (lambda (ptr) int)) + (pointer-s8-set! (lambda (ptr n) undefined)) + (pointer-tag (lambda (ptr) tag)) + (pointer-u16-ref (lambda (ptr) int)) + (pointer-u16-set! (lambda (ptr n) undefined)) + (pointer-u32-ref (lambda (ptr) int)) + (pointer-u32-set! (lambda (ptr n) undefined)) + (pointer-u8-ref (lambda (ptr) int)) + (pointer-u8-set! (lambda (ptr n) undefined)) + (pointer=? (lambda (ptr1 ptr2) bool)) + (pointer? (lambda (obj) bool)) + (procedure-data (lambda (proc))) + (record->vector (lambda (block) vector)) + (record-instance? (lambda (obj) bool)) + (set-invalid-procedure-call-handler! (lambda (proc) undefined)) + (set-procedure-data! (lambda (proc obj) undefined)) + (static-byte-vector->pointer (lambda (byte-vector) pointer)) + (string->byte-vector (lambda (str) byte-vector)) + (tag-pointer (lambda (ptr tag))) + (tagged-pointer? (lambda (obj tag) bool)) + (unbound-variable-value (lambda (:optional value))) + ) + (posix + (_exit (lambda (:optional n) undefined)) + (call-with-input-pipe (lambda (cmdline-string proc :optional mode))) + (call-with-output-pipe (lambda (cmdline-string proc :optional mode))) + (change-directory (lambda (dir))) + (change-file-mode (lambda (filename mode))) + (change-file-owner (lambda (filename user-n group-n))) + (close-input-pipe (lambda (input-port))) + (close-output-pipe (lambda (output-port))) + (create-directory (lambda (filename))) + (create-fifo (lambda (filename :optional mode))) + (create-pipe (lambda ())) + (create-session (lambda ())) + (create-symbolic-link (lambda (old-filename new-filename))) + (current-directory (lambda (:optional new-dir))) + (current-effective-group-id (lambda () int)) + (current-effective-user-id (lambda () int)) + (current-environment (lambda ())) + (current-group-id (lambda ())) + (current-process-id (lambda ())) + (current-user-id (lambda ())) + (delete-directory (lambda (dir))) + (directory (lambda (:optional dir show-dotfiles?) list)) + (directory? (lambda (filename) bool)) + (duplicate-fileno (lambda (old-n :optional new-n))) +;; (errno/acces integer) +;; (errno/again integer) +;; (errno/badf integer) +;; (errno/busy integer) +;; (errno/child integer) +;; (errno/exist integer) +;; (errno/fault integer) +;; (errno/intr integer) +;; (errno/inval integer) +;; (errno/io integer) +;; (errno/isdir integer) +;; (errno/mfile integer) +;; (errno/noent integer) +;; (errno/noexec integer) +;; (errno/nomem integer) +;; (errno/nospc integer) +;; (errno/notdir integer) +;; (errno/perm integer) +;; (errno/pipe integer) +;; (errno/rofs integer) +;; (errno/spipe integer) +;; (errno/srch integer) +;; (errno/wouldblock integer) + (fifo? (lambda (filename) bool)) + (file-access-time (lambda (filename) real)) + (file-change-time (lambda (filename) real)) + (file-close (lambda (fileno))) + (file-execute-access? (lambda (filename) bool)) + (file-link (lambda (old-filename new-filename))) + (file-lock (lambda (port :optional start len))) + (file-lock/blocking (lambda (port :optional start len))) + (file-mkstemp (lambda (template-filename))) + (file-modification-time (lambda (filename) real)) + (file-open (lambda (filename (flags open-mode open/binary open/excl open/fsync open/noctty open/nonblock open/rdonly open/rdwr open/read open/sync open/text) :optional mode) fileno)) + (file-owner (lambda (filename))) + (file-permissions (lambda (filename) int)) + (file-position (lambda (port-or-fileno) int)) + (file-read (lambda (fileno size :optional buffer-string))) + (file-read-access? (lambda (filename) bool)) + (file-select (lambda (read-fd-list write-fd-list :optional timeout))) + (file-size (lambda (filename) int)) + (file-stat (lambda (filename :optional follow-link?))) + (file-test-lock (lambda (port :optional start len))) + (file-truncate (lambda (filename-or-fileno offset))) + (file-unlock (lambda (lock))) + (file-write (lambda (fileno buffer-string :optional size))) + (file-write-access? (lambda (filename))) + (fileno/stderr integer) + (fileno/stdin integer) + (fileno/stdout integer) + (find-files (lambda (dir pred :optional action-proc identity limit))) + (get-groups (lambda ())) + (get-host-name (lambda ())) + (glob (lambda (pattern1 \.\.\.))) + (group-information (lambda (group-name-or-n))) + (initialize-groups (lambda (user-name base-group-n))) + (local-time->seconds (lambda (vector))) + (local-timezone-abbreviation (lambda ())) + (map-file-to-memory (lambda (address len protection flag fileno :optional offset))) + (memory-mapped-file-pointer (lambda (mmap))) + (memory-mapped-file? (lambda (obj))) + (open-input-file* (lambda (fileno :optional (flags open-mode open/binary open/excl open/fsync open/noctty open/nonblock open/rdonly open/rdwr open/read open/sync open/text)))) + (open-input-pipe (lambda (cmdline-string :optional mode))) + (open-output-file* (lambda (fileno :optional (flags open-mode open/append open/binary open/creat open/excl open/fsync open/noctty open/nonblock open/rdwr open/sync open/text open/trunc open/write open/wronly)))) + (open-output-pipe (lambda (cmdline-string :optional mode))) +;; (open/append integer) +;; (open/binary integer) +;; (open/creat integer) +;; (open/excl integer) +;; (open/fsync integer) +;; (open/noctty integer) +;; (open/nonblock integer) +;; (open/rdonly integer) +;; (open/rdwr integer) +;; (open/read integer) +;; (open/sync integer) +;; (open/text integer) +;; (open/trunc integer) +;; (open/write integer) +;; (open/wronly integer) + (parent-process-id (lambda ())) +;; (perm/irgrp integer) +;; (perm/iroth integer) +;; (perm/irusr integer) +;; (perm/irwxg integer) +;; (perm/irwxo integer) +;; (perm/irwxu integer) +;; (perm/isgid integer) +;; (perm/isuid integer) +;; (perm/isvtx integer) +;; (perm/iwgrp integer) +;; (perm/iwoth integer) +;; (perm/iwusr integer) +;; (perm/ixgrp integer) +;; (perm/ixoth integer) +;; (perm/ixusr integer) +;; (pipe/buf integer) + (port->fileno (lambda (port))) + (process (lambda (cmdline-string :optional arg-list env-list))) + (process-execute (lambda (filename :optional arg-list env-list))) + (process-fork (lambda (:optional thunk))) + (process-group-id (lambda ())) + (process-run (lambda (filename :optional list))) + (process-signal (lambda (pid :optional signal))) + (process-wait (lambda (:optional pid nohang?))) + (read-symbolic-link (lambda (filename) filename)) + (regular-file? (lambda (filename))) + (seconds->local-time (lambda (seconds))) + (seconds->string (lambda (seconds))) + (seconds->utc-time (lambda (seconds))) + (set-alarm! (lambda (seconds))) + (set-buffering-mode! (lambda (port mode :optional buf-size))) + (set-file-position! (lambda (port-or-fileno pos :optional whence))) + (set-group-id! (lambda (n))) + (set-groups! (lambda (group-n-list))) + (set-process-group-id! (lambda (process-n n))) + (set-root-directory! (lambda (dir)) "chroot") + (set-signal-handler! (lambda (sig-n proc))) + (set-signal-mask! (lambda (sig-n-list))) + (set-user-id! (lambda (n))) + (setenv (lambda (name value-string))) +;; (signal/abrt integer) +;; (signal/alrm integer) +;; (signal/chld integer) +;; (signal/cont integer) +;; (signal/fpe integer) +;; (signal/hup integer) +;; (signal/ill integer) +;; (signal/int integer) +;; (signal/io integer) +;; (signal/kill integer) +;; (signal/pipe integer) +;; (signal/prof integer) +;; (signal/quit integer) +;; (signal/segv integer) +;; (signal/stop integer) +;; (signal/term integer) +;; (signal/trap integer) +;; (signal/tstp integer) +;; (signal/urg integer) +;; (signal/usr1 integer) +;; (signal/usr2 integer) +;; (signal/vtalrm integer) +;; (signal/winch integer) +;; (signal/xcpu integer) +;; (signal/xfsz integer) + (sleep (lambda (seconds))) + (symbolic-link? (lambda (filename))) + (system-information (lambda ())) + (terminal-name (lambda (port))) + (terminal-port? (lambda (port))) + (time->string (lambda (vector))) + (unmap-file-from-memory (lambda (mmap :optional len))) + (unsetenv (lambda (name) undefined)) + (user-information (lambda ((or integer (string scheme-complete-user-name))) list)) + (utc-time->seconds (lambda (vector))) + (with-input-from-pipe (lambda (cmdline-string thunk :optional mode))) + (with-output-to-pipe (lambda (cmdline-string thunk :optional mode))) + ) + (regex + (glob->regexp (lambda (pattern))) + (glob? (lambda (obj))) + (grep (lambda (pattern list) list)) + (regexp (lambda (pattern ignore-case? ignore-space? utf-8?))) + (regexp-escape (lambda (str) str)) + (regexp? (lambda (obj) bool)) + (string-match (lambda (pattern str :optional start))) + (string-match-positions (lambda (pattern str :optional start))) + (string-search (lambda (pattern str :optional start))) + (string-search-positions (lambda (pattern str :optional start))) + (string-split-fields (lambda (pattern str :optional mode start))) + (string-substitute (lambda (pattern subst str :optional mode))) + (string-substitute* (lambda (str subst-list :optional mode))) + ) + (tcp + (tcp-abandon-port (lambda (port))) + (tcp-accept (lambda (listener))) + (tcp-accept-ready? (lambda (listener))) + (tcp-addresses (lambda (port))) + (tcp-buffer-size (lambda (:optional new-size))) + (tcp-close (lambda (listener))) + (tcp-connect (lambda ((string scheme-complete-host-name) :optional (string scheme-complete-port-name)))) + (tcp-listen (lambda (tcp-port-n :optional backlog-n host-string))) + (tcp-listener-fileno (lambda (listener))) + (tcp-listener-port (lambda (listener))) + (tcp-listener? (lambda (obj))) + (tcp-port-numbers (lambda (port))) + ) + (utils + (absolute-pathname? (lambda (pathname))) + (create-temporary-file (lambda (:optional ext-str))) + (decompose-pathname (lambda (pathname))) + (delete-file* (lambda (filename))) + (for-each-argv-line (lambda (proc) undefined)) + (for-each-line (lambda (proc :optional input-port) undefined)) + (make-absolute-pathname (lambda (dir filename :optional ext-str))) + (make-pathname (lambda (dir filename :optional ext-str))) + (pathname-directory (lambda (pathname))) + (pathname-extension (lambda (pathname))) + (pathname-file (lambda (pathname))) + (pathname-replace-directory (lambda (pathname dir))) + (pathname-replace-extension (lambda (pathname ext-str))) + (pathname-replace-file (lambda (pathname filename))) + (pathname-strip-directory (lambda (pathname))) + (pathname-strip-extension (lambda (pathname))) + (port-for-each (lambda (read-fn thunk) undefined)) + (port-map (lambda (read-fn thunk))) + (read-all (lambda (:optional file-or-port))) + (shift! (lambda (list :optional default))) + (system* (lambda (format-string arg1 \.\.\.))) + (unshift! (lambda (obj pair))) + ) + )) + +;; another big table - consider moving to a separate file +(defvar *scheme-implementation-exports* + '((chicken + (abort (lambda (obj) undefined)) + (add1 (lambda (z) z)) + (andmap (lambda (pred list) bool)) + (any? (lambda (obj) bool)) + (argc+argv (lambda () (values n ptr))) + (argv (lambda () list)) + (bit-set? (lambda (n index) bool)) + (bitwise-and (lambda (n \.\.\.) n)) + (bitwise-ior (lambda (n \.\.\.) n)) + (bitwise-not (lambda (n \.\.\.) n)) + (bitwise-xor (lambda (n \.\.\.) n)) + (blob->string (lambda (blob) string)) + (blob-size (lambda (blob) n)) + (blob? (lambda (obj) bool)) + (breakpoint (lambda (:optional name))) + (build-platform (lambda () symbol)) + (c-runtime (lambda () symbol)) + (call/cc (lambda (proc))) + (case-sensitive (lambda (:optional on?))) + (chicken-home (lambda () string)) + (chicken-version (lambda () string)) + (command-line-arguments (lambda () list)) + (condition-predicate (lambda (kind) pred)) + (condition-property-accessor (lambda (kind prop :optional err?) proc)) + (condition? (lambda (obj) bool)) + (continuation-capture (lambda (proc))) + (continuation-graft (lambda (continuation thunk))) + (continuation-return (lambda (continuation vals\.\.\.))) + (continuation? (lambda (obj) bool)) + (copy-read-table (lambda (read-table) read-table)) + (cpu-time (lambda () (values n n))) + (current-error-port (lambda () output-port)) + (current-exception-handler (lambda () proc)) + (current-gc-milliseconds (lambda () n)) + (current-milliseconds (lambda () n)) + (current-read-table (lambda () read-table)) + (current-seconds (lambda () x1)) + (define-reader-ctor (lambda (sym proc) undefined)) + (delete-file (lambda (filename) undefined)) + (disable-interrupts (lambda () undefined)) + (dynamic-load-libraries (lambda () list)) + (dynamic-wind (lambda (before-thunk thunk after-thunk))) + (enable-interrupts (lambda () undefined)) + (enable-warnings (lambda () undefined)) + (errno (lambda () n)) + (error (lambda (error-string args \.\.\.) undefined)) + (eval-handler (lambda () proc)) + (exit (lambda (:optional n) undefined)) + (exit-handler (lambda () proc)) + (extension-info (lambda (proc))) + (extension-information (lambda (proc))) + (feature? (lambda (sym) bool)) + (features (lambda () list)) + (file-exists? (lambda (filename) bool)) + (finite? (lambda (z) bool)) + (fixnum? (lambda (obj) bool)) + (flonum? (lambda (obj) bool)) + (flush-output (lambda (:optional port) undefined)) + (force (lambda (promise))) + (force-finalizers (lambda (f args \.\.\.))) + (fp* (lambda (x1 x2) x3)) + (fp+ (lambda (x1 x2) x3)) + (fp- (lambda (x1 x2) x3)) + (fp/ (lambda (x1 x2) x3)) + (fp< (lambda (x1 x2) x3)) + (fp<= (lambda (x1 x2) x3)) + (fp= (lambda (x1 x2) x3)) + (fp> (lambda (x1 x2) x3)) + (fp>= (lambda (x1 x2) x3)) + (fpmax (lambda (x1 x2) x3)) + (fpmin (lambda (x1 x2) x3)) + (fpneg (lambda (x1 x2) x3)) + (fx* (lambda (n1 n2) n)) + (fx+ (lambda (n1 n2) n)) + (fx- (lambda (n1 n2) n)) + (fx/ (lambda (n1 n2) n)) + (fx< (lambda (n1 n2) n)) + (fx<= (lambda (n1 n2) n)) + (fx= (lambda (n1 n2) n)) + (fx> (lambda (n1 n2) n)) + (fx>= (lambda (n1 n2) n)) + (fxand (lambda (n1 n2) n)) + (fxior (lambda (n1 n2) n)) + (fxmax (lambda (n1 n2) n)) + (fxmin (lambda (n1 n2) n)) + (fxmod (lambda (n1 n2) n)) + (fxneg (lambda (n1 n2) n)) + (fxnot (lambda (n1 n2) n)) + (fxshl (lambda (n1 n2) n)) + (fxshr (lambda (n1 n2) n)) + (fxxor (lambda (n1 n2) n)) + (gc (lambda () n)) + (gensym (lambda (:optional name) sym)) + (get-call-chain (lambda (:optional n) list)) + (get-keyword (lambda (sym list :optional default))) + (get-line-number (lambda (sexp) n)) + (get-output-string (lambda (string-output-port) string)) + (getenv (lambda (name) string)) + (getter-with-setter (lambda (get-proc set-proc) proc)) + (implicit-exit-handler (lambda (:optional proc) proc)) + (invalid-procedure-call-handler (lambda (:optional proc) proc)) + (keyword->string (lambda (sym) string)) + (keyword-style (lambda (:optional sym) sym)) + (keyword? (lambda (obj) bool)) + (load-library (lambda (sym) undefined)) + (load-noisily (lambda (string) undefined)) + (load-relative (lambda (string) undefined)) + (load-verbose (lambda (:optional bool) bool)) + (machine-byte-order (lambda () sym)) + (machine-type (lambda () sym)) + (macro? (lambda (obj) bool)) + (macroexpand (lambda (sexp) sexp)) + (macroexpand-1 (lambda (sexp) sexp)) + (make-blob (lambda (size) blob)) + (make-composite-condition (lambda (condition \.\.\.) condition)) + (make-parameter (lambda (val) proc)) + (make-property-condition (lambda (kind \.\.\.) condition)) + (match-error-control (lambda (:optional proc) proc)) + (match-error-procedure (lambda (:optional proc) proc)) + (memory-statistics (lambda () vector)) + (on-exit (lambda (thunk) undefined)) + (open-input-string (lambda (string) string-input-port)) + (open-output-string (lambda () string-output-port)) + (ormap (lambda (pred list \.\.\.) bool)) + (port-name (lambda (port) name)) + (port-position (lambda (port) n)) + (port? (lambda (obj) bool)) + (print (lambda (obj \.\.\.) undefined)) + (print* (lambda (obj \.\.\.) undefined)) + (print-backtrace (lambda (:optional n) undefined)) + (print-call-chain (lambda (:optional n) undefined)) + (print-error-message (lambda (err args \.\.\.) undefined)) + (procedure-information (lambda (proc))) + (program-name (lambda (:optional name) name)) + (provide (lambda (name))) + (provided? (lambda (name) bool)) + (rational? (lambda (obj) bool)) + (read-byte (lambda (:optional input-port) n)) + (register-feature! (lambda (name) undefined)) + (rename-file (lambda (old-name new-name) undefined)) + (repl (lambda () undefined)) + (repository-path (lambda (:optional dirname) dirname)) + (require (lambda (sym \.\.\.) undefined)) + (reset (lambda () undefined)) + (reset-handler (lambda (:optional proc) proc)) + (return-to-host (lambda () undefined)) + (reverse-list->string (lambda (list) string)) + (set-dynamic-load-mode! (lambda (obj) undefined)) + (set-extension-specifier! (lambda (name proc) undefined)) + (set-finalizer! (lambda (obj proc) undefined)) + (set-gc-report! (lambda (bool) undefined)) + (set-parameterized-read-syntax! (lambda (ch proc) undefined)) + (set-port-name! (lambda (port name) undefined)) + (set-read-syntax! (lambda (ch proc) undefined)) + (set-sharp-read-syntax! (lambda (ch proc) undefined)) + (setter (lambda (proc) proc)) + (signal (lambda (n) undefined)) + (signum (lambda (x1) x2)) + (singlestep (lambda (thunk))) + (software-type (lambda () sym)) + (software-version (lambda () sym)) + (string->blob (lambda (string) blob)) + (string->keyword (lambda (string) sym)) + (string->uninterned-symbol (lambda (string) sym)) + (string-copy (lambda (string) string)) + (sub1 (lambda (z1) z2)) + (syntax-error (lambda (args \.\.\.) undefined)) + (system (lambda (str) n)) + (test-feature? (lambda (obj) bool)) + (undefine-macro! (lambda (sym) undefined)) + (unregister-feature! (lambda (sym) undefined)) + (use (special symbol scheme-chicken-available-modules) + "import extensions into top-level namespace") + (vector-copy! (lambda (from-vector to-vector :optional start) undefined)) + (vector-resize (lambda (vec n :optional init))) + (void (lambda () undefined)) + (warning (lambda (msg-str args \.\.\.) undefined)) + (with-exception-handler (lambda (handler thunk))) + (write-byte (lambda (n :optional output-port) undefined)) + ) + (gauche + (E2BIG integer) + (EACCES integer) + (EADDRINUSE integer) + (EADDRNOTAVAIL integer) + (EADV integer) + (EAFNOSUPPORT integer) + (EAGAIN integer) + (EALREADY integer) + (EBADE integer) + (EBADF integer) + (EBADFD integer) + (EBADMSG integer) + (EBADR integer) + (EBADRQC integer) + (EBADSLT integer) + (EBFONT integer) + (EBUSY integer) + (ECANCELED integer) + (ECHILD integer) + (ECHRNG integer) + (ECOMM integer) + (ECONNABORTED integer) + (ECONNREFUSED integer) + (ECONNRESET integer) + (EDEADLK integer) + (EDEADLOCK integer) + (EDESTADDRREQ integer) + (EDOM integer) + (EDOTDOT integer) + (EDQUOT integer) + (EEXIST integer) + (EFAULT integer) + (EFBIG integer) + (EHOSTDOWN integer) + (EHOSTUNREACH integer) + (EIDRM integer) + (EILSEQ integer) + (EINPROGRESS integer) + (EINTR integer) + (EINVAL integer) + (EIO integer) + (EISCONN integer) + (EISDIR integer) + (EISNAM integer) + (EKEYEXPIRED integer) + (EKEYREJECTED integer) + (EKEYREVOKED integer) + (EL2HLT integer) + (EL2NSYNC integer) + (EL3HLT integer) + (EL3RST integer) + (ELIBACC integer) + (ELIBBAD integer) + (ELIBEXEC integer) + (ELIBMAX integer) + (ELIBSCN integer) + (ELNRNG integer) + (ELOOP integer) + (EMEDIUMTYPE integer) + (EMFILE integer) + (EMLINK integer) + (EMSGSIZE integer) + (EMULTIHOP integer) + (ENAMETOOLONG integer) + (ENAVAIL integer) + (ENETDOWN integer) + (ENETRESET integer) + (ENETUNREACH integer) + (ENFILE integer) + (ENOANO integer) + (ENOBUFS integer) + (ENOCSI integer) + (ENODATA integer) + (ENODEV integer) + (ENOENT integer) + (ENOEXEC integer) + (ENOKEY integer) + (ENOLCK integer) + (ENOLINK integer) + (ENOMEDIUM integer) + (ENOMEM integer) + (ENOMSG integer) + (ENONET integer) + (ENOPKG integer) + (ENOPROTOOPT integer) + (ENOSPC integer) + (ENOSR integer) + (ENOSTR integer) + (ENOSYS integer) + (ENOTBLK integer) + (ENOTCONN integer) + (ENOTDIR integer) + (ENOTEMPTY integer) + (ENOTNAM integer) + (ENOTSOCK integer) + (ENOTTY integer) + (ENOTUNIQ integer) + (ENXIO integer) + (EOPNOTSUPP integer) + (EOVERFLOW integer) + (EPERM integer) + (EPFNOSUPPORT integer) + (EPIPE integer) + (EPROTO integer) + (EPROTONOSUPPORT integer) + (EPROTOTYPE integer) + (ERANGE integer) + (EREMCHG integer) + (EREMOTE integer) + (EREMOTEIO integer) + (ERESTART integer) + (EROFS integer) + (ESHUTDOWN integer) + (ESOCKTNOSUPPORT integer) + (ESPIPE integer) + (ESRCH integer) + (ESRMNT integer) + (ESTALE integer) + (ESTRPIPE integer) + (ETIME integer) + (ETIMEDOUT integer) + (ETOOMANYREFS integer) + (ETXTBSY integer) + (EUCLEAN integer) + (EUNATCH integer) + (EUSERS integer) + (EWOULDBLOCK integer) + (EXDEV integer) + (EXFULL integer) + (F_OK integer) + (LC_ALL integer) + (LC_COLLATE integer) + (LC_CTYPE integer) + (LC_MONETARY integer) + (LC_NUMERIC integer) + (LC_TIME integer) + (RAND_MAX integer) + (R_OK integer) + (SEEK_CUR integer) + (SEEK_END integer) + (SEEK_SET integer) + (SIGABRT integer) + (SIGALRM integer) + (SIGBUS integer) + (SIGCHLD integer) + (SIGCONT integer) + (SIGFPE integer) + (SIGHUP integer) + (SIGILL integer) + (SIGINT integer) + (SIGIO integer) + (SIGIOT integer) + (SIGKILL integer) + (SIGPIPE integer) + (SIGPOLL integer) + (SIGPROF integer) + (SIGPWR integer) + (SIGQUIT integer) + (SIGSEGV integer) + (SIGSTKFLT integer) + (SIGSTOP integer) + (SIGTERM integer) + (SIGTRAP integer) + (SIGTSTP integer) + (SIGTTIN integer) + (SIGTTOU integer) + (SIGURG integer) + (SIGUSR1 integer) + (SIGUSR2 integer) + (SIGVTALRM integer) + (SIGWINCH integer) + (SIGXCPU integer) + (SIGXFSZ integer) + (SIG_BLOCK integer) + (SIG_SETMASK integer) + (SIG_UNBLOCK integer) + (W_OK integer) + (X_OK integer) + (acons (lambda (key value alist) alist)) + (acosh (lambda (z) z)) + (add-load-path (lambda (path) undefined)) + (add-method! (lambda (generic method) undefined)) + (all-modules (lambda () list)) + (allocate-instance (lambda (class list))) + (and-let* (syntax)) + (any (lambda (pred list))) + (any$ (lambda (pred) proc)) + (any-pred (lambda (pred \.\.\.) pred)) + (append! (lambda (list \.\.\.) list)) + (apply$ (lambda (proc) proc)) + (apply-generic (lambda (generic list))) + (apply-method (lambda (method list))) + (apply-methods (lambda (generic list list))) + (arity (lambda (proc) n)) + (arity-at-least-value (lambda (n))) + (arity-at-least? (lambda (proc) bool)) + (ash (lambda (n i) n)) + (asinh (lambda (z) z)) + (assoc$ (lambda (obj) proc)) + (atanh (lambda (z) z)) + (autoload (syntax)) + (begin0 (syntax)) + (bignum? (lambda (obj) bool)) + (bit-field (lambda (n start end) n)) + (byte-ready? (lambda (:optional input-port) bool)) + (call-with-input-string (lambda (str proc))) + (call-with-output-string (lambda (proc) str)) + (call-with-string-io (lambda (str proc) str)) + (case-lambda (syntax)) + (change-class (lambda (obj new-class))) + (change-object-class (lambda (obj orig-class new-class))) + (char->ucs (lambda (ch) int)) + (char-set (lambda (ch \.\.\.) char-set)) + (char-set-contains? (lambda (char-set ch) bool)) + (char-set-copy (lambda (char-set) char-set)) + (char-set? (lambda (obj) bool)) + (check-arg (syntax)) + (circular-list? (lambda (obj) bool)) + (clamp (lambda (x1 :optional min-x max-x) x2)) + (class-direct-methods (lambda (class) list)) + (class-direct-slots (lambda (class) list)) + (class-direct-subclasses (lambda (class) list)) + (class-direct-supers (lambda (class) list)) + (class-name (lambda (class) sym)) + (class-of (lambda (obj) class)) + (class-precedence-list (lambda (class) list)) + (class-slot-accessor (lambda (class id) proc)) + (class-slot-bound? (lambda (class id) bool)) + (class-slot-definition (lambda (class id))) + (class-slot-ref (lambda (class slot))) + (class-slot-set! (lambda (class slot val) undefined)) + (class-slots (lambda (class) list)) + (closure-code (lambda (proc))) + (closure? (lambda (obj) bool)) + (compare (lambda (obj1 obj2) n)) + (complement (lambda (proc) proc)) + (compose (lambda (proc \.\.\.) proc)) + (compute-applicable-methods (lambda (generic list))) + (compute-cpl (lambda (generic list))) + (compute-get-n-set (lambda (class slot))) + (compute-slot-accessor (lambda (class slot))) + (compute-slots (lambda (class))) + (cond-expand (syntax)) + (condition (syntax)) + (condition-has-type? (lambda (condition obj))) + (condition-ref (lambda (condition id))) + (condition-type? (lambda (obj) bool)) + (condition? (lambda (obj) bool)) + (copy-bit (lambda (index n i) n)) + (copy-bit-field (lambda (n start end from) n)) + (copy-port (lambda (from-port to-port :optional unit-sym) undefined)) + (cosh (lambda (z) z)) + (count$ (lambda (pred) proc)) + (current-class-of (lambda (obj) class)) + (current-error-port (lambda () output-port)) + (current-exception-handler (lambda () handler)) + (current-load-history (lambda () list)) + (current-load-next (lambda () list)) + (current-load-port (lambda () port)) + (current-module (lambda () env)) + (current-thread (lambda () thread)) + (current-time (lambda () time)) + (cut (syntax)) + (cute (lambda (args \.\.\.) proc)) + (debug-print (lambda (obj))) + (debug-print-width (lambda () int)) + (debug-source-info (lambda (obj))) + (dec! (syntax)) + (decode-float (lambda (x1) vector)) + (define-class (syntax)) + (define-condition-type (syntax)) + (define-constant (syntax)) + (define-generic (syntax)) + (define-in-module (syntax)) + (define-inline (syntax)) + (define-macro (syntax)) + (define-method (syntax)) + (define-module (syntax)) + (define-reader-ctor (lambda (sym proc) undefined)) + (define-values (syntax)) + (delete$ (lambda (obj) proc)) + (delete-keyword (lambda (id list) list)) + (delete-keyword! (lambda (id list) list)) + (delete-method! (lambda (generic method) undefined)) + (digit->integer (lambda (ch) n)) + (disasm (lambda (proc) undefined)) + (dolist (syntax)) + (dotimes (syntax)) + (dotted-list? (lambda (obj) bool)) + (dynamic-load (lambda (file))) + (eager (lambda (obj))) + (eq-hash (lambda (obj))) + (eqv-hash (lambda (obj))) + (error (lambda (msg-string args \.\.\.))) + (errorf (lambda (fmt-string args \.\.\.))) + (eval-when (syntax)) + (every$ (lambda (pred) pred)) + (every-pred (lambda (pred \.\.\.) pred)) + (exit (lambda (:optional n) undefined)) + (export (syntax)) + (export-all (syntax)) + (export-if-defined (syntax)) + (extend (syntax)) + (extract-condition (lambda (condition type))) + (file-exists? (lambda (filename) bool)) + (file-is-directory? (lambda (filename) bool)) + (file-is-regular? (lambda (filename) bool)) + (filter$ (lambda (pred) proc)) + (find (lambda (pred list))) + (find$ (lambda (pred) proc)) + (find-module (lambda (id) env)) + (find-tail$ (lambda (pred) proc)) + (fixnum? (lambda (obj) bool)) + (flonum? (lambda (obj) bool)) + (fluid-let (syntax)) + (flush (lambda (:optional output-port) undefined)) + (flush-all-ports (lambda () undefined)) + (fmod (lambda (x1 x2) x3)) + (fold (lambda (proc init list))) + (fold$ (lambda (proc :optional init) proc)) + (fold-right (lambda (proc init list))) + (fold-right$ (lambda (proc :optional init))) + (for-each$ (lambda (proc) (lambda (ls) undefined))) + (foreign-pointer-attribute-get (lambda (ptr attr))) + (foreign-pointer-attribute-set (lambda (ptr attr val))) + (foreign-pointer-attributes (lambda (ptr) list)) + (format (lambda (fmt-string arg \.\.\.))) + (format/ss (lambda (fmt-string arg \.\.\.))) + (frexp (lambda (x1) x2)) + (gauche-architecture (lambda () string)) + (gauche-architecture-directory (lambda () string)) + (gauche-character-encoding (lambda () symbol)) + (gauche-dso-suffix (lambda () string)) + (gauche-library-directory (lambda () string)) + (gauche-site-architecture-directory (lambda () string)) + (gauche-site-library-directory (lambda () string)) + (gauche-version (lambda () string)) + (gc (lambda () undefined)) + (gc-stat (lambda () list)) + (gensym (lambda (:optional name) symbol)) + (get-keyword (lambda (id list :optional default))) + (get-keyword* (syntax)) + (get-optional (syntax)) + (get-output-string (lambda (string-output-port) string)) + (get-remaining-input-string (lambda (port) string)) + (get-signal-handler (lambda (n) proc)) + (get-signal-handler-mask (lambda (n) n)) + (get-signal-handlers (lambda () list)) + (get-signal-pending-limit (lambda () n)) + (getter-with-setter (lambda (get-proc set-proc) proc)) + (global-variable-bound? (lambda (sym) bool)) + (global-variable-ref (lambda (sym))) + (guard (syntax)) + (has-setter? (lambda (proc) bool)) + (hash (lambda (obj))) + (hash-table (lambda (id pair \.\.\.) hash-table)) + (hash-table-delete! (lambda (hash-table key) undefined)) + (hash-table-exists? (lambda (hash-table key) bool)) + (hash-table-fold (lambda (hash-table proc init))) + (hash-table-for-each (lambda (hash-table proc) undefined)) + (hash-table-get (lambda (hash-table key :optional default))) + (hash-table-keys (lambda (hash-table) list)) + (hash-table-map (lambda (hash-table proc) list)) + (hash-table-num-entries (lambda (hash-table) n)) + (hash-table-pop! (lambda (hash-table key :optional default))) + (hash-table-push! (lambda (hash-table key value) undefined)) + (hash-table-put! (lambda (hash-table key value) undefined)) + (hash-table-stat (lambda (hash-table) list)) + (hash-table-type (lambda (hash-table) id)) + (hash-table-update! (lambda (hash-table key proc :optional default) undefined)) + (hash-table-values (lambda (hash-table) list)) + (hash-table? (lambda (obj) bool)) + (identifier->symbol (lambda (obj) sym)) + (identifier? (lambda (obj) bool)) + (identity (lambda (obj))) + (import (syntax)) + (inc! (syntax)) + (inexact-/ (lambda (x1 x2) x3)) + (initialize (lambda (obj))) + (instance-slot-ref (lambda (obj id))) + (instance-slot-set (lambda (obj id value))) + (integer->digit (lambda (n) ch)) + (integer-length (lambda (n) n)) + (is-a? (lambda (obj class) bool)) + (keyword->string (lambda (id) string)) + (keyword? (lambda (obj) bool)) + (last-pair (lambda (pair) pair)) + (lazy (syntax)) + (ldexp (lambda (x1 n) x2)) + (let-keywords* (syntax)) + (let-optionals* (syntax)) + (let/cc (syntax)) + (let1 (syntax)) + (library-exists? (lambda (filename) bool)) + (library-fold (lambda (string proc init))) + (library-for-each (lambda (string proc) undefined)) + (library-has-module? (lambda (filename id) bool)) + (library-map (lambda (string proc) list)) + (list* (lambda (obj \.\.\.) list)) + (list-copy (lambda (list) list)) + (logand (lambda (n \.\.\.) n)) + (logbit? (lambda (index n) bool)) + (logcount (lambda (n) n)) + (logior (lambda (n \.\.\.) n)) + (lognot (lambda (n) n)) + (logtest (lambda (n \.\.\.) bool)) + (logxor (lambda (n \.\.\.) n)) + (macroexpand (lambda (obj))) + (macroexpand-1 (lambda (obj))) + (make (lambda (class args \.\.\.))) + (make-byte-string (lambda (n :optional int) byte-string)) + (make-compound-condition (lambda (condition \.\.\.) condition)) + (make-condition (lambda (condition-type field+value \.\.\.) condition)) + (make-condition-type (lambda (id condition-type list) condition-type)) + (make-hash-table (lambda (:optional id) hash-table)) + (make-keyword (lambda (string) sym)) + (make-list (lambda (n :optional init) list)) + (make-module (lambda (id :optional if-exists-proc) env)) + (make-weak-vector (lambda (n) vector)) + (map$ (lambda (proc) proc)) + (member$ (lambda (obj) proc)) + (merge (lambda (list1 list2 proc) list)) + (merge! (lambda (list1 list2 proc) list)) + (method-more-specific? (lambda (method1 method2 list) bool)) + (min&max (lambda (x1 \.\.\.) (values x2 x3))) + (modf (lambda (x1) x2)) + (module-exports (lambda (env) list)) + (module-imports (lambda (env) list)) + (module-name (lambda (env) sym)) + (module-name->path (lambda (sym) string)) + (module-parents (lambda (env) list)) + (module-precedence-list (lambda (env) list)) + (module-table (lambda (env) hash-table)) + (module? (lambda (obj) bool)) + (null-list? (lambda (obj) bool)) + (object-* (lambda (z \.\.\.) z)) + (object-+ (lambda (z \.\.\.) z)) + (object-- (lambda (z \.\.\.) z)) + (object-/ (lambda (z \.\.\.) z)) + (object-apply (lambda (proc arg \.\.\.))) + (object-compare (lambda (obj1 obj2) n)) + (object-equal? (lambda (obj1 obj2) bool)) + (object-hash (lambda (obj) n)) + (open-coding-aware-port (lambda (input-port) input-port)) + (open-input-buffered-port (lambda ())) + (open-input-fd-port (lambda (fileno) input-port)) + (open-input-string (lambda (str) input-port)) + (open-output-buffered-port (lambda ())) + (open-output-fd-port (lambda (fileno) output-port)) + (open-output-string (lambda () string-output-port)) + (pa$ (lambda (proc arg \.\.\.) proc)) + (partition$ (lambda (pred) proc)) + (path->module-name (lambda (str) sym)) + (peek-byte (lambda (:optional input-port) n)) + (pop! (syntax (list))) + (port->byte-string (lambda (input-port) byte-string)) + (port->list (lambda (proc input-port) list)) + (port->sexp-list (lambda (port) list)) + (port->string (lambda (port) string)) + (port->string-list (lambda (port) list)) + (port-buffering (lambda (port) sym)) + (port-closed? (lambda (port) bool)) + (port-current-line (lambda (port) n)) + (port-file-number (lambda (port) n)) + (port-fold (lambda (proc init port))) + (port-fold-right (lambda (proc init port))) + (port-for-each (lambda (proc read-proc) undefined)) + (port-map (lambda (proc read-proc))) + (port-name (lambda (port) name)) + (port-position-prefix (lambda ())) + (port-seek (lambda (port offset (set int SEEK_SET SEEK_CUR SEEK_END)))) + (port-tell (lambda (port) n)) + (port-type (lambda (port) sym)) + (print (lambda (obj \.\.\.))) + (procedure-arity-includes? (lambda (proc n) bool)) + (procedure-info (lambda (proc))) + (profiler-reset (lambda () undefined)) + (profiler-show (lambda () undefined)) + (profiler-show-load-stats (lambda () undefined)) + (profiler-start (lambda () undefined)) + (profiler-stop (lambda () undefined)) + (program (syntax)) + (promise-kind (lambda ())) + (promise? (lambda (obj) bool)) + (proper-list? (lambda (obj) bool)) + (provide (lambda (str) undefined)) + (provided? (lambda (str) bool)) + (push! (syntax)) + (quotient&remainder (lambda (n1 n2) (values n1 n2))) + (raise (lambda (exn) undefined)) + (read-block (lambda (n :optional input-port) string)) + (read-byte (lambda (:optional input-port) n)) + (read-eval-print-loop (lambda () undefined)) + (read-from-string (lambda (str))) + (read-line (lambda (:optional input-port) str)) + (read-list (lambda (ch :optional input-port))) + (read-reference-has-value? (lambda ())) + (read-reference-value (lambda ())) + (read-reference? (lambda ())) + (read-with-shared-structure (lambda (:optional input-port))) + (read/ss (lambda (:optional input-port))) + (rec (syntax)) + (receive (syntax)) + (redefine-class! (lambda ())) + (reduce$ (lambda (proc :optional default) proc)) + (reduce-right$ (lambda (proc :optional default) proc)) + (ref (lambda (obj key \.\.\.))) + (ref* (lambda (obj key \.\.\.))) + (regexp->string (lambda (regexp) string)) + (regexp-case-fold? (lambda (regexp) bool)) + (regexp-compile (lambda (str) regexp)) + (regexp-optimize (lambda (str) str)) + (regexp-parse (lambda (str) list)) + (regexp-quote (lambda (str) str)) + (regexp-replace (lambda (regexp string subst) string)) + (regexp-replace* (lambda (string regexp subst \.\.\.) string)) + (regexp-replace-all (lambda (regexp string subst) string)) + (regexp-replace-all* (lambda (string regexp subst \.\.\.))) + (regexp? (lambda (obj) bool)) + (regmatch? (lambda (obj) bool)) + (remove$ (lambda (pred) proc)) + (report-error (lambda ())) + (require (syntax)) + (require-extension (syntax)) + (reverse! (lambda (list) list)) + (rxmatch (lambda (regexp string) regmatch)) + (rxmatch-after (lambda (regmatch :optional i) str)) + (rxmatch-before (lambda (regmatch :optional i) str)) + (rxmatch-case (syntax)) + (rxmatch-cond (syntax)) + (rxmatch-end (lambda (regmatch :optional i) n)) + (rxmatch-if (syntax)) + (rxmatch-let (syntax)) + (rxmatch-num-matches (lambda (regmatch) i)) + (rxmatch-start (lambda (regmatch :optional i) n)) + (rxmatch-substring (lambda (regmatch :optional i) str)) + (seconds->time (lambda (x1) time)) + (select-module (syntax)) + (set!-values (syntax)) + (set-signal-handler! (lambda (signals handler) undefined)) + (set-signal-pending-limit (lambda (n) undefined)) + (setter (lambda (proc) proc)) + (sinh (lambda (z) z)) + (slot-bound-using-accessor? (lambda (proc obj id) bool)) + (slot-bound-using-class? (lambda (class obj id) bool)) + (slot-bound? (lambda (obj id) bool)) + (slot-definition-accessor (lambda ())) + (slot-definition-allocation (lambda ())) + (slot-definition-getter (lambda ())) + (slot-definition-name (lambda ())) + (slot-definition-option (lambda ())) + (slot-definition-options (lambda ())) + (slot-definition-setter (lambda ())) + (slot-exists-using-class? (lambda (class obj id) bool)) + (slot-exists? (lambda (obj id) bool)) + (slot-initialize-using-accessor! (lambda ())) + (slot-missing (lambda (class obj id))) + (slot-push! (lambda (obj id value) undefined)) + (slot-ref (lambda (obj id))) + (slot-ref-using-accessor (lambda (proc obj id))) + (slot-ref-using-class (lambda (class obj id))) + (slot-set! (lambda (obj id value) undefined)) + (slot-set-using-accessor! (lambda (proc obj id value) undefined)) + (slot-set-using-class! (lambda (class obj id value) undefined)) + (slot-unbound (lambda (class obj id))) + (sort (lambda (seq :optional proc))) + (sort! (lambda (seq :optional proc))) + (sort-applicable-methods (lambda ())) + (sorted? (lambda (seq :optional proc))) + (split-at (lambda (list i) (values list list))) + (stable-sort (lambda (seq :optional proc))) + (stable-sort! (lambda (seq :optional proc))) + (standard-error-port (lambda () output-port)) + (standard-input-port (lambda () input-port)) + (standard-output-port (lambda () output-port)) + (string->regexp (lambda (str) regexp)) + (string-byte-ref (lambda (str i) n)) + (string-byte-set! (lambda (str i n) undefined)) + (string-complete->incomplete (lambda (str) str)) + (string-immutable? (lambda (str) bool)) + (string-incomplete->complete (lambda (str) str)) + (string-incomplete->complete! (lambda (str) str)) + (string-incomplete? (lambda (str) bool)) + (string-interpolate (lambda (str) list)) + (string-join (lambda (list :optional delim-str (set grammar infix strict-infix prefix suffix)))) +;; deprecated +;; (string-pointer-byte-index (lambda ())) +;; (string-pointer-copy (lambda ())) +;; (string-pointer-index (lambda ())) +;; (string-pointer-next! (lambda ())) +;; (string-pointer-prev! (lambda ())) +;; (string-pointer-ref (lambda ())) +;; (string-pointer-set! (lambda ())) +;; (string-pointer-substring (lambda ())) +;; (string-pointer? (lambda ())) + (string-scan (lambda (string item :optional (set return index before after before* after* both)))) + (string-size (lambda (str) n)) + (string-split (lambda (str splitter) list)) + (string-substitute! (lambda ())) + (subr? (lambda (obj) bool)) + (supported-character-encoding? (lambda (id) bool)) + (supported-character-encodings (lambda () list)) + (symbol-bound? (lambda (id) bool)) + (syntax-error (syntax)) + (syntax-errorf (syntax)) + (sys-abort (lambda () undefined)) + (sys-access (lambda (filename (flags amode R_OK W_OK X_OK F_OK)))) + (sys-alarm (lambda (x1) x2)) + (sys-asctime (lambda (time) str)) + (sys-basename (lambda (filename) str)) + (sys-chdir (lambda (dirname))) + (sys-chmod (lambda (filename n))) + (sys-chown (lambda (filename uid gid))) + (sys-close (lambda (fileno))) + (sys-crypt (lambda (key-str salt-str) str)) + (sys-ctermid (lambda () string)) + (sys-ctime (lambda (time) string)) + (sys-difftime (lambda (time1 time2) x1)) + (sys-dirname (lambda (filename) string)) + (sys-exec (lambda (command-string list) n)) + (sys-exit (lambda (n) undefined)) + (sys-fchmod (lambda (port-or-fileno n))) + (sys-fdset-max-fd (lambda (fdset))) + (sys-fdset-ref (lambda (fdset port-or-fileno))) + (sys-fdset-set! (lambda (fdset port-or-fileno))) + (sys-fork (lambda () n)) + (sys-fork-and-exec (lambda (command-string list) n)) + (sys-fstat (lambda (port-or-fileno) sys-stat)) + (sys-ftruncate (lambda (port-or-fileno n))) + (sys-getcwd (lambda () string)) + (sys-getdomainname (lambda () string)) + (sys-getegid (lambda () gid)) + (sys-getenv (lambda (name) string)) + (sys-geteuid (lambda () uid)) + (sys-getgid (lambda () gid)) + (sys-getgrgid (lambda () gid)) + (sys-getgrnam (lambda (name))) + (sys-getgroups (lambda () list)) + (sys-gethostname (lambda () string)) + (sys-getloadavg (lambda () list)) + (sys-getlogin (lambda () string)) + (sys-getpgid (lambda () gid)) + (sys-getpgrp (lambda () gid)) + (sys-getpid (lambda () pid)) + (sys-getppid (lambda () pid)) + (sys-getpwnam (lambda (name))) + (sys-getpwuid (lambda () uid)) + (sys-gettimeofday (lambda () (values x1 x2))) + (sys-getuid (lambda () uid)) + (sys-gid->group-name (lambda (gid) name)) + (sys-glob (lambda (string) list)) + (sys-gmtime (lambda (time) string)) + (sys-group-name->gid (lambda (name) gid)) + (sys-isatty (lambda (port-or-fileno) bool)) + (sys-kill (lambda (pid))) + (sys-lchown (lambda (filename uid gid))) + (sys-link (lambda (old-filename new-filename))) + (sys-localeconv (lambda () alist)) + (sys-localtime (lambda (time) string)) + (sys-lstat (lambda (filename) sys-stat)) + (sys-mkdir (lambda (dirname))) + (sys-mkfifo (lambda (filename))) + (sys-mkstemp (lambda (filename))) + (sys-mktime (lambda (time) x1)) + (sys-nanosleep (lambda (x1))) + (sys-normalize-pathname (lambda (filename) string)) + (sys-pause (lambda (x1))) + (sys-pipe (lambda (:optional buffering) (values input-port output-port))) + (sys-putenv (lambda (name string))) + (sys-random (lambda () n)) + (sys-readdir (lambda (dirname) list)) + (sys-readlink (lambda (filename) string)) + (sys-realpath (lambda (filename) string)) + (sys-remove (lambda (filename))) + (sys-rename (lambda (old-filename new-filename))) + (sys-rmdir (lambda (dirname))) + (sys-select (lambda (read-filenos write-filenos execpt-filenos :optional timeout-x))) + (sys-select! (lambda (read-filenos write-filenos execpt-filenos :optional timeout-x))) + (sys-setenv (lambda (name string))) + (sys-setgid (lambda (gid))) + (sys-setlocale (lambda (locale-string))) + (sys-setpgid (lambda (gid))) + (sys-setsid (lambda ())) + (sys-setuid (lambda (uid))) + (sys-sigmask (lambda ((set how SIG_SETMASK SIG_BLOCK SIG_UNBLOCK) sigset))) + (sys-signal-name (lambda (n))) + (sys-sigset (lambda (n \.\.\.) sigset)) + (sys-sigset-add! (lambda (sigset n))) + (sys-sigset-delete! (lambda (sigset n))) + (sys-sigset-empty! (lambda (sigset))) + (sys-sigset-fill! (lambda (sigset))) + (sys-sigsuspend (lambda (sigset))) + (sys-sigwait (lambda (sigset))) + (sys-sleep (lambda (x1))) + (sys-srandom (lambda (n))) + (sys-stat (lambda (filename))) +;; deprecated +;; (sys-stat->atime (lambda ())) +;; (sys-stat->ctime (lambda ())) +;; (sys-stat->dev (lambda ())) +;; (sys-stat->file-type (lambda ())) +;; (sys-stat->gid (lambda ())) +;; (sys-stat->ino (lambda ())) +;; (sys-stat->mode (lambda ())) +;; (sys-stat->mtime (lambda ())) +;; (sys-stat->nlink (lambda ())) +;; (sys-stat->rdev (lambda ())) +;; (sys-stat->size (lambda ())) +;; (sys-stat->type (lambda ())) +;; (sys-stat->uid (lambda ())) + (sys-strerror (lambda (errno) string)) + (sys-strftime (lambda (format-string time))) + (sys-symlink (lambda (old-filename new-filename))) + (sys-system (lambda (command) n)) + (sys-time (lambda () n)) + (sys-times (lambda () list)) +;; (sys-tm->alist (lambda ())) + (sys-tmpnam (lambda () string)) + (sys-truncate (lambda (filename n))) + (sys-ttyname (lambda (port-or-fileno) string)) + (sys-uid->user-name (lambda (uid) name)) + (sys-umask (lambda () n)) + (sys-uname (lambda () string)) + (sys-unlink (lambda (filename))) + (sys-unsetenv (lambda (name))) + (sys-user-name->uid (lambda (name) uid)) + (sys-utime (lambda (filename))) + (sys-wait (lambda ())) + (sys-wait-exit-status (lambda (n) n)) + (sys-wait-exited? (lambda (n) bool)) + (sys-wait-signaled? (lambda (n) bool)) + (sys-wait-stopped? (lambda (n) bool)) + (sys-wait-stopsig (lambda (n) n)) + (sys-wait-termsig (lambda (n) n)) + (sys-waitpid (lambda (pid))) + (tanh (lambda (z) z)) + (time (syntax)) + (time->seconds (lambda (time) x1)) + (time? (lambda (obj) bool)) + (toplevel-closure? (lambda (obj) bool)) + (touch-instance! (lambda ())) + (ucs->char (lambda (n) ch)) + (undefined (lambda () undefined)) + (undefined? (lambda (obj) bool)) + (unless (syntax)) + (until (syntax)) + (unwrap-syntax (lambda (obj))) + (update! (syntax)) + (update-direct-method! (lambda ())) + (update-direct-subclass! (lambda ())) + (use (special symbol scheme-gauche-available-modules)) + (use-version (syntax)) + (values-ref (syntax)) + (vector-copy (lambda (vector :optional start end fill) vector)) + (vm-dump (lambda () undefined)) + (vm-get-stack-trace (lambda () undefined)) + (vm-get-stack-trace-lite (lambda () undefined)) + (vm-set-default-exception-handler (lambda (handler) undefined)) + (warn (lambda (message-str args) undefined)) + (weak-vector-length (lambda (vector) n)) + (weak-vector-ref (lambda (vector i))) + (weak-vector-set! (lambda (vector i value) undefined)) + (when (syntax)) + (while (syntax)) + (with-error-handler (lambda (handler thunk))) + (with-error-to-port (lambda (port thunk))) + (with-exception-handler (lambda (handler thunk))) + (with-input-from-port (lambda (port thunk))) + (with-input-from-string (lambda (string thunk))) + (with-module (syntax)) + (with-output-to-port (lambda (port thunk))) + (with-output-to-string (lambda (thunk) string)) + (with-port-locking (lambda (port thunk))) + (with-ports (lambda (input-port output-port error-port thunk))) + (with-signal-handlers (syntax)) + (with-string-io (lambda (string thunk) string)) + (write* (lambda (obj :optional output-port) undefined)) + (write-byte (lambda (n :optional output-port) undefined)) + (write-limited (lambda (obj :optional output-port))) + (write-object (lambda (obj output-port))) + (write-to-string (lambda (obj) string)) + (write-with-shared-structure (lambda (obj :optional output-port))) + (write/ss (lambda (obj :optional output-port))) + (x->integer (lambda (obj) integer)) + (x->number (lambda (obj) number)) + (x->string (lambda (obj) string)) + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; special lookups (XXXX add more impls, try to abstract better) + +(defvar *scheme-chicken-base-repo* + (or (getenv "CHICKEN_REPOSITORY") + (let ((dir + (car (remove-if-not #'file-directory-p + '("/usr/lib/chicken" + "/usr/local/lib/chicken" + "/opt/lib/chicken" + "/opt/local/lib/chicken"))))) + (and dir + (car (reverse (sort (directory-files dir t "^[0-9]+$") + #'string-lessp))))) + (and (fboundp 'shell-command-to-string) + (let* ((res (shell-command-to-string "chicken-setup -R")) + (res (substring res 0 (- (length res) 1)))) + (and res (file-directory-p res) res))) + "/usr/local/lib/chicken")) + +(defvar *scheme-chicken-repo-dirs* + (remove-if-not + #'(lambda (x) (and (stringp x) (not (equal x "")))) + (let ((home (getenv "CHICKEN_HOME"))) + (if (and home (not (equal home ""))) + (let ((res (split-string home ";"))) + (if (member *scheme-chicken-repo-dirs* res) + res + (cons *scheme-chicken-repo-dirs* res))) + (list *scheme-chicken-base-repo*))))) + +(defun scheme-chicken-available-modules (&optional sym) + (append + (mapcar #'symbol-name (mapcar #'car *scheme-chicken-modules*)) + (mapcar + #'file-name-sans-extension + (directory-files "." nil ".*\\.scm$" t)) + (scheme-append-map + #'(lambda (dir) + (mapcar + #'file-name-sans-extension + (directory-files dir nil ".*\\.\\(so\\|scm\\)$" t))) + *scheme-chicken-repo-dirs*))) + +(defvar *scheme-gauche-repo-path* + (or (car (remove-if-not #'file-directory-p + '("/usr/share/gauche" + "/usr/local/share/gauche" + "/opt/share/gauche" + "/opt/local/share/gauche"))) + (and (fboundp 'shell-command-to-string) + (let* ((res (shell-command-to-string "gauche-config --syslibdir")) + (res (substring res 0 (- (length res) 1)))) + (and res (file-directory-p res) res))) + "/usr/local/share/gauche")) + +(defvar *scheme-gauche-site-repo-path* + (concat *scheme-gauche-repo-path* "/site/lib")) + +(defun scheme-gauche-available-modules (&optional sym) + (let ((version-dir + (concat + (car (directory-files *scheme-gauche-repo-path* t "^[0-9]")) + "/lib")) + (site-dir *scheme-gauche-site-repo-path*) + (other-dirs + (remove-if-not + #'(lambda (d) (and (not (equal d "")) (file-directory-p d))) + (split-string (or (getenv "GAUCHE_LOAD_PATH") "") ":")))) + (mapcar + #'(lambda (f) (subst-char-in-string ?/ ?. f)) + (mapcar + #'file-name-sans-extension + (scheme-append-map + #'(lambda (dir) + (let ((len (length dir))) + (mapcar #'(lambda (f) (substring f (+ 1 len))) + (scheme-directory-tree-files dir t "\\.scm")))) + (cons version-dir (cons site-dir other-dirs))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; utilities + +(defun scheme-append-map (proc init-ls) + (if (null init-ls) + '() + (let* ((ls (reverse init-ls)) + (res (funcall proc (pop ls)))) + (while (consp ls) + (setq res (append (funcall proc (pop ls)) res))) + res))) + +(defun scheme-flatten (ls) + (cond + ((consp ls) (cons (car ls) (scheme-flatten (cdr ls)))) + ((null ls) '()) + (t (list ls)))) + +(defun scheme-in-string-p () + (let ((orig (point))) + (save-excursion + (goto-char (point-min)) + (let ((parses (parse-partial-sexp (point) orig))) + (nth 3 parses))))) + +(defun scheme-beginning-of-sexp () + (let ((syn (char-syntax (char-before (point))))) + (if (or (eq syn ?\() + (and (eq syn ?\") (scheme-in-string-p))) + (forward-char -1) + (forward-sexp -1)))) + +(defun scheme-find-file-in-path (file path) + (car (remove-if-not + #'(lambda (dir) (file-exists-p (concat dir file))) + path))) + +;; visit a file and kill the buffer only if it wasn't already open +(defmacro scheme-with-find-file (path-expr &rest body) + (let ((path (gensym)) + (buf (gensym)) + (res (gensym))) + `(save-window-excursion + (let* ((,path (file-truename ,path-expr)) + (,buf (find-if #'(lambda (x) (equal ,path (buffer-file-name x))) + (buffer-list)))) + (if ,buf + (switch-to-buffer ,buf) + (switch-to-buffer (find-file-noselect ,path t t))) + (let ((,res (save-excursion ,@body))) + (unless ,buf (kill-buffer (current-buffer))) + ,res))))) + +(defun scheme-directory-tree-files (init-dir &optional full match) + (let ((res '()) + (stack (list init-dir))) + (while (consp stack) + (let* ((dir (pop stack)) + (files (cddr (directory-files dir full)))) + (setq res (append (if match + (remove-if-not + #'(lambda (f) (string-match match f)) + files) + files) + res)) + (setq stack + (append + (remove-if-not 'file-directory-p + (if full + files + (mapcar #'(lambda (f) (concat dir "/" f)) + files))) + stack)))) + res)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; sexp manipulation + +;; returns current argument position within sexp +(defun scheme-beginning-of-current-sexp-operator () + (let ((pos 0)) + (skip-syntax-backward "w_") + (while (and (not (bobp)) (not (eq ?\( (char-before)))) + (scheme-beginning-of-sexp) + (incf pos)) + pos)) + +(defun scheme-beginning-of-next-sexp () + (forward-sexp 2) + (backward-sexp 1)) + +(defun scheme-beginning-of-string () + (interactive) + (search-backward "\"" nil t) + (while (and (> (point) (point-min)) (eq ?\\ (char-before))) + (search-backward "\"" nil t))) + +;; for the enclosing sexp, returns a cons of the leading symbol (if +;; any) and the current position within the sexp (starting at 0) +;; (defun scheme-enclosing-sexp-prefix () +;; (save-excursion +;; (let ((pos (scheme-beginning-of-current-sexp-operator))) +;; (cons (scheme-symbol-at-point) pos)))) + +(defun scheme-enclosing-2-sexp-prefixes () + (save-excursion + (let* ((pos1 (scheme-beginning-of-current-sexp-operator)) + (sym1 (scheme-symbol-at-point))) + (backward-char) + (or + (ignore-errors + (let ((pos2 (scheme-beginning-of-current-sexp-operator))) + (list sym1 pos1 (scheme-symbol-at-point) pos2))) + (list sym1 pos1 nil 0))))) + +;; sexp-at-point is always fragile, both because the user can input +;; incomplete sexps and because some scheme sexps are not valid elisp +;; sexps. this is one of the few places we use it, so we're careful +;; to wrap it in ignore-errors. +(defun scheme-nth-sexp-at-point (n) + (ignore-errors + (save-excursion + (forward-sexp (+ n 1)) + (let ((end (point))) + (forward-sexp -1) + (car (read-from-string (buffer-substring (point) end))))))) + +(defun scheme-symbol-at-point () + (save-excursion + (skip-syntax-backward "w_") + (let ((start (point))) + (skip-syntax-forward "w_") + (and (< start (point)) + (intern (buffer-substring start (point))))))) + +(defun scheme-goto-next-top-level () + (let ((here (point))) + (or (ignore-errors (end-of-defun) (end-of-defun) + (beginning-of-defun) + (< here (point))) + (progn (forward-char) (re-search-forward "^(" nil t)) + (goto-char (point-max))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; variable extraction + +(defun scheme-sexp-type-at-point (&optional env) + (case (char-syntax (char-after)) + ((?\() + (forward-char 1) + (if (eq ?w (char-syntax (char-after))) + (let ((op (scheme-symbol-at-point))) + (cond + ((eq op 'lambda) + (let ((params + (scheme-nth-sexp-at-point 1))) + `(lambda ,params))) + (t + (let ((spec (scheme-env-lookup env op))) + (and spec + (consp (cadr spec)) + (eq 'lambda (caadr spec)) + (cddadr spec) + (car (cddadr spec))))))) + nil)) + ((?\") + 'string) + ((?\w) + (if (string-match "[0-9]" (string (char-after))) + 'number + nil)) + (t + nil))) + +(defun scheme-let-vars-at-point (&optional env) + (let ((end (or (ignore-errors + (save-excursion (forward-sexp) (point))) + (point-min))) + (vars '())) + (forward-char 1) + (while (< (point) end) + (when (eq ?\( (char-after)) + (save-excursion + (forward-char 1) + (if (eq ?w (char-syntax (char-after))) + (let* ((sym (scheme-symbol-at-point)) + (type (ignore-errors + (scheme-beginning-of-next-sexp) + (scheme-sexp-type-at-point env)))) + (push (if type (list sym type) (list sym)) vars))))) + (unless (ignore-errors (let ((here (point))) + (scheme-beginning-of-next-sexp) + (> (point) here))) + (goto-char end))) + (reverse vars))) + +(defun scheme-extract-match-clause-vars (x) + (cond + ((null x) '()) + ((symbolp x) + (if (memq x '(_ ___ \.\.\.)) + '() + (list (list x)))) + ((consp x) + (case (car x) + ((or not) + (scheme-extract-match-clause-vars (cdr x))) + ((and) + (if (and (consp (cdr x)) + (consp (cddr x)) + (symbolp (cadr x)) + (consp (caddr x)) + (not (memq (caaddr x) + '(= $ @ ? and or not quote quasiquote get! set!)))) + (cons (list (cadr x) (if (listp (caddr x)) 'list 'pair)) + (scheme-extract-match-clause-vars (cddr x))) + (scheme-extract-match-clause-vars (cddr x)))) + ((= $ @) + (if (consp (cdr x)) (scheme-extract-match-clause-vars (cddr x)) '())) + ((\?) + (if (and (consp (cdr x)) + (consp (cddr x)) + (symbolp (cadr x)) + (symbolp (caddr x))) + (cons (list (caddr x) (scheme-predicate->type (cadr x))) + (scheme-extract-match-clause-vars (cdddr x))) + (scheme-extract-match-clause-vars (cddr x)))) + ((get! set!) + (if (consp (cdr x)) (scheme-extract-match-clause-vars (cadr x)) '())) + ((quote) '()) + ((quasiquote) '()) ; XXXX + (t (union (scheme-extract-match-clause-vars (car x)) + (scheme-extract-match-clause-vars (cdr x)))))) + ((vectorp x) + (scheme-extract-match-clause-vars (concatenate 'list x))) + (t + '()))) + +;; call this from the first opening paren of the match clauses +(defun scheme-extract-match-vars (&optional pos limit) + (let ((match-vars '()) + (limit (or limit + (save-excursion + (or + (ignore-errors (end-of-defun) (point)) + (point-max)))))) + (save-excursion + (while (< (point) limit) + (let* ((end (ignore-errors (forward-sexp) (point))) + (start (and end (progn (backward-sexp) (point))))) + (cond + ((and pos start end (or (< pos start) (> pos end))) + (goto-char (if end (+ end 1) limit))) + (t + (forward-char 1) + (let* ((pat (scheme-nth-sexp-at-point 0)) + (new-vars (ignore-errors + (scheme-extract-match-clause-vars pat)))) + (setq match-vars (append new-vars match-vars))) + (goto-char (if (or pos (not end)) limit (+ end 1))))))) + match-vars))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; You can set the *scheme-default-implementation* to your preferred +;; implementation, for when we can't figure out the file from +;; heuristics. Alternately, in any given buffer, just +;; +;; (setq *scheme-current-implementation* whatever) + +(defgroup scheme-complete nil + "Smart tab completion" + :group 'scheme) + +(defcustom scheme-default-implementation nil + "Default scheme implementation to provide completion for +when scheme-complete can't infer the current implementation." + :type 'symbol + :group 'scheme-complete) + +(defvar *scheme-current-implementation* nil) +(make-variable-buffer-local '*scheme-current-implementation*) + +;; most implementations use their name as the script name +(defvar *scheme-interpreter-alist* + '(("csi" . chicken) + ("gosh" . gauche) + ("gsi" . gambit) + )) + +(defvar *scheme-imported-modules* '()) + +(defun scheme-current-implementation () + (unless *scheme-current-implementation* + (setq *scheme-current-implementation* + (save-excursion + (goto-char (point-min)) + (or (if (looking-at "#! *\\([^ \t\n]+\\)") + (let ((script (file-name-nondirectory (match-string 1)))) + (or (cdr (assoc script *scheme-interpreter-alist*)) + (intern script)))) + (cond + ((re-search-forward "(define-module +\\(.\\)" nil t) + (if (equal "(" (match-string 1)) + 'guile + 'gauche)) + ((re-search-forward "(use " nil t) + 'chicken) + ((re-search-forward "(module " nil t) + 'mzscheme)))))) + (or *scheme-current-implementation* + scheme-default-implementation)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun scheme-current-local-vars (&optional env) + (let ((vars '()) + (limit (save-excursion (beginning-of-defun) (+ (point) 1))) + (start (point)) + (scan-internal)) + (save-excursion + (while (> (point) limit) + (or (ignore-errors + (progn + (skip-chars-backward " \t\n" limit) + (scheme-beginning-of-sexp) + t)) + (goto-char limit)) + (when (and (> (point) (point-min)) + (eq ?\( (char-syntax (char-before (point)))) + (eq ?w (char-syntax (char-after (point))))) + (setq scan-internal t) + (let ((sym (scheme-symbol-at-point))) + (case sym + ((lambda) + (setq vars + (append + (mapcar #'list + (scheme-flatten (scheme-nth-sexp-at-point 1))) + vars))) + ((match match-let match-let*) + (setq vars + (append + (ignore-errors + (save-excursion + (let ((limit (save-excursion + (cond + ((eq sym 'match) + (backward-char 1) + (forward-sexp 1)) + (t + (forward-sexp 2))) + (point)))) + (forward-sexp 2) + (if (eq sym 'match) + (forward-sexp 1)) + (backward-sexp 1) + (if (not (eq sym 'match)) + (forward-char 1)) + (scheme-extract-match-vars + (and (or (eq sym 'match) (< start limit)) start) + limit)))) + vars))) + ((let let* letrec letrec* let-syntax letrec-syntax and-let* do) + (or + (ignore-errors + (save-excursion + (scheme-beginning-of-next-sexp) + (if (and (eq sym 'let) + (eq ?w (char-syntax (char-after (point))))) + ;; named let + (let* ((sym (scheme-symbol-at-point)) + (args (progn + (scheme-beginning-of-next-sexp) + (scheme-let-vars-at-point env)))) + (setq vars (cons `(,sym (lambda ,(mapcar #'car args))) + (append args vars)))) + (setq vars (append (scheme-let-vars-at-point env) vars))) + t)) + (goto-char limit))) + ((let-values let*-values) + (setq vars + (append (mapcar + #'list + (scheme-append-map + #'scheme-flatten + (remove-if-not #'consp + (scheme-nth-sexp-at-point 1)))) + vars))) + ((receive defun defmacro) + (setq vars + (append (mapcar #'list + (scheme-flatten + (scheme-nth-sexp-at-point 1))) + vars))) + (t + (if (string-match "^define\\(-.*\\)?" (symbol-name sym)) + (let ((defs (save-excursion + (backward-char) + (scheme-extract-definitions)))) + (setq vars + (append (scheme-append-map + #'(lambda (x) + (and (consp (cdr x)) + (consp (cadr x)) + (eq 'lambda (caadr x)) + (mapcar #'list + (scheme-flatten + (cadadr x))))) + defs) + defs + vars))) + (setq scan-internal nil)))) + ;; check for internal defines + (when scan-internal + (ignore-errors + (save-excursion + (forward-sexp + (+ 1 (if (numberp scan-internal) scan-internal 2))) + (backward-sexp) + (if (< (point) start) + (setq vars (append (scheme-current-definitions) vars)) + )))))))) + (reverse vars))) + +(defun scheme-extract-import-module-name (sexp &optional mzschemep) + (case (car sexp) + ((prefix) + (scheme-extract-import-module-name + (if mzschemep (caddr sexp) (cadr sexp)))) + ((prefix-all-except) + (scheme-extract-import-module-name (caddr sexp))) + ((for only except rename lib library) + (scheme-extract-import-module-name (cadr sexp) mzschemep)) + ((import) + (scheme-extract-import-module-name (cadr sexp) mzschemep)) + ((require) + (scheme-extract-import-module-name (cadr sexp) t)) + (t sexp))) + +(defun scheme-extract-import-module-imports (sexp &optional mzschemep) + (case (car sexp) + ((prefix) + (let* ((ids (scheme-extract-import-module-name + (if mzschemep (caddr sexp) (cadr sexp)) + mzschemep)) + (prefix0 (if mzschemep (cadr sexp) (caddr sexp))) + (prefix (if (symbolp prefix0) (symbol-name prefix0) prefix0))) + (mapcar #'(lambda (x) (intern (concat prefix (symbol-name x)))) ids))) + ((prefix-all-except) + (let ((prefix + (if (symbolp (cadr sexp)) (symbol-name (cadr sexp)) (cadr sexp))) + (exceptions (cddr sexp))) + (mapcar #'(lambda (x) + (if (memq x exceptions) + x + (intern (concat prefix (symbol-name x))))) + (scheme-extract-import-module-name (caddr sexp) t)))) + ((for) + (scheme-extract-import-module-name (cadr sexp) mzschemep)) + ((rename) + (if mzschemep + (list (caddr sexp)) + (mapcar 'cadr (cddr sexp)))) + ((except) + (remove-if #'(lambda (x) (memq x (cddr sexp))) + (scheme-extract-import-module-imports (cadr sexp) mzschemep))) + ((only) + (cddr sexp)) + ((import) + (scheme-extract-import-module-imports (cadr sexp) mzschemep)) + ((require for-syntax) + (scheme-extract-import-module-imports (cadr sexp) t)) + ((library) + (if (and (stringp (cadr sexp)) (file-exists-p (cadr sexp))) + (scheme-module-exports (intern (cadr sexp))))) + ((lib) + (if (and (equal "srfi" (caddr sexp)) + (stringp (cadr sexp)) + (string-match "^[0-9]+\\." (cadr sexp))) + (scheme-module-exports + (intern (file-name-sans-extension (concat "srfi-" (cadr sexp))))) + (scheme-module-exports + (intern (apply 'concat (append (cddr sexp) (list (cadr sexp)))))))) + (t sexp))) + +(defun scheme-extract-sexp-imports (sexp) + (case (car sexp) + ((begin) + (scheme-append-map #'scheme-extract-sexp-imports (cdr sexp))) + ((cond-expand) + (scheme-append-map #'scheme-extract-sexp-imports + (scheme-append-map #'cdr (cdr sexp)))) + ((use require-extension) + (scheme-append-map #'scheme-module-exports (cdr sexp))) + ((autoload) + (unless (member (cadr sexp) *scheme-imported-modules*) + (push (cadr sexp) *scheme-imported-modules*) + (mapcar #'(lambda (x) (cons (if (consp x) (car x) x) '((lambda obj)))) + (cddr sexp)))) + ((load) + (unless (member (cadr sexp) *scheme-imported-modules*) + (push (cadr sexp) *scheme-imported-modules*) + (and (file-exists-p (cadr sexp)) + (scheme-with-find-file (cadr sexp) + (scheme-current-globals))))) + ((library module) + (scheme-append-map #'scheme-extract-import-module-imports + (remove-if #'(lambda (x) (memq (car x) '(import require))) + (cdr sexp)))) + (t '()))) + +(defun scheme-module-symbol-p (sym) + (memq sym '(use require require-extension begin cond-expand + module library define-module autoload load))) + +(defun scheme-skip-shebang () + ;; skip shebang if present + (if (looking-at "#!") + ;; guile skips until a closing !# + (if (eq 'guile (scheme-current-implementation)) + (re-search-forward "!#" nil t) + (next-line)))) + +(defun scheme-current-imports () + (let ((imports '()) + (*scheme-imported-modules* '())) + (save-excursion + (goto-char (point-min)) + (scheme-skip-shebang) + ;; scan for module forms + (while (not (eobp)) + (if (ignore-errors (progn (forward-sexp) t)) + (let ((end (point))) + (backward-sexp) + (when (eq ?\( (char-after)) + (forward-char) + (when (and (not (eq ?\( (char-after))) + (scheme-module-symbol-p (scheme-symbol-at-point))) + (backward-char) + (ignore-errors + (setq imports + (append (scheme-extract-sexp-imports + (scheme-nth-sexp-at-point 0)) + imports))))) + (goto-char end)) + ;; if an incomplete sexp is found, try to recover at the + ;; next line beginning with an open paren + (scheme-goto-next-top-level)))) + imports)) + +;; we should be just inside the opening paren of an expression +(defun scheme-name-of-define () + (save-excursion + (scheme-beginning-of-next-sexp) + (if (eq ?\( (char-syntax (char-after))) + (forward-char)) + (and (memq (char-syntax (char-after)) '(?\w ?\_)) + (scheme-symbol-at-point)))) + +(defun scheme-type-of-define () + (save-excursion + (scheme-beginning-of-next-sexp) + (cond + ((eq ?\( (char-syntax (char-after))) + `(lambda ,(cdr (scheme-nth-sexp-at-point 0)))) + (t + (scheme-beginning-of-next-sexp) + (scheme-sexp-type-at-point))))) + +;; we should be at the opening paren of an expression +(defun scheme-extract-definitions (&optional env) + (save-excursion + (let ((sym (ignore-errors (and (eq ?\( (char-syntax (char-after))) + (progn (forward-char) + (scheme-symbol-at-point)))))) + (case sym + ((define-syntax defmacro define-macro) + (list (list (scheme-name-of-define) '(syntax)))) + ((define define-inline define-constant define-primitive defun) + (let ((name (scheme-name-of-define)) + (type (scheme-type-of-define))) + (list (if type (list name type) (list name))))) + ((defvar define-class) + (list (list (scheme-name-of-define) 'non-procedure))) + ((define-record) + (backward-char) + (ignore-errors + (let* ((sexp (scheme-nth-sexp-at-point 0)) + (name (symbol-name (cadr sexp)))) + `((,(intern (concat name "?")) (lambda (obj) boolean)) + (,(intern (concat "make-" name)) (lambda ,(cddr sexp) )) + ,@(scheme-append-map + #'(lambda (x) + `((,(intern (concat name "-" (symbol-name x))) + (lambda (non-procedure))) + (,(intern (concat name "-" (symbol-name x) "-set!")) + (lambda (non-procedure val) undefined)))) + (cddr sexp)))))) + ((define-record-type) + (backward-char) + (ignore-errors + (let ((sexp (scheme-nth-sexp-at-point 0))) + `((,(caaddr sexp) (lambda ,(cdaddr sexp))) + (,(cadddr sexp) (lambda (obj))) + ,@(scheme-append-map + #'(lambda (x) + (if (consp x) + (if (consp (cddr x)) + `((,(cadr x) (lambda (non-procedure))) + (,(caddr x) + (lambda (non-procedure val) undefined))) + `((,(cadr x) (lambda (non-procedure))))))) + (cddddr sexp)))))) + ((begin progn) + (forward-sexp) + (scheme-current-definitions)) + (t + '()))))) + +;; a little more liberal than -definitions, we try to scan to a new +;; top-level form (i.e. a line beginning with an open paren) if +;; there's an error during normal sexp movement +(defun scheme-current-globals () + (let ((globals '())) + (save-excursion + (goto-char (point-min)) + (or (ignore-errors (end-of-defun) (beginning-of-defun) t) + (re-search-forward "^(" nil t) + (goto-char (point-max))) + (while (not (eobp)) + (setq globals + (append (ignore-errors (scheme-extract-definitions)) globals)) + (scheme-goto-next-top-level))) + globals)) + +;; for internal defines, etc. +(defun scheme-current-definitions (&optional enclosing-end) + (let ((defs '()) + (end (or enclosing-end (point-max)))) + (save-excursion + (while (< (point) end) + (let ((here (point)) + (new-defs (scheme-extract-definitions))) + (cond + (new-defs + (setq defs (append new-defs defs)) + (or (ignore-errors (scheme-beginning-of-next-sexp) + (> (point) here)) + (goto-char end))) + (t ;; non-definition form, stop scanning + (goto-char end)))))) + defs)) + +(defun scheme-srfi-exports (i) + (and (integerp i) + (>= i 0) + (< i (length *scheme-srfi-info*)) + (let ((info (cdr (aref *scheme-srfi-info* i)))) + (if (and (consp info) (null (cdr info)) (symbolp (car info))) + (scheme-module-exports (car info)) + info)))) + +(defun scheme-module-exports (mod) + (unless (member mod *scheme-imported-modules*) + (push mod *scheme-imported-modules*) + (cond + ((and (consp mod) (eq 'srfi (car mod))) + (scheme-append-map #'scheme-srfi-exports (cdr mod))) + ((not (symbolp mod)) + '()) + ((string-match "^srfi-" (symbol-name mod)) + (scheme-srfi-exports + (string-to-number (substring (symbol-name mod) 5)))) + (t + (case (scheme-current-implementation) + ((chicken) + (let ((predefined (assq mod *scheme-chicken-modules*))) + (if predefined + (cdr predefined) + (mapcar + #'(lambda (x) (cons x '((lambda obj)))) + (or (mapcar #'intern + (scheme-file->lines + (concat "/usr/local/lib/chicken/3/" + (symbol-name mod) + ".exports"))) + (let ((setup-info (concat "/usr/local/lib/chicken/3/" + (symbol-name mod) + ".setup-info"))) + (and (file-exists-p setup-info) + (scheme-with-find-file setup-info + (let* ((alist (scheme-nth-sexp-at-point 0)) + (cell (assq 'exports alist))) + (cdr cell)))))))))) + ((gauche) + (let ((path (scheme-find-file-in-path + (concat (subst-char-in-string ?. ?/ (symbol-name mod)) + ".scm") + (list (concat + (car (directory-files + "/usr/local/share/gauche/" + t + "^[0-9]")) + "/lib") + "/usr/local/share/gauche/site/lib")))) + (if (not (file-exists-p path)) + '() + ;; XXXX parse, don't use regexps + (scheme-with-find-file path + (when (re-search-forward "(export" nil t) + (backward-sexp) + (backward-char) + (mapcar #'list (cdr (ignore-errors + (scheme-nth-sexp-at-point 0))))))))) + ((mzscheme) + (let ((path (scheme-find-file-in-path + (symbol-name mod) + '("." + "/usr/local/lib/plt/collects" + "/usr/local/lib/plt/collects/mzlib")))) + (if (not (file-exists-p path)) + '() + ;; XXXX parse, don't use regexps + (scheme-with-find-file path + (when (re-search-forward "(provide" nil t) + (backward-sexp) + (backward-char) + (mapcar #'list (cdr (ignore-errors + (scheme-nth-sexp-at-point 0))))))))) + (t '())))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; This is rather complicated because we to auto-generate docstring +;; summaries from the type information, which means inferring various +;; types from common names. The benefit is that you don't have to +;; input the same information twice, and can often cut&paste&munge +;; procedure descriptions from the original documentation. + +(defun scheme-translate-type (type) + (if (not (symbolp type)) + type + (case type + ((pred proc thunk handler dispatch producer consumer f fn g kons) + 'procedure) + ((num) 'number) + ((z) 'complex) + ((x1 x2 x3 y timeout seconds nanoseconds) 'real) + ((i j k n m int index size count len length bound nchars start end + pid uid gid fd fileno errno) + 'integer) + ((ch) 'char) + ((str name pattern) 'string) + ((file path pathname) 'filename) + ((dir dirname) 'directory) + ((sym id identifier) 'symbol) + ((ls alist lists) 'list) + ((vec) 'vector) + ((exc excn err error) 'exception) + ((ptr) 'pointer) + ((bool) 'boolean) + ((env) 'environment) + ((char string boolean number complex real integer procedure char-set + port input-port output-port pair list vector array stream hash-table + thread mutex condition-variable time exception date duration locative + random-source state condition condition-type queue sequence pointer + u8vector s8vector u16vector s16vector u32vector s32vector + u64vector s64vector f32vector f64vector undefined symbol + block filename directory mmap listener environment non-procedure + read-table continuation blob generic method class regexp regmatch + sys-stat fdset) + type) + ((parent seed option mode) 'non-procedure) + (t + (let* ((str (symbol-name type)) + (i (string-match "-?[0-9]+$" str))) + (if i + (scheme-translate-type (intern (substring str 0 i))) + (let ((i (string-match "-\\([^-]+\\)$" str))) + (if i + (scheme-translate-type (intern (substring str (+ i 1)))) + (if (string-match "\\?$" str) + 'boolean + 'object))))))))) + +(defun scheme-lookup-type (spec pos) + (let ((i 1) + (type nil)) + (while (and (consp spec) (<= i pos)) + (cond + ((eq :optional (car spec)) + (if (and (= i pos) (consp (cdr spec))) + (setq type (cadr spec))) + (setq i (+ pos 1))) + ((= i pos) + (setq type (car spec)) + (setq spec nil)) + ((and (consp (cdr spec)) (eq '\.\.\. (cadr spec))) + (setq type (car spec)) + (setq spec nil))) + (setq spec (cdr spec)) + (incf i)) + (if type + (setq type (scheme-translate-type type))) + type)) + +(defun scheme-predicate->type (pred) + (case pred + ((even? odd?) 'integer) + ((char-upper-case? char-lower-case? + char-alphabetic? char-numeric? char-whitespace?) + 'char) + (t + ;; catch all the `type?' predicates with pattern matching + ;; ... we could be smarter if the env was passed + (let ((str (symbol-name pred))) + (if (string-match "\\?$" str) + (scheme-translate-type + (intern (substring str 0 (- (length str) 1)))) + 'object))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; completion + +(eval-when (compile load eval) + (unless (fboundp 'event-matches-key-specifier-p) + (defalias 'event-matches-key-specifier-p 'eq))) + +(unless (fboundp 'read-event) + (defun read-event () + (aref (read-key-sequence nil) 0))) + +(unless (fboundp 'event-basic-type) + (defalias 'event-basic-type 'event-key)) + +(defun scheme-string-prefix-p (pref str) + (let ((p-len (length pref)) + (s-len (length str))) + (and (<= p-len s-len) + (equal pref (substring str 0 p-len))))) + +(defun scheme-do-completion (str coll &optional strs pred) + (let* ((coll (mapcar #'(lambda (x) + (cond + ((symbolp x) (list (symbol-name x))) + ((stringp x) (list x)) + (t x))) + coll)) + (completion1 (try-completion str coll pred)) + (completion2 (and strs (try-completion str strs pred))) + (completion (if (and completion2 + (or (not completion1) + (< (length completion2) + (length completion1)))) + completion2 + completion1))) + (cond + ((eq completion t)) + ((not completion) + (message "Can't find completion for \"%s\"" str) + (ding)) + ((not (string= str completion)) + (let ((prefix-p (scheme-string-prefix-p completion completion1))) + (unless prefix-p + (save-excursion + (backward-char (length str)) + (insert "\""))) + (insert (substring completion (length str))) + (unless prefix-p + (insert "\"") + (backward-char)))) + (t + (let ((win-config (current-window-configuration)) + (done nil)) + (message "Hit space to flush") + (with-output-to-temp-buffer "*Completions*" + (display-completion-list + (sort + (all-completions str (append strs coll) pred) + 'string-lessp))) + (while (not done) + (let* ((orig-event + (with-current-buffer (get-buffer "*Completions*") + (read-event))) + (event (event-basic-type orig-event))) + (cond + ((or (event-matches-key-specifier-p event 'tab) + (event-matches-key-specifier-p event 9)) + (save-selected-window + (select-window (get-buffer-window "*Completions*")) + (if (pos-visible-in-window-p (point-max)) + (goto-char (point-min)) + (scroll-up)))) + (t + (set-window-configuration win-config) + (if (or (event-matches-key-specifier-p event 'space) + (event-matches-key-specifier-p event 32)) + (bury-buffer (get-buffer "*Completions*")) + (setq unread-command-events (list orig-event))) + (setq done t)))))) + )))) + +(defun scheme-env-lookup (env sym) + (let ((spec nil) + (ls env)) + (while (and ls (not spec)) + (setq spec (assq sym (pop ls)))) + spec)) + +(defun scheme-current-env () + ;; r5rs + (let ((env (list *scheme-r5rs-info*))) + ;; base language + (let ((base (cdr (assq (scheme-current-implementation) + *scheme-implementation-exports*)))) + (if base (push base env))) + ;; imports + (let ((imports (ignore-errors (scheme-current-imports)))) + (if imports (push imports env))) + ;; top-level defs + (let ((top (ignore-errors (scheme-current-globals)))) + (if top (push top env))) + ;; current local vars + (let ((locals (ignore-errors (scheme-current-local-vars env)))) + (if locals (push locals env))) + env)) + +(defun scheme-env-filter (pred env) + (mapcar #'car + (apply #'concatenate + 'list + (mapcar #'(lambda (e) (remove-if-not pred e)) + env)))) + +;; checking return values: +;; a should be capable of returning instances of b +(defun scheme-type-match-p (a b) + (let ((a1 (scheme-translate-type a)) + (b1 (scheme-translate-type b))) + (and (not (eq a1 'undefined)) ; check a *does* return something + (or (eq a1 b1) ; and they're the same + (eq a1 'object) ; ... or a can return anything + (eq b1 'object) ; ... or b can receive anything + (if (symbolp a1) + (if (symbolp b1) + (case a1 ; ... or the types overlap + ((number complex real rational integer) + (memq b1 '(number complex real rational integer))) + ((port input-port output-port) + (memq b1 '(port input-port output-port))) + ((pair list) + (memq b1 '(pair list))) + ((non-procedure) + (not (eq 'procedure b1)))) + (and + (consp b1) + (if (eq 'or (car b1)) + ;; type unions + (find-if + #'(lambda (x) + (scheme-type-match-p + a1 (scheme-translate-type x))) + (cdr b1)) + (let ((b2 (scheme-translate-special-type b1))) + (and (not (equal b1 b2)) + (scheme-type-match-p a1 b2)))))) + (and (consp a1) + ;; type unions + (if (eq 'or (car a1)) + (find-if + #'(lambda (x) + (scheme-type-match-p (scheme-translate-type x) b1)) + (cdr a1)) + ;; other special types + (let ((a2 (scheme-translate-special-type a1)) + (b2 (scheme-translate-special-type b1))) + (and (or (not (equal a1 a2)) (not (equal b1 b2))) + (scheme-type-match-p a2 b2)))) + )))))) + +(defun scheme-translate-special-type (x) + (if (not (consp x)) + x + (case (car x) + ((list string) (car x)) + ((set special) (cadr x)) + ((flags) 'integer) + (t x)))) + +(defun scheme-nth* (n ls) + (while (and (consp ls) (> n 0)) + (setq n (- n 1) + ls (cdr ls))) + (and (consp ls) (car ls))) + +(defun scheme-file->lines (file) + (and (file-readable-p file) + (scheme-with-find-file file + (goto-char (point-min)) + (let ((res '())) + (while (not (eobp)) + (let ((start (point))) + (forward-line) + (push (buffer-substring-no-properties start (- (point) 1)) + res))) + (reverse res))))) + +(defun scheme-passwd-file-names (file &optional pat) + (delete + nil + (mapcar + #'(lambda (line) + (and (not (string-match "^[ ]*#" line)) + (or (not pat) (string-match pat line)) + (string-match "^\\([^:]*\\):" line) + (match-string 1 line))) + (scheme-file->lines file)))) + +(defun scheme-host-file-names (file) + (scheme-append-map + #'(lambda (line) + (let ((i (string-match "#" line))) + (if i (setq line (substring line 0 i)))) + (cdr (split-string line))) + (scheme-file->lines file))) + +(defun scheme-ssh-known-hosts-file-names (file) + (scheme-append-map + #'(lambda (line) + (split-string (car (split-string line)) ",")) + (scheme-file->lines file))) + +(defun scheme-ssh-config-file-names (file) + (scheme-append-map + #'(lambda (line) + (and (string-match "^ *Host" line) + (cdr (split-string line)))) + (scheme-file->lines file))) + +(defun scheme-complete-user-name (trans sym) + (if (string-match "apple" (emacs-version)) + (append (scheme-passwd-file-names "/etc/passwd" "^[^_].*") + (delete "Shared" (directory-files "/Users" nil "^[^.].*"))) + (scheme-passwd-file-names "/etc/passwd"))) + +(defun scheme-complete-host-name (trans sym) + (append (scheme-host-file-names "/etc/hosts") + (scheme-ssh-known-hosts-file-names "~/.ssh/known_hosts") + (scheme-ssh-config-file-names "~/.ssh/config"))) + +;; my /etc/services is 14k lines, so we try to optimize this +(defun scheme-complete-port-name (trans sym) + (and (file-readable-p "/etc/services") + (scheme-with-find-file "/etc/services" + (goto-char (point-min)) + (let ((rx (concat "^\\(" (regexp-quote (if (symbolp sym) + (symbol-name sym) + sym)) + "[^ ]*\\)")) + (res '())) + (while (not (eobp)) + (if (not (re-search-forward rx nil t)) + (goto-char (point-max)) + (let ((str (match-string-no-properties 1))) + (if (not (equal str (car res))) + (push str res))) + (forward-char 1))) + res)))) + +(defun scheme-complete-file-name (trans sym) + (let* ((file (file-name-nondirectory sym)) + (dir (file-name-directory sym)) + (res (file-name-all-completions file (or dir ".")))) + (if dir + (mapcar #'(lambda (f) (concat dir f)) res) + res))) + +(defun scheme-complete-directory-name (trans sym) + (let* ((file (file-name-nondirectory sym)) + (dir (file-name-directory sym)) + (res (file-name-all-completions file (or dir "."))) + (res2 (if dir (mapcar #'(lambda (f) (concat dir f)) res) res))) + (remove-if-not #'file-directory-p res2))) + +(defun scheme-string-completer (type) + (case type + ((filename) + '(scheme-complete-file-name file-name-nondirectory)) + ((directory) + '(scheme-complete-directory-name file-name-nondirectory)) + (t + (cond + ((and (consp type) (eq 'string (car type))) + (cadr type)) + ((and (consp type) (eq 'or (car type))) + (car (delete nil (mapcar #'scheme-string-completer (cdr type))))))))) + +(defun scheme-apply-string-completer (cmpl sym) + (let ((func (if (consp cmpl) (car cmpl) cmpl)) + (trans (and (consp cmpl) (cadr cmpl)))) + (funcall func trans sym))) + +(defun scheme-smart-complete (&optional arg) + (interactive "P") + (let* ((end (point)) + (start (save-excursion (skip-syntax-backward "w_") (point))) + (sym (buffer-substring-no-properties start end)) + (in-str-p (scheme-in-string-p)) + (x (save-excursion + (if in-str-p (scheme-beginning-of-string)) + (scheme-enclosing-2-sexp-prefixes))) + (inner-proc (car x)) + (inner-pos (cadr x)) + (outer-proc (caddr x)) + (outer-pos (cadddr x)) + (env (save-excursion + (if in-str-p (scheme-beginning-of-string)) + (scheme-current-env))) + (outer-spec (scheme-env-lookup env outer-proc)) + (outer-type (scheme-translate-type (cadr outer-spec))) + (inner-spec (scheme-env-lookup env inner-proc)) + (inner-type (scheme-translate-type (cadr inner-spec)))) + (cond + ;; return all env symbols when a prefix arg is given + (arg + (scheme-do-completion sym (scheme-env-filter #'(lambda (x) t) env))) + ;; for now just do file-name completion in strings + (in-str-p + (let* ((param-type + (and (consp inner-type) + (eq 'lambda (car inner-type)) + (scheme-lookup-type (cadr inner-type) inner-pos))) + (completer (or (scheme-string-completer param-type) + '(scheme-complete-file-name + file-name-nondirectory)))) + (scheme-do-completion + ;;(if (consp completer) (funcall (cadr completer) sym) sym) + sym + (scheme-apply-string-completer completer sym)))) + ;; outer special + ((and (consp outer-type) + (eq 'special (car outer-type)) + (cadddr outer-type)) + (scheme-do-completion sym (funcall (cadddr outer-type) sym))) + ;; inner special + ((and (consp inner-type) + (eq 'special (car inner-type)) + (caddr inner-type)) + (scheme-do-completion sym (funcall (caddr inner-type) sym))) + ;; completing inner procedure, complete procedures with a + ;; matching return type + ((and (consp outer-type) + (eq 'lambda (car outer-type)) + (not (zerop outer-pos)) + (scheme-nth* (- outer-pos 1) (cadr outer-type)) + (or (zerop inner-pos) + (and (>= 1 inner-pos) + (consp inner-type) + (eq 'lambda (car inner-type)) + (let ((param-type + (scheme-lookup-type (cadr inner-type) inner-pos))) + (and (consp param-type) + (eq 'lambda (car param-type)) + (eq (caddr inner-type) (caddr param-type))))))) + (let ((want-type (scheme-lookup-type (cadr outer-type) outer-pos))) + (scheme-do-completion + sym + (scheme-env-filter + #'(lambda (x) + (let ((type (cadr x))) + (or (memq type '(procedure object nil)) + (and (consp type) + (or (and (eq 'syntax (car type)) + (not (eq 'undefined (caddr type)))) + (and (eq 'lambda (car type)) + (scheme-type-match-p (caddr type) + want-type))))))) + env)))) + ;; completing a normal parameter + ((and inner-proc + (not (zerop inner-pos)) + (consp inner-type) + (eq 'lambda (car inner-type))) + (let* ((param-type (scheme-lookup-type (cadr inner-type) inner-pos)) + (set-or-flags + (or (and (consp param-type) + (case (car param-type) + ((set) (cddr param-type)) + ((flags) (cdr param-type)))) + ;; handle nested arithmetic functions inside a flags + ;; parameter + (and (not (zerop outer-pos)) + (consp outer-type) + (eq 'lambda (car outer-type)) + (let ((outer-param-type + (scheme-lookup-type (cadr outer-type) + outer-pos))) + (and (consp outer-param-type) + (eq 'flags (car outer-param-type)) + (memq (scheme-translate-type param-type) + '(number complex real rational integer)) + (memq (scheme-translate-type (caddr inner-type)) + '(number complex real rational integer)) + (cdr outer-param-type)))))) + (base-type (if set-or-flags + (if (and (consp param-type) + (eq 'set (car param-type))) + (scheme-translate-type (cadr param-type)) + 'integer) + param-type)) + (base-completions + (scheme-env-filter + #'(lambda (x) + (scheme-type-match-p (cadr x) base-type)) + env)) + (str-completions + (let ((completer (scheme-string-completer base-type))) + (and + completer + (scheme-apply-string-completer completer sym))))) + (scheme-do-completion + sym + (append set-or-flags base-completions) + str-completions))) + ;; completing a function + ((zerop inner-pos) + (scheme-do-completion + sym + (scheme-env-filter + #'(lambda (x) + (or (null (cdr x)) + (memq (cadr x) '(procedure object nil)) + (and (consp (cadr x)) + (memq (caadr x) '(lambda syntax))))) + env))) + ;; complete everything + (t + (scheme-do-completion sym (scheme-env-filter #'(lambda (x) t) env)) )))) + +(defun scheme-complete-or-indent (&optional arg) + (interactive "P") + (let* ((end (point)) + (func + (save-excursion + (beginning-of-line) + (if (re-search-forward "\\S-" end t) + 'scheme-smart-complete + 'lisp-indent-line)))) + (funcall func arg))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; optional eldoc function + +(defun scheme-translate-dot-to-optional (ls) + (let ((res '())) + (while (consp ls) + (setq res (cons (car ls) res)) + (setq ls (cdr ls))) + (if (not (null ls)) + (setq res (cons ls (cons :optional res)))) + (reverse res))) + +(defun scheme-optional-in-brackets (ls) + ;; put optional arguments inside brackets (via a vector) + (if (memq :optional ls) + (let ((res '())) + (while (and (consp ls) (not (eq :optional (car ls)))) + (push (pop ls) res)) + (reverse (cons (apply #'vector (cdr ls)) res))) + ls)) + +(defun scheme-base-type (x) + (if (not (consp x)) + x + (case (car x) + ((string list) (car x)) + ((set) (or (cadr x) (car x))) + ((flags) 'integer) + ((lambda) 'procedure) + ((syntax) 'syntax) + (t x)))) + +(defun scheme-sexp-to-string (sexp) + (with-output-to-string (princ sexp))) + +(defun scheme-get-current-symbol-info () + (let* ((sym (eldoc-current-symbol)) + (fnsym0 (eldoc-fnsym-in-current-sexp)) + (fnsym (if (consp fnsym0) (car fnsym0) fnsym0)) + (env (save-excursion + (if (scheme-in-string-p) (scheme-beginning-of-string)) + (scheme-current-env))) + (spec (or (and sym (scheme-env-lookup env sym)) + (and fnsym (scheme-env-lookup env fnsym))))) + (and (consp spec) + (consp (cdr spec)) + (let ((type (cadr spec))) + (concat + (cond + ((nth 3 spec) + "") + ((and (consp type) + (memq (car type) '(syntax lambda))) + (concat + (if (eq (car type) 'syntax) + "syntax: " + "") + (scheme-sexp-to-string + (cons (car spec) + (scheme-optional-in-brackets + (mapcar #'scheme-base-type + (scheme-translate-dot-to-optional + (cadr type)))))) + (if (and (consp (cddr type)) + (not (memq (caddr type) '(obj object)))) + (concat " => " (scheme-sexp-to-string (caddr type))) + ""))) + ((and (consp type) (eq (car type) 'special)) + (scheme-sexp-to-string (car spec))) + (t + (scheme-sexp-to-string type))) + (if (and (not (nth 3 spec)) (nth 4 spec)) " - " "") + (or (nth 4 spec) "")))))) + +(provide 'scheme-complete) + +;; Local Variables: +;; eval: (put 'scheme-with-find-file 'lisp-indent-hook 1) +;; End: diff --git a/emacs/scheme48.el b/emacs/scheme48.el new file mode 100644 index 0000000..39548c3 --- /dev/null +++ b/emacs/scheme48.el @@ -0,0 +1,397 @@ +;;; scheme48.el --- A major mode for Scheme48 development + +;; Copyright (C) 1992 Jonathan Rees +;; Copyright (C) 2005, 2006 Jorgen Schaefer + +;; Version: 9 +;; Author: Jonathan Rees (cmuscheme48.el) +;; Jorgen Schaefer <forcer@forcix.cx> (scheme48-mode) +;; URL: http://www.emacswiki.org/cgi-bin/emacs/Scheme48Mode + +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions +;; are met: +;; 1. Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; 2. Redistributions in binary form must reproduce the above copyright +;; notice, this list of conditions and the following disclaimer in the +;; documentation and/or other materials provided with the distribution. +;; 3. The name of the authors may not be used to endorse or promote products +;; derived from this software without specific prior written permission. + +;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR +;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, +;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;; Commentary: + +;; This file provides `scheme48-mode', a major mode for improved +;; interaction with Scheme48. It's the same as the canonical +;; `scheme-mode', but provides some commands which tell Scheme48 from +;; which a specific definition came from. This allows Scheme48 to put +;; the definition in the correct package by itself. + +;; This is based om the cmuscheme48.el which comes with Scheme48. + +;; You can set a buffer-local variable named `scheme48-package' to +;; send definitions to that package. This can be done by file +;; variables, so the following works: + +;; -*- mode: scheme48; scheme48-package: mypackage -*- + +;; To use the special packages CONFIG, USER and EXEC, use the package +;; name in parens, like this: + +;; -*- mode: scheme48; scheme48-package: (exec) -*- + +;;; Thanks: + +;; Thanks to Taylor Campbell (Riastradh on irc.freenode.net) for his +;; extensive list of indentation settings and the idea with the +;; scheme48-package local variable. + +;; Thanks to Emilio Lopes for the idea to highlight the new keywords +;; as well. + +;;; Code: + +(require 'cmuscheme) +(require 'scheme) + +(defcustom scheme48-compatibility-bindings-p nil + "Use the compatbility bindings? +The old cmuscheme48.el provided a few non-standard bindings, +which can be re-enabled by setting this variable to a non-nil +value before loading this file." + :group 'scheme + :type 'boolean) + +(defcustom scheme48-keywords + '(;; R5RS + (dynamic-wind 0) + + ;; Scheme48 + (destructure 1) + (enum-case 2) + (environment-define! 2 no-font-lock) + (environment-set! 2 no-font-lock) + (guard 1) + (iterate 3) + (make-usual-resumer 2 no-font-lock) + (mvlet 1) + (mvlet* 1) + (search-tree-modify! 2 no-font-lock) + (usual-resumer 0 no-font-lock) + (with-exception-handler 1) + (with-handler 1) + (with-interaction-environment 1) + (with-nondeterminism 0) + + ;; I/O-related + (call-with-current-input-port 1) + (call-with-current-noise-port 1) + (call-with-current-output-port 1) + (call-with-string-output-port 0) + (limit-output 2 no-font-lock) + (recurring-write 2 no-font-lock) + (silently 0) + (with-current-ports 3) + + ;; Configuration language + (define-interface 1) + (define-structure 2) + (structure 1) + (structures 1) + ;; These don't improve (for some, even degrade) the readability. + ;; (modify 1 no-font-lock) + ;; (subset 1 no-font-lock) + + ;; Concurrency-related + (atomically 0) + (atomically! 0) + (call-ensuring-atomicity 0) + (call-ensuring-atomicity! 0) + (ensure-atomicity 0) + (ensure-atomicity! 0) + (interrupt-thread 1 no-font-lock) + (let-fluid 2) + (let-fluids defun) + (spawn-on-scheduler 1 no-font-lock) + (with-new-proposal 1) + + ;; SCSH + (with-current-input-port 2) + (with-current-output-port 2) + (awk 3) + (close-after 2 no-font-lock) + (if-match 2) + (with-cwd 1) + (with-cwd* 1) + + ;; Others + (let-optionals scheme-let-indent) + (let-optionals* scheme-let-indent) + + ;; SRFI-2 + (and-let* 1) + + ;; SRFI-8 + (receive 2) + + ;; SRFI-11 + (let-values 1) + (let*-values 1) + ) + "A list of Scheme48-related keywords. +The list consists of lists of the form (KEYWORD INDENT [NO-FONT-LOCK]. +The keywords named KEYWORD will be indented according to INDENT, +and will also be highlighted as keywords unless NO-FONT-LOCK is +non-nil." + :group 'scheme + :type '(repeat (list symbol sexp boolean))) + +(defvar scheme48-package nil + "The name of the package definitions from this file should go to.") +(make-variable-buffer-local 'scheme48-package) + +(put 'scheme48-package 'safe-local-variable 'scheme48-safe-variable) + +(defun scheme48-safe-variable (var) + "Return non-nil when VAR is a valid value of `scheme48-package'." + (or (symbolp var) + (stringp var) + (and (consp var) + (or (and (null (cdr var)) + (memq (car var) + '(config user exec))) + (and (null (cddr var)) + (eq 'for-syntax (car var)) + (or (symbolp (cadr var)) + (stringp (cadr var)))))))) + +(defvar scheme48-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\M-\C-x" 'scheme48-send-definition) ;gnu convention + (define-key map "\C-x\C-e" 'scheme48-send-last-sexp) ;gnu convention + (define-key map "\C-c\C-e" 'scheme48-send-definition) + (define-key map "\C-c\M-e" 'scheme48-send-definition-and-go) + (define-key map "\C-c\C-r" 'scheme48-send-region) + (define-key map "\C-c\M-r" 'scheme48-send-region-and-go) + (define-key map "\C-c\C-l" 'scheme48-load-file) + (when scheme48-compatibility-bindings-p + (define-key map "\C-ce" 'scheme48-send-definition) + (define-key map "\C-c\C-e" 'scheme48-send-definition-and-go) + (define-key map "\C-cr" 'scheme48-send-region) + (define-key map "\C-c\C-r" 'scheme48-send-region-and-go) + (define-key map "\C-cl" 'scheme48-load-file)) + map) + "The keymap used in `scheme48-mode'.") + +(define-derived-mode scheme48-mode scheme-mode "Scheme48" + "Major mode for improved Scheme48 interaction. +This mode is derived from `scheme-mode', so see there for +information. + +The commands that send code to the Scheme48 process attach +information as to from which file the code comes from. This +allows Scheme48 to put the corresponding definitions in the +package associated with that file name. + +\\{scheme48-mode-map}" + (scheme48-initialize) + (set (make-local-variable 'scheme-trace-command) + ",trace %s") + (set (make-local-variable 'scheme-untrace-command) + ",untrace %s") + (set (make-local-variable 'scheme-macro-expand-command) + ",expand %s") + (when (boundp 'package) + (message "The `package' local variable is deprecated. Use `scheme48-package' instead.") + (when (not scheme48-package) + (setq scheme48-package package)))) + +(defvar scheme48-mode-initialized-p nil + "This is non-nil when `scheme48-mode' has been initialized. +Set it to nil if you want the next invocation of `scheme48-mode' +to re-read `scheme48-keywords'.") + +(defun scheme48-initialize () + "Initialize `scheme48-mode' from `scheme48-keywords'. +Only run when `scheme48-mode-initialized-p' is nil. +This is done so that the user can modify `scheme48-keywords' +before the first time the mode is run, but after this package has +been loaded." + (when (not scheme48-mode-initialized-p) + (mapc (lambda (entry) + (put (car entry) + 'scheme-indent-function + (cadr entry)) + (put (intern (upcase (symbol-name (car entry)))) + 'scheme-indent-function + (cadr entry))) + scheme48-keywords) + (let ((regexp (concat "(" + (regexp-opt + (delete nil + (mapcar (lambda (elt) + (if (nth 2 elt) + nil + (symbol-name (car elt)))) + scheme48-keywords)) + t) + "\\>"))) + (font-lock-add-keywords 'scheme48-mode + (list (list regexp 1 'font-lock-keyword-face)))) + (setq scheme48-mode-initialized-p t))) + +(defun scheme48-send-region (start end) + "Send the current region to the inferior Scheme process." + (interactive "r") + (cond + (scheme48-package + (scheme48-send-with-prefix (scheme48-package-sender scheme48-package) + start + end)) + ((buffer-file-name (current-buffer)) + (comint-send-string (scheme-proc) + (concat ",from-file " + (scheme48-enough-scheme-file-name + (buffer-file-name (current-buffer))) + "\n")) + (comint-send-region (scheme-proc) start end) + (comint-send-string (scheme-proc) " ,end\n")) + (t + (comint-send-region (scheme-proc) start end) + (comint-send-string (scheme-proc) "\n")))) + +(defun scheme48-send-with-prefix (prefix start end) + "Send all Scheme definitions in the region to the Scheme process." + (let ((region (buffer-substring-no-properties start end)) + (p prefix)) ; Emacs lossage - prefix is suddenly nil below + (with-temp-buffer + (insert region "\n") + ;; `backward-sexp' relies on this. Thanks to Riastradh for + ;; finding it out :-) + (set-syntax-table scheme-mode-syntax-table) + (set (make-local-variable 'parse-sexp-ignore-comments) t) + ;; Add prefix + (while (> (point) + (progn (backward-sexp) + (point))) + (save-excursion + (insert "\n" p " "))) + (comint-send-region (scheme-proc) + (point-min) + (point-max))))) + +(defun scheme48-send-definition () + "Send the current definition to the inferior Scheme48 process." + (interactive) + (save-excursion + (end-of-defun) + (let ((end (point))) + (beginning-of-defun) + (scheme48-send-region (point) end)))) + +(defun scheme48-send-last-sexp () + "Send the previous sexp to the inferior Scheme process." + (interactive) + (scheme48-send-region (save-excursion (backward-sexp) (point)) (point))) + +(defun scheme48-send-region-and-go (start end) + "Send the current region to the inferior Scheme48 process, +and switch to the process buffer." + (interactive "r") + (scheme48-send-region start end) + (switch-to-scheme t)) + +(defun scheme48-send-definition-and-go () + "Send the current definition to the inferior Scheme48, +and switch to the process buffer." + (interactive) + (scheme48-send-definition) + (switch-to-scheme t)) + +(defun scheme48-load-file (file-name) + "Load a Scheme file into the inferior Scheme48 process." + (interactive (comint-get-source "Load Scheme48 file: " + scheme-prev-l/c-dir/file + scheme-source-modes t)) ; T because LOAD + ; needs an exact name + (comint-check-source file-name) ; Check to see if buffer needs saved. + (setq scheme-prev-l/c-dir/file (cons (file-name-directory file-name) + (file-name-nondirectory file-name))) + (comint-send-string + (scheme-proc) + (concat (if scheme48-package + (concat (scheme48-package-sender scheme48-package) + " ") + "") + ",load " + (scheme48-enough-scheme-file-name file-name) + "\n"))) + +(defun scheme48-package-sender (package) + "Return the prefix to send a definition to PACKAGE." + (cond + ((equal package '(config)) + ",config") + ((equal package '(user)) + ",user") + ((equal package '(exec)) + ",exec") + ((and (consp package) + (eq 'for-syntax (car package))) + (format ",in %s ,for-syntax" (cadr package))) + (t + (format ",in %s" package)))) + +;;; This assumes that when you load things into Scheme 48, you type +;;; names of files in your home directory using the syntax "~/". +;;; Similarly for current directory. Maybe we ought to send multiple +;;; file names to Scheme and let it look at all of them. + +(defcustom scheme48-home-directory-kludge t + "*Whether the home directory should be simplified. + +When telling Scheme48 about the file name, it's a difference +whether we send a file name beginning with \"~/\" or the actual +expanded path name. If this is non-nil and the file name for +`scheme48-enough-scheme-file-name' starts with the user's home +directory, that is replaced with \"~/\"." + :group 'scheme + :type 'boolean) + +(defun scheme48-enough-scheme-file-name (file) + "Return a canonical name for FILE. +This will trim off the directory used in the *scheme* buffer, +or replace a home directory at the beginning with ~/ if +`scheme48-home-directory-kludge' is non-nil." + (let ((file (expand-file-name file)) + (scheme-dir (with-current-buffer scheme-buffer + (expand-file-name default-directory)))) + (or (scheme48-replace-prefix file scheme-dir) + (and scheme48-home-directory-kludge + (scheme48-replace-prefix file (expand-file-name "~/") "~/")) + file))) + +(defun scheme48-replace-prefix (file prefix &optional replace) + "Replace PREFIX at the beginning of FILE with REPLACE, or \"\"." + (let ((replace (or replace "")) + (len (length prefix))) + (if (and (> (length file) + len) + (string-equal (substring file 0 len) + prefix)) + (concat replace (substring file len)) + nil))) + +(provide 'scheme48) +;;; scheme48.el ends here diff --git a/emacs/screencast.el b/emacs/screencast.el new file mode 100644 index 0000000..ec9ec0a --- /dev/null +++ b/emacs/screencast.el @@ -0,0 +1,778 @@ +;;; screencast.el --- demonstrate the capabilities of Emacs + +;; Copyright (C) 2009 ESBEN Andreasen <esbenandreasen@gmail.com> + +;; Authors: Esben Andreasen <esbenandreasen@gmail.com> + +;; Keywords: demo screencast + +;; This file is not an official part of 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 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.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file allows you to create video-like sessions, which +;; demonstrates the capabilities of Emacs. + +;;; Usage: + +;; Install this file to an appropriate directory in your load-path, +;; and add these expressions to your ~/.emacs + +;; (auto-load 'screencast "screencast") + +;; Try it out by evaluating (screencast-screencast-producer) and (screencast-screencast-user) + +;; Your own screencast files should have a (require 'screencast) + +;;; Conventions: + +;; PRODUCER : creates a screencast + +;; USER : sees a screencast + +;; producer sections in this document contains variables which the producer +;; should modify as need be, and functions to be called during the creation of a +;; screencast + +;;; Change-log: + +;; 1.0: core functionality + +;; 1.1: PRODUCER ADDITIONS: +;; public variables which contain information about the current screencast +;; ability to change last-command and last-command-char +;; ability to use let and flet, while still outputting command descriptions +;; ability to create blinking sections to move the attention towards those +;; ability to show the region as if transient-mark-mode was on +;; +;; split the screencasts for the producer into a basic and an advanced +;; voice synthesizing of typed text. Requires festival to be installed. +;; global speed control +;; typed strings in screencasts can not contain tabs and newlines +;;; Code: + +(defconst screencast-message-buffer-name "*Screencast Messages*" + "The name of the buffer to put messages from the screencast in") + +(defconst screencast-version 1.1 "The version number of the screencast-mode") + +(defconst screencast-speed-relation-speech-type 18.0 + "When this is correctly adjusted, speech and typing should end +at the same time. Lower values means faster speech.") +;;;; BEGIN USER VARIABLES +(defvar screencast-pause-length 2 "The length of a pause ('p) in the screencast") + +(defvar screencast-pause-char-length 0.12 + "The time between each typed character in the function `screencast-insert-with-delay'") + +(defvar screencast-pause-command-length 3 + "The time between the announcement of the function call, and the call itself.") + +(defvar screencast-speech nil "If non-nil, slowly typed strings are read aloud") + +(defvar screencast-speed 1.0 "How fast the screencast should be. Higher values equals higher speed. This can not be changed _during_ the screencast.") +;;;; BEGIN PRODUCER VARIABLES +;; these variables should be changed as needed by the producer + +(defvar screencast-dont-print-list '( + progn + let + flet + save-excursion + save-window-excursion + i + screencast-producer-insert-with-delay + screencast-producer-set-last-command + screencast-producer-set-last-char + screencast-producer-new-buffer + screencast-producer-show-region + screencast-producer-blink-regions) + "A list of lists of function names which aren't printed as + being evaluated in the messages, this includes all producer + functions by default") + +(defvar screencast-producer-blink-time 0.5 + "The time a blink lasts.") + +;; variables which can be read during run-time to obtain information about the +;; current screencast +(defvar screencast-producer-nopause nil + "Variable to be used for producer functions if they are using + pauses, they should deactivate the pause if this variable is non-nil.") + +(defvar screencast-producer-command-buffer nil + "Variable to be used for producer functions if they are using + need the current command-buffer.") + +(defvar screencast-producer-step-number 0 + "Variable to be used for producer functions if they need to +know the current step number. +This is a _COPY_ of the value the screencast uses!") + +(defvar screencast-producer-beginat 0 + "Variable to be used for producer functions if they need to + know where the screencast is supposed to be using pauses at") +;;;; END PRODUCER VARIABLES + + +;;;; BEGIN MODE +(defvar screencast-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "RET") 'screencast-goto-step) + map) + "Keymap for `screencast-mode'." + ) + +(define-derived-mode screencast-mode nil "screencast" + "Major mode for viewing screencasts." + (auto-fill-mode 1) + ) +;;;; END MODE + +;;;; BEGIN PRODUCER FUNCTIONS +(defun screencast-producer-insert-with-delay (string) + "Screencast producer function. _i_nserts STRING with a delay between each character. +See `screencast-insert-with-delay' for more details." + (let ((screencast-speech nil)) + (screencast-insert-with-delay string screencast-producer-nopause))) + +(defalias 'i 'screencast-producer-insert-with-delay + "Short name for `screencast-producer-insert-with-delay'. +This is chosen as it improves readability a lot in the screencast-source.") + +(defun screencast-producer-set-last-command (f last) + "Sets the last-command to LAST before evaluating F. +Also prints the info about F, like it would have done normally." + (screencast-producer-show-command (car f)) + (eval-with-last f last) + ) + +(defun eval-with-last (f last) + (eval (list 'progn + ;; wtf? that's the only way it works (lines can be permuted!) + '(setq last-command last) + '(setq this-command last) + f))) + +(defun screencast-producer-set-last-char (char f) + "Sets the last-command to CHAR before evaluating F. +Also prints the info about F, like it would have done normally." + (screencast-producer-show-command (car f)) + (eval (list 'progn + '(setq last-command-char (string-to-char char)) + f))) + +(defun screencast-producer-show-command (command) + "Shows the COMMAND, and how it can be called in the message-buffer." + (pop-to-buffer (get-buffer screencast-message-buffer-name)) + (screencast-show-command command + screencast-producer-step-number + screencast-producer-command-buffer) + (pop-to-buffer (get-buffer screencast-producer-command-buffer))) + +(defun screencast-producer-new-buffer (list command-buffer-name) + "Screencast producer function. Creates an new screencast with + COMMAND-BUFFER-NAME as the command-buffer. The message-buffer + remains the same. Once the inner screencast ends, the original + command-buffer regains its status. + + +IMPORTANT: + +You are responsible for killing the `COMMAND-BUFFER' +before the outermost screencast ends, otherwise you'll receive +the modified buffer the next time you run the outermost +screencast." + ;; we want to start an 'inner screencast', but the current buffer is the + ;; command-buffer, and the expected starting buffer is the + ;; screencast-message-buffer + (pop-to-buffer (get-buffer screencast-message-buffer-name)) + (screencast-internal list + (get-buffer command-buffer-name) + screencast-producer-beginat) + ) + +(defun screencast-producer-show-region (beg end) + "Marks the currently active region as if transient mark mode was on." + (unless screencast-producer-nopause + (let ((overlay (make-overlay beg end))) + (overlay-put overlay 'face (cons beg end)) + ;; unless there's a LOT of regions, the blinks will be synchronous + (run-with-timer screencast-pause-length nil 'delete-overlay overlay) + ) + (sit-for screencast-pause-length) + ) + ) + +(defun screencast-producer-blink-regions (regions) + "The REGIONS will blink. +A region is a pair: (beg . end)." + (unless screencast-producer-nopause + (dotimes (n 5) + (dolist (region regions) + (let ((overlay (make-overlay (car region) (cdr region)))) + (overlay-put overlay 'face 'region) + ;; unless there's a LOT of regions, the blinks will be synchronous + (run-with-timer screencast-producer-blink-time nil 'delete-overlay overlay)) + ) + (sit-for (* 2 screencast-producer-blink-time)) + ))) + +;;;; END PRODUCER FUNCTIONS +;;;; BEGIN CORE +(defun make-region-clickable (beg end action &optional key) + "Makes the chosen region clickable, executing chosen action. +Default key is [mouse-1]." + (let ((map (make-sparse-keymap)) + (keyc (if key + key + [mouse-1])) + ) + (define-key map keyc action) + (put-text-property + beg + end + 'keymap map)) + ) + +(defun screencast-fontify-step-region () + "Fontifies regions with step-references. +To be called immediately after functions which put step-numbers +in the message-buffer. Will fontify from the beginning of the +line with the step number to the end of the buffer." + (save-excursion + (goto-char (point-max)) + (let ((beg (search-backward-regexp "^Step [[:digit:]]+:" (point-min)))) + (screencast-put-shadow-and-make-clickable beg (point-max)) + ))) + +(defun screencast-put-shadow-and-make-clickable (beg end) + "The region between BEG and END becomes shadowed and clickable. +`screencast-goto-step' is evalled when clicked" + (add-text-properties beg (- end 0) + (list + 'face 'shadow + 'mouse-face 'highlight + 'help-echo "mouse-1: continue from this step" + )) + (make-region-clickable beg (- end 0) 'screencast-goto-step)) + +(defun screencast-get-step () + "Returns the step-number of a step-reference region. +If not in step-reference region, returns nil" + + (if + ;; check if we are at a step-reference region + (save-excursion + (goto-char (line-end-position)) + (or + ;; first line + (search-backward-regexp "^Step [[:digit:]]+:" (line-beginning-position) t) + ;; second line + (search-backward-regexp "^ Callable with:" (line-beginning-position) t))) + ;; get the step number + (save-excursion + (search-backward-regexp "^Step \\([[:digit:]]+\\):") + (let ((beg (match-beginning 1)) + (end (match-end 1))) + (string-to-number + (buffer-substring-no-properties beg end)))) + ;; not in step-reference region + nil)) + +(defun repeat-string (s n) + (apply 'concat (make-list n s))) + +(defun screencast-make-break (nopause) + (screencast-newline-only-once) + (newline) + (screencast-line) + (newline) + (screencast-pause-maybe nopause) + (screencast-pause-maybe nopause) + ) + +(defun screencast-pause-maybe (nopause &optional length) + "Pauses the program, unless NOPAUSE is non-nil. + If length is nil, a default pause LENGTH is used." + (unless nopause + (let ((l (if length + length + screencast-pause-length))) + (sit-for l)))) + +(defun n-first (n list) + "The n first elements of a list." + (loop for x in list repeat n collect x)) + +(defun buffer-recreate (buffer-name) + "Kills the buffer with BUFFER-NAME, and recreates it." + (let ((buffer (get-buffer buffer-name))) + (when buffer + (when (buffer-file-name buffer) + (save-excursion + (set-buffer buffer) + (unless (let ((start (substring-no-properties buffer-name 0 1))) + (or (string= start " ") (string= start "*"))) + (save-buffer))) + (kill-buffer buffer-name))) + (get-buffer-create buffer-name)) + ) +(defun screencast-goto-step (&optional arg) + "Restarts the screencast at the chosen ARG step. Default is the first step." + (interactive "p") + (let ((step (if (not (= 1 arg)) + arg + (screencast-get-step))) + ;; bug? using (point), standing at point max gives nil values! + (list (get-text-property (point-min) 'screencast-list)) + (name (get-text-property (point-min) 'screencast-command-buffer-name))) + ;; (print step) + ;; (print list) + ;; (print name) + (screencast list name + -1 ; we just ran the screencast, so version should be no problem + (if step + (- step 1) ; the command just before! + + 0)) + )) + +(defun screencast-newline-only-once () + "Inserts a newline at point if, and only if the current line is nonempty." + (unless (= (line-beginning-position) (line-end-position)) + (newline)) + ) + +(defun screencast-make-region-clickable (beg end action &optional key) + "Makes the chosen region clickable, executing chosen action. +Default key is [mouse-1]." + (let ((map (make-sparse-keymap)) + (keyc (if key + key + [mouse-1])) + ) + (define-key map keyc action) + (put-text-property + beg + end + 'keymap map)) + ) + +(defun screencast-show-command (com step command-buffer) + "Inserts the STEP number and key-binding for a command, COM." + (screencast-newline-only-once) + (insert "Step " (number-to-string step) ": `" (symbol-name com) "'") + (newline) + (insert " Callable with: ") + (insert (where-is-return com command-buffer)) + (screencast-fontify-step-region) + (newline) + ) + +(defun screencast-line (&optional length) + (let ((l (if length + length + 25))) + (screencast-newline-only-once) + (insert (repeat-string "-" l)) + (center-line) + (newline) + )) + +(defun screencast-header () + (screencast-newline-only-once) + (newline) + (screencast-line 50) + (newline)) + +(defun screencast-speech-start (string nopause) + "Starts the speech-synthesizer with STRING, unless NOPAUSE is nonnil. +Also requires `screencast-speech' to be non-nil. +The speech speed depends on the typing speed (`screencast-speed-relation-speech-type')." + (when (and (not nopause) screencast-speech) + (let* ((duration (concat + "-b \"(Parameter.set 'Duration_Stretch " + (number-to-string (* screencast-pause-char-length + screencast-speed-relation-speech-type)) ")\"")) + (tosay (replace-regexp-in-string "'" "'\"'\"'" string)) + (say (concat "-b '(SayText \"" tosay "\")'")) + ) + (save-window-excursion + (shell-command + (concat "festival " duration " " say "&")) + )))) + +(defun screencast-speech-wait-for (nopause) + "Blocks until the speech synthesizer is done speaking." + (when (and (not nopause) screencast-speech) + (shell-command "while [ `pgrep festival` ] ; do sleep 0.1; done;") + (sit-for 0.1)) ; needed + ) + +(defun screencast-insert-with-delay (string &optional nopause) + "Inserts STRING with a delay between each character. +If NOPAUSE is non-nil, the delay will be 0. + +The pause between each character is given by `screencast-pause-char-length'." + (let ((string (screencast-strip-newlines-and-normalize-whitespace string))) + (screencast-speech-start string nopause) + (let ((l (string-to-list string))) + (dolist (c l) + (insert c) + ;; simple filling. If the char position equals fill-column. The + ;; whole word is moved to the next line. + (when (and (= (- (line-end-position) (line-beginning-position)) fill-column)) + (search-backward " ") + (insert "\n ") ; two space indentation as the previous space is moved too + (end-of-line) ; ? + ) + (screencast-pause-maybe nopause screencast-pause-char-length))) + (screencast-speech-wait-for nopause) + ) + ) + +(defun screencast-strip-newlines-and-normalize-whitespace (string) + "Replaces all newlines and tabs in STRING by a single +whitespace, also collapses multiple whitespaces." + (replace-regexp-in-string "[ ]+" " " (replace-regexp-in-string "\n" " " string))) + +(defalias 'screencast 'screencast-producer-screencast "Renaming for simplicity") + +(defun screencast-producer-screencast (list command-buffer-name + version &optional beginat init) + "Prints and evaluates a list, LIST, of strings and functions in a tempo humans can follow. +The strings in LIST is printed to the screencast-message-buffer. +Functions are evaluated in the buffer named COMMAND-BUFFER-NAME. +VERSION is the version of screencast-mode the screencast is +written for, older versions of screencast-mode might not support +everything in newer screencasts. +The first BEGINAT elements of the list will be done without +delays. +INIT is a list of functions to be evaluated in the message-buffer +prior to the first message" + (when (> version screencast-version) + (error + (concat "The version of the screencast (" (number-to-string + version) ") is newer than the version of the screencast-mode +itself (" (number-to-string screencast-version) "). You might still be able +to run the screencast successfully though, just change the +screencasts version number to try it out."))) + + + ;; preparations: + (let* ( + ;; speed adjustments + (screencast-pause-length (/ screencast-pause-length + screencast-speed)) + (screencast-pause-char-length (/ + screencast-pause-char-length + screencast-speed)) + (screencast-pause-command-length (/ + screencast-pause-command-length + screencast-speed)) + ;; buffers + (message-buffer (buffer-recreate screencast-message-buffer-name)) + (command-buffer (if (string= command-buffer-name + screencast-message-buffer-name) + message-buffer + (buffer-recreate command-buffer-name))) + ;; numbers + (screencast-step-number 0) + (beginat (if beginat + beginat + 0))) + (delete-other-windows) + (split-window-horizontally) + (switch-to-buffer message-buffer) + (pop-to-buffer message-buffer) + (display-buffer command-buffer) + (screencast-mode) + (toggle-read-only 0) + ;; evaluate all the functions of init + (dolist (f init) + (eval f)) + + ;; show + (screencast-internal list command-buffer beginat) + ;; save the arguments in the buffer + (add-text-properties (point-min) (point-max) + (list 'screencast-list list + 'screencast-command-buffer-name command-buffer-name)) + (toggle-read-only 1) + ) + ) + +(defun screencast-internal (list command-buffer beginat) + "The internal version of screencast, refer to the documentation string + there." + ;; producer variables + (setq screencast-producer-command-buffer command-buffer) + (setq screencast-producer-beginat beginat) + ;; make sure we are visiting the file in case it is needed (e.g. compile!) + (save-excursion + (set-buffer command-buffer) + (unless (buffer-file-name) + (set-visited-file-name (buffer-name)) + )) + ;; for each element in the list + (dolist (c list) + (let ((nopause + (if (>= screencast-step-number beginat) + nil + t))) + ;; producer variables + (setq screencast-producer-nopause nopause) + (setq screencast-producer-step-number screencast-step-number) + (cond + ((symbolp c) + ;; special symbols + (cond + ((eq 's c) ; step + (screencast-newline-only-once) + (insert "Step " (number-to-string screencast-step-number) ":") + (screencast-fontify-step-region) + ) + ((eq 'l c) ; line + (screencast-line)) + ((eq 'n c) ; newline + (newline)) + ((eq 'p c) ; pause + (screencast-pause-maybe nopause)) + ((eq 'b c) ; break + (screencast-make-break nopause) + ) + (t + (error (concat "Screencast-internal encountered an error: Unknown symbol: " (symbol-name c))))) + ) + ((listp c) + ;; function + (progn + (unless (member (car c) screencast-dont-print-list) ; these need no print + (screencast-show-command (car c) screencast-step-number command-buffer) + ) + (unless nopause + (screencast-pause-maybe nopause screencast-pause-command-length) ; pause + ) + (if (member (car c) '(let flet)) + (progn + ;; we want the environment - but also to print the commands! + (eval (list (car c) ; the members above + (cadr c) ;the lets of flets + '(screencast-internal (cddr c) command-buffer beginat))) ;the rest + ) + ;; evaluate standard + (progn + ;; save excursion style which allows for inner screencasts + (pop-to-buffer command-buffer) + (eval c) + (pop-to-buffer screencast-message-buffer-name))) + (pop-to-buffer screencast-message-buffer-name) ; needed to regain real focus! + )) + ((stringp c) + ;; it's a string - instert it. + (screencast-insert-with-delay c nopause)) + (t + (error (concat "I don't know what to do with element:" c))) + ) + (setq screencast-step-number (+ 1 screencast-step-number)) ; inc the step number + ) + ) + ) + +(defun where-is-return (definition buffer) + "A modification of where-is, which returns the message-string instead of printing it. + Also skips the removes name from the output. + BUFFER is the buffer to call where-is in." + (save-excursion + (set-buffer buffer) + (let ((func (indirect-function definition)) + (defs nil) + (return-string "")) + ;; In DEFS, find all symbols that are aliases for DEFINITION. + (mapatoms (lambda (symbol) + (and (fboundp symbol) + (not (eq symbol definition)) + (eq func (condition-case () + (indirect-function symbol) + (error symbol))) + (push symbol defs)))) + ;; Look at all the symbols--first DEFINITION, + ;; then its aliases. + (dolist (symbol (cons definition defs)) + (let* ((remapped (command-remapping symbol)) + (keys (where-is-internal + symbol overriding-local-map nil nil remapped)) + (keys (mapconcat 'key-description keys ", ")) + string) + (setq string + (if t + (if (> (length keys) 0) + (if remapped + (format "%s (%s) (remapped from %s)" + keys remapped symbol) + (format "%s" keys)) + (format "M-x %s RET" symbol)) + (if (> (length keys) 0) + (if remapped + (format "%s is remapped to %s which is on %s" + symbol remapped keys) + (format "%s is on %s" symbol keys)) + ;; If this is the command the user asked about, + ;; and it is not on any key, say so. + ;; For other symbols, its aliases, say nothing + ;; about them unless they are on keys. + (if (eq symbol definition) + (format "%s is not on any key" symbol))))) + (when string + (unless (eq symbol definition) + (setq return-string (concat return-string ";\n its alias "))) ; + (setq return-string (concat return-string string))))) + return-string))) +;;;; END CORE + +;;;; BEGIN DOCUMENTATION +(defconst screencast-screencast-text-producer + '( + "Hello, this is the screencast for creating your own + screencasts." n + "If you create a list (first argument) of strings, each + string will be typed to the message buffer (this buffer), at + a human-readable pace." n + "If you put a 'p in the list, a pause will be inserted. " p + p p p p "See?" p p + l + "(The above line was inserted instantly with the symbol 'l)" + n + "(Blank lines can be inserted using the 'n symbol, newlines + in strings are removed)" n n n + "All of the above is combined in the symbol 'b, which creates + a break in the screencast. This could be used between two + different sections for instance." b + "You can also put functions in the list, these will be + evaluated in the command-buffer (second argument)." n + "The function is written as a list, with the function name + first, and the arguments after that, e.g. '(backward-char + 2)." n n p + "Each time a function is evaluated, a message is displayed in + the message buffer, using the where-is function." n + "In addition to this a step-number is displayed, this + step-number corresponds to the functions position in the + list." n + "Let's try out some functions:" n + "((insert \"THIS IS AN INSERTION\n\") will be evaluated)" p + (insert "THIS IS AN INSERTION\n") + "You can call the special function `screencast-producer-insert-with-delay', aliased to `i' to insert with delay in the command-buffer."n + (i + "this is also an insertion, but it is done at typing speed") + "Hmm.." p p "let's delete the line we just typed in the + command buffer [[(kill-whole-line 1)]]" + (kill-whole-line 1) + "Notice the keybindings which are displayed." b + "The fourth (optional) argument given to the screencast + function is the step-number to start using pauses, and output + to the message buffer at, e.g. it is a fast-forward. Which is + _very_ nice when producing a screencast." n + "These step-numbers can also be printed separately in the + message-buffer using the 's symbol in the list." n s n + "See?" b + "Once you have finished a screencast and want it published, + you can record it as a video (.ogv) using + `screencast-record'."n + "As a part of the recording - the + font-size (`screencast-record-font') is changed, as well as + the fill-column variable (`screencast-record-fill-column') + for improved readability on a video."n + "As a consequence, you should _never_ use fill-paragraph and + the like, to get a nicely formatted source-file."n + "But the Emacs community will benefit the most if you publish + the screencast file itself - so please do!"n + "You can publish it at + http://www.emacswiki.org/emacs/ScreencastSources" b + "This screencast should cover the basic options for creating + a screencast, and can be seen in the constant + `screencast-screencast-text-producer'."n + "A screencast covering the more advanced functions of + screencast is available in the function + `screencast-screencast-producer-advanced'." b + "Happy screencasting!" ) + "The text the screencast-screencast-producer is based upon") + +(defconst screencast-screencast-text-user '( + "Hello, welcome to the screencast for viewing screencasts in + screencast mode."n + "Screencasts are like movies, they type some explanatory + text (like this), and executes functions in order to show you + the capabilities of different tools in Emacs."n + "Once a screencast has finished, you can move the cursor to + an executed function and press RET or MOUSE-1 to review the + screencast from that step."n + "Alternatively you can use the numeric prefix argument to + pinpoint the step to begin at."n + "If no prefix argument is given, and point isn't at an + executed function, the screencast is restarted from the first + step." )) + +(defconst screencast-screencast-text-producer-advanced + '( + "This screencast covers the advanced functions of screencast-mode."n + "Please read the documentation for the functions as well."n + "Regarding the functions and variables in this file:"n + "You, as a producer, are supposed to be using the functions starting with `screencast-producer-' (and `screencast' itself ofcourse), they are tailored for ease of use. The others are for internal use - and there's no guarantee they are stable throughout versions." + b + "It is possible to use multiple command-buffers:" + (screencast-producer-new-buffer + '((i "I'm a new command-buffer")) + "new-command-buffer") + (progn (kill-buffer "new-command-buffer")) + "It is done via the function `screencast-producer-new-buffer' which takes a list and a buffer - almost like the screencast function itself. " + b + "If you don't want to document everything you do, for instance moving the cursor, you can put the functions you want to \"hide\" inside a `progn'." + b + "If you need temporary variables or functions (for instance when you need to override a function which uses the mini-buffer), you can just put in a `let' or `flet'" + b + "If you need to modify the last-command-char (for self-insert-commands) or the last-command (for continued killing) there's also support for that:"n + "Use `screencast-producer-set-last-char' or `screencast-producer-set-last-command'" + "The text the screencast-screencast-producer-advanced is based upon")) + +(defun screencast-screencast-producer-advanced(&optional arg) + "Displays the screencast for creating advanced screencasts." + (interactive "P") + (apply (if arg + 'screencast-record + 'screencast) + screencast-screencast-text-producer-advanced "screencast-screencast-producer" 1.1 ())) + +(defun screencast-screencast-producer(&optional arg) + "Displays the screencast for creating screencasts." + (interactive "P") + (apply (if arg + 'screencast-record + 'screencast) + screencast-screencast-text-producer "screencast-screencast-producer" 1 ())) + +(defun screencast-screencast-user(&optional arg) + "Displays the screencast for using screencasts." + (interactive "P") + (apply (if arg + 'screencast-record + 'screencast) + screencast-screencast-text-user "screencast-screencast-user" 1 ())) +;;;; END DOCUMENTATION +(provide 'screencast) + diff --git a/emacs/sml-mode.el b/emacs/sml-mode.el new file mode 100644 index 0000000..ecff59d --- /dev/null +++ b/emacs/sml-mode.el @@ -0,0 +1,1901 @@ +;;; sml-mode.el --- Major mode for editing (Standard) ML -*- lexical-binding: t; coding: utf-8 -*- + +;; Copyright (C) 1989,1999,2000,2004,2007,2010-2012 Free Software Foundation, Inc. + +;; Maintainer: (Stefan Monnier) <monnier@iro.umontreal.ca> +;; Version: 6.1 +;; Keywords: SML +;; Author: Lars Bo Nielsen +;; Olin Shivers +;; Fritz Knabe (?) +;; Steven Gilmore (?) +;; Matthew Morley <mjm@scs.leeds.ac.uk> +;; Matthias Blume <blume@cs.princeton.edu> +;; (Stefan Monnier) <monnier@iro.umontreal.ca> + +;; 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 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; A major mode to edit Standard ML (SML) code. +;; Provides the following features, among others: +;; - Indentation. +;; - Syntax highlighting. +;; - Prettified display of ->, =>, fn, ... +;; - Imenu. +;; - which-function-mode. +;; - Skeletons/templates. +;; - Electric pipe key. +;; - outline-minor-mode (with some known problems). +;; - Interaction with a read-eval-print loop. + +;;;; Known bugs: + +;; - Indentation after "functor toto() where type foo = bar =" +;; Because the last is treated as an equality comparison. +;; - indentation of a declaration after a long `datatype' can be slow. + +;;;; News: + +;;;;; Changes since 5.0: + +;; - sml-electric-pipe-mode to make the | key electric. +;; - Removal of a lot of compatibility code. Requires Emacs-24. +;; - Integrate in GNU ELPA. + +;;;;; Changes since 4.1: + +;; - New indentation code using SMIE when available. +;; - `sml-back-to-outer-indent' is now on S-tab (aka `backtab') rather +;; than M-tab. +;; - Support for electric-layout-mode and electric-indent-mode. +;; - `sml-mark-defun' tries to be more clever. +;; - A single file (sml-mode.el) is needed unless you want to use an +;; interactive process like SML/NJ, or if your Emacs does not provide SMIE. + +;;;;; Changes since 4.0: + +;; - Switch to GPLv3+. +;; - When possible (i.e. running under Emacs>=23), be case-sensitive when +;; expanding abbreviations, and don't expand them in comments and strings. +;; - When you `next-error' to a type error, highlight the actual parts of the +;; types that differ. +;; - Flush the recorded errors not only upon sml-compile and friends, but also +;; when typing commands directly at the prompt. +;; - New command sml-mlton-typecheck. +;; - Simple support to parse errors and warnings in MLton's output. +;; - Simple support for MLton's def-use files. + +;;;;; Changes since 3.9.5: + +;; - No need to add the dir to your load-path any more. +;; The sml-mode-startup.el file does it for you. +;; - Symbols like -> can be displayed as real arrows. +;; See sml-font-lock-symbols. +;; - Fix some incompatibilities with the upcoming Emacs-21.4. +;; - Indentation rules improved. New customizable variable +;; `sml-rightalign-and'. Also `sml-symbol-indent' is now customizable. + +;;;;; Changes since 3.9.3: + +;; - New add-log support (try C-x 4 a from within an SML function). +;; - Imenu support +;; - sml-bindings has disappeared. +;; - The code skeletons are now abbrevs as well. +;; - A new *sml* process is sent the content of sml-config-file +;; (~/.sml-proc.sml) if it exists. +;; - `sml-compile' works yet a bit differently. The command can begin +;; with `cd "path";' and it will be replaced by OS.FileSys.chDir. +;; - run-sml now pops up the new buffer. It can also run the command on +;; another machine. And it always prompts for the command name. +;; Use a prefix argument if you want to give args or to specify a host on +;; which to run the command. +;; - mouse-2 to yank in *sml* should work again (but won't work for next-error +;; any more). +;; - New major-modes sml-cm-mode, sml-lex-mode and sml-yacc-mode. +;; - sml-load-hook has disappeared as has inferior-sml-load-hook. +;; - sml-mode-startup.el is now automatically generated and you're supposed to +;; `load' it from .emacs or site-start.el. +;; - Minor bug fixes. + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'smie nil 'noerror) +(require 'electric) + +(defgroup sml () + "Editing SML code." + :group 'languages) + +(defcustom sml-indent-level 4 + "Basic indentation step for SML code." + :type 'integer) + +(defcustom sml-indent-args sml-indent-level + "Indentation of args placed on a separate line." + :type 'integer) + +(defcustom sml-rightalign-and t + "If non-nil, right-align `and' with its leader. +If nil: If t: + datatype a = A datatype a = A + and b = B and b = B" + :type 'boolean) + +(defcustom sml-electric-pipe-mode t + "If non-nil, automatically insert appropriate template when hitting |." + :type 'boolean) + +(defvar sml-mode-hook nil + "Run upon entering `sml-mode'. +This is a good place to put your preferred key bindings.") + +;; font-lock setup + +(defvar sml-outline-regexp + ;; `st' and `si' are to match structure and signature. + "\\|s[ti]\\|[ \t]*\\(let[ \t]+\\)?\\(fun\\|and\\)\\_>" + "Regexp matching a major heading. +This actually can't work without extending `outline-minor-mode' with the +notion of \"the end of an outline\".") + +;; +;; Internal defines +;; + +(defvar sml-mode-map + (let ((map (make-sparse-keymap))) + ;; Text-formatting commands: + (define-key map "\C-c\C-m" 'sml-insert-form) + (define-key map "\M-|" 'sml-electric-pipe) + (define-key map "\M-\ " 'sml-electric-space) + (define-key map [backtab] 'sml-back-to-outer-indent) + map) + "The keymap used in `sml-mode'.") + +(defvar sml-mode-syntax-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\* ". 23n" st) + (modify-syntax-entry ?\( "()1" st) + (modify-syntax-entry ?\) ")(4" st) + (mapc (lambda (c) (modify-syntax-entry c "_" st)) "._'") + (mapc (lambda (c) (modify-syntax-entry c "." st)) ",;") + ;; `!' is not really a prefix-char, oh well! + (mapc (lambda (c) (modify-syntax-entry c "'" st)) "~#!") + (mapc (lambda (c) (modify-syntax-entry c "." st)) "%&$+-/:<=>?@`^|") + st) + "The syntax table used in `sml-mode'.") + + +(easy-menu-define sml-mode-menu sml-mode-map "Menu used in `sml-mode'." + '("SML" + ("Process" + ["Start SML repl" sml-run t] + ["-" nil nil] + ["Compile the project" sml-prog-proc-compile t] + ["Send file" sml-prog-proc-load-file t] + ["Switch to SML repl" sml-prog-proc-switch-to t] + ["--" nil nil] + ["Send buffer" sml-prog-proc-send-buffer t] + ["Send region" sml-prog-proc-send-region t] + ["Send function" sml-send-function t] + ["Goto next error" next-error t]) + ["Insert SML form" sml-insert-form t] + ("Forms" :filter sml-forms-menu) + ["Indent region" indent-region t] + ["Outdent line" sml-back-to-outer-indent t] + ["-----" nil nil] + ["Customize SML-mode" (customize-group 'sml) t] + ["SML mode help" describe-mode t])) + +;; +;; Regexps +;; + +(defun sml-syms-re (syms) + (concat "\\_<" (regexp-opt syms t) "\\_>")) + +;; + +(defconst sml-module-head-syms + '("signature" "structure" "functor" "abstraction")) + + +(defconst sml-=-starter-syms + (list* "|" "val" "fun" "and" "datatype" "type" "abstype" "eqtype" + sml-module-head-syms) + "Symbols that can be followed by a `='.") +(defconst sml-=-starter-re + (concat "\\S.|\\S.\\|" (sml-syms-re (cdr sml-=-starter-syms))) + "Symbols that can be followed by a `='.") + +(defconst sml-non-nested-of-starter-re + (sml-syms-re '("datatype" "abstype" "exception")) + "Symbols that can introduce an `of' that shouldn't behave like a paren.") + +(defconst sml-starters-syms + (append sml-module-head-syms + '("abstype" "datatype" "exception" "fun" + "local" "infix" "infixr" "sharing" "nonfix" + "open" "type" "val" "and" + "withtype" "with")) + "The starters of new expressions.") + +(defconst sml-pipeheads + '("|" "of" "fun" "fn" "and" "handle" "datatype" "abstype" + "(" "{" "[") + "A `|' corresponds to one of these.") + +(defconst sml-keywords-regexp + (sml-syms-re '("abstraction" "abstype" "and" "andalso" "as" "before" "case" + "datatype" "else" "end" "eqtype" "exception" "do" "fn" + "fun" "functor" "handle" "if" "in" "include" "infix" + "infixr" "let" "local" "nonfix" "o" "of" "op" "open" "orelse" + "overload" "raise" "rec" "sharing" "sig" "signature" + "struct" "structure" "then" "type" "val" "where" "while" + "with" "withtype")) + "A regexp that matches any and all keywords of SML.") + +(eval-and-compile + (defconst sml-id-re "\\sw\\(?:\\sw\\|\\s_\\)*")) + +(defconst sml-tyvarseq-re + (concat "\\(?:\\(?:'+" sml-id-re "\\|(\\(?:[,']\\|" sml-id-re + "\\|\\s-\\)+)\\)\\s-+\\)?")) + +;;; Font-lock settings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defcustom sml-font-lock-symbols nil + "Display \\ and -> and such using symbols in fonts. +This may sound like a neat trick, but be extra careful: it changes the +alignment and can thus lead to nasty surprises w.r.t layout." + :type 'boolean) + +(defconst sml-font-lock-symbols-alist + '(("fn" . ?λ) + ("andalso" . ?â§) ;; ?â + ("orelse" . ?â¨) ;; ?â + ;; ("as" . ?â¡) + ("not" . ?¬) + ("div" . ?÷) + ("*" . ?Ã) + ("o" . ?â) + ("->" . ?â) + ("=>" . ?â) + ("<-" . ?â) + ("<>" . ?â ) + (">=" . ?â¥) + ("<=" . ?â¤) + ("..." . ?â¯) + ;; ("::" . ?â·) + ;; Some greek letters for type parameters. + ("'a" . ?α) + ("'b" . ?β) + ("'c" . ?γ) + ("'d" . ?δ) + )) + +(defun sml-font-lock-compose-symbol () + "Compose a sequence of ascii chars into a symbol. +Regexp match data 0 points to the chars." + ;; Check that the chars should really be composed into a symbol. + (let* ((start (match-beginning 0)) + (end (match-end 0)) + (syntaxes (if (eq (char-syntax (char-after start)) ?w) + '(?w) '(?. ?\\)))) + (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes) + (memq (char-syntax (or (char-after end) ?\ )) syntaxes) + (memq (get-text-property start 'face) + '(font-lock-doc-face font-lock-string-face + font-lock-comment-face))) + ;; No composition for you. Let's actually remove any composition + ;; we may have added earlier and which is now incorrect. + (remove-text-properties start end '(composition)) + ;; That's a symbol alright, so add the composition. + (compose-region start end (cdr (assoc (match-string 0) + sml-font-lock-symbols-alist))))) + ;; Return nil because we're not adding any face property. + nil) + +(defun sml-font-lock-symbols-keywords () + (when sml-font-lock-symbols + `((,(regexp-opt (mapcar 'car sml-font-lock-symbols-alist) t) + (0 (sml-font-lock-compose-symbol)))))) + +;; The font lock regular expressions. + +(defconst sml-font-lock-keywords + `(;;(sml-font-comments-and-strings) + (,(concat "\\_<\\(fun\\|and\\)\\s-+" sml-tyvarseq-re + "\\(" sml-id-re "\\)\\s-+[^ \t\n=]") + (1 font-lock-keyword-face) + (2 font-lock-function-name-face)) + (,(concat "\\_<\\(\\(?:data\\|abs\\|with\\|eq\\)?type\\)\\s-+" + sml-tyvarseq-re "\\(" sml-id-re "\\)") + (1 font-lock-keyword-face) + (2 font-lock-type-def-face)) + (,(concat "\\_<\\(val\\)\\s-+\\(?:" sml-id-re "\\_>\\s-*\\)?\\(" + sml-id-re "\\)\\s-*[=:]") + (1 font-lock-keyword-face) + (2 font-lock-variable-name-face)) + (,(concat "\\_<\\(structure\\|functor\\|abstraction\\)\\s-+\\(" + sml-id-re "\\)") + (1 font-lock-keyword-face) + (2 font-lock-module-def-face)) + (,(concat "\\_<\\(signature\\)\\s-+\\(" sml-id-re "\\)") + (1 font-lock-keyword-face) + (2 font-lock-interface-def-face)) + + (,sml-keywords-regexp . font-lock-keyword-face) + ,@(sml-font-lock-symbols-keywords)) + "Regexps matching standard SML keywords.") + +(defface font-lock-type-def-face + '((t (:bold t))) + "Font Lock mode face used to highlight type definitions." + :group 'font-lock-highlighting-faces) +(defvar font-lock-type-def-face 'font-lock-type-def-face + "Face name to use for type definitions.") + +(defface font-lock-module-def-face + '((t (:bold t))) + "Font Lock mode face used to highlight module definitions." + :group 'font-lock-highlighting-faces) +(defvar font-lock-module-def-face 'font-lock-module-def-face + "Face name to use for module definitions.") + +(defface font-lock-interface-def-face + '((t (:bold t))) + "Font Lock mode face used to highlight interface definitions." + :group 'font-lock-highlighting-faces) +(defvar font-lock-interface-def-face 'font-lock-interface-def-face + "Face name to use for interface definitions.") + +;; +;; Code to handle nested comments and unusual string escape sequences +;; + +(defvar sml-syntax-prop-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\\ "." st) + (modify-syntax-entry ?* "." st) + st) + "Syntax table for text-properties.") + +(defconst sml-font-lock-syntactic-keywords + `(("^\\s-*\\(\\\\\\)" (1 ',sml-syntax-prop-table)))) + +(defconst sml-font-lock-defaults + '(sml-font-lock-keywords nil nil nil nil + (font-lock-syntactic-keywords . sml-font-lock-syntactic-keywords))) + + +;;; Indentation with SMIE + +(defconst sml-smie-grammar + ;; We have several problem areas where SML's syntax can't be handled by an + ;; operator precedence grammar: + ;; + ;; "= A before B" is "= A) before B" if this is the + ;; `boolean-=' but it is "= (A before B)" if it's the `definitional-='. + ;; We can work around the problem by tweaking the lexer to return two + ;; different tokens for the two different kinds of `='. + ;; "of A | B" in a "case" we want "of (A | B, but in a `datatype' + ;; we want "of A) | B". + ;; "= A | B" can be "= A ) | B" if the = is from a "fun" definition, + ;; but it is "= (A | B" if it is a `datatype' definition (of course, if + ;; the previous token introducing the = is `and', deciding whether + ;; it's a datatype or a function requires looking even further back). + ;; "functor foo (...) where type a = b = ..." the first `=' looks very much + ;; like a `definitional-=' even tho it's just an equality constraint. + ;; Currently I don't even try to handle `where' at all. + (smie-prec2->grammar + (smie-merge-prec2s + (smie-bnf->prec2 + '((exp ("if" exp "then" exp "else" exp) + ("case" exp "of" branches) + ("let" decls "in" cmds "end") + ("struct" decls "end") + ("sig" decls "end") + (sexp) + (sexp "handle" branches) + ("fn" sexp "=>" exp)) + ;; "simple exp"s are the ones that can appear to the left of `handle'. + (sexp (sexp ":" type) ("(" exps ")") + (sexp "orelse" sexp) + (marg ":>" type) + (sexp "andalso" sexp)) + (cmds (cmds ";" cmds) (exp)) + (exps (exps "," exps) (exp)) ; (exps ";" exps) + (branches (sexp "=>" exp) (branches "|" branches)) + ;; Operator precedence grammars handle separators much better then + ;; starters/terminators, so let's pretend that let/fun are separators. + (decls (sexp "d=" exp) + (sexp "d=" databranches) + (funbranches "|" funbranches) + (sexp "=of" type) ;After "exception". + ;; FIXME: Just like PROCEDURE in Pascal and Modula-2, this + ;; interacts poorly with the other constructs since I + ;; can't make "local" a separator like fun/val/type/... + ("local" decls "in" decls "end") + ;; (decls "local" decls "in" decls "end") + (decls "functor" decls) + (decls "signature" decls) + (decls "structure" decls) + (decls "type" decls) + (decls "open" decls) + (decls "and" decls) + (decls "infix" decls) + (decls "infixr" decls) + (decls "nonfix" decls) + (decls "abstype" decls) + (decls "datatype" decls) + (decls "exception" decls) + (decls "fun" decls) + (decls "val" decls)) + (type (type "->" type) + (type "*" type)) + (funbranches (sexp "d=" exp)) + (databranches (sexp "=of" type) (databranches "d|" databranches)) + ;; Module language. + ;; (mexp ("functor" marg "d=" mexp) + ;; ("structure" marg "d=" mexp) + ;; ("signature" marg "d=" mexp)) + (marg (marg ":" type) (marg ":>" type)) + (toplevel (decls) (exp) (toplevel ";" toplevel))) + ;; '(("local" . opener)) + ;; '((nonassoc "else") (right "handle")) + '((nonassoc "of") (assoc "|")) ; "case a of b => case c of d => e | f" + '((nonassoc "handle") (assoc "|")) ; Idem for "handle". + '((assoc "->") (assoc "*")) + '((assoc "val" "fun" "type" "datatype" "abstype" "open" "infix" "infixr" + "nonfix" "functor" "signature" "structure" "exception" + ;; "local" + ) + (assoc "and")) + '((assoc "orelse") (assoc "andalso") (nonassoc ":")) + '((assoc ";")) '((assoc ",")) '((assoc "d|"))) + + (smie-precs->prec2 + '((nonassoc "andalso") ;To anchor the prec-table. + (assoc "before") ;0 + (assoc ":=" "o") ;3 + (nonassoc ">" ">=" "<>" "<" "<=" "=") ;4 + (assoc "::" "@") ;5 + (assoc "+" "-" "^") ;6 + (assoc "/" "*" "quot" "rem" "div" "mod") ;7 + (nonassoc " -dummy- "))) ;Bogus anchor at the end. + ))) + +(defvar sml-indent-separator-outdent 2) + +(defun sml-smie-rules (kind token) + ;; I much preferred the pcase version of the code, especially while + ;; edebugging the code. But that will have to wait until we get rid of + ;; support for Emacs-23. + (case kind + (:elem (case token + (basic sml-indent-level) + (args sml-indent-args))) + (:list-intro (member token '("fn"))) + (:after + (cond + ((equal token "struct") 0) + ((equal token "=>") (if (smie-rule-hanging-p) 0 2)) + ((equal token "in") (if (smie-rule-parent-p "local") 0)) + ((equal token "of") 3) + ((member token '("(" "{" "[")) (if (not (smie-rule-hanging-p)) 2)) + ((equal token "else") (if (smie-rule-hanging-p) 0)) ;; (:next "if" 0) + ((member token '("|" "d|" ";" ",")) (smie-rule-separator kind)) + ((equal token "d=") + (if (and (smie-rule-parent-p "val") (smie-rule-next-p "fn")) -3)))) + (:before + (cond + ((equal token "=>") (if (smie-rule-parent-p "fn") 3)) + ((equal token "of") 1) + ;; In case the language is extended to allow a | directly after of. + ((and (equal token "|") (smie-rule-prev-p "of")) 1) + ((member token '("|" "d|" ";" ",")) (smie-rule-separator kind)) + ;; Treat purely syntactic block-constructs as being part of their parent, + ;; when the opening statement is hanging. + ((member token '("let" "(" "[" "{")) + (if (smie-rule-hanging-p) (smie-rule-parent))) + ;; Treat if ... else if ... as a single long syntactic construct. + ;; Similarly, treat fn a => fn b => ... as a single construct. + ((member token '("if" "fn")) + (and (not (smie-rule-bolp)) + (smie-rule-prev-p (if (equal token "if") "else" "=>")) + (smie-rule-parent))) + ((equal token "and") + ;; FIXME: maybe "and" (c|sh)ould be handled as an smie-separator. + (cond + ((smie-rule-parent-p "datatype") (if sml-rightalign-and 5 0)) + ((smie-rule-parent-p "fun" "val") 0))) + ((equal token "d=") + (cond + ((smie-rule-parent-p "datatype") (if (smie-rule-bolp) 2)) + ((smie-rule-parent-p "structure" "signature") 0))) + ;; Indent an expression starting with "local" as if it were starting + ;; with "fun". + ((equal token "local") (smie-indent-keyword "fun")) + ;; FIXME: type/val/fun/... are separators but "local" is not, even though + ;; it appears in the same list. Try to fix up the problem by hand. + ;; ((or (equal token "local") + ;; (equal (cdr (assoc token smie-grammar)) + ;; (cdr (assoc "fun" smie-grammar)))) + ;; (let ((parent (save-excursion (smie-backward-sexp)))) + ;; (when (or (and (equal (nth 2 parent) "local") + ;; (null (car parent))) + ;; (progn + ;; (setq parent (save-excursion (smie-backward-sexp "fun"))) + ;; (eq (car parent) (nth 1 (assoc "fun" smie-grammar))))) + ;; (goto-char (nth 1 parent)) + ;; (cons 'column (smie-indent-virtual))))) + )))) + +(defun sml-smie-definitional-equal-p () + "Figure out which kind of \"=\" this is. +Assumes point is right before the = sign." + ;; The idea is to look backward for the first occurrence of a token that + ;; requires a definitional "=" and then see if there's such a definitional + ;; equal between that token and ourselves (in which case we're not + ;; a definitional = ourselves). + ;; The "search for =" is naive and will match "=>" and "<=", but it turns + ;; out to be OK in practice because such tokens very rarely (if ever) appear + ;; between the =-starter and the corresponding definitional equal. + ;; One known problem case is code like: + ;; "functor foo (structure s : S) where type t = s.t =" + ;; where the "type t = s.t" is mistaken for a type definition. + (let ((re (concat "\\(" sml-=-starter-re "\\)\\|="))) + (save-excursion + (and (re-search-backward re nil t) + (or (match-beginning 1) + ;; If we first hit a "=", then that = is probably definitional + ;; and we're an equality, but not necessarily. One known + ;; problem case is code like: + ;; "functor foo (structure s : S) where type t = s.t =" + ;; where the first = is more like an equality (tho it doesn't + ;; matter much) and the second is definitional. + ;; + ;; FIXME: The test below could be used to recognize that the + ;; second = is not a mere equality, but that's not enough to + ;; parse the construct properly: we'd need something + ;; like a third kind of = token for structure definitions, in + ;; order for the parser to be able to skip the "type t = s.t" + ;; as a sub-expression. + ;; + ;; (and (not (looking-at "=>")) + ;; (not (eq ?< (char-before))) ;Not a <= + ;; (re-search-backward re nil t) + ;; (match-beginning 1) + ;; (equal "type" (buffer-substring (- (match-end 1) 4) + ;; (match-end 1)))) + ))))) + +(defun sml-smie-non-nested-of-p () + ;; FIXME: Maybe datatype-|-p makes this nested-of business unnecessary. + "Figure out which kind of \"of\" this is. +Assumes point is right before the \"of\" symbol." + (save-excursion + (and (re-search-backward (concat "\\(" sml-non-nested-of-starter-re + "\\)\\|\\_<case\\_>") nil t) + (match-beginning 1)))) + +(defun sml-smie-datatype-|-p () + "Figure out which kind of \"|\" this is. +Assumes point is right before the | symbol." + (save-excursion + (forward-char 1) ;Skip the |. + (let ((after-type-def + '("|" "of" "in" "datatype" "and" "exception" "abstype" "infix" + "infixr" "nonfix" "local" "val" "fun" "structure" "functor" + "signature"))) + (or (member (sml-smie-forward-token-1) after-type-def) ;Skip the tag. + (member (sml-smie-forward-token-1) after-type-def))))) + +(defun sml-smie-forward-token-1 () + (forward-comment (point-max)) + (buffer-substring-no-properties + (point) + (progn + (or (/= 0 (skip-syntax-forward "'w_")) + (skip-syntax-forward ".'")) + (point)))) + +(defun sml-smie-forward-token () + (let ((sym (sml-smie-forward-token-1))) + (cond + ((equal "op" sym) + (concat "op " (sml-smie-forward-token-1))) + ((member sym '("|" "of" "=")) + ;; The important lexer for indentation's performance is the backward + ;; lexer, so for the forward lexer we delegate to the backward one. + (save-excursion (sml-smie-backward-token))) + (t sym)))) + +(defun sml-smie-backward-token-1 () + (forward-comment (- (point))) + (buffer-substring-no-properties + (point) + (progn + (or (/= 0 (skip-syntax-backward ".'")) + (skip-syntax-backward "'w_")) + (point)))) + +(defun sml-smie-backward-token () + (let ((sym (sml-smie-backward-token-1))) + (unless (zerop (length sym)) + ;; FIXME: what should we do if `sym' = "op" ? + (let ((point (point))) + (if (equal "op" (sml-smie-backward-token-1)) + (concat "op " sym) + (goto-char point) + (cond + ((string= sym "=") (if (sml-smie-definitional-equal-p) "d=" "=")) + ((string= sym "of") (if (sml-smie-non-nested-of-p) "=of" "of")) + ((string= sym "|") (if (sml-smie-datatype-|-p) "d|" "|")) + (t sym))))))) + +;;;; +;;;; Imenu support +;;;; + +(defvar sml-imenu-regexp + (concat "^[ \t]*\\(let[ \t]+\\)?" + (regexp-opt (append sml-module-head-syms + '("and" "fun" "datatype" "abstype" "type")) t) + "\\_>")) + +(defun sml-imenu-create-index () + (let (alist) + (goto-char (point-max)) + (while (re-search-backward sml-imenu-regexp nil t) + (save-excursion + (let ((kind (match-string 2)) + (column (progn (goto-char (match-beginning 2)) (current-column))) + (location + (progn (goto-char (match-end 0)) + (forward-comment (point-max)) + (when (looking-at sml-tyvarseq-re) + (goto-char (match-end 0))) + (point))) + (name (sml-smie-forward-token))) + ;; Eliminate trivial renamings. + (when (or (not (member kind '("structure" "signature"))) + (progn (search-forward "=") + (forward-comment (point-max)) + (looking-at "sig\\|struct"))) + (push (cons (concat (make-string (/ column 2) ?\ ) name) location) + alist))))) + alist)) + +;;; Generic prog-proc interaction. + +(require 'comint) +(require 'compile) + +(defvar sml-prog-proc-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [?\C-c ?\C-l] 'sml-prog-proc-load-file) + (define-key map [?\C-c ?\C-c] 'sml-prog-proc-compile) + (define-key map [?\C-c ?\C-z] 'sml-prog-proc-switch-to) + (define-key map [?\C-c ?\C-r] 'sml-prog-proc-send-region) + (define-key map [?\C-c ?\C-b] 'sml-prog-proc-send-buffer) + ;; FIXME: Add + ;; (define-key map [?\M-C-x] 'sml-prog-proc-send-defun) + ;; (define-key map [?\C-x ?\C-e] 'sml-prog-proc-send-last-sexp) + ;; FIXME: Add menu. Now, that's trickier because keymap inheritance + ;; doesn't play nicely with menus! + map) + "Keymap for `sml-prog-proc-mode'.") + +(defvar sml-prog-proc--buffer nil + "The inferior-process buffer to which to send code.") +(make-variable-buffer-local 'sml-prog-proc--buffer) + +(defstruct (sml-prog-proc-descriptor + (:constructor sml-prog-proc-make) + (:predicate nil) + (:copier nil)) + (name nil :read-only t) + (run nil :read-only t) + (load-cmd nil :read-only t) + (chdir-cmd nil :read-only t) + (command-eol "\n" :read-only t) + (compile-commands-alist nil :read-only t)) + +(defvar sml-prog-proc-descriptor nil + "Struct containing the various functions to create a new process, ...") + +(defmacro sml-prog-proc--prop (prop) + `(,(intern (format "sml-prog-proc-descriptor-%s" prop)) + (or sml-prog-proc-descriptor + ;; FIXME: Look for available ones and pick one. + (error "Not a `sml-prog-proc' buffer")))) +(defmacro sml-prog-proc--call (method &rest args) + `(funcall (sml-prog-proc--prop ,method) ,@args)) + +;; The inferior process and his buffer are basically interchangeable. +;; Currently the code takes sml-prog-proc--buffer as the main reference, +;; but all users should either use sml-prog-proc-proc or sml-prog-proc-buffer +;; to find the info. + +(defun sml-prog-proc-proc () + "Return the inferior process for the code in current buffer." + (or (and (buffer-live-p sml-prog-proc--buffer) + (get-buffer-process sml-prog-proc--buffer)) + (when (derived-mode-p 'sml-prog-proc-mode 'sml-prog-proc-comint-mode) + (setq sml-prog-proc--buffer (current-buffer)) + (get-buffer-process sml-prog-proc--buffer)) + (let ((ppd sml-prog-proc-descriptor) + (buf (sml-prog-proc--call run))) + (with-current-buffer buf + (if (and ppd (null sml-prog-proc-descriptor)) + (set (make-local-variable 'sml-prog-proc-descriptor) ppd))) + (setq sml-prog-proc--buffer buf) + (get-buffer-process sml-prog-proc--buffer)))) + +(defun sml-prog-proc-buffer () + "Return the buffer of the inferior process." + (process-buffer (sml-prog-proc-proc))) + +(defun sml-prog-proc-switch-to () + "Switch to the buffer running the read-eval-print process." + (pop-to-buffer (sml-prog-proc-buffer))) + +(defun sml-prog-proc-send-string (proc str) + "Send command STR to PROC, with an EOL terminator appended." + (with-current-buffer (process-buffer proc) + ;; FIXME: comint-send-string does not pass the string through + ;; comint-input-filter-function, so we have to do it by hand. + ;; Maybe we should insert the command into the buffer and then call + ;; comint-send-input? + (sml-prog-proc-comint-input-filter-function nil) + (comint-send-string proc (concat str (sml-prog-proc--prop command-eol))))) + +(defun sml-prog-proc-load-file (file &optional and-go) + "Load FILE into the read-eval-print process. +FILE is the file visited by the current buffer. +If prefix argument AND-GO is used, then we additionally switch +to the buffer where the process is running." + (interactive + (list (or buffer-file-name + (read-file-name "File to load: " nil nil t)) + current-prefix-arg)) + (comint-check-source file) + (let ((proc (sml-prog-proc-proc))) + (sml-prog-proc-send-string proc (sml-prog-proc--call load-cmd file)) + (when and-go (pop-to-buffer (process-buffer proc))))) + +(defvar sml-prog-proc--tmp-file nil) + +(defun sml-prog-proc-send-region (start end &optional and-go) + "Send the content of the region to the read-eval-print process. +START..END delimit the region; AND-GO if non-nil indicate to additionally +switch to the process's buffer." + (interactive "r\nP") + (if (> start end) (let ((tmp end)) (setq end start) (setq start tmp)) + (if (= start end) (error "Nothing to send: the region is empty"))) + (let ((proc (sml-prog-proc-proc)) + (tmp (make-temp-file "emacs-region"))) + (write-region start end tmp nil 'silently) + (when sml-prog-proc--tmp-file + (ignore-errors (delete-file (car sml-prog-proc--tmp-file))) + (set-marker (cdr sml-prog-proc--tmp-file) nil)) + (setq sml-prog-proc--tmp-file (cons tmp (copy-marker start))) + (sml-prog-proc-send-string proc (sml-prog-proc--call load-cmd tmp)) + (when and-go (pop-to-buffer (process-buffer proc))))) + +(defun sml-prog-proc-send-buffer (&optional and-go) + "Send the content of the current buffer to the read-eval-print process. +AND-GO if non-nil indicate to additionally switch to the process's buffer." + (interactive "P") + (sml-prog-proc-send-region (point-min) (point-max) and-go)) + +(define-derived-mode sml-prog-proc-mode prog-mode "Sml-Prog-Proc" + "Major mode for editing source code and interact with an interactive loop." + ) + +;;; Extended comint-mode for Sml-Prog-Proc. + +(defun sml-prog-proc-chdir (dir) + "Change the working directory of the inferior process to DIR." + (interactive "DChange to directory: ") + (let ((dir (expand-file-name dir)) + (proc (sml-prog-proc-proc))) + (with-current-buffer (process-buffer proc) + (sml-prog-proc-send-string proc (sml-prog-proc--call chdir-cmd dir)) + (setq default-directory (file-name-as-directory dir))))) + +(defun sml-prog-proc-comint-input-filter-function (str) + ;; `compile.el' doesn't know that file location info from errors should be + ;; recomputed afresh (without using stale info from earlier compilations). + (compilation-forget-errors) ;Has to run before compilation-fake-loc. + (if (and sml-prog-proc--tmp-file (marker-buffer (cdr sml-prog-proc--tmp-file))) + (compilation-fake-loc (cdr sml-prog-proc--tmp-file) + (car sml-prog-proc--tmp-file))) + str) + +(defvar sml-prog-proc-comint-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-l" 'sml-prog-proc-load-file) + map)) + +(define-derived-mode sml-prog-proc-comint-mode comint-mode "Sml-Prog-Proc-Comint" + "Major mode for an inferior process used to run&compile source code." + ;; Enable compilation-minor-mode, but only after the child mode is setup + ;; since the child-mode might want to add rules to + ;; compilation-error-regexp-alist. + (add-hook 'after-change-major-mode-hook #'compilation-minor-mode nil t) + ;; The keymap of compilation-minor-mode is too unbearable, so we + ;; need to hide most of the bindings. + (let ((map (make-sparse-keymap))) + (dolist (keys '([menu-bar] [follow-link])) + ;; Preserve some of the bindings. + (define-key map keys (lookup-key compilation-minor-mode-map keys))) + (add-to-list 'minor-mode-overriding-map-alist + (cons 'compilation-minor-mode map))) + + (add-hook 'comint-input-filter-functions + #'sml-prog-proc-comint-input-filter-function nil t)) + +(defvar sml-prog-proc--compile-command nil + "The command used by default by `sml-prog-proc-compile'.") + +(defun sml-prog-proc-compile (command &optional and-go) + "Pass COMMAND to the read-eval-loop process to compile the current file. + +You can then use the command \\[next-error] to find the next error message +and move to the source code that caused it. + +Interactively, prompts for the command if `compilation-read-command' is +non-nil. With prefix arg, always prompts. + +Prefix arg AND-GO also means to switch to the read-eval-loop buffer afterwards." + (interactive + (let* ((dir default-directory) + (cmd "cd \".")) + ;; Look for files to determine the default command. + (while (and (stringp dir) + (progn + (dolist (cf (sml-prog-proc--prop compile-commands-alist)) + (when (file-exists-p (expand-file-name (cdr cf) dir)) + (setq cmd (concat cmd "\"; " (car cf))) + (return nil))) + (not cmd))) + (let ((newdir (file-name-directory (directory-file-name dir)))) + (setq dir (unless (equal newdir dir) newdir)) + (setq cmd (concat cmd "/..")))) + (setq cmd + (cond + ((local-variable-p 'sml-prog-proc--compile-command) + sml-prog-proc--compile-command) + ((string-match "^\\s-*cd\\s-+\"\\.\"\\s-*;\\s-*" cmd) + (substring cmd (match-end 0))) + ((string-match "^\\s-*cd\\s-+\"\\(\\./\\)" cmd) + (replace-match "" t t cmd 1)) + ((string-match ";" cmd) cmd) + (t sml-prog-proc--compile-command))) + ;; code taken from compile.el + (list (if (or compilation-read-command current-prefix-arg) + (read-from-minibuffer "Compile command: " + cmd nil nil '(compile-history . 1)) + cmd)))) + ;; ;; now look for command's file to determine the directory + ;; (setq dir default-directory) + ;; (while (and (stringp dir) + ;; (dolist (cf (sml-prog-proc--prop compile-commands-alist) t) + ;; (when (and (equal cmd (car cf)) + ;; (file-exists-p (expand-file-name (cdr cf) dir))) + ;; (return nil)))) + ;; (let ((newdir (file-name-directory (directory-file-name dir)))) + ;; (setq dir (unless (equal newdir dir) newdir)))) + ;; (setq dir (or dir default-directory)) + ;; (list cmd dir))) + (set (make-local-variable 'sml-prog-proc--compile-command) command) + (save-some-buffers (not compilation-ask-about-save) nil) + (let ((dir default-directory)) + (when (string-match "^\\s-*cd\\s-+\"\\([^\"]+\\)\"\\s-*;" command) + (setq dir (match-string 1 command)) + (setq command (replace-match "" t t command))) + (setq dir (expand-file-name dir)) + (let ((proc (sml-prog-proc-proc)) + (eol (sml-prog-proc--prop command-eol))) + (with-current-buffer (process-buffer proc) + (setq default-directory dir) + (sml-prog-proc-send-string + proc (concat (sml-prog-proc--call chdir-cmd dir) + ;; Strip the newline, to avoid adding a prompt. + (if (string-match "\n\\'" eol) + (replace-match " " t t eol) eol) + command)) + (when and-go (pop-to-buffer (process-buffer proc))))))) + + +;;; SML Sml-Prog-Proc support. + +(defcustom sml-program-name "sml" + "Program to run as Standard SML read-eval-print loop." + :type 'string) + +(defcustom sml-default-arg "" + "Default command line option to pass to `sml-program-name', if any." + :type 'string) + +(defcustom sml-host-name "" + "Host on which to run `sml-program-name'." + :type 'string) + +(defcustom sml-config-file "~/.smlproc.sml" + "File that should be fed to the SML process when started." + :type 'string) + + +(defcustom sml-prompt-regexp "^[-=>#] *" + "Regexp used to recognise prompts in the inferior SML process." + :type 'regexp) + +(defcustom sml-compile-commands-alist + '(("CMB.make()" . "all-files.cm") + ("CMB.make()" . "pathconfig") + ("CM.make()" . "sources.cm") + ("use \"load-all\"" . "load-all")) + "Commands used by default by `sml-sml-prog-proc-compile'. +Each command is associated with its \"main\" file. +It is perfectly OK to associate several files with a command or several +commands with the same file.") + +;; FIXME: Try to auto-detect the process and set those vars accordingly. + +(defvar sml-use-command "use \"%s\"" + "Template for loading a file into the inferior SML process. +Set to \"use \\\"%s\\\"\" for SML/NJ or Edinburgh ML; +set to \"PolyML.use \\\"%s\\\"\" for Poly/ML, etc.") + +(defvar sml-cd-command "OS.FileSys.chDir \"%s\"" + "Command template for changing working directories under SML. +Set this to nil if your compiler can't change directories. + +The format specifier \"%s\" will be converted into the directory name +specified when running the command \\[sml-cd].") + +(defvar sml-error-regexp-alist + `( ;; Poly/ML messages + ("^\\(Error\\|Warning:\\) in '\\(.+\\)', line \\([0-9]+\\)" 2 3) + ;; Moscow ML + ("^File \"\\([^\"]+\\)\", line \\([0-9]+\\)\\(-\\([0-9]+\\)\\)?, characters \\([0-9]+\\)-\\([0-9]+\\):" 1 2 5) + ;; SML/NJ: the file-pattern is anchored to avoid + ;; pathological behavior with very long lines. + ("^[-= ]*\\(.*[^\n)]\\)\\( (.*)\\)?:\\([0-9]+\\)\\.\\([0-9]+\\)\\(-\\([0-9]+\\)\\.\\([0-9]+\\)\\)? \\(Error\\|Warnin\\(g\\)\\): .*" 1 + (3 . 6) (4 . 7) (9)) + ;; SML/NJ's exceptions: see above. + ("^ +\\(raised at: \\)?\\(.+\\):\\([0-9]+\\)\\.\\([0-9]+\\)\\(-\\([0-9]+\\)\\.\\([0-9]+\\)\\)" 2 + (3 . 6) (4 . 7))) + "Alist that specifies how to match errors in compiler output. +See `compilation-error-regexp-alist' for a description of the format.") + +(defconst sml-pp-functions + (sml-prog-proc-make :name "SML" + :run (lambda () (call-interactively #'sml-run)) + :load-cmd (lambda (file) (format sml-use-command file)) + :chdir-cmd (lambda (dir) (format sml-cd-command dir)) + :compile-commands-alist sml-compile-commands-alist + :command-eol ";\n" + )) + +;; font-lock support +(defconst inferior-sml-font-lock-keywords + `(;; prompt and following interactive command + ;; FIXME: Actually, this should already be taken care of by comint. + (,(concat "\\(" sml-prompt-regexp "\\)\\(.*\\)") + (1 font-lock-prompt-face) + (2 font-lock-command-face keep)) + ;; CM's messages + ("^\\[\\(.*GC #.*\n\\)*.*\\]" . font-lock-comment-face) + ;; SML/NJ's irritating GC messages + ("^GC #.*" . font-lock-comment-face)) + "Font-locking specification for inferior SML mode.") + +(defface font-lock-prompt-face + '((t (:bold t))) + "Font Lock mode face used to highlight prompts." + :group 'font-lock-highlighting-faces) +(defvar font-lock-prompt-face 'font-lock-prompt-face + "Face name to use for prompts.") + +(defface font-lock-command-face + '((t (:bold t))) + "Font Lock mode face used to highlight interactive commands." + :group 'font-lock-highlighting-faces) +(defvar font-lock-command-face 'font-lock-command-face + "Face name to use for interactive commands.") + +(defconst inferior-sml-font-lock-defaults + '(inferior-sml-font-lock-keywords nil nil nil nil)) + +(defun sml--read-run-cmd () + (list + (read-string "SML command: " sml-program-name) + (if (or current-prefix-arg (> (length sml-default-arg) 0)) + (read-string "Any args: " sml-default-arg) + sml-default-arg) + (if (or current-prefix-arg (> (length sml-host-name) 0)) + (read-string "On host: " sml-host-name) + sml-host-name))) + +;;;###autoload +(defalias 'run-sml 'sml-run) + +;;;###autoload +(defun sml-run (cmd arg &optional host) + "Run the program CMD with given arguments ARG. +The command is run in buffer *CMD* using mode `inferior-sml-mode'. +If the buffer already exists and has a running process, then +just go to this buffer. + +If a prefix argument is used, the user is also prompted for a HOST +on which to run CMD using `remote-shell-program'. + +\(Type \\[describe-mode] in the process's buffer for a list of commands.)" + (interactive (sml--read-run-cmd)) + (let* ((pname (file-name-nondirectory cmd)) + (args (split-string arg)) + (file (when (and sml-config-file (file-exists-p sml-config-file)) + sml-config-file))) + ;; And this -- to keep these as defaults even if + ;; they're set in the mode hooks. + (setq sml-program-name cmd) + (setq sml-default-arg arg) + (setq sml-host-name host) + ;; For remote execution, use `remote-shell-program' + (when (> (length host) 0) + (setq args (list* host "cd" default-directory ";" cmd args)) + (setq cmd remote-shell-program)) + ;; Go for it. + (save-current-buffer + (let ((exec-path (if (and (file-name-directory cmd) + (not (file-name-absolute-p cmd))) + ;; If the command has slashes, make sure we + ;; first look relative to the current directory. + ;; Emacs-21 does it for us, but not Emacs-20. + (cons default-directory exec-path) exec-path))) + (pop-to-buffer (apply 'make-comint pname cmd file args))) + + (inferior-sml-mode) + (goto-char (point-max)) + (current-buffer)))) + +(defun sml-send-function (&optional and-go) + "Send current paragraph to the inferior SML process. +With a prefix argument AND-GO switch to the repl buffer as well." + (interactive "P") + (save-excursion + (sml-mark-function) + (sml-prog-proc-send-region (point) (mark))) + (if and-go (sml-prog-proc-switch-to))) + +(defvar inferior-sml-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map comint-mode-map) + (define-key map "\C-c\C-s" 'sml-run) + (define-key map "\t" 'completion-at-point) + map) + "Keymap for inferior-sml mode.") + + +(declare-function smerge-refine-subst "smerge-mode" + (beg1 end1 beg2 end2 props-c)) + +(defun inferior-sml-next-error-hook () + ;; Try to recognize SML/NJ type error message and to highlight finely the + ;; difference between the two types (in case they're large, it's not + ;; always obvious to spot it). + ;; + ;; Sample messages: + ;; + ;; Data.sml:31.9-33.33 Error: right-hand-side of clause doesn't agree with function result type [tycon mismatch] + ;; expression: Hstring + ;; result type: Hstring * int + ;; in declaration: + ;; des2hs = (fn SYM_ID hs => hs + ;; | SYM_OP hs => hs + ;; | SYM_CHR hs => hs) + ;; Data.sml:35.44-35.63 Error: operator and operand don't agree [tycon mismatch] + ;; operator domain: Hstring * Hstring + ;; operand: (Hstring * int) * (Hstring * int) + ;; in expression: + ;; HSTRING.ieq (h1,h2) + ;; vparse.sml:1861.6-1922.14 Error: case object and rules don't agree [tycon mismatch] + ;; rule domain: STConstraints list list option + ;; object: STConstraints list option + ;; in expression: + (save-current-buffer + (when (and (derived-mode-p 'sml-mode 'inferior-sml-mode) + (boundp 'next-error-last-buffer) + (bufferp next-error-last-buffer) + (set-buffer next-error-last-buffer) + (derived-mode-p 'inferior-sml-mode) + ;; The position of `point' is not guaranteed :-( + (looking-at (concat ".*\\[tycon mismatch\\]\n" + " \\(operator domain\\|expression\\|rule domain\\): +"))) + (require 'smerge-mode) + (save-excursion + (let ((b1 (match-end 0)) + e1 b2 e2) + (when (re-search-forward "\n in \\(expression\\|declaration\\):\n" + nil t) + (setq e2 (match-beginning 0)) + (when (re-search-backward + "\n \\(operand\\|result type\\|object\\): +" + b1 t) + (setq e1 (match-beginning 0)) + (setq b2 (match-end 0)) + (smerge-refine-subst b1 e1 b2 e2 + '((face . smerge-refined-change)))))))))) + +(define-derived-mode inferior-sml-mode sml-prog-proc-comint-mode "Inferior-SML" + "Major mode for interacting with an inferior SML process. + +The following commands are available: +\\{inferior-sml-mode-map} + +An SML process can be fired up (again) with \\[sml]. + +Customisation: Entry to this mode runs the hooks on `comint-mode-hook' +and `inferior-sml-mode-hook' (in that order). + +Variables controlling behaviour of this mode are + +`sml-program-name' (default \"sml\") + Program to run as SML. + +`sml-use-command' (default \"use \\\"%s\\\"\") + Template for loading a file into the inferior SML process. + +`sml-cd-command' (default \"System.Directory.cd \\\"%s\\\"\") + SML command for changing directories in SML process (if possible). + +`sml-prompt-regexp' (default \"^[\\-=] *\") + Regexp used to recognise prompts in the inferior SML process. + +You can send text to the inferior SML process from other buffers containing +SML source. + `switch-to-sml' switches the current buffer to the SML process buffer. + `sml-send-function' sends the current *paragraph* to the SML process. + `sml-send-region' sends the current region to the SML process. + + Prefixing the sml-send-<whatever> commands with \\[universal-argument] + causes a switch to the SML process buffer after sending the text. + +For information on running multiple processes in multiple buffers, see +documentation for variable `sml-buffer'. + +Commands: +RET after the end of the process' output sends the text from the + end of process to point. +RET before the end of the process' output copies the current line + to the end of the process' output, and sends it. +DEL converts tabs to spaces as it moves back. +TAB file name completion, as in shell-mode, etc.." + (setq comint-prompt-regexp sml-prompt-regexp) + (sml-mode-variables) + + ;; We have to install it globally, 'cause it's run in the *source* buffer :-( + (add-hook 'next-error-hook 'inferior-sml-next-error-hook) + + ;; Make TAB add a " rather than a space at the end of a file name. + (set (make-local-variable 'comint-completion-addsuffix) '(?/ . ?\")) + + (set (make-local-variable 'font-lock-defaults) + inferior-sml-font-lock-defaults) + + ;; Compilation support (used for `next-error'). + (set (make-local-variable 'compilation-error-regexp-alist) + sml-error-regexp-alist) + ;; FIXME: move it to sml-mode? + (set (make-local-variable 'compilation-error-screen-columns) nil) + + (setq mode-line-process '(": %s"))) + +;;; MORE CODE FOR SML-MODE + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.s\\(ml\\|ig\\)\\'" . sml-mode)) + +(defvar comment-quote-nested) + +;;;###autoload +(define-derived-mode sml-mode sml-prog-proc-mode "SML" + "\\<sml-mode-map>Major mode for editing Standard ML code. +This mode runs `sml-mode-hook' just before exiting. +See also (info \"(sml-mode)Top\"). +\\{sml-mode-map}" + (set (make-local-variable 'sml-prog-proc-descriptor) sml-pp-functions) + (set (make-local-variable 'font-lock-defaults) sml-font-lock-defaults) + (set (make-local-variable 'outline-regexp) sml-outline-regexp) + (set (make-local-variable 'imenu-create-index-function) + 'sml-imenu-create-index) + (set (make-local-variable 'add-log-current-defun-function) + 'sml-current-fun-name) + ;; Treat paragraph-separators in comments as paragraph-separators. + (set (make-local-variable 'paragraph-separate) + (concat "\\([ \t]*\\*)?\\)?\\(" paragraph-separate "\\)")) + (set (make-local-variable 'require-final-newline) t) + (set (make-local-variable 'electric-indent-chars) + (cons ?\; (if (boundp 'electric-indent-chars) + electric-indent-chars '(?\n)))) + (set (make-local-variable 'electric-layout-rules) + `((?\; . ,(lambda () + (save-excursion + (skip-chars-backward " \t;") + (unless (or (bolp) + (progn (skip-chars-forward " \t;") + (eolp))) + 'after)))))) + (when sml-electric-pipe-mode + (add-hook 'post-self-insert-hook #'sml-post-self-insert-pipe nil t)) + (sml-mode-variables)) + +(defun sml-mode-variables () + (set-syntax-table sml-mode-syntax-table) + (setq local-abbrev-table sml-mode-abbrev-table) + ;; Setup indentation and sexp-navigation. + (smie-setup sml-smie-grammar #'sml-smie-rules + :backward-token #'sml-smie-backward-token + :forward-token #'sml-smie-forward-token) + (set (make-local-variable 'parse-sexp-ignore-comments) t) + (set (make-local-variable 'comment-start) "(* ") + (set (make-local-variable 'comment-end) " *)") + (set (make-local-variable 'comment-start-skip) "(\\*+\\s-*") + (set (make-local-variable 'comment-end-skip) "\\s-*\\*+)") + ;; No need to quote nested comments markers. + (set (make-local-variable 'comment-quote-nested) nil)) + +(defun sml-funname-of-and () + "Name of the function this `and' defines, or nil if not a function. +Point has to be right after the `and' symbol and is not preserved." + (forward-comment (point-max)) + (if (looking-at sml-tyvarseq-re) (goto-char (match-end 0))) + (let ((sym (sml-smie-forward-token))) + (forward-comment (point-max)) + (unless (or (member sym '(nil "d=")) + (member (sml-smie-forward-token) '("d="))) + sym))) + +(defun sml-find-forward (re) + (while (progn (forward-comment (point-max)) + (not (looking-at re))) + (or (ignore-errors (forward-sexp 1) t) (forward-char 1)))) + +(defun sml-electric-pipe () + "Insert a \"|\". +Depending on the context insert the name of function, a \"=>\" etc." + (interactive) + (unless (save-excursion (skip-chars-backward "\t ") (bolp)) (insert "\n")) + (insert "| ") + (unless (sml-post-self-insert-pipe (1- (point))) + (indent-according-to-mode))) + +(defun sml-post-self-insert-pipe (&optional acp) + (when (or acp (and (eq ?| last-command-event) + (setq acp (electric--after-char-pos)))) + (let ((text + (save-excursion + (goto-char (1- acp)) ;Jump before the "|" we just inserted. + (let ((sym (sml-find-matching-starter sml-pipeheads + ;; (sml-op-prec "|" 'back) + ))) + (sml-smie-forward-token) + (forward-comment (point-max)) + (cond + ((string= sym "|") + (let ((f (sml-smie-forward-token))) + (sml-find-forward "\\(=>\\|=\\||\\)\\S.") + (cond + ((looking-at "|") nil) ; A datatype or an OR pattern? + ((looking-at "=>") " => ") ;`case', or `fn' or `handle'. + ((looking-at "=") ;A function. + (cons (concat f " ")" = "))))) + ((string= sym "and") + ;; Could be a datatype or a function. + (let ((funname (sml-funname-of-and))) + (if funname (cons (concat funname " ") " = ") nil))) + ((string= sym "fun") + (while (and (setq sym (sml-smie-forward-token)) + (string-match "^'" sym)) + (forward-comment (point-max))) + (cons (concat sym " ") " = ")) + ((member sym '("case" "handle" "of")) " => ") ;; "fn"? + ;;((member sym '("abstype" "datatype")) "") + (t nil)))))) + (when text + (save-excursion + (goto-char (1- acp)) + (unless (save-excursion (skip-chars-backward "\t ") (bolp)) + (insert "\n"))) + (unless (memq (char-before) '(?\s ?\t)) (insert " ")) + (let ((use-region (and (use-region-p) (< (point) (mark))))) + ;; (skeleton-proxy-new `(nil ,(if (consp text) (pop text)) _ ,text)) + (when (consp text) (insert (pop text))) + (if (not use-region) + (save-excursion (insert text)) + (goto-char (mark)) + (insert text))) + (indent-according-to-mode) + t)))) + + +;;; Misc + +(defun sml-mark-function () + "Mark the surrounding function. Or try to at least." + (interactive) + ;; FIXME: Provide beginning-of-defun-function so mark-defun "just works". + (let ((start (point))) + (sml-beginning-of-defun) + (let ((beg (point))) + (smie-forward-sexp 'halfsexp) + (if (or (< start beg) (> start (point))) + (progn + (goto-char start) + (mark-paragraph)) + (push-mark nil t t) + (goto-char beg))))) + +(defun sml-back-to-outer-indent () + "Unindents to the next outer level of indentation." + (interactive) + (save-excursion + (forward-line 0) + (let ((start-column (current-indentation)) + indent) + (when (> start-column 0) + (save-excursion + (while (>= (setq indent + (if (re-search-backward "^[ \t]*[^\n\t]" nil t) + (current-indentation) + 0)) + start-column)) + (skip-chars-forward " \t") + (let ((pos (point))) + (move-to-column start-column) + (when (re-search-backward " \\([^ \t\n]\\)" pos t) + (goto-char (match-beginning 1)) + (setq indent (current-column))))) + (indent-line-to indent))))) + +(defun sml-find-matching-starter (syms) + (let ((halfsexp nil) + tok) + ;;(sml-smie-forward-token) + (while (not (or (bobp) + (member (nth 2 (setq tok (smie-backward-sexp halfsexp))) + syms))) + (cond + ((null (car tok)) nil) + ((numberp (car tok)) (setq halfsexp 'half)) + (t (goto-char (cadr tok))))) + (if (nth 2 tok) (goto-char (cadr tok))) + (nth 2 tok))) + +(defun sml-skip-siblings () + (let (tok) + (while (and (not (bobp)) + (progn (setq tok (smie-backward-sexp 'half)) + (cond + ((null (car tok)) t) + ((numberp (car tok)) t) + (t nil))))) + (if (nth 2 tok) (goto-char (cadr tok))) + (nth 2 tok))) + +(defun sml-beginning-of-defun () + (let ((sym (sml-find-matching-starter sml-starters-syms))) + (if (member sym '("fun" "and" "functor" "signature" "structure" + "abstraction" "datatype" "abstype")) + (save-excursion (sml-smie-forward-token) (forward-comment (point-max)) + (sml-smie-forward-token)) + ;; We're inside a "non function declaration": let's skip all other + ;; declarations that we find at the same level and try again. + (sml-skip-siblings) + ;; Obviously, let's not try again if we're at bobp. + (unless (bobp) (sml-beginning-of-defun))))) + +(defcustom sml-max-name-components 3 + "Maximum number of components to use for the current function name." + :type 'integer) + +(defun sml-current-fun-name () + (save-excursion + (let ((count sml-max-name-components) + fullname name) + (end-of-line) + (while (and (> count 0) + (setq name (sml-beginning-of-defun))) + (decf count) + (setq fullname (if fullname (concat name "." fullname) name)) + ;; Skip all other declarations that we find at the same level. + (sml-skip-siblings)) + fullname))) + + +;;; INSERTING PROFORMAS (COMMON SML-FORMS) + +(defvar sml-forms-alist nil + "Alist of code templates. +You can extend this alist to your heart's content. For each additional +template NAME in the list, declare a keyboard macro or function (or +interactive command) called 'sml-form-NAME'. +If 'sml-form-NAME' is a function it takes no arguments and should +insert the template at point\; if this is a command it may accept any +sensible interactive call arguments\; keyboard macros can't take +arguments at all. +`sml-forms-alist' understands let, local, case, abstype, datatype, +signature, structure, and functor by default.") + +(defmacro sml-def-skeleton (name interactor &rest elements) + (let ((fsym (intern (concat "sml-form-" name)))) + `(progn + (add-to-list 'sml-forms-alist ',(cons name fsym)) + (define-abbrev sml-mode-abbrev-table ,name "" ',fsym nil 'system) + (let ((abbrev (abbrev-symbol ,name sml-mode-abbrev-table))) + (abbrev-put abbrev :case-fixed t) + (abbrev-put abbrev :enable-function + (lambda () (not (nth 8 (syntax-ppss)))))) + (define-skeleton ,fsym + ,(format "SML-mode skeleton for `%s..' expressions" name) + ,interactor + ,(concat name " ") > + ,@elements)))) +(put 'sml-def-skeleton 'lisp-indent-function 2) + +(sml-def-skeleton "let" nil + @ "\nin " > _ "\nend" >) + +(sml-def-skeleton "if" nil + @ " then " > _ "\nelse " > _) + +(sml-def-skeleton "local" nil + @ "\nin" > _ "\nend" >) + +(sml-def-skeleton "case" "Case expr: " + str "\nof " > _ " => ") + +(sml-def-skeleton "signature" "Signature name: " + str " =\nsig" > "\n" > _ "\nend" >) + +(sml-def-skeleton "structure" "Structure name: " + str " =\nstruct" > "\n" > _ "\nend" >) + +(sml-def-skeleton "functor" "Functor name: " + str " () : =\nstruct" > "\n" > _ "\nend" >) + +(sml-def-skeleton "datatype" "Datatype name and type params: " + str " =" \n) + +(sml-def-skeleton "abstype" "Abstype name and type params: " + str " =" \n _ "\nwith" > "\nend" >) + +;; + +(sml-def-skeleton "struct" nil + _ "\nend" >) + +(sml-def-skeleton "sig" nil + _ "\nend" >) + +(sml-def-skeleton "val" nil + @ " = " > _) + +(sml-def-skeleton "fn" nil + @ " =>" > _) + +(sml-def-skeleton "fun" nil + @ " =" > _) + +;; + +(defun sml-forms-menu (_menu) + (mapcar (lambda (x) (vector (car x) (cdr x) t)) + sml-forms-alist)) + +(defvar sml-last-form "let") + +(defun sml-electric-space () + "Expand a symbol into an SML form, or just insert a space. +If the point directly precedes a symbol for which an SML form exists, +the corresponding form is inserted." + (interactive) + (let ((abbrev-mode (not abbrev-mode)) + (last-command-event ?\s) + ;; Bind `this-command' to fool skeleton's special abbrev handling. + (this-command 'self-insert-command)) + (call-interactively 'self-insert-command))) + +(defun sml-insert-form (name newline) + "Interactive short-cut to insert the NAME common SML form. +If a prefix argument is given insert a NEWLINE and indent first, or +just move to the proper indentation if the line is blank\; otherwise +insert at point (which forces indentation to current column). + +The default form to insert is 'whatever you inserted last time' +\(just hit return when prompted\)\; otherwise the command reads with +completion from `sml-forms-alist'." + (interactive + (list (completing-read + (format "Form to insert (default %s): " sml-last-form) + sml-forms-alist nil t nil nil sml-forms-alist) + current-prefix-arg)) + (setq sml-last-form name) + (unless (or (not newline) + (save-excursion (beginning-of-line) (looking-at "\\s-*$"))) + (insert "\n")) + (when (memq (char-syntax (preceding-char)) '(?_ ?w)) (insert " ")) + (let ((f (cdr (assoc name sml-forms-alist)))) + (cond + ((commandp f) (command-execute f)) + (f (funcall f)) + (t (error "Undefined SML form: %s" name))))) + +;;; +;;; MLton support +;;; + +(defvar sml-mlton-command "mlton" + "Command to run MLton. Can include arguments.") + +(defvar sml-mlton-mainfile nil) + +(defconst sml-mlton-error-regexp-alist + ;; I wish they just changed MLton to use one of the standard + ;; error formats. + `(("^\\(?:Error\\|\\(Warning\\)\\): \\(.+\\) \\([0-9]+\\)\\.\\([0-9]+\\)\\.$" + 2 3 4 + ;; If subgroup 1 matched, then it's a warning, otherwise it's an error. + (1)))) + +(defvar compilation-error-regexp-alist) +(eval-after-load "compile" + '(dolist (x sml-mlton-error-regexp-alist) + (add-to-list 'compilation-error-regexp-alist x))) + +(defun sml-mlton-typecheck (mainfile) + "Typecheck using MLton. +MAINFILE is the top level file of the project." + (interactive + (list (if (and sml-mlton-mainfile (not current-prefix-arg)) + sml-mlton-mainfile + (read-file-name "Main file: ")))) + (setq sml-mlton-mainfile mainfile) + (save-some-buffers) + (require 'compile) + (dolist (x sml-mlton-error-regexp-alist) + (add-to-list 'compilation-error-regexp-alist x)) + (with-current-buffer (find-file-noselect mainfile) + (compile (concat sml-mlton-command + " -stop tc " ;Stop right after type checking. + (shell-quote-argument + (file-relative-name buffer-file-name)))))) + +;;; +;;; MLton's def-use info. +;;; + +(defvar sml-defuse-file nil) + +(defun sml-defuse-file () + (or sml-defuse-file (sml-defuse-set-file))) + +(defun sml-defuse-set-file () + "Specify the def-use file to use." + (interactive) + (setq sml-defuse-file (read-file-name "Def-use file: "))) + +(defun sml-defuse-symdata-at-point () + (save-excursion + (sml-smie-forward-token) + (let ((symname (sml-smie-backward-token))) + (if (equal symname "op") + (save-excursion (setq symname (sml-smie-forward-token)))) + (when (string-match "op " symname) + (setq symname (substring symname (match-end 0))) + (forward-word) + (forward-comment (point-max))) + (list symname + ;; Def-use files seem to count chars, not columns. + ;; We hope here that they don't actually count bytes. + ;; Also they seem to start counting at 1. + (1+ (- (point) (progn (beginning-of-line) (point)))) + (save-restriction + (widen) (1+ (count-lines (point-min) (point)))) + buffer-file-name)))) + +(defconst sml-defuse-def-regexp + "^[[:alpha:]]+ \\([^ \n]+\\) \\(.+\\) \\([0-9]+\\)\\.\\([0-9]+\\)$") +(defconst sml-defuse-use-regexp-format "^ %s %d\\.%d $") + +(defun sml-defuse-jump-to-def () + "Jump to the definition corresponding to the symbol at point." + (interactive) + (let ((symdata (sml-defuse-symdata-at-point))) + (if (null (car symdata)) + (error "Not on a symbol") + (with-current-buffer (find-file-noselect (sml-defuse-file)) + (goto-char (point-min)) + (unless (re-search-forward + (format sml-defuse-use-regexp-format + (concat "\\(?:" + ;; May be an absolute file name. + (regexp-quote (nth 3 symdata)) + "\\|" + ;; Or a relative file name. + (regexp-quote (file-relative-name + (nth 3 symdata))) + "\\)") + (nth 2 symdata) + (nth 1 symdata)) + nil t) + ;; FIXME: This is typically due to editing: any minor editing will + ;; mess everything up. We should try to fail more gracefully. + (error "Def-use info not found")) + (unless (re-search-backward sml-defuse-def-regexp nil t) + ;; This indicates a bug in this code. + (error "Internal failure while looking up def-use")) + (unless (equal (match-string 1) (nth 0 symdata)) + ;; FIXME: This again is most likely due to editing. + (error "Incoherence in the def-use info found")) + (let ((line (string-to-number (match-string 3))) + (char (string-to-number (match-string 4)))) + (pop-to-buffer (find-file-noselect (match-string 2))) + (goto-char (point-min)) + (forward-line (1- line)) + (forward-char (1- char))))))) + +;;; +;;; SML/NJ's Compilation Manager support +;;; + +(defvar sml-cm-mode-syntax-table sml-mode-syntax-table) +(defvar sml-cm-font-lock-keywords + `(,(concat "\\_<" (regexp-opt '("library" "group" "is" "structure" + "functor" "signature" "funsig") t) + "\\_>"))) +;;;###autoload +(add-to-list 'completion-ignored-extensions ".cm/") +;; This was used with the old compilation manager. +(add-to-list 'completion-ignored-extensions "CM/") +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.cm\\'" . sml-cm-mode)) +;;;###autoload +(define-derived-mode sml-cm-mode fundamental-mode "SML-CM" + "Major mode for SML/NJ's Compilation Manager configuration files." + (set (make-local-variable 'sml-prog-proc-descriptor) sml-pp-functions) + (set (make-local-variable 'font-lock-defaults) + '(sml-cm-font-lock-keywords nil t nil nil))) + +;;; +;;; ML-Lex support +;;; + +(defvar sml-lex-font-lock-keywords + (append + `((,(concat "^%" sml-id-re) . font-lock-builtin-face) + ("^%%" . font-lock-module-def-face)) + sml-font-lock-keywords)) +(defconst sml-lex-font-lock-defaults + (cons 'sml-lex-font-lock-keywords (cdr sml-font-lock-defaults))) + +;;;###autoload +(define-derived-mode sml-lex-mode sml-mode "SML-Lex" + "Major Mode for editing ML-Lex files." + (set (make-local-variable 'font-lock-defaults) sml-lex-font-lock-defaults)) + +;;; +;;; ML-Yacc support +;;; + +(defface sml-yacc-bnf-face + '((t (:foreground "darkgreen"))) + "Face used to highlight (non)terminals in `sml-yacc-mode'.") +(defvar sml-yacc-bnf-face 'sml-yacc-bnf-face) + +(defcustom sml-yacc-indent-action 16 + "Indentation column of the opening paren of actions." + :type 'integer) + +(defcustom sml-yacc-indent-pipe nil + "Indentation column of the pipe char in the BNF. +If nil, align it with `:' or with previous cases." + :type 'integer) + +(defcustom sml-yacc-indent-term nil + "Indentation column of the (non)term part. +If nil, align it with previous cases." + :type 'integer) + +(defvar sml-yacc-font-lock-keywords + (cons `((concat "^\\(" sml-id-re "\\s-*:\\|\\s-*|\\)\\(\\s-*" sml-id-re + "\\)*\\s-*\\(\\(%" sml-id-re "\\)\\s-+" sml-id-re "\\|\\)") + (0 (save-excursion + (save-match-data + (goto-char (match-beginning 0)) + (unless (or (re-search-forward "\\_<of\\_>" + (match-end 0) 'move) + (progn (forward-comment (point-max)) + (not (looking-at "(")))) + sml-yacc-bnf-face)))) + (4 font-lock-builtin-face t t)) + sml-lex-font-lock-keywords)) +(defconst sml-yacc-font-lock-defaults + (cons 'sml-yacc-font-lock-keywords (cdr sml-font-lock-defaults))) + +(defun sml-yacc-indent-line () + "Indent current line of ML-Yacc code." + (let ((savep (> (current-column) (current-indentation))) + (indent (max (or (ignore-errors (sml-yacc-indentation)) 0) 0))) + (if savep + (save-excursion (indent-line-to indent)) + (indent-line-to indent)))) + +(defun sml-yacc-indentation () + (save-excursion + (back-to-indentation) + (or (and (looking-at (eval-when-compile + (concat "%\\|" sml-id-re "\\s-*:"))) + 0) + (when (save-excursion + (condition-case nil (progn (up-list -1) nil) (scan-error t))) + ;; We're outside an action. + (cond + ;; Special handling of indentation inside %term and %nonterm + ((save-excursion + (and (re-search-backward "^%\\(\\sw+\\)" nil t) + (member (match-string 1) '("term" "nonterm")))) + (if (numberp sml-yacc-indent-term) sml-yacc-indent-term + (let ((offset (if (looking-at "|") -2 0))) + (forward-line -1) + (looking-at "\\s-*\\(%\\sw*\\||\\)?\\s-*") + (goto-char (match-end 0)) + (+ offset (current-column))))) + ((looking-at "(") sml-yacc-indent-action) + ((looking-at "|") + (if (numberp sml-yacc-indent-pipe) sml-yacc-indent-pipe + (backward-sexp 1) + (while (progn (forward-comment (- (point))) + (/= 0 (skip-syntax-backward "w_")))) + (forward-comment (- (point))) + (if (not (looking-at "\\s-$")) + (1- (current-column)) + (skip-syntax-forward " ") + (- (current-column) 2)))))) + ;; default to SML rules + (smie-indent-calculate)))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.grm\\'" . sml-yacc-mode)) +;;;###autoload +(define-derived-mode sml-yacc-mode sml-mode "SML-Yacc" + "Major Mode for editing ML-Yacc files." + (set (make-local-variable 'indent-line-function) 'sml-yacc-indent-line) + (set (make-local-variable 'font-lock-defaults) sml-yacc-font-lock-defaults)) + + + +;;;; ChangeLog: + +;; 2012-10-31 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; * sml-mode.el: Integrate BUGS&NEWS; re-add run-sml. +;; +;; 2012-10-22 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Add SML-mode. +;; +;; 2012-10-22 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Cleanup copyright; Merge prog-proc into sml-mode.el +;; +;; 2012-10-19 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Move sml-compile to prog-proc. +;; +;; 2012-10-19 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; * sml-mode.el (sml-electric-pipe-mode): New var. +;; (sml-pipeheads): Add (, {, and [ to more reliably detect cases where +;; the pipe is not part of a case/fun/... +;; (sml-tyvarseq-re): Use shy groups. +;; (sml-font-lock-keywords): Adjust accordingly. +;; (sml-compile): Avoid the 3rd part of dolist's spec. +;; (sml-post-self-insert-pipe): New fun, extracted from sml-electric-pipe. +;; (sml-mode): Use it to obey sml-electric-pipe-mode. +;; (sml-electric-pipe): Use sml-post-self-insert-pipe. +;; * makefile.pkg (ELFILES): Remove sml-proc.el. +;; * prog-proc.el: Rename from sml-prog-proc.el. +;; +;; 2012-10-15 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Add sml-compile back into sml-mode +;; +;; 2012-10-04 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Move sml-proc to either prog-proc or sml-mode. +;; +;; 2012-10-04 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Fix compilation +;; +;; 2012-10-03 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Start preparing for the move to ELPA. +;; +;; 2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Merge from trunk +;; +;; 2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Merge sml-defs.el into sml-mode.el. +;; * sml-mode.el: Merge code from sml-defs.el. +;; Remove ":group 'sml" since they're now redundant. +;; * makefile.pkg (ELFILES): Adjust. +;; +;; 2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; * sml-mode.el (sml-mark-function): New implementation using SMIE. +;; * sml-defs.el (sml-mode-map): Use backtab. +;; Remove leftover unused sml-drag-region binding. +;; +;; 2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; - +;; +;; 2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Merge from trunk +;; +;; 2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Use SMIE by default and make sml-oldindent optional. +;; * sml-mode.el: Only load sml-oldindent if necessary. +;; (sml-use-smie): Default to t. +;; (sml-smie-datatype-|-p): Better handle incomplete datatype branch. +;; (sml-mode): Use prog-mode. Setup electric-layout and electric-indent. +;; (sml-mode-variables): Always setup SMIE if possible. +;; (sml-imenu-create-index, sml-funname-of-and, sml-electric-pipe) +;; (sml-beginning-of-defun, sml-defuse-symdata-at-point) +;; (sml-yacc-font-lock-keywords, sml-yacc-indentation): +;; Avoid sml-oldindent functions. +;; (sml-find-forward): Move from sml-oldindent and re-implement. +;; (sml-electric-semi): Use self-insert-command so electric-layout and +;; electric-indent can do their job. +;; (sml-smie-find-matching-starter, sml-find-matching-starter) +;; (sml-smie-skip-siblings, sml-skip-siblings): New functions. +;; * sml-oldindent.el (sml-starters-indent-after, sml-exptrail-syms): +;; Remove, unused. +;; (sml-find-forward): Move back to sml-mode.el. +;; (sml-old-find-matching-starter): Rename from sml-find-matching-starter. +;; (sml-old-skip-siblings): Move&rename from sml-mode:sml-skip-siblings. +;; +;; 2012-04-11 Stefan Monnier <monnier@iro.umontreal.ca> +;; +;; Merge from trunk +;; + +(provide 'sml-mode) + +;;; sml-mode.el ends here diff --git a/emacs/solarized-theme.el b/emacs/solarized-theme.el new file mode 100644 index 0000000..cdca306 --- /dev/null +++ b/emacs/solarized-theme.el @@ -0,0 +1,4 @@ +(require 'solarized-dark-theme) +(require 'solarized-light-theme) + +(provide 'solarized-theme) diff --git a/emacs/solarized.el b/emacs/solarized.el new file mode 100644 index 0000000..527213e --- /dev/null +++ b/emacs/solarized.el @@ -0,0 +1,1096 @@ +;;; solarized.el --- Solarized for Emacs. + +;; Copyright (C) 2011-2013 Bozhidar Batsov + +;; Author: Bozhidar Batsov <bozhidar@batsov.com> +;; Author: Thomas Frössman <thomasf@jossystem.se> +;; URL: http://github.com/bbatsov/solarized-emacs +;; Version: 1.0.0 + +;; 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 3 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, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; A port of Solarized to Emacs. +;; +;;; Installation: +;; +;; Drop the `solarized-theme.el` somewhere in your `load-path` and +;; the two themes in a folder that is on `custom-theme-load-path' +;; and enjoy! +;; +;; Don't forget that the theme requires Emacs 24. +;; +;;; Bugs +;; +;; None that I'm aware of. +;; +;;; Credits +;; +;; Ethan Schoonover created the original theme for vim on such this port +;; is based. +;; +;;; Code: + +(defun create-solarized-theme (variant theme-name &optional childtheme) + (let* ((class '((class color) (min-colors 89))) + ;; Solarized palette + (base03 "#002b36") + (base02 "#073642") + ;; emphasized content + (base01 "#586e75") + ;; primary content + (base00 "#657b83") + (base0 "#839496") + ;; comments + (base1 "#93a1a1") + ;; background highlight light + (base2 "#eee8d5") + ;; background light + (base3 "#fdf6e3") + + ;; Solarized accented colors + (yellow "#b58900") + (orange "#cb4b16") + (red "#dc322f") + (magenta "#d33682") + (violet "#6c71c4") + (blue "#268bd2") + (cyan "#2aa198") + (green "#859900") + + ;; Darker and lighter accented colors + ;; Only use these in exceptional circumstances! + (yellow-d "#7B6000") + (yellow-l "#DEB542") + (orange-d "#8B2C02") + (orange-l "#F2804F") + (red-d "#990A1B") + (red-l "#FF6E64") + (magenta-d "#93115C") + (magenta-l "#F771AC") + (violet-d "#3F4D91") + (violet-l "#9EA0E5") + (blue-d "#00629D") + (blue-l "#69B7F0") + (cyan-d "#00736F") + (cyan-l "#69CABF") + (green-d "#546E00") + (green-l "#B4C342") + + ;; Light/Dark adaptive solarized colors + (solarized-fg (if (eq variant 'light) base00 base0)) + (solarized-bg (if (eq variant 'light) base3 base03)) + (solarized-hl (if (eq variant 'light) base2 base02)) + (solarized-emph (if (eq variant 'light) base01 base1)) + (solarized-comments (if (eq variant 'light) base1 base01)) + + ;; Light/Dark adaptive higher/lower contrast accented colors + ;; Only use these in exceptional cirmumstances! + (solarized-fg-hc (if (eq variant 'light) base3 base03)) + (solarized-fg-lc (if (eq variant 'light) base03 base3)) + + (yellow-hc (if (eq variant 'light) yellow-d yellow-l)) + (yellow-lc (if (eq variant 'light) yellow-l yellow-d)) + (orange-hc (if (eq variant 'light) orange-d orange-l)) + (orange-lc (if (eq variant 'light) orange-l orange-d)) + (red-hc (if (eq variant 'light) red-d red-l)) + (red-lc (if (eq variant 'light) red-l red-d)) + (magenta-hc (if (eq variant 'light) magenta-d magenta-l)) + (magenta-lc (if (eq variant 'light) magenta-l magenta-d)) + (violet-hc (if (eq variant 'light) violet-d violet-l)) + (violet-lc (if (eq variant 'light) violet-l violet-d)) + (blue-hc (if (eq variant 'light) blue-d blue-l)) + (blue-lc (if (eq variant 'light) blue-l blue-d)) + (cyan-hc (if (eq variant 'light) cyan-d cyan-l)) + (cyan-lc (if (eq variant 'light) cyan-l cyan-d)) + (green-hc (if (eq variant 'light) green-d green-l)) + (green-lc (if (eq variant 'light) green-l green-d))) + (custom-theme-set-faces + theme-name + '(button ((t (:underline t)))) + + ;; basic coloring + `(default ((,class (:foreground ,solarized-fg :background ,solarized-bg)))) + `(shadow ((,class (:foreground ,solarized-comments)))) + `(match ((,class (:background ,solarized-hl :foreground ,solarized-emph :weight bold)))) + `(cursor ((,class (:foreground ,solarized-bg :background ,solarized-fg :inverse-video t)))) + `(escape-glyph-face ((,class (:foreground ,red)))) + `(fringe ((,class (:foreground ,solarized-fg :background ,solarized-hl)))) + `(header-line ((,class (:foreground ,yellow + :background ,solarized-hl + :box (:line-width -1 :style released-button))))) + `(highlight ((,class (:background ,solarized-hl)))) + `(link ((,class (:foreground ,yellow :underline t :weight bold)))) + `(link-visited ((,class (:foreground ,yellow :underline t :weight normal)))) + `(success ((,class (:foreground ,green )))) + `(warning ((,class (:foreground ,yellow )))) + `(error ((,class (:foreground ,orange)))) + `(lazy-highlight ((,class (:foreground ,solarized-emph :background ,solarized-hl :bold t)))) + `(escape-glyph ((,class (:foreground ,violet)))) + + ;; compilation + `(compilation-column-face ((,class (:foreground ,yellow)))) + `(compilation-enter-directory-face ((,class (:foreground ,green)))) + `(compilation-error-face ((,class (:foreground ,red :weight bold :underline t)))) + `(compilation-face ((,class (:foreground ,solarized-fg)))) + `(compilation-info-face ((,class (:foreground ,blue)))) + `(compilation-info ((,class (:foreground ,green :underline t)))) + `(compilation-leave-directory-face ((,class (:foreground ,green)))) + `(compilation-line-face ((,class (:foreground ,yellow)))) + `(compilation-line-number ((,class (:foreground ,yellow)))) + `(compilation-message-face ((,class (:foreground ,blue)))) + `(compilation-warning-face ((,class (:foreground ,yellow :weight bold :underline t)))) + + `(compilation-mode-line-exit + ((,class (:inherit compilation-info :foreground ,green :weight bold)))) + `(compilation-mode-line-fail + ((,class (:inherit compilation-error :foreground ,red :weight bold)))) + `(compilation-mode-line-run ((,class (:foreground ,orange :weight bold)))) + + ;; cua + `(cua-global-mark ((,class (:background ,yellow :foreground ,solarized-bg)))) + `(cua-rectangle ((,class (:inherit region :background ,magenta :foreground ,solarized-bg)))) + `(cua-rectangle-noselect ((,class (:inherit region :background ,solarized-hl + :foreground ,solarized-comments)))) + + ;; diary + `(diary ((,class (:foreground ,yellow)))) + + ;; dired + `(dired-directory ((,class (:foreground ,blue :weight normal)))) + `(dired-flagged ((,class (:foreground ,red)))) + `(dired-header ((,class (:foreground ,solarized-bg :background ,blue)))) + `(dired-ignored ((,class (:inherit shadow)))) + `(dired-mark ((,class (:foreground ,yellow :weight bold)))) + `(dired-marked ((,class (:foreground ,magenta :weight bold)))) + `(dired-perm-write ((,class (:foreground ,solarized-fg :underline t)))) + `(dired-symlink ((,class (:foreground ,cyan :weight normal :slant italic)))) + `(dired-warning ((,class (:foreground ,orange :underline t)))) + + ;; dropdown + `(dropdown-list-face ((,class (:background ,solarized-hl :foreground ,cyan)))) + `(dropdown-list-selection-face ((,class (:background ,cyan-lc :foreground ,cyan-hc)))) + + ;; grep + `(grep-context-face ((,class (:foreground ,solarized-fg)))) + `(grep-error-face ((,class (:foreground ,red :weight bold :underline t)))) + `(grep-hit-face ((,class (:foreground ,blue)))) + `(grep-match-face ((,class (:foreground ,orange :weight bold)))) + + ;; faces used by isearch + `(isearch ((,class (:foreground ,yellow :background ,solarized-hl :bold t)))) + `(isearch-fail ((,class (:foreground ,red :background ,solarized-bg :bold t)))) + + ;; man + `(Man-overstrike ((,class (:foreground ,blue :weight bold)))) + `(Man-reverse ((,class (:foreground ,orange)))) + `(Man-underline ((,class (:foreground ,green :underline t)))) + + ;; misc faces + `(menu ((,class (:foreground ,solarized-fg :background ,solarized-bg)))) + `(minibuffer-prompt ((,class (:foreground ,solarized-emph)))) + `(mode-line + ((,class (:foreground ,solarized-fg + :background ,solarized-hl + :box (:line-width -1 :style released-button))))) + `(mode-line-buffer-id ((,class (:foreground ,solarized-emph :weight bold)))) + `(mode-line-inactive + ((,class (:foreground ,solarized-fg + :background ,solarized-bg + :box (:line-width -1 :style released-button))))) + `(region ((,class (:foreground ,solarized-bg :background ,solarized-emph)))) + `(secondary-selection ((,class (:background ,solarized-hl)))) + + `(trailing-whitespace ((,class (:background ,red)))) + `(vertical-border ((,class (:foreground ,solarized-fg)))) + + ;; font lock + `(font-lock-builtin-face ((,class (:foreground ,blue :slant italic)))) + `(font-lock-comment-delimiter-face ((,class (:foreground ,solarized-comments)))) + `(font-lock-comment-face ((,class (:foreground ,solarized-comments)))) + `(font-lock-constant-face ((,class (:foreground ,blue :weight bold)))) + `(font-lock-doc-face ((,class (:foreground ,cyan :slant italic)))) + `(font-lock-doc-string-face ((,class (:foreground ,blue)))) + `(font-lock-function-name-face ((,class (:foreground ,blue)))) + `(font-lock-keyword-face ((,class (:foreground ,green :weight bold)))) + `(font-lock-negation-char-face ((,class (:foreground ,solarized-fg)))) + `(font-lock-preprocessor-face ((,class (:foreground ,blue)))) + `(font-lock-string-face ((,class (:foreground ,cyan)))) + `(font-lock-type-face ((,class (:foreground ,yellow)))) + `(font-lock-variable-name-face ((,class (:foreground ,blue)))) + `(font-lock-warning-face ((,class (:foreground ,orange :weight bold :underline t)))) + + `(c-annotation-face ((,class (:inherit font-lock-constant-face)))) + + ;;; external + + ;; ace-jump-mode + `(ace-jump-face-background + ((,class (:foreground ,solarized-comments :background ,solarized-bg :inverse-video nil)))) + `(ace-jump-face-foreground + ((,class (:foreground ,red :background ,solarized-bg :inverse-video nil)))) + + ;; auto-complete + `(ac-candidate-face ((,class (:background ,solarized-hl :foreground ,cyan)))) + `(ac-selection-face ((,class (:background ,cyan-lc :foreground ,cyan-hc)))) + `(ac-candidate-mouse-face ((,class (:background ,cyan-hc :foreground ,cyan-lc)))) + `(ac-completion-face ((,class (:foreground ,solarized-emph :underline t)))) + `(ac-gtags-candidate-face ((,class (:background ,solarized-hl :foreground ,blue)))) + `(ac-gtags-selection-face ((,class (:background ,blue-lc :foreground ,blue-hc)))) + `(ac-yasnippet-candidate-face ((,class (:background ,solarized-hl :foreground ,yellow)))) + `(ac-yasnippet-selection-face ((,class (:background ,yellow-lc :foreground ,yellow-hc)))) + + ;; auto highlight symbol + `(ahs-definition-face ((,class (:foreground ,solarized-bg :background ,blue :underline t)))) + `(ahs-edit-mode-face ((,class (:foreground ,solarized-bg :background ,yellow)))) + `(ahs-face ((,class (:foreground ,solarized-bg :background ,blue)))) + `(ahs-plugin-bod-face ((,class (:foreground ,solarized-bg :background ,blue)))) + `(ahs-plugin-defalt-face ((,class (:foreground ,solarized-bg :background ,cyan)))) + `(ahs-plugin-whole-buffer-face ((,class (:foreground ,solarized-bg :background ,green)))) + `(ahs-warning-face ((,class (:foreground ,red :weight bold)))) + + ;; android mode + `(android-mode-debug-face ((,class (:foreground ,green)))) + `(android-mode-error-face ((,class (:foreground ,orange :weight bold)))) + `(android-mode-info-face ((,class (:foreground ,solarized-fg)))) + `(android-mode-verbose-face ((,class (:foreground ,solarized-comments)))) + `(android-mode-warning-face ((,class (:foreground ,yellow)))) + + ;; bm + `(bm-face ((,class (:background ,yellow-lc :foreground ,solarized-bg)))) + `(bm-fringe-face ((,class (:background ,yellow-lc :foreground ,solarized-bg)))) + `(bm-fringe-persistent-face ((,class (:background ,green-lc :foreground ,solarized-bg)))) + `(bm-persistent-face ((,class (:background ,green-lc :foreground ,solarized-bg)))) + + ;; calfw + `(cfw:face-day-title ((,class (:background ,solarized-hl)))) + `(cfw:face-annotation ((,class (:inherit cfw:face-day-title :foreground ,yellow)))) + `(cfw:face-default-content ((,class (:foreground ,green)))) + `(cfw:face-default-day ((,class (:inherit cfw:face-day-title :weight bold)))) + `(cfw:face-disable ((,class (:inherit cfw:face-day-title :foreground ,solarized-comments)))) + `(cfw:face-grid ((,class (:foreground ,solarized-comments)))) + `(cfw:face-header ((,class (:foreground ,blue-hc :background ,blue-lc :weight bold)))) + `(cfw:face-holiday ((,class (:background nil :foreground ,red :weight bold)))) + `(cfw:face-periods ((,class (:foreground ,magenta)))) + `(cfw:face-select ((,class (:background ,magenta-lc :foreground ,magenta-hc)))) + `(cfw:face-saturday ((,class (:foreground ,cyan-hc :background ,cyan-lc)))) + `(cfw:face-sunday ((,class (:foreground ,red-hc :background ,red-lc :weight bold)))) + `(cfw:face-title ((,class (:inherit variable-pitch :foreground ,yellow :weight bold :height 2.0)))) + `(cfw:face-today ((,class (:weight bold :background ,solarized-hl :foreground nil)))) + `(cfw:face-today-title ((,class (:background ,yellow-lc :foreground ,yellow-hc :weight bold)))) + `(cfw:face-toolbar ((,class (:background ,solarized-hl :foreground ,solarized-fg)))) + `(cfw:face-toolbar-button-off ((,class (:background ,yellow-lc :foreground ,yellow-hc :weight bold)))) + `(cfw:face-toolbar-button-on ((,class (:background ,yellow-hc :foreground ,yellow-lc :weight bold)))) + + ;; clojure-test-mode + `(clojure-test-failure-face ((t (:foreground ,orange :weight bold :underline t)))) + `(clojure-test-error-face ((t (:foreground ,red :weight bold :underline t)))) + `(clojure-test-success-face ((t (:foreground ,green :weight bold :underline t)))) + + ;; ctable + `(ctbl:face-cell-select ((,class (:background ,blue :foreground ,solarized-bg)))) + `(ctbl:face-continue-bar ((,class (:background ,solarized-hl :foreground ,solarized-bg)))) + `(ctbl:face-row-select ((,class (:background ,cyan :foreground ,solarized-bg)))) + + ;; coffee + `(coffee-mode-class-name ((,class (:foreground ,yellow :weight bold)))) + `(coffee-mode-function-param ((,class (:foreground ,violet :slant italic)))) + + ;; custom + `(custom-variable-tag ((,class (:foreground ,cyan)))) + `(custom-comment-tag ((,class (:foreground ,solarized-comments)))) + `(custom-group-tag ((,class (:foreground ,blue)))) + `(custom-state ((,class (:foreground ,green)))) + + ;; diff + `(diff-added ((,class (:foreground ,green :background ,solarized-bg)))) + `(diff-changed ((,class (:foreground ,yellow :background ,solarized-bg)))) + `(diff-removed ((,class (:foreground ,red :background ,solarized-bg)))) + `(diff-header ((,class (:background ,solarized-bg)))) + `(diff-file-header + ((,class (:background ,solarized-bg :foreground ,solarized-fg :weight bold)))) + + ;; ediff + `(ediff-fine-diff-A ((,class (:background ,orange-lc)))) + `(ediff-fine-diff-B ((,class (:background ,green-lc)))) + `(ediff-even-diff-A ((,class (:background ,solarized-comments :foreground ,solarized-fg-lc )))) + `(ediff-odd-diff-A ((,class (:background ,solarized-comments :foreground ,solarized-fg-hc )))) + `(ediff-even-diff-B ((,class (:background ,solarized-comments :foreground ,solarized-fg-hc )))) + `(ediff-odd-diff-B ((,class (:background ,solarized-comments :foreground ,solarized-fg-lc )))) + + ;; epc + `(epc:face-title ((,class (:foreground ,magenta :weight bold)))) + + ;; eshell + `(eshell-prompt ((,class (:foreground ,yellow :weight bold)))) + `(eshell-ls-archive ((,class (:foreground ,red :weight bold)))) + `(eshell-ls-backup ((,class (:inherit font-lock-comment)))) + `(eshell-ls-clutter ((,class (:inherit font-lock-comment)))) + `(eshell-ls-directory ((,class (:foreground ,blue :weight bold)))) + `(eshell-ls-executable ((,class (:foreground ,red :weight bold)))) + `(eshell-ls-unreadable ((,class (:foreground ,solarized-fg)))) + `(eshell-ls-missing ((,class (:inherit font-lock-warning)))) + `(eshell-ls-product ((,class (:inherit font-lock-doc)))) + `(eshell-ls-special ((,class (:foreground ,yellow :weight bold)))) + `(eshell-ls-symlink ((,class (:foreground ,cyan :weight bold)))) + + ;; fic + `(fic-author-face ((,class (:background ,solarized-bg :foreground ,orange :underline t :slant italic)))) + `(fic-face ((,class (:background ,solarized-bg :foreground ,orange :weight normal :slant italic)))) + + ;; flymake + `(flymake-errline + ((,class (:foreground ,red-hc :background ,red-lc :weight bold :underline t)))) + `(flymake-infoline ((,class (:foreground ,green-hc :background ,green-lc)))) + `(flymake-warnline + ((,class (:foreground ,yellow-hc :background ,yellow-lc :weight bold :underline t)))) + + ;; flycheck + `(flycheck-error-face + ((,class (:foreground ,red-hc :background ,red-lc :weight bold :underline t)))) + `(flycheck-warning-face + ((,class (:foreground ,yellow-hc :background ,yellow-lc :weight bold :underline t)))) + + ;; flyspell + `(flyspell-duplicate ((,class (:foreground ,yellow :weight bold :underline t)))) + `(flyspell-incorrect ((,class (:foreground ,red :weight bold :underline t)))) + + ;; erc + `(erc-action-face ((,class (:inherit erc-default-face)))) + `(erc-bold-face ((,class (:weight bold)))) + `(erc-current-nick-face ((,class (:foreground ,blue :weight bold)))) + `(erc-dangerous-host-face ((,class (:inherit font-lock-warning)))) + `(erc-default-face ((,class (:foreground ,solarized-fg)))) + `(erc-direct-msg-face ((,class (:inherit erc-default)))) + `(erc-error-face ((,class (:inherit font-lock-warning)))) + `(erc-fool-face ((,class (:inherit erc-default)))) + `(erc-highlight-face ((,class (:inherit hover-highlight)))) + `(erc-input-face ((,class (:foreground ,yellow)))) + `(erc-keyword-face ((,class (:foreground ,blue :weight bold)))) + `(erc-nick-default-face ((,class (:foreground ,yellow :weight bold)))) + `(erc-my-nick-face ((,class (:foreground ,red :weight bold)))) + `(erc-nick-msg-face ((,class (:inherit erc-default)))) + `(erc-notice-face ((,class (:foreground ,green)))) + `(erc-pal-face ((,class (:foreground ,orange :weight bold)))) + `(erc-prompt-face ((,class (:foreground ,orange :background ,solarized-bg :weight bold)))) + `(erc-timestamp-face ((,class (:foreground ,green)))) + `(erc-underline-face ((t (:underline t)))) + + ;; git-gutter + `(git-gutter:added ((,class (:background ,green :foreground ,solarized-bg :weight bold)))) + `(git-gutter:deleted ((,class (:background ,red :foreground ,solarized-bg :weight bold)))) + `(git-gutter:modified ((,class (:background ,blue :foreground ,solarized-bg :weight bold)))) + `(git-gutter:unchanged ((,class (:background ,solarized-hl :foreground ,solarized-bg :weight bold)))) + ;; I use the following git-gutter settings along with those faces + ;; (when window-system + ;; (let ((symbol ".")) + ;; (setq git-gutter:added-sign symbol + ;; git-gutter:deleted-sign symbol + ;; git-gutter:modified-sign symbol + ;; git-gutter:unchanged-sign " "))) + + ;; git-gutter-fr + `(git-gutter-fr:added ((,class (:foreground ,green :weight bold)))) + `(git-gutter-fr:deleted ((,class (:foreground ,red :weight bold)))) + `(git-gutter-fr:modified ((,class (:foreground ,blue :weight bold)))) + + ;; guide-key + `(guide-key/highlight-command-face ((,class (:foreground ,blue)))) + `(guide-key/key-face ((,class (:foreground ,solarized-comments)))) + `(guide-key/prefix-command-face ((,class (:foreground ,green)))) + + ;; gnus + `(gnus-group-mail-1-face ((,class (:weight bold :inherit gnus-group-mail-1-empty)))) + `(gnus-group-mail-1-empty-face ((,class (:inherit gnus-group-news-1-empty)))) + `(gnus-group-mail-2-face ((,class (:weight bold :inherit gnus-group-mail-2-empty)))) + `(gnus-group-mail-2-empty-face ((,class (:inherit gnus-group-news-2-empty)))) + `(gnus-group-mail-3-face ((,class (:weight bold :inherit gnus-group-mail-3-empty)))) + `(gnus-group-mail-3-empty-face ((,class (:inherit gnus-group-news-3-empty)))) + `(gnus-group-mail-4-face ((,class (:weight bold :inherit gnus-group-mail-4-empty)))) + `(gnus-group-mail-4-empty-face ((,class (:inherit gnus-group-news-4-empty)))) + `(gnus-group-mail-5-face ((,class (:weight bold :inherit gnus-group-mail-5-empty)))) + `(gnus-group-mail-5-empty-face ((,class (:inherit gnus-group-news-5-empty)))) + `(gnus-group-mail-6-face ((,class (:weight bold :inherit gnus-group-mail-6-empty)))) + `(gnus-group-mail-6-empty-face ((,class (:inherit gnus-group-news-6-empty)))) + `(gnus-group-mail-low-face ((,class (:weight bold :inherit gnus-group-mail-low-empty)))) + `(gnus-group-mail-low-empty-face ((,class (:inherit gnus-group-news-low-empty)))) + `(gnus-group-news-1-face ((,class (:weight bold :inherit gnus-group-news-1-empty)))) + `(gnus-group-news-2-face ((,class (:weight bold :inherit gnus-group-news-2-empty)))) + `(gnus-group-news-3-face ((,class (:weight bold :inherit gnus-group-news-3-empty)))) + `(gnus-group-news-4-face ((,class (:weight bold :inherit gnus-group-news-4-empty)))) + `(gnus-group-news-5-face ((,class (:weight bold :inherit gnus-group-news-5-empty)))) + `(gnus-group-news-6-face ((,class (:weight bold :inherit gnus-group-news-6-empty)))) + `(gnus-group-news-low-face ((,class (:weight bold :inherit gnus-group-news-low-empty)))) + `(gnus-header-content-face ((,class (:inherit message-header-other)))) + `(gnus-header-from-face ((,class (:inherit message-header-from)))) + `(gnus-header-name-face ((,class (:inherit message-header-name)))) + `(gnus-header-newsgroups-face ((,class (:inherit message-header-other)))) + `(gnus-header-subject-face ((,class (:inherit message-header-subject)))) + `(gnus-summary-cancelled-face ((,class (:foreground ,orange)))) + `(gnus-summary-high-ancient-face ((,class (:foreground ,blue)))) + `(gnus-summary-high-read-face ((,class (:foreground ,green :weight bold)))) + `(gnus-summary-high-ticked-face ((,class (:foreground ,orange :weight bold)))) + `(gnus-summary-high-unread-face ((,class (:foreground ,solarized-fg :weight bold)))) + `(gnus-summary-low-ancient-face ((,class (:foreground ,blue)))) + `(gnus-summary-low-read-face ((t (:foreground ,green)))) + `(gnus-summary-low-ticked-face ((,class (:foreground ,orange :weight bold)))) + `(gnus-summary-low-unread-face ((,class (:foreground ,solarized-fg)))) + `(gnus-summary-normal-ancient-face ((,class (:foreground ,blue)))) + `(gnus-summary-normal-read-face ((,class (:foreground ,green)))) + `(gnus-summary-normal-ticked-face ((,class (:foreground ,orange :weight bold)))) + `(gnus-summary-normal-unread-face ((,class (:foreground ,solarized-fg)))) + `(gnus-summary-selected-face ((,class (:foreground ,yellow :weight bold)))) + `(gnus-cite-1-face ((,class (:foreground ,blue)))) + `(gnus-cite-10-face ((,class (:foreground ,yellow)))) + `(gnus-cite-11-face ((,class (:foreground ,yellow)))) + `(gnus-cite-2-face ((,class (:foreground ,blue)))) + `(gnus-cite-3-face ((,class (:foreground ,blue)))) + `(gnus-cite-4-face ((,class (:foreground ,green)))) + `(gnus-cite-5-face ((,class (:foreground ,green)))) + `(gnus-cite-6-face ((,class (:foreground ,green)))) + `(gnus-cite-7-face ((,class (:foreground ,red)))) + `(gnus-cite-8-face ((,class (:foreground ,red)))) + `(gnus-cite-9-face ((,class (:foreground ,red)))) + `(gnus-group-news-1-empty-face ((,class (:foreground ,yellow)))) + `(gnus-group-news-2-empty-face ((,class (:foreground ,green)))) + `(gnus-group-news-3-empty-face ((,class (:foreground ,green)))) + `(gnus-group-news-4-empty-face ((,class (:foreground ,blue)))) + `(gnus-group-news-5-empty-face ((,class (:foreground ,blue)))) + `(gnus-group-news-6-empty-face ((,class (:foreground ,solarized-bg)))) + `(gnus-group-news-low-empty-face ((,class (:foreground ,solarized-bg)))) + `(gnus-signature-face ((,class (:foreground ,yellow)))) + `(gnus-x-face ((,class (:background ,solarized-fg :foreground ,solarized-bg)))) + + ;; helm (these probably needs tweaking) + `(helm-apt-deinstalled ((,class (:foreground ,solarized-comments)))) + `(helm-apt-installed ((,class (:foreground ,green)))) + `(helm-bookmark-directory ((,class (:inherit helm-ff-directory)))) + `(helm-bookmark-file ((,class (:foreground ,solarized-fg)))) + `(helm-bookmark-gnus ((,class (:foreground ,cyan)))) + `(helm-bookmark-info ((,class (:foreground ,green)))) + `(helm-bookmark-man ((,class (:foreground ,violet)))) + `(helm-bookmark-w3m ((,class (:foreground ,yellow)))) + `(helm-bookmarks-su ((,class (:foreground ,orange)))) + `(helm-buffer-not-saved ((,class (:foreground ,orange)))) + `(helm-buffer-saved-out ((,class (:foreground ,red :background ,solarized-bg + :inverse-video t)))) + `(helm-buffer-size ((,class (:foreground ,solarized-comments)))) + `(helm-candidate-number ((,class (:background ,solarized-hl :foreground ,solarized-emph + :bold t)))) + `(helm-ff-directory ((,class (:background ,solarized-bg :foreground ,blue)))) + `(helm-ff-executable ((,class (:foreground ,green)))) + `(helm-ff-file ((,class (:background ,solarized-bg :foreground ,solarized-fg)))) + `(helm-ff-invalid-symlink ((,class (:background ,solarized-bg :foreground ,orange + :slant italic)))) + `(helm-ff-prefix ((,class (:background ,yellow :foreground ,solarized-bg)))) + `(helm-ff-symlink ((,class (:foreground ,cyan)))) + `(helm-grep-file ((,class (:foreground ,cyan :underline t)))) + `(helm-grep-finish ((,class (:foreground ,green)))) + `(helm-grep-lineno ((,class (:foreground ,orange)))) + `(helm-grep-match ((,class (:inherit match)))) + `(helm-grep-running ((,class (:foreground ,red)))) + `(helm-header ((,class (:inherit header-line)))) + `(helm-lisp-completion-info ((,class (:foreground ,solarized-fg)))) + `(helm-lisp-show-completion ((,class (:foreground ,yellow :background ,solarized-hl + :bold t)))) + `(helm-M-x-key ((,class (:foreground ,orange :underline t)))) + `(helm-moccur-buffer ((,class (:foreground ,cyan :underline t)))) + `(helm-match ((,class (:inherit match)))) + `(helm-selection ((,class (:background ,solarized-hl :underline t)))) + `(helm-selection-line ((,class (:background ,solarized-hl :foreground ,solarized-emph + :underline nil)))) + `(helm-separator ((,class (:foreground ,red)))) + `(helm-source-header ((,class (:background ,blue-lc :foreground ,solarized-bg + :underline nil)))) + `(helm-time-zone-current ((,class (:foreground ,green)))) + `(helm-time-zone-home ((,class (:foreground ,red)))) + `(helm-visible-mark ((,class (:background ,solarized-bg :foreground ,magenta :bold t)))) + + ;; hi-lock-mode + `(hi-yellow ((,class (:foreground ,yellow-lc :background ,yellow-hc)))) + `(hi-pink ((,class (:foreground ,magenta-lc :background ,magenta-hc)))) + `(hi-green ((,class (:foreground ,green-lc :background ,green-hc)))) + `(hi-blue ((,class (:foreground ,blue-lc :background ,blue-hc)))) + `(hi-black-b ((,class (:foreground ,solarized-emph :background ,solarized-bg :weight bold)))) + `(hi-blue-b ((,class (:foreground ,blue-lc :weight bold)))) + `(hi-green-b ((,class (:foreground ,green-lc :weight bold)))) + `(hi-red-b ((,class (:foreground ,red :weight bold)))) + `(hi-black-hb ((,class (:foreground ,solarized-emph :background ,solarized-bg :weight bold)))) + + ;; highlight-changes + `(highlight-changes ((,class (:foreground ,orange)))) + `(highlight-changes-delete ((,class (:foreground ,red :underline t)))) + + ;; hl-line-mode + `(hl-line ((,class (:background ,solarized-hl)))) + `(hl-line-face ((,class (:background ,solarized-hl)))) + + ;; ido-mode + `(ido-first-match ((,class (:foreground ,green :weight bold)))) + `(ido-only-match ((,class (:foreground ,solarized-bg :background ,green :weight bold)))) + `(ido-subdir ((,class (:foreground ,blue)))) + `(ido-incomplete-regexp ((,class (:foreground ,red :weight bold )))) + `(ido-indicator ((,class (:background ,red :foreground ,solarized-bg :width condensed)))) + `(ido-virtual ((,class (:foreground ,cyan)))) + + `(jabber-activity-face ((,class (:weight bold :foreground ,red)))) + `(jabber-activity-personal-face ((,class (:weight bold :foreground ,blue)))) + `(jabber-chat-error ((,class (:weight bold :foreground ,red)))) + `(jabber-chat-prompt-foreign ((,class (:weight bold :foreground ,red)))) + `(jabber-chat-prompt-local ((,class (:weight bold :foreground ,blue)))) + `(jabber-chat-prompt-system ((,class (:weight bold :foreground ,green)))) + `(jabber-chat-text-foreign ((,class (:foreground ,base1)))) + `(jabber-chat-text-local ((,class (:foreground ,base0)))) + `(jabber-chat-rare-time-face ((,class (:underline t :foreground ,green)))) + `(jabber-roster-user-away ((,class (:slant italic :foreground ,green)))) + `(jabber-roster-user-chatty ((,class (:weight bold :foreground ,orange)))) + `(jabber-roster-user-dnd ((,class (:slant italic :foreground ,red)))) + `(jabber-roster-user-error ((,class (:weight light :slant italic :foreground ,red)))) + `(jabber-roster-user-offline ((,class (:foreground ,base01)))) + `(jabber-roster-user-online ((,class (:weight bold :foreground ,blue)))) + `(jabber-roster-user-xa ((,class (:slant italic :foreground ,magenta)))) + + ;; js2-mode colors + `(js2-error ((,class (:foreground ,red)))) + `(js2-external-variable ((,class (:foreground ,orange)))) + `(js2-function-param ((,class (:foreground ,green)))) + `(js2-instance-member ((,class (:foreground ,magenta)))) + `(js2-jsdoc-html-tag-delimiter ((,class (:foreground ,cyan)))) + `(js2-jsdoc-html-tag-name ((,class (:foreground ,orange)))) + `(js2-jsdoc-tag ((,class (:foreground ,cyan)))) + `(js2-jsdoc-type ((,class (:foreground ,blue)))) + `(js2-jsdoc-value ((,class (:foreground ,violet)))) + `(js2-magic-paren ((,class (:underline t)))) + `(js2-private-function-call ((,class (:foreground ,yellow)))) + `(js2-private-member ((,class (:foreground ,blue)))) + `(js2-warning ((,class (:underline ,orange)))) + + ;; jedi + `(jedi:highlight-function-argument ((,class (:inherit bold)))) + + ;; linum-mode + `(linum ((,class (:foreground ,solarized-fg :background ,solarized-bg)))) + + ;; magit + `(magit-section-title ((,class (:foreground ,yellow :weight bold)))) + `(magit-branch ((,class (:foreground ,orange :weight bold)))) + `(magit-item-highlight ((,class (:background ,solarized-hl)))) + `(magit-log-author ((,class (:foreground ,cyan)))) + `(magit-log-graph ((,class (:foreground ,solarized-comments)))) + `(magit-log-head-label-bisect-bad ((,class (:background ,red-hc :foreground ,red-lc :box 1)))) + `(magit-log-head-label-bisect-good ((,class (:background ,green-hc :foreground ,green-lc + :box 1)))) + `(magit-log-head-label-default ((,class (:background ,solarized-hl :box 1)))) + `(magit-log-head-label-local ((,class (:background ,blue-lc :foreground ,blue-hc :box 1)))) + `(magit-log-head-label-patches ((,class (:background ,red-lc :foreground ,red-hc :box 1)))) + `(magit-log-head-label-remote ((,class (:background ,green-lc :foreground ,green-hc :box 1)))) + `(magit-log-head-label-tags ((,class (:background ,yellow-lc :foreground ,yellow-hc :box 1)))) + `(magit-log-sha1 ((,class (:foreground ,yellow)))) + + ;; message-mode + `(message-cited-text ((,class (:foreground ,solarized-comments)))) + `(message-header-name ((,class (:foreground ,green)))) + `(message-header-other ((,class (:foreground ,green)))) + `(message-header-to ((,class (:foreground ,yellow :weight bold)))) + `(message-header-cc ((,class (:foreground ,orange :weight bold)))) + `(message-header-newsgroups ((,class (:foreground ,yellow :weight bold)))) + `(message-header-subject ((,class (:foreground ,orange)))) + `(message-header-xheader ((,class (:foreground ,cyan)))) + `(message-mml ((,class (:foreground ,yellow :weight bold)))) + `(message-separator ((,class (:foreground ,solarized-comments :slant italic)))) + + ;; mew + `(mew-face-header-subject ((,class (:foreground ,orange)))) + `(mew-face-header-from ((,class (:foreground ,yellow)))) + `(mew-face-header-date ((,class (:foreground ,green)))) + `(mew-face-header-to ((,class (:foreground ,red)))) + `(mew-face-header-key ((,class (:foreground ,green)))) + `(mew-face-header-private ((,class (:foreground ,green)))) + `(mew-face-header-important ((,class (:foreground ,blue)))) + `(mew-face-header-marginal ((,class (:foreground ,solarized-fg :weight bold)))) + `(mew-face-header-warning ((,class (:foreground ,red)))) + `(mew-face-header-xmew ((,class (:foreground ,green)))) + `(mew-face-header-xmew-bad ((,class (:foreground ,red)))) + `(mew-face-body-url ((,class (:foreground ,orange)))) + `(mew-face-body-comment ((,class (:foreground ,solarized-fg :slant italic)))) + `(mew-face-body-cite1 ((,class (:foreground ,green)))) + `(mew-face-body-cite2 ((,class (:foreground ,blue)))) + `(mew-face-body-cite3 ((,class (:foreground ,orange)))) + `(mew-face-body-cite4 ((,class (:foreground ,yellow)))) + `(mew-face-body-cite5 ((,class (:foreground ,red)))) + `(mew-face-mark-review ((,class (:foreground ,blue)))) + `(mew-face-mark-escape ((,class (:foreground ,green)))) + `(mew-face-mark-delete ((,class (:foreground ,red)))) + `(mew-face-mark-unlink ((,class (:foreground ,yellow)))) + `(mew-face-mark-refile ((,class (:foreground ,green)))) + `(mew-face-mark-unread ((,class (:foreground ,red)))) + `(mew-face-eof-message ((,class (:foreground ,green)))) + `(mew-face-eof-part ((,class (:foreground ,yellow)))) + + ;; mingus + `(mingus-directory-face ((,class (:foreground ,blue)))) + `(mingus-pausing-face ((,class (:foreground ,magenta)))) + `(mingus-playing-face ((,class (:foreground ,cyan)))) + `(mingus-playlist-face ((,class (:foreground ,cyan )))) + `(mingus-song-file-face ((,class (:foreground ,yellow)))) + `(mingus-stopped-face ((,class (:foreground ,red)))) + + ;; moccur + `(moccur-current-line-face ((,class (:underline t)))) + `(moccur-edit-done-face ((,class + (:foreground ,solarized-comments + :background ,solarized-bg + :slant italic)))) + `(moccur-edit-face + ((,class (:background ,yellow :foreground ,solarized-bg)))) + `(moccur-edit-file-face ((,class (:background ,solarized-hl)))) + `(moccur-edit-reject-face ((,class (:foreground ,red)))) + `(moccur-face ((,class (:background ,solarized-hl :foreground ,solarized-emph + :weight bold)))) + `(search-buffers-face ((,class (:background ,solarized-hl :foreground ,solarized-emph + :weight bold)))) + `(search-buffers-header-face ((,class (:background ,solarized-hl :foreground ,yellow + :weight bold)))) + + ;; mu4e + `(mu4e-cited-1-face ((,class (:foreground ,green :slant italic :weight normal)))) + `(mu4e-cited-2-face ((,class (:foreground ,blue :slant italic :weight normal)))) + `(mu4e-cited-3-face ((,class (:foreground ,orange :slant italic :weight normal)))) + `(mu4e-cited-4-face ((,class (:foreground ,yellow :slant italic :weight normal)))) + `(mu4e-cited-5-face ((,class (:foreground ,cyan :slant italic :weight normal)))) + `(mu4e-cited-6-face ((,class (:foreground ,green :slant italic :weight normal)))) + `(mu4e-cited-7-face ((,class (:foreground ,blue :slant italic :weight normal)))) + `(mu4e-flagged-face ((,class (:foreground ,magenta :weight bold)))) + `(mu4e-view-url-number-face ((,class (:foreground ,orange :weight bold)))) + `(mu4e-warning-face ((,class (:foreground ,red :slant normal :weight bold)))) + + ;; mumamo + `(mumamo-background-chunk-submode1 ((,class (:background ,solarized-hl)))) + + ;; nav + `(nav-face-heading ((,class (:foreground ,yellow)))) + `(nav-face-button-num ((,class (:foreground ,cyan)))) + `(nav-face-dir ((,class (:foreground ,green)))) + `(nav-face-hdir ((,class (:foreground ,red)))) + `(nav-face-file ((,class (:foreground ,solarized-fg)))) + `(nav-face-hfile ((,class (:foreground ,red)))) + + ;; nav-flash + `(nav-flash-face ((,class (:background ,solarized-hl)))) + + ;; org-mode + `(org-agenda-structure + ((,class (:inherit font-lock-comment-face :foreground ,magenta :inverse-video t)))) + `(org-agenda-date + ((,class (:foreground ,solarized-fg :background ,solarized-hl :weight bold + :box (:line-width 4 :color ,solarized-hl) ))) t) + `(org-agenda-date-weekend ((,class (:inherit org-agenda-date :slant italic))) t) + `(org-agenda-date-today + ((,class (:inherit org-agenda-date :slant italic underline: t))) t) + `(org-agenda-done ((,class (:foreground ,green))) t) + `(org-archived ((,class (:foreground ,solarized-comments :weight normal)))) + `(org-block ((,class (:foreground ,solarized-comments)))) + `(org-block-begin-line ((,class (:foreground ,solarized-comments :slant italic)))) + `(org-checkbox ((,class (:background ,solarized-bg :foreground ,solarized-fg + :box (:line-width 1 :style released-button))))) + `(org-code ((,class (:foreground ,solarized-comments)))) + `(org-date ((,class (:foreground ,blue :underline t)))) + `(org-done ((,class (:weight bold :foreground ,green)))) + `(org-ellipsis ((,class (:foreground ,solarized-comments)))) + `(org-formula ((,class (:foreground ,yellow)))) + `(org-headline-done ((,class (:foreground ,green)))) + `(org-hide ((,class (:foreground ,solarized-bg)))) + `(org-level-1 ((,class (:foreground ,orange)))) + `(org-level-2 ((,class (:foreground ,green)))) + `(org-level-3 ((,class (:foreground ,blue)))) + `(org-level-4 ((,class (:foreground ,yellow)))) + `(org-level-5 ((,class (:foreground ,cyan)))) + `(org-level-6 ((,class (:foreground ,green)))) + `(org-level-7 ((,class (:foreground ,red)))) + `(org-level-8 ((,class (:foreground ,blue)))) + `(org-link ((,class (:foreground ,yellow :underline t)))) + `(org-sexp-date ((,class (:foreground ,violet)))) + `(org-scheduled ((,class (:foreground ,green)))) + `(org-scheduled-previously ((,class (:foreground ,yellow)))) + `(org-scheduled-today ((,class (:foreground ,blue :weight normal)))) + `(org-special-keyword ((,class (:foreground ,solarized-comments :weight bold)))) + `(org-table ((,class (:foreground ,green)))) + `(org-tag ((,class (:weight bold)))) + `(org-time-grid ((,class (:foreground ,cyan)))) + `(org-todo ((,class (:foreground ,red :weight bold)))) + `(org-upcoming-deadline ((,class (:foreground ,yellow :weight normal :underline nil)))) + `(org-warning ((,class (:foreground ,orange :weight normal :underline nil)))) + ;; org-habit (clear=blue, ready=green, alert=yellow, overdue=red. future=lower contrast) + `(org-habit-clear-face ((,class (:background ,blue-lc :foreground ,blue-hc)))) + `(org-habit-clear-future-face ((,class (:background ,blue-lc)))) + `(org-habit-ready-face ((,class (:background ,green-lc :foreground ,green)))) + `(org-habit-ready-future-face ((,class (:background ,green-lc)))) + `(org-habit-alert-face ((,class (:background ,yellow :foreground ,yellow-lc)))) + `(org-habit-alert-future-face ((,class (:background ,yellow-lc)))) + `(org-habit-overdue-face ((,class (:background ,red :foreground ,red-lc)))) + `(org-habit-overdue-future-face ((,class (:background ,red-lc)))) + ;; latest additions + `(org-agenda-dimmed-todo-face ((,class (:foreground ,solarized-comments)))) + `(org-agenda-restriction-lock ((,class (:background ,yellow)))) + `(org-clock-overlay ((,class (:background ,yellow)))) + `(org-column ((,class (:background ,solarized-hl :strike-through nil + :underline nil :slant normal :weight normal)))) + `(org-column-title ((,class (:background ,solarized-hl :underline t :weight bold)))) + `(org-date-selected ((,class (:foreground ,red :inverse-video t)))) + `(org-document-info ((,class (:foreground ,solarized-fg)))) + `(org-document-title ((,class (:foreground ,solarized-emph :weight bold :height 1.44)))) + `(org-drawer ((,class (:foreground ,cyan)))) + `(org-footnote ((,class (:foreground ,magenta :underline t)))) + `(org-latex-and-export-specials ((,class (:foreground ,orange)))) + `(org-mode-line-clock-overrun ((,class (:inherit modeline :background ,red)))) + + ;; outline + `(outline-8 ((,class (:inherit default)))) + `(outline-7 ((,class (:inherit outline-8 :height 1.0)))) + `(outline-6 ((,class (:inherit outline-7 :height 1.0)))) + `(outline-5 ((,class (:inherit outline-6 :height 1.0)))) + `(outline-4 ((,class (:inherit outline-5 :height 1.0)))) + `(outline-3 ((,class (:inherit outline-4 :height 1.0)))) + `(outline-2 ((,class (:inherit outline-3 :height 1.0)))) + `(outline-1 ((,class (:inherit outline-2 :height 1.0)))) + + ;; pretty-mode + `(pretty-mode-symbol-face ((,class (:foreground ,green)))) + + ;; popup + `(popup-face ((,class (:background ,solarized-hl :foreground ,solarized-fg)))) + `(popup-isearch-match ((,class (:background ,yellow :foreground ,solarized-bg)))) + `(popup-menu-face ((,class (:background ,solarized-hl :foreground ,solarized-fg)))) + `(popup-menu-mouse-face ((,class (:background ,blue :foreground ,solarized-fg)))) + `(popup-menu-selection-face ((,class (:background ,magenta :foreground ,solarized-bg)))) + `(popup-scroll-bar-background-face ((,class (:background ,solarized-comments)))) + `(popup-scroll-bar-foreground-face ((,class (:background ,solarized-emph)))) + `(popup-tip-face ((,class (:background ,solarized-hl :foreground ,solarized-fg)))) + + ;; rainbow-delimiters + `(rainbow-delimiters-depth-1-face ((,class (:foreground ,cyan)))) + `(rainbow-delimiters-depth-2-face ((,class (:foreground ,yellow)))) + `(rainbow-delimiters-depth-3-face ((,class (:foreground ,blue)))) + `(rainbow-delimiters-depth-4-face ((,class (:foreground ,orange)))) + `(rainbow-delimiters-depth-5-face ((,class (:foreground ,green)))) + `(rainbow-delimiters-depth-6-face ((,class (:foreground ,yellow)))) + `(rainbow-delimiters-depth-7-face ((,class (:foreground ,blue)))) + `(rainbow-delimiters-depth-8-face ((,class (:foreground ,orange)))) + `(rainbow-delimiters-depth-9-face ((,class (:foreground ,green)))) + `(rainbow-delimiters-depth-10-face ((,class (:foreground ,yellow)))) + `(rainbow-delimiters-depth-11-face ((,class (:foreground ,blue)))) + `(rainbow-delimiters-depth-12-face ((,class (:foreground ,orange)))) + `(rainbow-delimiters-unmatched-face + ((,class (:foreground ,solarized-fg :background ,solarized-bg :inverse-video t)))) + + ;; rst-mode + `(rst-level-1-face ((,class (:background ,yellow :foreground ,solarized-bg)))) + `(rst-level-2-face ((,class (:background ,cyan :foreground ,solarized-bg)))) + `(rst-level-3-face ((,class (:background ,blue :foreground ,solarized-bg)))) + `(rst-level-4-face ((,class (:background ,violet :foreground ,solarized-bg)))) + `(rst-level-5-face ((,class (:background ,magenta :foreground ,solarized-bg)))) + `(rst-level-6-face ((,class (:background ,red :foreground ,solarized-bg)))) + + ;; rpm-mode + `(rpm-spec-dir-face ((,class (:foreground ,green)))) + `(rpm-spec-doc-face ((,class (:foreground ,green)))) + `(rpm-spec-ghost-face ((,class (:foreground ,red)))) + `(rpm-spec-macro-face ((,class (:foreground ,yellow)))) + `(rpm-spec-obsolete-tag-face ((,class (:foreground ,red)))) + `(rpm-spec-package-face ((,class (:foreground ,red)))) + `(rpm-spec-section-face ((,class (:foreground ,yellow)))) + `(rpm-spec-tag-face ((,class (:foreground ,blue)))) + `(rpm-spec-var-face ((,class (:foreground ,red)))) + + ;; sh-mode + `(sh-quoted-exec ((,class (:foreground ,violet :weight bold)))) + `(sh-escaped-newline ((,class (:foreground ,yellow :weight bold)))) + `(sh-heredoc ((,class (:foreground ,yellow :weight bold)))) + + ;; smartparens + `(sp-pair-overlay-face ((,class (:background ,solarized-hl)))) + `(sp-wrap-overlay-face ((,class (:background ,solarized-hl)))) + `(sp-wrap-tag-overlay-face ((,class (:background ,solarized-hl)))) + + ;; show-paren + `(show-paren-match + ((,class (:foreground ,cyan :background ,solarized-bg :weight normal :inverse-video t)))) + `(show-paren-mismatch + ((,class (:foreground ,red :background ,solarized-bg :weight normal :inverse-video t)))) + + ;; mic-paren + `(paren-face-match + ((,class (:foreground ,cyan :background ,solarized-bg :weight normal :inverse-video t)))) + `(paren-face-mismatch + ((,class (:foreground ,red :background ,solarized-bg :weight normal :inverse-video t)))) + `(paren-face-no-match + ((,class (:foreground ,red :background ,solarized-bg :weight normal :inverse-video t)))) + + ;; SLIME + `(slime-repl-inputed-output-face ((,class (:foreground ,red)))) + + ;; speedbar + `(speedbar-button-face ((,class (:inherit variable-pitch :foreground ,solarized-comments)))) + `(speedbar-directory-face ((,class (:inherit variable-pitch :foreground ,blue)))) + `(speedbar-file-face ((,class (:inherit variable-pitch :foreground ,solarized-fg)))) + `(speedbar-highlight-face ((,class (:inherit variable-pitch :background ,solarized-hl)))) + `(speedbar-selected-face ((,class (:inherit variable-pitch :foreground ,yellow :underline t)))) + `(speedbar-separator-face ((,class (:inherit variable-pitch + :background ,blue :foreground ,solarized-bg + :overline ,cyan-lc)))) + `(speedbar-tag-face ((,class (:inherit variable-pitch :foreground ,green)))) + + ;; sunrise commander headings + `(sr-active-path-face ((,class (:background ,blue :foreground ,solarized-bg + :height 100 :weight bold)))) + `(sr-editing-path-face ((,class (:background ,yellow :foreground ,solarized-bg + :weight bold :height 100)))) + `(sr-highlight-path-face ((,class (:background ,green :foreground ,solarized-bg + :weight bold :height 100)))) + `(sr-passive-path-face ((,class (:background ,solarized-comments :foreground ,solarized-bg + :weight bold :height 100)))) + ;; sunrise commander marked + `(sr-marked-dir-face ((,class (:inherit dired-marked)))) + `(sr-marked-file-face ((,class (:inherit dired-marked)))) + `(sr-alt-marked-dir-face ((,class (:background ,magenta :foreground ,solarized-bg + :weight bold)))) + `(sr-alt-marked-file-face ((,class (:background ,magenta :foreground ,solarized-bg + :weight bold)))) + ;; sunrise commander fstat + `(sr-directory-face ((,class (:inherit dired-directory :weight normal)))) + `(sr-symlink-directory-face ((,class (:inherit dired-directory :slant italic :weight normal)))) + `(sr-symlink-face ((,class (:inherit dired-symlink :slant italic :weight normal)))) + `(sr-broken-link-face ((,class (:inherit dired-warning :slant italic :weight normal)))) + ;; sunrise commander file types + `(sr-compressed-face ((,class (:foreground ,solarized-fg)))) + `(sr-encrypted-face ((,class (:foreground ,solarized-fg)))) + `(sr-log-face ((,class (:foreground ,solarized-fg)))) + `(sr-packaged-face ((,class (:foreground ,solarized-fg)))) + `(sr-html-face ((,class (:foreground ,solarized-fg)))) + `(sr-xml-face ((,class (:foreground ,solarized-fg)))) + ;; sunrise commander misc + `(sr-clex-hotchar-face ((,class (:background ,red :foreground ,solarized-bg :weight bold)))) + + ;; table + `(table-cell ((,class (:foreground ,solarized-fg :background ,solarized-hl)))) + + ;; term + `(term-color-black ((t (:foreground ,base03 + :background ,base02)))) + `(term-color-red ((t (:foreground ,red + :background ,red-d)))) + `(term-color-green ((t (:foreground ,green + :background ,green-d)))) + `(term-color-yellow ((t (:foreground ,yellow + :background ,yellow-d)))) + `(term-color-blue ((t (:foreground ,blue + :background ,blue-d)))) + `(term-color-magenta ((t (:foreground ,magenta + :background ,magenta-d)))) + `(term-color-cyan ((t (:foreground ,cyan + :background ,cyan-d)))) + `(term-color-white ((t (:foreground ,base00 + :background ,base0)))) + '(term-default-fg-color ((t (:inherit term-color-white)))) + '(term-default-bg-color ((t (:inherit term-color-black)))) + + + ;; tooltip. (NOTE: This setting has no effect on the os widgets for me + ;; zencoding uses this) + `(tooltip ((,class (:background ,yellow-lc :foreground ,yellow-hc + :inherit variable-pitch)))) + + ;; tuareg + `(tuareg-font-lock-governing-face ((,class (:foreground ,magenta :weight bold)))) + `(tuareg-font-lock-multistage-face ((,class (:foreground ,blue :background ,solarized-hl :weight bold)))) + `(tuareg-font-lock-operator-face ((,class (:foreground ,solarized-emph)))) + `(tuareg-font-lock-error-face ((,class (:foreground ,yellow :background ,red :weight bold)))) + `(tuareg-font-lock-interactive-output-face ((,class (:foreground ,cyan)))) + `(tuareg-font-lock-interactive-error-face ((,class (:foreground ,red)))) + + ;; undo-tree + `(undo-tree-visualizer-default-face + ((,class (:foreground ,solarized-comments :background ,solarized-bg)))) + `(undo-tree-visualizer-unmodified-face ((,class (:foreground ,green)))) + `(undo-tree-visualizer-current-face ((,class (:foreground ,blue :inverse-video t)))) + `(undo-tree-visualizer-active-branch-face + ((,class (:foreground ,solarized-emph :background ,solarized-bg :weight bold)))) + `(undo-tree-visualizer-register-face ((,class (:foreground ,yellow)))) + + ;; volatile highlights + `(vhl/default-face ((,class (:background ,green-lc :foreground ,green-hc)))) + + ;; w3m + `(w3m-anchor ((,class (:inherit link)))) + `(w3m-arrived-anchor ((,class (:inherit link-visited)))) + `(w3m-form ((,class (:background ,solarized-bg :foreground ,solarized-fg)))) + `(w3m-header-line-location-title ((,class (:background ,solarized-hl :foreground ,yellow)))) + `(w3m-header-line-location-content ((,class (:background ,solarized-hl :foreground ,solarized-fg)))) + `(w3m-bold ((,class (:foreground ,solarized-emph :weight bold)))) + `(w3m-image-anchor ((,class (:background ,solarized-bg :foreground ,cyan :inherit link)))) + `(w3m-image ((,class (:background ,solarized-bg :foreground ,cyan)))) + `(w3m-lnum-minibuffer-prompt ((,class (:foreground ,solarized-emph)))) + `(w3m-lnum-match ((,class (:background ,solarized-hl)))) + `(w3m-lnum ((,class (:underline nil :bold nil :foreground ,red)))) + `(w3m-session-select ((,class (:foreground ,solarized-fg)))) + `(w3m-session-selected ((,class (:foreground ,solarized-emph :bold t :underline t)))) + `(w3m-tab-background ((,class (:background ,solarized-bg :foreground ,solarized-fg)))) + `(w3m-tab-selected-background ((,class (:background ,solarized-bg :foreground ,solarized-fg)))) + `(w3m-tab-mouse ((,class (:background ,solarized-hl :foreground ,yellow)))) + `(w3m-tab-selected ((,class (:background ,solarized-hl :foreground ,solarized-emph :bold t)))) + `(w3m-tab-unselected ((,class (:background ,solarized-hl :foreground ,solarized-fg)))) + `(w3m-tab-selected-retrieving ((,class (:background ,solarized-hl :foreground ,red)))) + `(w3m-tab-unselected-retrieving ((,class (:background ,solarized-hl :foreground ,orange)))) + `(w3m-tab-unselected-unseen ((,class (:background ,solarized-hl :foreground ,violet)))) + + ;; web-mode + `(web-mode-builtin-face ((,class (:foreground ,red)))) + `(web-mode-comment-face ((,class (:foreground ,solarized-comments)))) + `(web-mode-constant-face ((,class (:foreground ,blue :weight bold)))) + `(web-mode-css-at-rule-face ((,class (:foreground ,violet :slant italic)))) + `(web-mode-css-prop-face ((,class (:foreground ,violet)))) + `(web-mode-css-pseudo-class-face ((,class (:foreground ,green :slant italic)))) + `(web-mode-css-rule-face ((,class (:foreground ,blue)))) + `(web-mode-doctype-face ((,class (:foreground ,solarized-comments + :slant italic :weight bold)))) + `(web-mode-folded-face ((,class (:underline t)))) + `(web-mode-function-name-face ((,class (:foreground ,blue)))) + `(web-mode-html-attr-name-face ((,class (:foreground ,blue :slant normal)))) + `(web-mode-html-attr-value-face ((,class (:foreground ,cyan :slant italic)))) + `(web-mode-html-tag-face ((,class (:foreground ,green)))) + `(web-mode-keyword-face ((,class (:foreground ,yellow :weight bold)))) + `(web-mode-preprocessor-face ((,class (:foreground ,yellow :slant italic :weight bold)))) + `(web-mode-string-face ((,class (:foreground ,cyan)))) + `(web-mode-type-face ((,class (:foreground ,yellow)))) + `(web-mode-variable-name-face ((,class (:foreground ,blue)))) + + ;; whitespace-mode + `(whitespace-space ((,class (:background ,solarized-bg :foreground ,yellow-lc + :inverse-video t)))) + `(whitespace-hspace ((,class (:background ,solarized-bg :foreground ,red-lc + :inverse-video t)))) + `(whitespace-tab ((,class (:background ,solarized-bg :foreground ,orange-lc + :inverse-video t)))) + `(whitespace-newline ((,class (:foreground ,solarized-comments)))) + `(whitespace-trailing ((,class (:foreground ,blue-lc :background ,solarized-bg + :inverse-video t)))) + ; removing inverse video on this + `(whitespace-line ((,class (:background ,solarized-bg :foreground ,magenta + :inverse-video nil)))) + `(whitespace-space-before-tab ((,class (:background ,solarized-bg :foreground ,green-lc + :inverse-video t)))) + `(whitespace-indentation ((,class (:background ,solarized-bg :foreground ,magenta-lc + :inverse-video t)))) + `(whitespace-empty ((,class (:background ,solarized-fg :foreground ,red-lc :inverse-video t)))) + `(whitespace-space-after-tab ((,class (:background ,solarized-bg :foreground ,violet-lc + :inverse-video t)))) + + ;; wanderlust + `(wl-highlight-folder-few-face ((,class (:foreground ,red)))) + `(wl-highlight-folder-many-face ((,class (:foreground ,red)))) + `(wl-highlight-folder-path-face ((,class (:foreground ,orange)))) + `(wl-highlight-folder-unread-face ((,class (:foreground ,blue)))) + `(wl-highlight-folder-zero-face ((,class (:foreground ,solarized-fg)))) + `(wl-highlight-folder-unknown-face ((,class (:foreground ,blue)))) + `(wl-highlight-message-citation-header ((,class (:foreground ,red)))) + `(wl-highlight-message-cited-text-1 ((,class (:foreground ,red)))) + `(wl-highlight-message-cited-text-2 ((,class (:foreground ,green)))) + `(wl-highlight-message-cited-text-3 ((,class (:foreground ,blue)))) + `(wl-highlight-message-cited-text-4 ((,class (:foreground ,blue)))) + `(wl-highlight-message-header-contents-face ((,class (:foreground ,green)))) + `(wl-highlight-message-headers-face ((,class (:foreground ,red)))) + `(wl-highlight-message-important-header-contents ((,class (:foreground ,green)))) + `(wl-highlight-message-header-contents ((,class (:foreground ,green)))) + `(wl-highlight-message-important-header-contents2 ((,class (:foreground ,green)))) + `(wl-highlight-message-signature ((,class (:foreground ,green)))) + `(wl-highlight-message-unimportant-header-contents ((,class (:foreground ,solarized-fg)))) + `(wl-highlight-summary-answered-face ((,class (:foreground ,blue)))) + `(wl-highlight-summary-disposed-face ((,class (:foreground ,solarized-fg + :slant italic)))) + `(wl-highlight-summary-new-face ((,class (:foreground ,blue)))) + `(wl-highlight-summary-normal-face ((,class (:foreground ,solarized-fg)))) + `(wl-highlight-summary-thread-top-face ((,class (:foreground ,yellow)))) + `(wl-highlight-thread-indent-face ((,class (:foreground ,magenta)))) + `(wl-highlight-summary-refiled-face ((,class (:foreground ,solarized-fg)))) + `(wl-highlight-summary-displaying-face ((,class (:underline t :weight bold)))) + + ;; which-func-mode + `(which-func ((,class (:foreground ,green)))) + + ;; window-number-mode + `(window-number-face ((,class (:foreground ,green)))) + + ;; yascroll + `(yascroll:thumb-text-area + ((,class (:foreground ,solarized-comments :background ,solarized-comments)))) + `(yascroll:thumb-fringe + ((,class (:foreground ,solarized-comments :background ,solarized-comments)))) + + ;; zencoding + `(zencoding-preview-input ((,class (:background ,solarized-hl :box ,solarized-emph))))) + + + (custom-theme-set-variables + theme-name + `(ansi-color-names-vector [,solarized-bg ,red ,green ,yellow + ,blue ,magenta ,cyan ,solarized-fg]) + ;; fill-column-indicator + `(fci-rule-color ,solarized-hl) + + ;; highlight-changes + `(highlight-changes-colors '(,magenta ,violet)) + + ;; highlight-tail + `(highlight-tail-colors + '((,solarized-hl . 0)(,green-lc . 20)(,cyan-lc . 30)(,blue-lc . 50) + (,yellow-lc . 60)(,orange-lc . 70)(,magenta-lc . 85)(,solarized-hl . 100))) + + `(vc-annotate-color-map + '((20 . ,red) + (40 . "#CF4F1F") + (60 . "#C26C0F") + (80 . ,yellow) + (100 . "#AB8C00") + (120 . "#A18F00") + (140 . "#989200") + (160 . "#8E9500") + (180 . ,green) + (200 . "#729A1E") + (220 . "#609C3C") + (240 . "#4E9D5B") + (260 . "#3C9F79") + (280 . ,cyan) + (300 . "#299BA6") + (320 . "#2896B5") + (340 . "#2790C3") + (360 . ,blue))) + `(vc-annotate-very-old-color nil) + `(vc-annotate-background nil)) + + ;; call chained theme function + (when childtheme (funcall childtheme)))) + +;;;###autoload +(when (and (boundp 'custom-theme-load-path) load-file-name) + (add-to-list 'custom-theme-load-path + (file-name-as-directory (file-name-directory load-file-name)))) + +;; Local Variables: +;; no-byte-compile: t +;; End: + +(provide 'solarized) + +;;; solarized.el ends here diff --git a/emacs/sql-complete.el b/emacs/sql-complete.el new file mode 100644 index 0000000..13765bc --- /dev/null +++ b/emacs/sql-complete.el @@ -0,0 +1,105 @@ +;;; sql-complete.el --- provide completion for tables and columns + +;; Copyright (C) 2001 Free Software Foundation, Inc. + +;; Author: Alex Schroeder <alex@gnu.org> +;; Maintainer: Alex Schroeder <alex@gnu.org> +;; Version: 0.0.1 +;; Keywords: comm languages processes + +;; This file is NOT part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Trying to provide a framework for completion that will eventually +;; make it into sql.el. + + + +;;; Code: + +(require 'sql) + +(defcustom sql-oracle-data-dictionary + "select '(\"'||table_name||'\" \"'||column_name||'\")' + from user_tab_columns + order by table_name;" + "SQL Statement to determine all tables and columns." + :group 'SQL + :type 'string) + +;; backends + +(defun sql-data-dictionary (statement) + "Return table and columns from the Oracle Data Dictionary using SQL. +STATEMENT must be a SQL statement that returns the data dictionary +one column per line. Each line must look like this: + +\(\"table-name\" \"column-name\") + +Any lines not looking like this will be skipped to allow for column +headers and other fancy markup. + +This currently depends very much on a good `comint-prompt-regexp'." + (when (null sql-buffer) + (error "No SQLi buffer available")) + (save-excursion + (set-buffer sql-buffer) + (let (result end) + (comint-simple-send sql-buffer statement) + (comint-previous-prompt 1) + (while (= 0 (forward-line 1)) + (message "%S" (point)) + (when (looking-at "^(.*)$") + (let* ((entry (car (read-from-string (match-string 0)))) + (table (car entry)) + (column (cadr entry)) + (item (cdr (assoc table result)))) + (if item + (nconc item (list column)) + (setq result (append (list entry) result)))))) + result))) + +;; framework + +(defvar sql-data-dictionary nil + "The data dictionary to use for completion. +Each element of the list has the form +\(TABLE COLUMN1 COLUMN2 ...)") + +(defun sql-oracle-data-dictionary () + (interactive) + ;; FIXME No cleanup + (setq sql-data-dictionary + (sql-data-dictionary sql-oracle-data-dictionary))) + +(defun sql-complete () + (interactive) + (let ((completions (apply 'append sql-data-dictionary))) + (comint-dynamic-simple-complete + (comint-word "A-Za-z_") + completions))) + +(defun sql-complete-table () + (interactive) + (let ((completions (mapcar 'car sql-data-dictionary))) + (comint-dynamic-simple-complete + (comint-word "A-Za-z_") + completions))) + +;;; sql-complete.el ends here diff --git a/emacs/sunrise-commander.el b/emacs/sunrise-commander.el new file mode 100644 index 0000000..4ed55ac --- /dev/null +++ b/emacs/sunrise-commander.el @@ -0,0 +1,4247 @@ +;;; sunrise-commander.el --- two-pane file manager for Emacs based on Dired and inspired by MC -*- lexical-binding: t -*- + +;; Copyright (C) 2007-2012 José Alfredo Romero Latouche. + +;; Author: José Alfredo Romero L. <escherdragon@gmail.com> +;; Å tÄpán NÄmec <stepnem@gmail.com> +;; Maintainer: José Alfredo Romero L. <escherdragon@gmail.com> +;; Created: 24 Sep 2007 +;; Version: 6 +;; RCS Version: $Rev: 434 $ +;; Keywords: files, dired, midnight commander, norton, orthodox +;; URL: http://www.emacswiki.org/emacs/sunrise-commander.el +;; Compatibility: GNU Emacs 22+ + +;; This file is not part of 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 3 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 de- +;; tails. + +;; You should have received a copy of the GNU General Public License along with +;; this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; The Sunrise Commmander is an double-pane file manager for Emacs. It's built +;; atop of Dired and takes advantage of all its power, but also provides many +;; handy features of its own: + +;; * Sunrise is implemented as a derived major mode confined inside the pane +;; buffers, so its buffers and Dired ones can live together without easymenu or +;; viper to avoid key binding collisions. + +;; * It automatically closes unused buffers and tries to never keep open more +;; than the one or two used to display the panes, though this behavior may be +;; disabled if desired. + +;; * Each pane has its own history stack: press M-y / M-u for moving backwards / +;; forwards in the history of directories. + +;; * Press M-t to swap (transpose) the panes. + +;; * Press C-= for "smart" file comparison using `ediff'. It compares together +;; the first two files marked on each pane or, if no files have been marked, it +;; assumes that the second pane contains a file with the same name as the +;; selected one and tries to compare these two. You can also mark whole lists of +;; files to be compared and then just press C-= for comparing the next pair. + +;; * Press = for fast "smart" file comparison -- like above, but using regular +;; diff. + +;; * Press C-M-= for directory comparison (by date / size / contents of files). + +;; * Press C-c C-s to change the layout of the panes (horizontal/vertical/top) + +;; * Press C-c / to interactively refine the contents of the current pane using +;; fuzzy (a.k.a. flex) matching, then: +;; - press Delete or Backspace to revert the buffer to its previous state +;; - press Return, C-n or C-p to exit and accept the current narrowed state +;; - press Esc or C-g to abort the operation and revert the buffer +;; - use ! to prefix characters that should NOT appear after a given position +;; Once narrowed and accepted, you can restore the original contents of the pane +;; by pressing g (revert-buffer). + +;; * Sticky search: press C-c s to launch an interactive search that will remain +;; active from directory to directory, until you hit a regular file or press C-g + +;; * Press C-x C-q to put the current pane in Editable Dired mode (allows to +;; edit the pane as if it were a regular file -- press C-c C-c to commit your +;; changes to the filesystem, or C-c C-k to abort). + +;; * Press y to recursively calculate the total size (in bytes) of all files and +;; directories currently selected/marked in the active pane. + +;; * Sunrise VIRTUAL mode integrates dired-virtual mode to Sunrise, allowing to +;; capture find and locate results in regular files and to use them later as if +;; they were directories with all Dired and Sunrise operations at your +;; fingertips. +;; The results of the following operations are displayed in VIRTUAL mode: +;; - find-name-dired (press C-c C-n), +;; - find-grep-dired (press C-c C-g), +;; - find-dired (press C-c C-f), +;; - locate (press C-c C-l), +;; - list all recently visited files (press C-c C-r -- requires recentf), +;; - list all directories in active pane's history ring (press C-c C-d). + +;; * Supports AVFS (http://avf.sourceforge.net/) for transparent navigation +;; inside compressed archives (*.zip, *.tgz, *.tar.bz2, *.deb, etc. etc.) +;; You need to have AVFS with coda or fuse installed and running on your system +;; for this to work, though. + +;; * Opening terminals directly from Sunrise: +;; - Press C-c C-t to inconditionally open a new terminal into the currently +;; selected directory in the active pane. +;; - Use C-c t to switch to the last opened terminal, or (when already inside +;; a terminal) to cycle through all open terminals. +;; - Press C-c T to switch to the last opened terminal and change directory +;; to the one in the current directory. +;; - Press C-c M-t to be prompted for a program name, and then open a new +;; terminal using that program into the currently selected directory +;; (eshell is a valid value; if no program can be found with the given name +;; then the value of `sr-terminal-program' is used instead). + +;; * Terminal integration and Command line expansion: integrates tightly with +;; `eshell' and `term-mode' to allow interaction between terminal emulators in +;; line mode (C-c C-j) and the panes: the most important navigation commands +;; (up, down, mark, unmark, go to parent dir) can be executed on the active pane +;; directly from the terminal by pressing the usual keys with Meta: <M-up>, +;; <M-down>, etc. Additionally, the following substitutions are automagically +;; performed in `eshell' and `term-line-mode': +;; %f - expands to the currently selected file in the left pane +;; %F - expands to the currently selected file in the right pane +;; %m - expands to the list of paths of all marked files in the left pane +;; %M - expands to the list of paths of all marked files in the right pane +;; %n - expands to the list of names of all marked files in the left pane +;; %N - expands to the list of names of all marked files in the right pane +;; %d - expands to the current directory in the left pane +;; %D - expands to the current directory in the right pane +;; %a - expands to the list of paths of all marked files in the active pane +;; %A - expands to the current directory in the active pane +;; %p - expands to the list of paths of all marked files in the passive pane +;; %P - expands to the current directory in the passive pane + +;; * Cloning of complete directory trees: press K to clone the selected files +;; and directories into the passive pane. Cloning is a more general operation +;; than copying, in which all directories are recursively created with the same +;; names and structures at the destination, while what happens to the files +;; within them depends on the option you choose: +;; - "(D)irectories only" ignores all files, copies only directories, +;; - "(C)opies" performs a regular recursive copy of all files and dirs, +;; - "(H)ardlinks" makes every new file a (hard) link to the original one +;; - "(S)ymlinks" creates absolute symbolic links for all files in the tree, +;; - "(R)elative symlinksâ creates relative symbolic links. + +;; * Passive navigation: the usual navigation keys (n, p, Return, U, ;) combined +;; with Meta allow to move across the passive pane without actually having to +;; switch to it. + +;; * Synchronized navigation: press C-c C-z to enable / disable synchronized +;; navigation. In this mode, the passive navigation keys (M-n, M-p, M-Return, +;; etc.) operate on both panes simultaneously. I've found this quite useful for +;; comparing hierarchically small to medium-sized directory trees (for large to +;; very large directory trees one needs something on the lines of diff -r +;; though). + +;; * And much more -- press ? while in Sunrise mode for basic help, or h for a +;; complete list of all keybindings available (use C-e and C-y to scroll). + +;; There is no help window like in MC, but if you really miss it, just get and +;; install the sunrise-x-buttons extension. + +;; A lot of this code was once adapted from Kevin's mc.el, but it has evolved +;; considerably since then. Another part (the code for file copying and +;; renaming) derives originally from the Dired extensions written by Kurt +;; Nørmark for LAML (http://www.cs.aau.dk/~normark/scheme/distribution/laml/). + +;; It was written on GNU Emacs 24 on Linux and tested on GNU Emacs 22, 23 and 24 +;; for Linux and on EmacsW32 (version 23) for Windows. I have also received +;; feedback from users reporting it works OK on the Mac. It does not work either +;; on GNU Emacs 21 or XEmacs -- please drop me a line if you would like to help +;; porting it. All contributions and/or bug reports will be very welcome. + +;; For more details on the file manager, several available extensions and many +;; cool tips & tricks visit http://www.emacswiki.org/emacs/Sunrise_Commander + +;;; Installation and Usage: + +;; 1) Put this file somewhere in your Emacs `load-path'. + +;; 2) Add a (require 'sunrise-commander) to your .emacs file. + +;; 3) Choose some unused extension for files to be opened in Sunrise VIRTUAL +;; mode and add it to `auto-mode-alist', e.g. if you want to name your virtual +;; directories like *.svrm just add to your .emacs file a line like the +;; following: +;; +;; (add-to-list 'auto-mode-alist '("\\.srvm\\'" . sr-virtual-mode)) + +;; 4) Evaluate the new lines, or reload your .emacs file, or restart Emacs. + +;; 5) Type M-x sunrise to invoke the Sunrise Commander (or much better: bind the +;; function to your favorite key combination). The command `sunrise-cd' invokes +;; Sunrise and automatically selects the current file wherever it is in the +;; filesystem. Type h at any moment for information on available key bindings. + +;; 6) Type M-x customize-group <RET> sunrise <RET> to customize options, fonts +;; and colors (activate AVFS support here, too). + +;; 7) Enjoy :) + +;;; Code: + +(require 'dired) +(require 'dired-x) +(require 'enriched) +(require 'find-dired) +(require 'font-lock) +(require 'hl-line) +(require 'sort) +(require 'term) +(eval-when-compile (require 'cl) + (require 'desktop) + (require 'dired-aux) + (require 'esh-mode) + (require 'recentf) + (require 'tramp)) + +(defgroup sunrise nil + "The Sunrise Commander File Manager." + :group 'files) + +(defcustom sr-show-file-attributes t + "Whether to initially display file attributes in Sunrise panes. +You can always toggle file attributes display pressing +\\<sr-mode-map>\\[sr-toggle-attributes]." + :group 'sunrise + :type 'boolean) + +(defcustom sr-autoload-extensions t + "Whether to load extensions immediately after their declaration, or when the +SC core is loaded (e.g. when using autoload cookies)." + :group 'sunrise + :type 'boolean) + +(defcustom sr-show-hidden-files nil + "Whether to initially display hidden files in Sunrise panes. +You can always toggle hidden files display pressing +\\<sr-mode-map>\\[dired-omit-mode]. +You can also customize what files are considered hidden by setting +`dired-omit-files' and `dired-omit-extensions' in your .emacs file." + :group 'sunrise + :type 'boolean) + +(defcustom sr-terminal-kill-buffer-on-exit t + "Whether to kill terminal buffers after their shell process ends." + :group 'sunrise + :type 'boolean) + +(defcustom sr-terminal-program "eshell" + "The program to use for terminal emulation. +If this value is set to \"eshell\", the Emacs shell (`eshell') +will be used." + :group 'sunrise + :type 'string) + +(defcustom sr-listing-switches "-al" + "Listing switches passed to `ls' when building Sunrise buffers. +\(Cf. `dired-listing-switches'.) + Most portable value: -al + Recommended value on GNU systems: \ +--time-style=locale --group-directories-first -alDhgG" + :group 'sunrise + :type 'string) + +(defcustom sr-virtual-listing-switches "-ald" + "Listing switches for building buffers in `sr-virtual-mode'. +Should not contain the -D option. See also `sr-listing-switches'." + :group 'sunrise + :type 'string) + +(defcustom sr-avfs-root nil + "Root of the AVFS virtual filesystem used for navigating compressed archives. +Setting this value activates AVFS support." + :group 'sunrise + :type '(choice + (const :tag "AVFS support disabled" nil) + (directory :tag "AVFS root directory"))) + +(defcustom sr-avfs-handlers-alist '(("\\.[jwesh]ar$" . "#uzip/") + ("\\.wsar$" . "#uzip/") + ("\\.xpi$" . "#uzip/") + ("\\.apk$" . "#uzip/") + ("\\.iso$" . "#iso9660/") + ("\\.patch$" . "#/") + ("\\.txz$" . "#/") + ("." . "#/")) + "List of AVFS handlers to manage specific file extensions." + :group 'sunrise + :type 'alist) + +(defcustom sr-md5-shell-command "md5sum %f | cut -d' ' -f1 2>/dev/null" + "Shell command to use for calculating MD5 sums for files. +Used when comparing directories using the ``(c)ontents'' option. +Use %f as a placeholder for the name of the file." + :group 'sunrise + :type 'string) + +(defcustom sr-window-split-style 'horizontal + "The current window split configuration. +May be `horizontal', `vertical' or `top'." + :group 'sunrise + :type '(choice + (const horizontal) + (const vertical) + (const top))) + +(defcustom sr-windows-locked t + "When non-nil, vertical size of the panes will remain constant." + :group 'sunrise + :type 'boolean) + +(defcustom sr-windows-default-ratio 66 + "Percentage of the total height of the frame to use by default for the Sunrise +Commander panes." + :group 'sunrise + :type 'integer + :set (defun sr-set-windows-default-ratio (symbol value) + "Setter function for the `sr-windows-default-ratio' custom option." + (if (and (integerp value) (>= value 0) (<= value 100)) + (set-default symbol value) + (error "Invalid value: %s" value)))) + +(defcustom sr-history-length 20 + "Number of entries to keep in each pane's history rings." + :group 'sunrise + :type 'integer) + +(defcustom sr-kill-unused-buffers t + "Whether buffers should be killed automatically by Sunrise when not displayed +in any of the panes." + :group 'sunrise + :type 'boolean) + +(defcustom sr-confirm-kill-viewer t + "Whether to ask for confirmation before killing a buffer opened in quick-view +mode." + :group 'sunrise + :type 'boolean) + +(defcustom sr-attributes-display-mask nil + "Contols hiding/transforming columns with `sr-toggle-attributes'. +If set, its value must be a list of symbols, one for each +attributes column. If the symbol is nil, then the corresponding +column will be hidden, and if it's not nil then the column will +be left untouched. The symbol may also be the name of a function +that takes one string argument and evaluates to a different +string -- in this case this function will be used to transform +the contents of the corresponding column and its result will be +displayed instead." + :group 'sunrise + :type '(repeat symbol)) + +(defcustom sr-fast-backup-extension ".bak" + "Determines the extension to append to the names of new files +created with the `sr-fast-backup-files' function (@!). This can +be either a simple string or an s-expression to be evaluated at +run-time." + :group 'sunrise + :type '(choice + (string :tag "Literal text") + (sexp :tag "Symbolic expression"))) + +(defcustom sr-fuzzy-negation-character ?! + "Character to use for negating patterns when fuzzy-narrowing a pane." + :group 'sunrise + :type '(choice + (const :tag "Fuzzy matching negation disabled" nil) + (character :tag "Fuzzy matching negation character" ?!))) + +(defcustom sr-init-hook nil + "List of functions to be called before the Sunrise panes are displayed." + :group 'sunrise + :type 'hook + :options '(auto-insert)) + +(defcustom sr-start-hook nil + "List of functions to be called after the Sunrise panes are displayed." + :group 'sunrise + :type 'hook + :options '(auto-insert)) + +(defcustom sr-refresh-hook nil + "List of functions to be called every time a pane is refreshed." + :group 'sunrise + :type 'hook + :options '(auto-insert)) + +(defcustom sr-quit-hook nil + "List of functions to be called after the Sunrise panes are hidden." + :group 'sunrise + :type 'hook + :options '(auto-insert)) + +(defvar sr-restore-buffer nil + "Buffer to restore when Sunrise quits.") + +(defvar sr-prior-window-configuration nil + "Window configuration before Sunrise was started.") + +(defvar sr-running nil + "True when Sunrise commander mode is running.") + +(defvar sr-synchronized nil + "True when synchronized navigation is on") + +(defvar sr-current-window-overlay nil + "Holds the current overlay which marks the current Dired buffer.") + +(defvar sr-clex-hotchar-overlay nil + "Overlay used to highlight the hot character (%) during CLEX operations.") + +(defvar sr-left-directory "~/" + "Dired directory for the left window. See variable `dired-directory'.") + +(defvar sr-left-buffer nil + "Dired buffer for the left window.") + +(defvar sr-left-window nil + "The left window of Dired.") + +(defvar sr-right-directory "~/" + "Dired directory for the right window. See variable `dired-directory'.") + +(defvar sr-right-buffer nil + "Dired buffer for the right window.") + +(defvar sr-right-window nil + "The right window of Dired.") + +(defvar sr-current-frame nil + "The frame Sunrise is active on (if any).") + +(defvar sr-this-directory "~/" + "Dired directory in the active pane. +This isn't necessarily the same as `dired-directory'.") + +(defvar sr-other-directory "~/" + "Dired directory in the passive pane.") + +(defvar sr-selected-window 'left + "The window to select when Sunrise starts up.") + +(defvar sr-selected-window-width nil + "The width the selected window should have on startup.") + +(defvar sr-history-registry '((left) (right)) + "Registry of visited directories for both panes.") + +(defvar sr-history-stack '((left 0 . 0) (right 0 . 0)) + "History stack counters. +The first counter on each side tracks (by value) the absolute +depth of the stack and (by sign) the direction it is currently +being traversed. The second counter points at the position of the +element that is immediately beneath the top of the stack.") + +(defvar sr-ti-openterms nil + "Stack of currently open terminal buffers.") + +(defvar sr-ediff-on nil + "Flag that indicates whether an `ediff' is being currently done.") + +(defvar sr-clex-on nil + "Flag that indicates that a CLEX operation is taking place.") + +(defvar sr-virtual-buffer nil + "Local flag that indicates the current buffer was originally in + VIRTUAL mode.") + +(defvar sr-dired-directory "" + "Directory inside which `sr-mode' is currently active.") + +(defvar sr-start-message + "Been coding all night? Enjoy the Sunrise! (or press q to quit)" + "Message to display when Sunrise is started.") + +(defvar sr-panes-height nil + "Current height of the pane windows. +Initial value is 2/3 the viewport height.") + +(defvar sr-current-path-faces nil + "List of faces to display the path in the current pane (first wins)") +(make-variable-buffer-local 'sr-current-path-faces) + +(defvar sr-inhibit-highlight nil + "Special variable used to temporarily inhibit highlighting in panes.") + +(defvar sr-find-items nil + "Special variable used by `sr-find' to control the scope of find operations.") + +(defvar sr-desktop-save-handlers nil + "List of extension-defined handlers to save Sunrise buffers with desktop.") + +(defvar sr-desktop-restore-handlers nil + "List of extension-defined handlers to restore Sunrise buffers from desktop.") + +(defvar sr-backup-buffer nil + "Variable holding a buffer-local value of the backup buffer.") +(make-variable-buffer-local 'sr-backup-buffer) + +(defvar sr-goto-dir-function nil + "Function to use to navigate to a given directory, or nil to do +the default. The function receives one argument DIR, which is +the directory to go to.") + +(defconst sr-side-lookup (list '(left . right) '(right . left)) + "Trivial alist used by the Sunrise Commander to lookup its own passive side.") + +(defface sr-active-path-face + '((((type tty) (class color) (min-colors 8)) + :background "green" :foreground "yellow" :bold t) + (((type tty) (class mono)) :inverse-video t) + (t :background "#ace6ac" :foreground "yellow" :bold t :height 120)) + "Face of the directory path in the active pane." + :group 'sunrise) + +(defface sr-passive-path-face + '((((type tty) (class color) (min-colors 8) (background dark)) + :background "black" :foreground "cyan") + (((type tty) (class color) (min-colors 8) (background light)) + :background "white" :foreground "cyan") + (t :background "white" :foreground "lightgray" :bold t :height 120)) + "Face of the directory path in the passive pane." + :group 'sunrise) + +(defface sr-editing-path-face + '((t :background "red" :foreground "yellow" :bold t :height 120)) + "Face of the directory path in the active pane while in editable pane mode." + :group 'sunrise) + +(defface sr-highlight-path-face + '((t :background "yellow" :foreground "#ace6ac" :bold t :height 120)) + "Face of the directory path on mouse hover." + :group 'sunrise) + +(defface sr-clex-hotchar-face + '((t :foreground "red" :bold t)) + "Face of the hot character (%) in CLEX mode. +Indicates that a CLEX substitution may be about to happen." + :group 'sunrise) + +;;; ============================================================================ +;;; This is the core of Sunrise: the main idea is to apply `sr-mode' only inside +;;; Sunrise buffers while keeping all of `dired-mode' untouched. + +;;; preserve this variable when switching from `dired-mode' to another mode +(put 'dired-subdir-alist 'permanent-local t) + +;;;###autoload +(define-derived-mode sr-mode dired-mode "Sunrise Commander" + "Two-pane file manager for Emacs based on Dired and inspired by MC. +The following keybindings are available: + + /, j .......... go to directory + p, n .......... move cursor up/down + M-p, M-n ...... move cursor up/down in passive pane + ^, J .......... go to parent directory + M-^, M-J ...... go to parent directory in passive pane + Tab ........... switch to other pane + C-Tab.......... switch to viewer window + C-c Tab ....... switch to viewer window (console compatible) + RET, f ........ visit selected file/directory + M-RET, M-f .... visit selected file/directory in passive pane + C-c RET ....... visit selected in passive pane (console compatible) + b ............. visit selected file/directory in default browser + F ............. visit all marked files, each in its own window + C-u F ......... visit all marked files in the background + o,v ........... quick visit selected file (scroll with C-M-v, C-M-S-v) + C-u o, C-u v .. kill quick-visited buffer (restores normal scrolling) + X ............. execute selected file + C-u X.......... execute selected file with arguments + + + ............. create new directory + M-+ ........... create new empty file(s) + C ............. copy marked (or current) files and directories + R ............. rename marked (or current) files and directories + D ............. delete marked (or current) files and directories + S ............. soft-link selected file/directory to passive pane + Y ............. do relative soft-link of selected file in passive pane + H ............. hard-link selected file to passive pane + K ............. clone selected files and directories into passive pane + M-C ........... copy (using traditional dired-do-copy) + M-R ........... rename (using traditional dired-do-rename) + M-D ........... delete (using traditional dired-do-delete) + M-S............ soft-link (using traditional dired-do-symlink) + M-Y............ do relative soft-link (traditional dired-do-relsymlink) + M-H............ hard-link selected file/directory (dired-do-hardlink) + A ............. search marked files for regular expression + Q ............. perform query-replace-regexp on marked files + C-c s ......... start a \"sticky\" interactive search in the current pane + + M-a ........... move to beginning of current directory + M-e ........... move to end of current directory + M-y ........... go to previous directory in history + M-u ........... go to next directory in history + C-M-y ......... go to previous directory in history on passive pane + C-M-u ......... go to next directory in history on passive pane + + g, C-c C-c .... refresh pane + s ............. sort entries (by name, number, size, time or extension) + r ............. reverse the order of entries in the active pane (sticky) + C-o ........... show/hide hidden files (requires dired-omit-mode) + C-Backspace ... hide/show file attributes in pane + C-c Backspace . hide/show file attributes in pane (console compatible) + y ............. show file type / size of selected files and directories. + M-l ........... truncate/continue long lines in pane + C-c v ......... put current panel in VIRTUAL mode + C-c C-v ....... create new pure VIRTUAL buffer + C-c C-w ....... browse directory tree using w3m + + M-t ........... transpose panes + M-o ........... synchronize panes + C-c C-s ....... change panes layout (vertical/horizontal/top-only) + [ ............. enlarges the right pane by 5 columns + ] ............. enlarges the left pane by 5 columns + } ............. enlarges the panes vertically by 1 row + C-} ........... enlarges the panes vertically as much as it can + C-c } ......... enlarges the panes vertically as much as it can + { ............. shrinks the panes vertically by 1 row + C-{ ........... shrinks the panes vertically as much as it can + C-c { ......... shrinks the panes vertically as much as it can + \\ ............. restores the size of all windows back to «normal» + C-c C-z ....... enable/disable synchronized navigation + + C-= ........... smart compare files (ediff) + C-c = ......... smart compare files (console compatible) + = ............. fast smart compare files (plain diff) + C-M-= ......... compare panes + C-x = ......... compare panes (console compatible) + + C-c C-f ....... execute Find-dired in Sunrise VIRTUAL mode + C-c C-n ....... execute find-Name-dired in Sunrise VIRTUAL mode + C-c C-g ....... execute find-Grep-dired in Sunrise VIRTUAL mode + C-u C-c C-g ... execute find-Grep-dired with additional grep options + C-c C-l ....... execute Locate in Sunrise VIRTUAL mode + C-c C-r ....... browse list of Recently visited files (requires recentf) + C-c C-c ....... [after find, locate or recent] dismiss virtual buffer + C-c / ......... narrow the contents of current pane using fuzzy matching + C-c b ......... partial Branch view of selected items in current pane + C-c p ......... Prune paths matching regular expression from current pane + ; ............. follow file (go to same directory as selected file) + M-; ........... follow file in passive pane + C-M-o ......... follow a projection of current directory in passive pane + + C-> ........... save named checkpoint (a.k.a. \"bookmark panes\") + C-c > ......... save named checkpoint (console compatible) + C-. ........ restore named checkpoint + C-c . ........ restore named checkpoint + + C-x C-q ....... put pane in Editable Dired mode (commit with C-c C-c) + @! ............ fast backup files (not dirs!), each to [filename].bak + + C-c t ......... open new terminal or switch to already open one + C-c T ......... open terminal AND/OR change directory to current + C-c C-t ....... open always a new terminal in current directory + C-c M-t ....... open a new terminal using an alternative shell program + q, C-x k ...... quit Sunrise Commander, restore previous window setup + M-q ........... quit Sunrise Commander, don't restore previous windows + +Additionally, the following traditional commander-style keybindings are provided +\(these may be disabled by customizing the `sr-use-commander-keys' option): + + F2 ............ go to directory + F3 ............ quick visit selected file + F4 ............ visit selected file + F5 ............ copy marked (or current) files and directories + F6 ............ rename marked (or current) files and directories + F7 ............ create new directory + F8 ............ delete marked (or current) files and directories + F10 ........... quit Sunrise Commander + C-F3 .......... sort contents of current pane by name + C-F4 .......... sort contents of current pane by extension + C-F5 .......... sort contents of current pane by time + C-F6 .......... sort contents of current pane by size + C-F7 .......... sort contents of current pane numerically + S-F7 .......... soft-link selected file/directory to passive pane + Insert ........ mark file + C-PgUp ........ go to parent directory + +Any other dired keybinding (not overridden by any of the above) can be used in +Sunrise, like G for changing group, M for changing mode and so on. + +Some more bindings are available in terminals opened using any of the Sunrise +functions (i.e. one of: C-c t, C-c T, C-c C-t, C-c M-t): + + C-c Tab ....... switch focus to the active pane + C-c t ......... cycle through all currently open terminals + C-c T ......... cd to the directory in the active pane + C-c C-t ....... open new terminal, cd to directory in the active pane + C-c ; ......... follow the current directory in the active pane + C-c { ......... shrink the panes vertically as much as possible + C-c } ......... enlarge the panes vertically as much as possible + C-c \\ ......... restore the size of all windows back to «normal» + C-c C-j ....... put terminal in line mode + C-c C-k ....... put terminal back in char mode + +The following bindings are available only in line mode (eshell is considered to +be *always* in line mode): + + M-<up>, M-P ... move cursor up in the active pane + M-<down>, M-N . move cursor down in the active pane + M-Return ...... visit selected file/directory in the active pane + M-J ........... go to parent directory in the active pane + M-G ........... refresh active pane + M-Tab ......... switch to passive pane (without leaving the terminal) + M-M ........... mark selected file/directory in the active pane + M-Backspace ... unmark previous file/directory in the active pane + M-U ........... remove all marks from the active pane + C-Tab ......... switch focus to the active pane + +In a terminal in line mode the following substitutions are also performed +automatically: + + %f - expands to the currently selected file in the left pane + %F - expands to the currently selected file in the right pane + %m - expands to the list of paths of all marked files in the left pane + %M - expands to the list of paths of all marked files in the right pane + %n - expands to the list of names of all marked files in the left pane + %N - expands to the list of names of all marked files in the right pane + %d - expands to the current directory in the left pane + %D - expands to the current directory in the right pane + %a - expands to the list of paths of all marked files in the active pane + %A - expands to the current directory in the active pane + %p - expands to the list of paths of all marked files in the passive pane + %P - expands to the current directory in the passive pane + %% - inserts a single % sign. +" + :group 'sunrise + (unless (string-match "\\(Sunrise\\)" (buffer-name)) + (rename-buffer (concat (buffer-name) " (Sunrise)") t)) + (set-keymap-parent sr-mode-map dired-mode-map) + (sr-highlight) + (dired-omit-mode dired-omit-mode) + + (make-local-variable 'truncate-partial-width-windows) + (setq truncate-partial-width-windows (sr-truncate-v t)) + + (set (make-local-variable 'dired-header-face) 'sr-passive-path-face) + (set (make-local-variable 'dired-recursive-deletes) 'top) + (set (make-local-variable 'truncate-lines) nil) + (set (make-local-variable 'desktop-save-buffer) 'sr-desktop-save-buffer) + (set (make-local-variable 'revert-buffer-function) 'sr-revert-buffer) + (set (make-local-variable 'buffer-quit-function) 'sr-quit) + (set (make-local-variable 'sr-show-file-attributes) sr-show-file-attributes) + (set (make-local-variable 'hl-line-sticky-flag) nil) + (hl-line-mode 1) +) + +;;;###autoload +(define-derived-mode sr-virtual-mode dired-virtual-mode "Sunrise VIRTUAL" + "Sunrise Commander Virtual Mode. Useful for reusing find and locate results." + :group 'sunrise + (set-keymap-parent sr-virtual-mode-map sr-mode-map) + (sr-highlight) + (enriched-mode -1) + + (make-local-variable 'truncate-partial-width-windows) + (setq truncate-partial-width-windows (sr-truncate-v t)) + + (set (make-local-variable 'dired-header-face) 'sr-passive-path-face) + (set (make-local-variable 'truncate-lines) nil) + (set (make-local-variable 'desktop-save-buffer) 'sr-desktop-save-buffer) + (set (make-local-variable 'revert-buffer-function) 'sr-revert-buffer) + (set (make-local-variable 'buffer-quit-function) 'sr-quit) + (set (make-local-variable 'sr-show-file-attributes) sr-show-file-attributes) + (set (make-local-variable 'hl-line-sticky-flag) nil) + (hl-line-mode 1) + + (define-key sr-virtual-mode-map "\C-c\C-c" 'sr-virtual-dismiss)) + +(defmacro sr-within (dir form) + "Evaluate FORM in Sunrise context." + `(unwind-protect + (progn + (setq sr-dired-directory + (file-name-as-directory (abbreviate-file-name ,dir))) + (ad-activate 'dired-find-buffer-nocreate) + ,form) + (ad-deactivate 'dired-find-buffer-nocreate) + (setq sr-dired-directory ""))) + +(defmacro sr-save-aspect (&rest body) + "Restore omit mode, hidden attributes and point after a directory transition." + `(let ((inhibit-read-only t) + (omit (or dired-omit-mode -1)) + (attrs (eval 'sr-show-file-attributes)) + (path-faces sr-current-path-faces)) + ,@body + (dired-omit-mode omit) + (if path-faces + (setq sr-current-path-faces path-faces)) + (if (string= "NUMBER" (get sr-selected-window 'sorting-order)) + (sr-sort-by-operation 'sr-numerical-sort-op)) + (if (get sr-selected-window 'sorting-reverse) + (sr-reverse-pane)) + (setq sr-show-file-attributes attrs) + (sr-display-attributes (point-min) (point-max) sr-show-file-attributes) + (sr-restore-point-if-same-buffer))) + +(defmacro sr-alternate-buffer (form) + "Execute FORM in a new buffer, after killing the previous one." + `(let ((dispose nil)) + (unless (or (not (or dired-directory (eq major-mode 'sr-tree-mode))) + (eq sr-left-buffer sr-right-buffer)) + (setq dispose (current-buffer))) + ,form + (setq sr-this-directory default-directory) + (sr-keep-buffer) + (sr-highlight) + (when (and sr-kill-unused-buffers (buffer-live-p dispose)) + (with-current-buffer dispose + (bury-buffer) + (set-buffer-modified-p nil) + (unless (kill-buffer dispose) + (kill-local-variable 'sr-current-path-faces)))))) + +(defmacro sr-in-other (form) + "Execute FORM in the context of the passive pane. +Helper macro for passive & synchronized navigation." + `(let ((home sr-selected-window)) + (let ((sr-inhibit-highlight t)) + (if sr-synchronized ,form) + (sr-change-window) + (condition-case description + ,form + (error (message (cadr description))))) + (if (not sr-running) + (sr-select-window home) + (run-hooks 'sr-refresh-hook) + (sr-change-window)))) + +(defmacro sr-silently (&rest body) + "Inhibit calls to `message' in BODY." + `(letf (((symbol-function 'message) (lambda (_msg &rest _args) (ignore)))) + ,@body)) + +(eval-and-compile + (defun sr-symbol (side type) + "Synthesize Sunrise symbols (`sr-left-buffer', `sr-right-window', etc.)." + (intern (concat "sr-" (symbol-name side) "-" (symbol-name type))))) + +(defun sr-dired-mode () + "Set Sunrise mode in every Dired buffer opened in Sunrise (called in a hook)." + (if (and sr-running + (eq (selected-frame) sr-current-frame) + (sr-equal-dirs dired-directory default-directory) + (not (eq major-mode 'sr-mode))) + (let ((dired-listing-switches dired-listing-switches) + (sorting-options (or (get sr-selected-window 'sorting-options) ""))) + (unless (and (featurep 'tramp) + (string-match tramp-file-name-regexp default-directory)) + (setq dired-listing-switches + (concat sr-listing-switches sorting-options))) + (sr-mode) + (dired-unadvertise dired-directory)))) +(add-hook 'dired-before-readin-hook 'sr-dired-mode) + +(defun sr-bookmark-jump () + "Handle panes opened from bookmarks in Sunrise." + (when (and sr-running + (memq (selected-window) (list sr-left-window sr-right-window))) + (let ((last-buf (symbol-value (sr-symbol sr-selected-window 'buffer)))) + (setq dired-omit-mode (with-current-buffer last-buf dired-omit-mode)) + (setq sr-this-directory default-directory) + (if (sr-equal-dirs sr-this-directory sr-other-directory) + (sr-synchronize-panes t) + (revert-buffer)) + (sr-keep-buffer) + (unless (memq last-buf (list (current-buffer) (sr-other 'buffer))) + (kill-buffer last-buf))))) +(add-hook 'bookmark-after-jump-hook 'sr-bookmark-jump) + +(defun sr-virtualize-pane () + "Put the current normal view in VIRTUAL mode." + (interactive) + (when (eq major-mode 'sr-mode) + (let ((focus (dired-get-filename 'verbatim t))) + (sr-save-aspect + (when (eq sr-left-buffer sr-right-buffer) + (dired default-directory) + (sr-keep-buffer)) + (sr-virtual-mode)) + (if focus (sr-focus-filename focus))))) + +(defun sr-virtual-dismiss () + "Restore normal pane view in Sunrise VIRTUAL mode." + (interactive) + (when (eq major-mode 'sr-virtual-mode) + (let ((focus (dired-get-filename 'verbatim t))) + (sr-process-kill) + (sr-save-aspect + (sr-alternate-buffer (sr-goto-dir sr-this-directory)) + (if focus (sr-focus-filename focus)) + (revert-buffer))))) + +(defun sr-select-window (side) + "Select/highlight the given Sunrise window (right or left)." + (select-window (symbol-value (sr-symbol side 'window))) + (setq sr-selected-window side) + (setq sr-this-directory default-directory) + (sr-highlight)) + +(defun sr-viewer-window () + "Return an active window that can be used as the viewer." + (if (or (memq major-mode '(sr-mode sr-virtual-mode sr-tree-mode)) + (memq (current-buffer) (list sr-left-buffer sr-right-buffer))) + (let ((current-window (selected-window)) (target-window)) + (dotimes (_times 2) + (setq current-window (next-window current-window)) + (unless (memq current-window (list sr-left-window sr-right-window)) + (setq target-window current-window))) + target-window) + (selected-window))) + +(defun sr-select-viewer-window (&optional force-setup) + "Select a window that is not a Sunrise pane. +If no suitable active window can be found and FORCE-SETUP is set, +calls the function `sr-setup-windows' and tries once again." + (interactive "p") + (let ((viewer (sr-viewer-window))) + (if (memq major-mode '(sr-mode sr-virtual-mode sr-tree-mode)) + (hl-line-mode 1)) + (if viewer + (select-window viewer) + (when force-setup + (sr-setup-windows) + (select-window (sr-viewer-window)))))) + +(defun sr-backup-buffer () + "Create a backup copy of the current buffer. +Used as a cache during revert operations." + (if (buffer-live-p sr-backup-buffer) (sr-kill-backup-buffer)) + (let ((buf (current-buffer))) + (setq sr-backup-buffer (generate-new-buffer "*Sunrise Backup*")) + (with-current-buffer sr-backup-buffer + (insert-buffer-substring buf)) + (run-hooks 'sr-refresh-hook))) + +(defun sr-kill-backup-buffer () + "Kill the backup buffer associated to the current one, if there is any." + (when (buffer-live-p sr-backup-buffer) + (kill-buffer sr-backup-buffer) + (setq sr-backup-buffer nil))) +(add-hook 'kill-buffer-hook 'sr-kill-backup-buffer) +(add-hook 'change-major-mode-hook 'sr-kill-backup-buffer) + +(add-to-list 'enriched-translations '(invisible (t "x-invisible"))) +(defun sr-enrich-buffer () + "Activate `enriched-mode' before saving a Sunrise buffer to a file. +This is done so all its dired-filename attributes are kept in the file." + (if (memq major-mode '(sr-mode sr-virtual-mode)) + (enriched-mode 1))) +(add-hook 'before-save-hook 'sr-enrich-buffer) + +(defun sr-extend-with (extension &optional filename) + "Try to enhance Sunrise with EXTENSION (argument must be a symbol). +An extension can be loaded from optional FILENAME. If found, the extension is +immediately loaded, but only if `sr-autoload-extensions' is not nil." + (when sr-autoload-extensions + (require extension filename t))) + +(defadvice dired-find-buffer-nocreate + (before sr-advice-findbuffer (dirname &optional mode)) + "A hack to avoid some Dired mode quirks in the Sunrise Commander." + (if (sr-equal-dirs sr-dired-directory dirname) + (setq mode 'sr-mode))) +;; ^--- activated by sr-within macro + +(defadvice dired-dwim-target-directory + (around sr-advice-dwim-target ()) + "Tweak the target directory guessing mechanism when Sunrise Commander is on." + (if (and sr-running (eq (selected-frame) sr-current-frame)) + (setq ad-return-value sr-other-directory) + ad-do-it)) +(ad-activate 'dired-dwim-target-directory) + +(defadvice other-window + (around sr-advice-other-window (count &optional all-frames)) + "Select the correct Sunrise Commander pane when switching from other windows." + (if (or (not sr-running) sr-ediff-on) + ad-do-it + (let ((from (selected-window))) + ad-do-it + (unless (memq from (list sr-left-window sr-right-window)) + ;; switching from outside + (sr-select-window sr-selected-window)) + (with-no-warnings + (when (eq (selected-window) (sr-other 'window)) + ;; switching from the other pane + (sr-change-window)))))) +(ad-activate 'other-window) + +(defadvice use-hard-newlines + (around sr-advice-use-hard-newlines (&optional arg insert)) + "Stop asking if I want hard lines the in Sunrise Commander, just guess." + (if (memq major-mode '(sr-mode sr-virtual-mode)) + (let ((inhibit-read-only t)) + (setq insert 'guess) + ad-do-it) + ad-do-it)) +(ad-activate 'use-hard-newlines) + +(defadvice dired-insert-set-properties + (after sr-advice-dired-insert-set-properties (beg end)) + "Manage hidden attributes in files added externally (e.g. from find-dired) to +the Sunrise Commander." + (when (memq major-mode '(sr-mode sr-virtual-mode)) + (with-no-warnings + (sr-display-attributes beg end sr-show-file-attributes)))) +(ad-activate 'dired-insert-set-properties) + +;;; ============================================================================ +;;; Sunrise Commander keybindings: + +(define-key sr-mode-map "\C-m" 'sr-advertised-find-file) +(define-key sr-mode-map "f" 'sr-advertised-find-file) +(define-key sr-mode-map "X" 'sr-advertised-execute-file) +(define-key sr-mode-map "o" 'sr-quick-view) +(define-key sr-mode-map "v" 'sr-quick-view) +(define-key sr-mode-map "/" 'sr-goto-dir) +(define-key sr-mode-map "j" 'sr-goto-dir) +(define-key sr-mode-map "^" 'sr-dired-prev-subdir) +(define-key sr-mode-map "J" 'sr-dired-prev-subdir) +(define-key sr-mode-map ";" 'sr-follow-file) +(define-key sr-mode-map "\M-t" 'sr-transpose-panes) +(define-key sr-mode-map "\M-o" 'sr-synchronize-panes) +(define-key sr-mode-map "\C-\M-o" 'sr-project-path) +(define-key sr-mode-map "\M-y" 'sr-history-prev) +(define-key sr-mode-map "\M-u" 'sr-history-next) +(define-key sr-mode-map "\C-c>" 'sr-checkpoint-save) +(define-key sr-mode-map "\C-c." 'sr-checkpoint-restore) +(define-key sr-mode-map "\C-c\C-z" 'sr-sync) +(define-key sr-mode-map "\C-c\C-c" 'revert-buffer) + +(define-key sr-mode-map "\t" 'sr-change-window) +(define-key sr-mode-map "\C-c\t" 'sr-select-viewer-window) +(define-key sr-mode-map "\M-a" 'sr-beginning-of-buffer) +(define-key sr-mode-map "\M-e" 'sr-end-of-buffer) +(define-key sr-mode-map "\C-c\C-s" 'sr-split-toggle) +(define-key sr-mode-map "]" 'sr-enlarge-left-pane) +(define-key sr-mode-map "[" 'sr-enlarge-right-pane) +(define-key sr-mode-map "}" 'sr-enlarge-panes) +(define-key sr-mode-map "{" 'sr-shrink-panes) +(define-key sr-mode-map "\\" 'sr-lock-panes) +(define-key sr-mode-map "\C-c}" 'sr-max-lock-panes) +(define-key sr-mode-map "\C-c{" 'sr-min-lock-panes) +(define-key sr-mode-map "\C-o" 'dired-omit-mode) +(define-key sr-mode-map "b" 'sr-browse-file) +(define-key sr-mode-map "\C-c\C-w" 'sr-browse-pane) +(define-key sr-mode-map "\C-c\d" 'sr-toggle-attributes) +(define-key sr-mode-map "\M-l" 'sr-toggle-truncate-lines) +(define-key sr-mode-map "s" 'sr-interactive-sort) +(define-key sr-mode-map "r" 'sr-reverse-pane) +(define-key sr-mode-map "\C-e" 'sr-scroll-up) +(define-key sr-mode-map "\C-y" 'sr-scroll-down) +(define-key sr-mode-map " " 'sr-scroll-quick-view) +(define-key sr-mode-map "\M- " 'sr-scroll-quick-view-down) +(define-key sr-mode-map [?\S- ] 'sr-scroll-quick-view-down) + +(define-key sr-mode-map "C" 'sr-do-copy) +(define-key sr-mode-map "K" 'sr-do-clone) +(define-key sr-mode-map "R" 'sr-do-rename) +(define-key sr-mode-map "D" 'sr-do-delete) +(define-key sr-mode-map "x" 'sr-do-flagged-delete) +(define-key sr-mode-map "S" 'sr-do-symlink) +(define-key sr-mode-map "Y" 'sr-do-relsymlink) +(define-key sr-mode-map "H" 'sr-do-hardlink) +(define-key sr-mode-map "\M-C" 'dired-do-copy) +(define-key sr-mode-map "\M-R" 'dired-do-rename) +(define-key sr-mode-map "\M-D" 'dired-do-delete) +(define-key sr-mode-map "\M-S" 'dired-do-symlink) +(define-key sr-mode-map "\M-Y" 'dired-do-relsymlink) +(define-key sr-mode-map "\M-H" 'dired-do-hardlink) +(define-key sr-mode-map "\C-x\C-q" 'sr-editable-pane) +(define-key sr-mode-map "@" 'sr-fast-backup-files) +(define-key sr-mode-map "\M-+" 'sr-create-files) + +(define-key sr-mode-map "=" 'sr-diff) +(define-key sr-mode-map "\C-c=" 'sr-ediff) +(define-key sr-mode-map "\C-x=" 'sr-compare-panes) + +(define-key sr-mode-map "\C-c\C-f" 'sr-find) +(define-key sr-mode-map "\C-c\C-n" 'sr-find-name) +(define-key sr-mode-map "\C-c\C-g" 'sr-find-grep) +(define-key sr-mode-map "\C-cb" 'sr-flatten-branch) +(define-key sr-mode-map "\C-cp" 'sr-prune-paths) +(define-key sr-mode-map "\C-c\C-l" 'sr-locate) +(define-key sr-mode-map "\C-c/" 'sr-fuzzy-narrow) +(define-key sr-mode-map "\C-c\C-r" 'sr-recent-files) +(define-key sr-mode-map "\C-c\C-d" 'sr-recent-directories) +(define-key sr-mode-map "\C-cv" 'sr-virtualize-pane) +(define-key sr-mode-map "\C-c\C-v" 'sr-pure-virtual) +(define-key sr-mode-map "Q" 'sr-do-query-replace-regexp) +(define-key sr-mode-map "F" 'sr-do-find-marked-files) +(define-key sr-mode-map "A" 'sr-do-search) +(define-key sr-mode-map "\C-cs" 'sr-sticky-isearch-forward) +(define-key sr-mode-map "\C-cr" 'sr-sticky-isearch-backward) +(define-key sr-mode-map "\C-x\C-f" 'sr-find-file) +(define-key sr-mode-map "y" 'sr-show-files-info) + +(define-key sr-mode-map "\M-n" 'sr-next-line-other) +(define-key sr-mode-map [M-down] 'sr-next-line-other) +(define-key sr-mode-map [A-down] 'sr-next-line-other) +(define-key sr-mode-map "\M-p" 'sr-prev-line-other) +(define-key sr-mode-map [M-up] 'sr-prev-line-other) +(define-key sr-mode-map [A-up] 'sr-prev-line-other) +(define-key sr-mode-map "\M-j" 'sr-goto-dir-other) +(define-key sr-mode-map "\M-\C-m" 'sr-advertised-find-file-other) +(define-key sr-mode-map "\M-f" 'sr-advertised-find-file-other) +(define-key sr-mode-map "\C-c\C-m" 'sr-advertised-find-file-other) +(define-key sr-mode-map "\M-^" 'sr-prev-subdir-other) +(define-key sr-mode-map "\M-J" 'sr-prev-subdir-other) +(define-key sr-mode-map "\M-m" 'sr-mark-other) +(define-key sr-mode-map "\M-M" 'sr-unmark-backward-other) +(define-key sr-mode-map "\M-U" 'sr-unmark-all-marks-other) +(define-key sr-mode-map "\M-;" 'sr-follow-file-other) +(define-key sr-mode-map "\C-\M-y" 'sr-history-prev-other) +(define-key sr-mode-map "\C-\M-u" 'sr-history-next-other) + +(define-key sr-mode-map "\C-ct" 'sr-term) +(define-key sr-mode-map "\C-cT" 'sr-term-cd) +(define-key sr-mode-map "\C-c\C-t" 'sr-term-cd-newterm) +(define-key sr-mode-map "\C-c\M-t" 'sr-term-cd-program) +(define-key sr-mode-map "\C-c;" 'sr-follow-viewer) +(define-key sr-mode-map "q" 'sr-quit) +(define-key sr-mode-map "\C-xk" 'sr-kill-pane-buffer) +(define-key sr-mode-map "\M-q" 'sunrise-cd) +(define-key sr-mode-map "h" 'sr-describe-mode) +(define-key sr-mode-map "?" 'sr-summary) +(define-key sr-mode-map "k" 'dired-do-kill-lines) +(define-key sr-mode-map [remap undo] 'sr-undo) +(define-key sr-mode-map [remap undo-only] 'sr-undo) +(define-key sr-mode-map [backspace] 'dired-unmark-backward) + +(define-key sr-mode-map [mouse-1] 'sr-mouse-advertised-find-file) +(define-key sr-mode-map [mouse-2] 'sr-mouse-change-window) + +(define-key sr-mode-map [(control >)] 'sr-checkpoint-save) +(define-key sr-mode-map [(control .)] 'sr-checkpoint-restore) +(define-key sr-mode-map [(control tab)] 'sr-select-viewer-window) +(define-key sr-mode-map [(control backspace)] 'sr-toggle-attributes) +(define-key sr-mode-map [(control ?\=)] 'sr-ediff) +(define-key sr-mode-map [(control meta ?\=)] 'sr-compare-panes) +(define-key sr-mode-map [(control })] 'sr-max-lock-panes) +(define-key sr-mode-map [(control {)] 'sr-min-lock-panes) + +(define-key sr-mode-map (kbd "<down-mouse-1>") 'ignore) + +(defvar sr-commander-keys + '(([(f2)] . sr-goto-dir) + ([(f3)] . sr-quick-view) + ([(f4)] . sr-advertised-find-file) + ([(f5)] . sr-do-copy) + ([(f6)] . sr-do-rename) + ([(f7)] . dired-create-directory) + ([(f8)] . sr-do-delete) + ([(f10)] . sr-quit) + ([(control f3)] . sr-sort-by-name) + ([(control f4)] . sr-sort-by-extension) + ([(control f5)] . sr-sort-by-time) + ([(control f6)] . sr-sort-by-size) + ([(control f7)] . sr-sort-by-number) + ([(shift f7)] . sr-do-symlink) + ([(insert)] . sr-mark-toggle) + ([(control prior)] . sr-dired-prev-subdir)) + "Traditional commander-style keybindings for the Sunrise Commander.") + +(defcustom sr-use-commander-keys t + "Whether to use traditional commander-style function keys (F5 = copy, etc)" + :group 'sunrise + :type 'boolean + :set (defun sr-set-commander-keys (symbol value) + "Setter function for the `sr-use-commander-keys' custom option." + (if value + (mapc (lambda (x) + (define-key sr-mode-map (car x) (cdr x))) sr-commander-keys) + (mapc (lambda (x) + (define-key sr-mode-map (car x) nil)) sr-commander-keys)) + (set-default symbol value))) + +;;; ============================================================================ +;;; Initialization and finalization functions: + +;;;###autoload +(defun sunrise (&optional left-directory right-directory filename) + "Toggle the Sunrise Commander file manager. +If LEFT-DIRECTORY is given, the left window will display that +directory (same for RIGHT-DIRECTORY). Specifying nil for any of +these values uses the default, ie. $HOME." + (interactive) + (message "Starting Sunrise Commander...") + + (if (not sr-running) + (let ((welcome sr-start-message)) + (if left-directory + (setq sr-left-directory left-directory)) + (if right-directory + (setq sr-right-directory right-directory)) + + (sr-switch-to-nonpane-buffer) + (setq sr-restore-buffer (current-buffer) + sr-current-frame (window-frame (selected-window)) + sr-prior-window-configuration (current-window-configuration) + sr-running t) + (sr-setup-windows) + (if filename + (condition-case description + (sr-focus-filename (file-name-nondirectory filename)) + (error (setq welcome (cadr description))))) + (setq sr-this-directory default-directory) + (message "%s" welcome) + (sr-highlight) ;;<-- W32Emacs needs this + (hl-line-mode 1)) + (let ((my-frame (window-frame (selected-window)))) + (sr-quit) + (message "All life leaps out to greet the light...") + (unless (eq my-frame (window-frame (selected-window))) + (select-frame my-frame) + (sunrise left-directory right-directory filename))))) + +;;;###autoload +(defun sr-dired (&optional target switches) + "Visit the given target (file or directory) in `sr-mode'." + (interactive + (list + (read-file-name "Visit (file or directory): " nil nil nil))) + (let* ((target (expand-file-name (or target default-directory))) + (file (if (file-directory-p target) nil target)) + (directory (if file (file-name-directory target) target)) + (dired-omit-mode (if sr-show-hidden-files -1 1)) + (sr-listing-switches (or switches sr-listing-switches))) + (unless (file-readable-p directory) + (error "%s is not readable!" (sr-directory-name-proper directory))) + (unless (and sr-running (eq (selected-frame) sr-current-frame)) (sunrise)) + (sr-select-window sr-selected-window) + (if file + (sr-follow-file file) + (sr-goto-dir directory)) + (hl-line-mode 1) + (sr-display-attributes (point-min) (point-max) sr-show-file-attributes) + (sr-this 'buffer))) + +(defun sr-choose-cd-target () + "Select a suitable target directory for cd operations." + (if (and sr-running (eq (selected-frame) sr-current-frame)) + sr-this-directory + default-directory)) + +;;;###autoload +(defun sunrise-cd () + "Toggle the Sunrise Commander FM keeping the current file in focus. +If Sunrise is off, enable it and focus the file displayed in the current buffer. +If Sunrise is on, disable it and switch to the buffer currently displayed in the +viewer window." + (interactive) + (if (not (and sr-running + (eq (window-frame sr-left-window) (selected-frame)))) + (sr-dired (or (buffer-file-name) (sr-choose-cd-target))) + (sr-quit t) + (message "Hast thou a charm to stay the morning-star in his deep course?"))) + +(defun sr-this (&optional type) + "Return object of type TYPE corresponding to the active side of the manager. +If TYPE is not specified (nil), returns a symbol (`left' or `right'). +If TYPE is `buffer' or `window', returns the corresponding buffer +or window." + (if type + (symbol-value (sr-symbol sr-selected-window type)) + sr-selected-window)) + +(defun sr-other (&optional type) + "Return object of type TYPE corresponding to the passive side of the manager. +If TYPE is not specified (nil), returns a symbol (`left' or `right'). +If TYPE is `buffer' or `window', returns the corresponding +buffer or window." + (let ((side (cdr (assq sr-selected-window sr-side-lookup)))) + (if type + (symbol-value (sr-symbol side type)) + side))) + +;;; ============================================================================ +;;; Window management functions: + +(defmacro sr-setup-pane (side) + "Helper macro for the function `sr-setup-windows'." + `(let ((sr-selected-window ',side)) + (setq ,(sr-symbol side 'window) (selected-window)) + (if (buffer-live-p ,(sr-symbol side 'buffer)) + (progn + (switch-to-buffer ,(sr-symbol side 'buffer)) + (setq ,(sr-symbol side 'directory) default-directory)) + (sr-dired ,(sr-symbol side 'directory))))) + +(defun sr-setup-visible-panes () + "Set up sunrise on all visible panes." + (sr-setup-pane left) + (unless (eq sr-window-split-style 'top) + (other-window 1) + (sr-setup-pane right))) + +(defun sr-setup-windows() + "Set up the Sunrise window configuration (two windows in `sr-mode')." + (run-hooks 'sr-init-hook) + ;;get rid of all windows except one (not any of the panes!) + (sr-select-viewer-window) + (delete-other-windows) + (if (buffer-live-p other-window-scroll-buffer) + (switch-to-buffer other-window-scroll-buffer) + (sr-switch-to-nonpane-buffer)) + + ;;now create the viewer window + (unless (and sr-panes-height (< sr-panes-height (frame-height))) + (setq sr-panes-height (sr-get-panes-size))) + (if (and (<= sr-panes-height (* 2 window-min-height)) + (eq sr-window-split-style 'vertical)) + (setq sr-panes-height (* 2 window-min-height))) + (split-window (selected-window) sr-panes-height) + + (case sr-window-split-style + (horizontal (split-window-horizontally)) + (vertical (split-window-vertically)) + (top (ignore)) + (t (error "Unrecognised `sr-window-split-style' value: %s" + sr-window-split-style))) + + (sr-setup-visible-panes) + + ;;select the correct window + (sr-select-window sr-selected-window) + (sr-restore-panes-width) + (run-hooks 'sr-start-hook)) + +(defun sr-switch-to-nonpane-buffer () + "Try to switch to a buffer that is *not* a Sunrise pane." + (let ((start (current-buffer))) + (while (and + start + (or (memq major-mode '(sr-mode sr-virtual-mode sr-tree-mode)) + (memq (current-buffer) (list sr-left-buffer sr-right-buffer)))) + (bury-buffer) + (if (eq start (current-buffer)) (setq start nil))))) + +(defun sr-restore-prior-configuration () + "Restore the configuration stored in `sr-prior-window-configuration' if any." + (set-window-configuration sr-prior-window-configuration) + (if (buffer-live-p sr-restore-buffer) + (set-buffer sr-restore-buffer))) + +(defun sr-lock-window (_frame) + "Resize the left Sunrise pane to have the \"right\" size." + (when sr-running + (if (not (window-live-p sr-left-window)) + (setq sr-running nil) + (let ((sr-windows-locked sr-windows-locked)) + (when (> window-min-height (- (frame-height) + (window-height sr-left-window))) + (setq sr-windows-locked nil)) + (and sr-windows-locked + (not sr-ediff-on) + (not (eq sr-window-split-style 'vertical)) + (window-live-p sr-left-window) + (save-selected-window + (select-window sr-left-window) + (let ((my-delta (- sr-panes-height (window-height)))) + (enlarge-window my-delta)) + (scroll-right) + (when (window-live-p sr-right-window) + (select-window sr-right-window) + (scroll-right)))))))) + +;; This keeps the size of the Sunrise panes constant: +(add-hook 'window-size-change-functions 'sr-lock-window) + +(defun sr-highlight(&optional face) + "Set up the path line in the current buffer. +With optional FACE, register this face as the current face to display the active +path line." + (when (and (memq major-mode '(sr-mode sr-virtual-mode sr-tree-mode)) + (not sr-inhibit-highlight)) + (let ((inhibit-read-only t)) + (save-excursion + (goto-char (point-min)) + (sr-hide-avfs-root) + (sr-highlight-broken-links) + (sr-graphical-highlight face) + (sr-force-passive-highlight) + (run-hooks 'sr-refresh-hook))))) + +(defun sr-unhighlight (face) + "Remove FACE from the list of faces of the active path line." + (when face + (setq sr-current-path-faces (delq face sr-current-path-faces)) + (overlay-put sr-current-window-overlay 'face + (or (car sr-current-path-faces) 'sr-active-path-face)))) + +(defun sr-hide-avfs-root () + "Hide the AVFS virtual filesystem root (if any) on the path line." + (if sr-avfs-root + (let ((start nil) (end nil) + (next (search-forward sr-avfs-root (point-at-eol) t))) + (if next (setq start (- next (length sr-avfs-root)))) + (while next + (setq end (point) + next (search-forward sr-avfs-root (point-at-eol) t))) + (when end + (add-text-properties start end '(invisible t)))))) + +(defun sr-highlight-broken-links () + "Mark broken symlinks with an exclamation mark." + (let ((dired-marker-char ?!)) + (while (search-forward-regexp dired-re-sym nil t) + (unless (or (not (eq 32 (char-after (line-beginning-position)))) + (file-exists-p (dired-get-filename))) + (dired-mark 1))))) + +(defsubst sr-invalid-overlayp () + "Test for invalidity of the current buffer's graphical path line overlay. +Returns t if the overlay is no longer valid and should be replaced." + (or (not (overlayp sr-current-window-overlay)) + (eq (overlay-start sr-current-window-overlay) + (overlay-end sr-current-window-overlay)))) + +(defun sr-graphical-highlight (&optional face) + "Set up the graphical path line in the current buffer. +\(Fancy fonts and clickable path.)" + (let ((begin) (end) (inhibit-read-only t)) + + (when (sr-invalid-overlayp) + ;;determine begining and end + (save-excursion + (goto-char (point-min)) + (search-forward-regexp "\\S " nil t) + (setq begin (1- (point))) + (end-of-line) + (setq end (1- (point)))) + + ;;build overlay + (when sr-current-window-overlay + (delete-overlay sr-current-window-overlay)) + (set (make-local-variable 'sr-current-window-overlay) + (make-overlay begin end)) + + ;;path line hover effect: + (add-text-properties + begin + end + '(mouse-face sr-highlight-path-face + help-echo "click to move up") + nil)) + (when face + (setq sr-current-path-faces (cons face sr-current-path-faces))) + (overlay-put sr-current-window-overlay 'face + (or (car sr-current-path-faces) 'sr-active-path-face)) + (overlay-put sr-current-window-overlay 'window (selected-window)))) + +(defun sr-force-passive-highlight (&optional revert) + "Set up the graphical path line in the passive pane. +With optional argument REVERT, executes `revert-buffer' on the passive buffer." + (unless (or (not (buffer-live-p (sr-other 'buffer))) + (eq sr-left-buffer sr-right-buffer)) + (with-current-buffer (sr-other 'buffer) + (when sr-current-window-overlay + (delete-overlay sr-current-window-overlay)) + (when (and revert + (memq major-mode '(sr-mode sr-virtual-mode sr-tree-mode))) + (revert-buffer))))) + +(defun sr-quit (&optional norestore) + "Quit Sunrise and restore Emacs to the previous state." + (interactive) + (if sr-running + (progn + (setq sr-running nil) + (sr-save-directories) + (sr-save-panes-width) + (if norestore + (progn + (sr-select-viewer-window) + (delete-other-windows)) + (sr-restore-prior-configuration)) + (sr-bury-panes) + (setq buffer-read-only nil) + (run-hooks 'sr-quit-hook) + (setq sr-current-frame nil)) + (bury-buffer))) + +(add-hook 'delete-frame-functions + (lambda (frame) + (if (and sr-running (eq frame sr-current-frame)) (sr-quit)))) + +(defun sr-save-directories () + "Save current directories in the panes to use them at the next startup." + (when (window-live-p sr-left-window) + (set-buffer (window-buffer sr-left-window)) + (when (memq major-mode '(sr-mode sr-tree-mode)) + (setq sr-left-directory default-directory) + (setq sr-left-buffer (current-buffer)))) + + (when (window-live-p sr-right-window) + (set-buffer (window-buffer sr-right-window)) + (when (memq major-mode '(sr-mode sr-tree-mode)) + (setq sr-right-directory default-directory) + (setq sr-right-buffer (current-buffer))))) + +(defun sr-bury-panes () + "Send both pane buffers to the end of the `buffer-list'." + (mapc (lambda (x) + (bury-buffer (symbol-value (sr-symbol x 'buffer)))) + '(left right))) + +(defun sr-save-panes-width () + "Save the width of the panes to use them at the next startup." + (unless sr-selected-window-width + (if (and (window-live-p sr-left-window) + (window-live-p sr-right-window)) + (setq sr-selected-window-width + (window-width + (symbol-value (sr-symbol sr-selected-window 'window)))) + (setq sr-selected-window-width t)))) + +(defun sr-restore-panes-width () + "Restore the last registered pane width." + (when (and (eq sr-window-split-style 'horizontal) + (numberp sr-selected-window-width)) + (enlarge-window-horizontally + (min (- sr-selected-window-width (window-width)) + (- (frame-width) (window-width) window-min-width))))) + +(defun sr-resize-panes (&optional reverse) + "Enlarge (or shrink, if REVERSE is t) the left pane by 5 columns." + (when (and (window-live-p sr-left-window) + (window-live-p sr-right-window)) + (let ((direction (or (and reverse -1) 1))) + (save-selected-window + (select-window sr-left-window) + (enlarge-window-horizontally (* 5 direction)))) + (setq sr-selected-window-width nil))) + +(defun sr-enlarge-left-pane () + "Enlarge the left pane by 5 columns." + (interactive) + (when (< (1+ window-min-width) (window-width sr-right-window)) + (sr-resize-panes) + (sr-save-panes-width))) + +(defun sr-enlarge-right-pane () + "Enlarge the right pane by 5 columns." + (interactive) + (when (< (1+ window-min-width) (window-width sr-left-window)) + (sr-resize-panes t) + (sr-save-panes-width))) + +(defun sr-get-panes-size (&optional size) + "Tell what the maximal, minimal and normal pane sizes should be." + (let ((frame (frame-height))) + (case size + (max (max (- frame window-min-height 1) 5)) + (min (min (1+ window-min-height) 5)) + (t (/ (* sr-windows-default-ratio (frame-height)) 100))))) + +(defun sr-enlarge-panes () + "Enlarge both panes vertically." + (interactive) + (let ((sr-windows-locked nil) + (max (sr-get-panes-size 'max)) + (ratio 1) + delta) + (save-selected-window + (when (eq sr-window-split-style 'vertical) + (select-window sr-right-window) + (setq ratio 2) + (setq delta (- max (window-height))) + (if (> (/ max ratio) (window-height)) + (shrink-window (if (< 2 delta) -2 -1)))) + (select-window sr-left-window) + (if (> (/ max ratio) (window-height)) + (shrink-window -1)) + (setq sr-panes-height (* (window-height) ratio))))) + +(defun sr-shrink-panes () + "Shink both panes vertically." + (interactive) + (let ((sr-windows-locked nil) + (min (sr-get-panes-size 'min)) + (ratio 1) + delta) + (save-selected-window + (when (eq sr-window-split-style 'vertical) + (select-window sr-right-window) + (setq ratio 2) + (setq delta (- (window-height) min)) + (if (< min (window-height)) + (shrink-window (if (< 2 delta) 2 1)))) + (select-window sr-left-window) + (if (< min (window-height)) + (shrink-window 1)) + (setq sr-panes-height (* (window-height) ratio))))) + +(defun sr-lock-panes (&optional height) + "Resize and lock the panes at some vertical position. +The optional argument determines the height to lock the panes at. +Valid values are `min' and `max'; given any other value, locks +the panes at normal position." + (interactive) + (if sr-running + (if (not (and (window-live-p sr-left-window) + (or (window-live-p sr-right-window) + (eq sr-window-split-style 'top)))) + (sr-setup-windows) + (setq sr-panes-height (sr-get-panes-size height)) + (let ((locked sr-windows-locked)) + (setq sr-windows-locked t) + (if height + (shrink-window 1) + (setq sr-selected-window-width t) + (balance-windows)) + (unless locked + (sit-for 0.1) + (setq sr-windows-locked nil)))) + (sunrise))) + +(defun sr-max-lock-panes () + (interactive) + (sr-save-panes-width) + (sr-lock-panes 'max)) + +(defun sr-min-lock-panes () + (interactive) + (sr-save-panes-width) + (sr-lock-panes 'min)) + +;;; ============================================================================ +;;; File system navigation functions: + +(defun sr-advertised-find-file (&optional filename) + "Handle accesses to file system objects through the user interface. +Includes cases when the user presses return, f or clicks on the path line." + (interactive) + (unless filename + (if (eq 1 (line-number-at-pos)) ;; <- Click or Enter on path line. + (let* ((path (buffer-substring (point) (point-at-eol))) + (levels (1- (length (split-string path "/"))))) + (if (< 0 levels) + (sr-dired-prev-subdir levels) + (sr-beginning-of-buffer))) + (setq filename (dired-get-filename nil t) + filename (and filename (expand-file-name filename))))) + (if filename + (if (file-exists-p filename) + (sr-find-file filename) + (error "Sunrise: nonexistent target")))) + +(defun sr-advertised-execute-file (&optional prefix) + "Execute the currently selected file in a new subprocess." + (interactive "P") + (let ((path (dired-get-filename nil t)) (label) (args)) + (if path + (setq label (file-name-nondirectory path)) + (error "Sunrise: no executable file on this line")) + (unless (and (not (file-directory-p path)) (file-executable-p path)) + (error "Sunrise: \"%s\" is not an executable file" label)) + (when prefix + (setq args (read-string (format "arguments for \"%s\": " label)) + label (format "%s %s" label args))) + (message "Sunrise: executing \"%s\" in new process" label) + (if args + (apply #'start-process (append (list "Sunrise Subprocess" nil path) + (split-string args))) + (start-process "Sunrise Subprocess" nil path)))) + +(defun sr-find-file (filename &optional wildcards) + "Determine the proper way of handling an object in the file system. +FILENAME can be either a regular file, a regular directory, a +Sunrise VIRTUAL directory, or a virtual directory served by +AVFS." + (interactive (find-file-read-args "Find file or directory: " nil)) + (cond ((file-directory-p filename) (sr-find-regular-directory filename)) + ((and (sr-avfs-directory-p filename) (sr-avfs-dir filename)) + (sr-find-regular-directory (sr-avfs-dir filename))) + ((sr-virtual-directory-p filename) (sr-find-virtual-directory filename)) + (t (sr-find-regular-file filename wildcards)))) + +(defun sr-virtual-directory-p (filename) + "Tell whether FILENAME is the path to a Sunrise VIRTUAL directory." + (eq 'sr-virtual-mode (assoc-default filename auto-mode-alist 'string-match))) + +(defun sr-avfs-directory-p (filename) + "Tell whether FILENAME can be seen as the root of an AVFS virtual directory." + (let ((mode (assoc-default filename auto-mode-alist 'string-match))) + (and sr-avfs-root + (or (eq 'archive-mode mode) + (eq 'tar-mode mode) + (and (listp mode) (eq 'jka-compr (cadr mode))) + (not (equal "." (sr-assoc-key filename + sr-avfs-handlers-alist + 'string-match))))))) + +(defun sr-find-regular-directory (directory) + "Visit the given regular directory in the active pane." + (setq directory (file-name-as-directory directory)) + (let ((parent (expand-file-name "../"))) + (if (and (not (sr-equal-dirs parent default-directory)) + (sr-equal-dirs directory parent)) + (sr-dired-prev-subdir) + (sr-goto-dir directory)))) + +(defun sr-find-virtual-directory (sr-virtual-dir) + "Visit the given Sunrise VIRTUAL directory in the active pane." + (sr-save-aspect + (sr-alternate-buffer (find-file sr-virtual-dir))) + (sr-history-push sr-virtual-dir) + (set-visited-file-name nil t) + (sr-keep-buffer) + (sr-backup-buffer)) + +(defun sr-find-regular-file (filename &optional wildcards) + "Deactivate Sunrise and visit FILENAME as a regular file with WILDCARDS. +\(See `find-file' for more details on wildcard expansion.)" + (condition-case description + (let ((buff (find-file-noselect filename nil nil wildcards))) + (sr-save-panes-width) + (sr-quit) + (set-window-configuration sr-prior-window-configuration) + (switch-to-buffer buff)) + (error (message "%s" (cadr description))))) + +(defun sr-avfs-dir (filename) + "Return the virtual path for accessing FILENAME through AVFS. +Returns nil if AVFS cannot manage this kind of file." + (let* ((handler (assoc-default filename sr-avfs-handlers-alist 'string-match)) + (vdir (concat filename handler))) + (unless (sr-overlapping-paths-p sr-avfs-root vdir) + (setq vdir (concat sr-avfs-root vdir))) + (if (file-attributes vdir) vdir nil))) + +(defun sr-goto-dir (dir) + "Change the current directory in the active pane to the given one." + (interactive "DChange directory (file or pattern): ") + (if sr-goto-dir-function + (funcall sr-goto-dir-function dir) + (unless (and (eq major-mode 'sr-mode) (sr-equal-dirs dir default-directory)) + (if (and sr-avfs-root + (null (posix-string-match "#" dir))) + (setq dir (replace-regexp-in-string + (expand-file-name sr-avfs-root) "" dir))) + (sr-save-aspect + (sr-within dir (sr-alternate-buffer (dired dir)))) + (sr-history-push default-directory) + (sr-beginning-of-buffer)))) + +(defun sr-dired-prev-subdir (&optional count) + "Go to the parent directory, or COUNT subdirectories upwards." + (interactive "P") + (unless (sr-equal-dirs default-directory "/") + (let* ((count (or count 1)) + (to (replace-regexp-in-string "x" "../" (make-string count ?x))) + (from (expand-file-name (substring to 1))) + (from (sr-directory-name-proper from)) + (from (replace-regexp-in-string "\\(?:#.*/?$\\|/$\\)" "" from)) + (to (replace-regexp-in-string "\\.\\./$" "" (expand-file-name to)))) + (sr-goto-dir to) + (unless (sr-equal-dirs from to) + (sr-focus-filename from))))) + +(defun sr-follow-file (&optional target-path) + "Go to the same directory where the selected file is. +Very useful inside Sunrise VIRTUAL buffers." + (interactive) + (if (null target-path) + (setq target-path (dired-get-filename nil t))) + + (let ((target-dir (file-name-directory target-path)) + (target-symlink (file-symlink-p target-path)) + (target-file)) + + ;; if the target is a symlink and there's nothing more interesting to do + ;; then follow the symlink: + (when (and target-symlink + (string= target-dir (dired-current-directory)) + (not (eq major-mode 'sr-virtual-mode))) + (unless (file-exists-p target-symlink) + (error "Sunrise: file is a symlink to a nonexistent target")) + (setq target-path target-symlink) + (setq target-dir (file-name-directory target-symlink))) + + (setq target-file (file-name-nondirectory target-path)) + + (when target-dir ;; <-- nil in symlinks to other files in same directory: + (setq target-dir (sr-chop ?/ target-dir)) + (sr-goto-dir target-dir)) + (sr-focus-filename target-file))) + +(defun sr-follow-viewer () + "Go to the directory of the file displayed in the viewer window." + (interactive) + (when sr-running + (let* ((viewer (sr-viewer-window)) + (viewer-buffer (if viewer (window-buffer viewer))) + (target-dir) (target-file)) + (when viewer-buffer + (with-current-buffer viewer-buffer + (setq target-dir default-directory + target-file (sr-directory-name-proper (buffer-file-name))))) + (sr-select-window sr-selected-window) + (if target-dir (sr-goto-dir target-dir)) + (if target-file (sr-focus-filename target-file))))) + +(defun sr-project-path () + "Find projections of the active directory over the passive one. + +Locates interactively all descendants of the directory in the passive pane that +have a path similar to the directory in the active pane. + +For instance, if the active pane is displaying directory /a/b/c and the passive +one is displaying /x/y, this command will check for the existence of any of the +following: /x/y/a/b/c, /x/y/b/c, /x/y/c and /x/y. Each (existing) directory +located according to this schema will be known hereafter as a 'projection of the +directory /a/b/c over /x/y'. + +If many projections of the active directory over the passive one exist, one can +rotate among all of them by invoking `sr-project-path' repeatedly : they will be +visited in order, from longest path to shortest." + + (interactive) + (let* ((sr-synchronized nil) + (path (sr-chop ?/ (expand-file-name (dired-current-directory)))) + (pos (if (< 0 (length path)) 1)) (candidate) (next-key)) + (while pos + (setq candidate (concat sr-other-directory (substring path pos)) + pos (string-match "/" path (1+ pos)) + pos (if pos (1+ pos))) + (when (and (file-directory-p candidate) + (not (sr-equal-dirs sr-this-directory candidate))) + (sr-goto-dir-other candidate) + (setq next-key (read-key-sequence "(press C-M-o again for more)")) + (if (eq (lookup-key sr-mode-map next-key) 'sr-project-path) + (sr-history-prev-other) + (setq unread-command-events (listify-key-sequence next-key) + pos nil)))) + (unless next-key + (message "Sunrise: sorry, no suitable projections found")))) + +(defun sr-history-push (element) + "Push a new path into the history stack of the current pane." + (unless (or (null element) + (and (featurep 'tramp) + (string-match tramp-file-name-regexp element))) + (let* ((pane (assoc sr-selected-window sr-history-registry)) + (hist (cdr pane)) + (len (length hist))) + (if (>= len sr-history-length) + (nbutlast hist (- len sr-history-length))) + (setq element (abbreviate-file-name (sr-chop ?/ element)) + hist (delete element hist)) + (push element hist) + (setcdr pane hist)) + (sr-history-stack-reset))) + +(defun sr-history-next () + "Navigate forward in the history of the active pane." + (interactive) + (let ((side (assoc sr-selected-window sr-history-stack))) + (unless (zerop (cadr side)) + (sr-history-move -1)) + (when (zerop (cadr side)) + (sr-history-stack-reset)))) + +(defun sr-history-prev () + "Navigate backwards in the history of the active pane." + (interactive) + (let ((history (cdr (assoc sr-selected-window sr-history-registry))) + (stack (cdr (assoc sr-selected-window sr-history-stack)))) + (when (< (abs (cdr stack)) (1- (length history))) + (sr-history-move 1)))) + +(defun sr-history-move (step) + "Traverse the history of the active pane in a stack-like fashion. +This function re-arranges the history list of the current pane so as to make it +simulate a stack of directories, from which one can 'pop' the current directory +and 'push' it back, keeping the most recently visited entries always near the +top of the stack." + (let* ((side (assoc sr-selected-window sr-history-stack)) + (depth (cadr side)) (goal) (target-dir)) + (when (> 0 (* step depth)) + (sr-history-stack-reset)) + (setq goal (1+ (cddr side)) + depth (* step (+ (abs depth) step)) + target-dir (sr-history-pick goal)) + (when target-dir + (sr-goto-dir target-dir) + (setcdr side (cons depth goal))))) + +(defun sr-history-stack-reset () + "Reset the current history stack counter." + (let ((side (assoc sr-selected-window sr-history-stack))) + (setcdr side '(0 . 0)))) + +(defun sr-history-pick (position) + "Return directory at POSITION in current history. +If the entry was removed or made inaccessible since our last visit, remove it +from the history list and check among the previous ones until an accessible +directory is found, or the list runs out of entries." + (let* ((history (cdr (assoc sr-selected-window sr-history-registry))) + (target (nth position history))) + (while (and target (not (file-accessible-directory-p target))) + (delete target history) + (setq target (nth position history))) + target)) + +(defun sr-require-checkpoints-extension (&optional noerror) + "Bootstrap code for checkpoint support. +Just tries to require the appropriate checkpoints extension +depending on the version of bookmark.el being used." + (require 'bookmark nil t) + (let* ((feature + (cond ((fboundp 'bookmark-make-record) 'sunrise-x-checkpoints) + (t 'sunrise-x-old-checkpoints))) + (name (symbol-name feature))) + (or + (not (featurep 'sunrise-commander)) + (require feature nil t) + noerror + (error "Feature `%s' not found!\ +For checkpoints to work, download http://joseito.republika.pl/%s.el.gz\ +and add it to your `load-path'" name name)))) + +(defmacro sr-checkpoint-command (function-name) + `(defun ,function-name (&optional arg) + (interactive) + (sr-require-checkpoints-extension) + (if (commandp #',function-name) + (call-interactively #',function-name) + (funcall #',function-name arg)))) +(sr-checkpoint-command sr-checkpoint-save) +(sr-checkpoint-command sr-checkpoint-restore) +(sr-checkpoint-command sr-checkpoint-handler) +;;;###autoload (autoload 'sr-checkpoint-handler "sunrise-commander" "" t) + +(defun sr-do-find-marked-files (&optional noselect) + "Sunrise replacement for `dired-do-find-marked-files'." + (interactive "P") + (let* ((files (delq nil (mapcar (lambda (x) + (and (file-regular-p x) x)) + (dired-get-marked-files))))) + (unless files + (error "Sunrise: no regular files to open")) + (unless noselect (sr-quit)) + (dired-simultaneous-find-file files noselect))) + +;;; ============================================================================ +;;; Graphical interface interaction functions: + +(defun sr-change-window() + "Change to the other Sunrise pane." + (interactive) + (if (and (window-live-p sr-left-window) (window-live-p sr-right-window)) + (let ((here sr-this-directory)) + (setq sr-this-directory sr-other-directory) + (setq sr-other-directory here) + (sr-select-window (sr-other))))) + +(defun sr-mouse-change-window (e) + "Change to the Sunrise pane clicked in by the mouse." + (interactive "e") + (mouse-set-point e) + (if (eq (selected-window) (sr-other 'window)) + (sr-change-window))) + +(defun sr-beginning-of-buffer() + "Go to the first directory/file in Dired." + (interactive) + (goto-char (point-min)) + (when (re-search-forward directory-listing-before-filename-regexp nil t) + (dotimes (_times 2) + (when (looking-at "\.\.?/?$") + (dired-next-line 1))))) + +(defun sr-end-of-buffer() + "Go to the last directory/file in Dired." + (interactive) + (goto-char (point-max)) + (re-search-backward directory-listing-before-filename-regexp) + (dired-next-line 0)) + +(defun sr-focus-filename (filename) + "Try to select FILENAME in the current buffer." + (if (and dired-omit-mode + (string-match (dired-omit-regexp) filename)) + (dired-omit-mode -1)) + (let ((sr-inhibit-highlight t) + (expr (sr-chop ?/ filename))) + (cond ((file-symlink-p filename) + (setq expr (concat (regexp-quote expr) " ->"))) + ((file-directory-p filename) + (setq expr (concat (regexp-quote expr) "\\(?:/\\|$\\)"))) + ((file-regular-p filename) + (setq expr (concat (regexp-quote expr) "$")))) + (setq expr (concat "[0-9] +" expr)) + (beginning-of-line) + (unless (re-search-forward expr nil t) + (re-search-backward expr nil t))) + (beginning-of-line) + (re-search-forward directory-listing-before-filename-regexp nil t)) + +(defun sr-split-toggle() + "Change Sunrise window layout from horizontal to vertical to top and so on." + (interactive) + (case sr-window-split-style + (horizontal (sr-split-setup 'vertical)) + (vertical (sr-split-setup 'top)) + (top (progn + (sr-split-setup 'horizontal) + (sr-in-other (revert-buffer)))) + (t (sr-split-setup 'horizontal)))) + +(defun sr-split-setup(split-type) + (setq sr-window-split-style split-type) + (when sr-running + (when (eq sr-window-split-style 'top) + (sr-select-window 'left) + (delete-window sr-right-window) + (setq sr-panes-height (window-height))) + (sr-setup-windows)) + (message "Sunrise: split style changed to \"%s\"" (symbol-name split-type))) + +(defun sr-transpose-panes () + "Change the order of the panes." + (interactive) + (unless (eq sr-left-buffer sr-right-buffer) + (mapc (lambda (x) + (let ((left (sr-symbol 'left x)) (right (sr-symbol 'right x)) (tmp)) + (setq tmp (symbol-value left)) + (set left (symbol-value right)) + (set right tmp))) + '(directory buffer window)) + (let ((tmp sr-this-directory)) + (setq sr-this-directory sr-other-directory + sr-other-directory tmp)) + (select-window sr-right-window) + (sr-setup-visible-panes) + (sr-select-window sr-selected-window))) + +(defun sr-synchronize-panes (&optional reverse) + "Change the directory in the other pane to that in the current one. +If the optional parameter REVERSE is non-nil, performs the +opposite operation, ie. changes the directory in the current pane +to that in the other one." + (interactive "P") + (let ((target (current-buffer)) (sr-inhibit-highlight t)) + (sr-change-window) + (if reverse + (setq target (current-buffer)) + (sr-alternate-buffer (switch-to-buffer target)) + (sr-history-push default-directory)) + (sr-change-window) + (when reverse + (sr-alternate-buffer (switch-to-buffer target)) + (sr-history-push default-directory) + (revert-buffer))) + (sr-highlight)) + +(defun sr-browse-pane () + "Browse the directory in the active pane." + (interactive) + (if (not (featurep 'browse-url)) + (error "Sunrise: feature `browse-url' not available!") + (let ((url (concat "file://" (expand-file-name default-directory)))) + (message "Browsing directory %s " default-directory) + (if (featurep 'w3m) + (eval '(w3m-goto-url url)) + (browse-url url))))) + +(defun sr-browse-file (&optional file) + "Display the selected file in the default web browser." + (interactive) + (unless (featurep 'browse-url) + (error "ERROR: Feature browse-url not available!")) + (setq file (or file (dired-get-filename))) + (save-selected-window + (sr-select-viewer-window) + (let ((buff (current-buffer))) + (browse-url (concat "file://" file)) + (unless (eq buff (current-buffer)) + (sr-scrollable-viewer (current-buffer))))) + (message "Browsing \"%s\" in web browser" file)) + +(defun sr-revert-buffer (&optional _ignore-auto _no-confirm) + "Revert the current pane using the contents of the backup buffer (if any). +If the buffer is non-virtual the backup buffer is killed." + (interactive) + (if (buffer-live-p sr-backup-buffer) + (let ((marks (dired-remember-marks (point-min) (point-max))) + (focus (dired-get-filename 'verbatim t)) + (inhibit-read-only t)) + (erase-buffer) + (insert-buffer-substring sr-backup-buffer) + (sr-beginning-of-buffer) + (dired-mark-remembered marks) + (if focus (sr-focus-filename focus)) + (dired-change-marks ?\t ?*) + (if (eq 'sr-mode major-mode) (sr-kill-backup-buffer))) + (unless (or (eq major-mode 'sr-virtual-mode) + (local-variable-p 'sr-virtual-buffer)) + (dired-revert) + (if (string= "NUMBER" (get sr-selected-window 'sorting-order)) + (sr-sort-by-number t) + (if (get sr-selected-window 'sorting-reverse) + (sr-reverse-pane))))) + (sr-display-attributes (point-min) (point-max) sr-show-file-attributes) + (sr-highlight)) + +(defun sr-kill-pane-buffer () + "Kill the buffer currently displayed in the active pane, or quit Sunrise. +Custom variable `sr-kill-unused-buffers' controls whether unused buffers are +killed automatically by Sunrise when the user navigates away from the directory +they contain. When this flag is set, all requests to kill the current buffer are +managed by just calling `sr-quit'." + (interactive) + (if sr-kill-unused-buffers + (sr-quit) + (kill-buffer (current-buffer)) + (let ((_x (pop (cdr (assoc sr-selected-window sr-history-registry))))) + (sr-history-stack-reset)))) + +(defun sr-quick-view (&optional arg) + "Quickly view the currently selected item. +On regular files, opens the file in quick-view mode (see `sr-quick-view-file' +for more details), on directories, visits the selected directory in the passive +pane, and on symlinks follows the file the link points to in the passive pane. +With optional argument kills the last quickly viewed file without opening a new +buffer." + (interactive "P") + (if arg + (sr-quick-view-kill) + (let ((name (dired-get-filename nil t))) + (cond ((file-directory-p name) (sr-quick-view-directory name)) + ((file-symlink-p name) (sr-quick-view-symlink name)) + (t (sr-quick-view-file)))))) + +(defun sr-quick-view-kill () + "Kill the last buffer opened using quick view (if any)." + (let ((buf other-window-scroll-buffer)) + (when (and (buffer-live-p buf) + (or (not sr-confirm-kill-viewer) + (y-or-n-p (format "Kill buffer %s? " (buffer-name buf))))) + (setq other-window-scroll-buffer nil) + (save-window-excursion (kill-buffer buf))))) + +(defun sr-quick-view-directory (name) + "Open the directory NAME in the passive pane." + (let ((name (expand-file-name name))) + (sr-in-other (sr-advertised-find-file name)))) + +(defun sr-quick-view-symlink (name) + "Follow the target of the symlink NAME in the passive pane." + (let ((name (expand-file-name (file-symlink-p name)))) + (if (file-exists-p name) + (sr-in-other (sr-follow-file name)) + (error "Sunrise: file is a symlink to a nonexistent target")))) + +(defun sr-quick-view-file () + "Open the selected file on the viewer window without selecting it. +Kills any other buffer opened previously the same way." + (let ((split-width-threshold (* 10 (window-width))) + (filename (expand-file-name (dired-get-filename nil t)))) + (save-selected-window + (condition-case description + (progn + (sr-select-viewer-window) + (find-file filename) + (if (and (not (eq (current-buffer) other-window-scroll-buffer)) + (buffer-live-p other-window-scroll-buffer)) + (kill-buffer other-window-scroll-buffer)) + (sr-scrollable-viewer (current-buffer))) + (error (message "%s" (cadr description))))))) + +;; These clean up after a quick view: +(add-hook 'sr-quit-hook (defun sr-sr-quit-function () + (setq other-window-scroll-buffer nil))) +(add-hook 'kill-buffer-hook + (defun sr-kill-viewer-function () + (if (eq (current-buffer) other-window-scroll-buffer) + (setq other-window-scroll-buffer nil)))) + +(defun sr-mask-attributes (beg end) + "Manage the hiding of attributes in region from BEG to END. +Selective hiding of specific attributes can be controlled by customizing the +`sr-attributes-display-mask' variable." + (let ((cursor beg) props) + (labels ((sr-make-display-props + (display-function-or-flag) + (cond ((functionp display-function-or-flag) + `(display + ,(apply display-function-or-flag + (list (buffer-substring cursor (1- (point))))))) + ((null display-function-or-flag) '(invisible t)) + (t nil)))) + (if sr-attributes-display-mask + (block block + (mapc (lambda (do-display) + (search-forward-regexp "\\w") + (search-forward-regexp "\\s-") + (setq props (sr-make-display-props do-display)) + (when props + (add-text-properties cursor (point) props)) + (setq cursor (point)) + (if (>= (point) end) (return-from block))) + sr-attributes-display-mask)) + (unless (>= cursor end) + (add-text-properties cursor end '(invisible t))))))) + +(defun sr-display-attributes (beg end visiblep) + "Manage the display of file attributes in the region from BEG to END. +if VISIBLEP is nil then shows file attributes in region, otherwise hides them." + (let ((inhibit-read-only t) (next)) + (save-excursion + (goto-char beg) + (forward-line -1) + (while (and (null next) (< (point) end)) + (forward-line 1) + (setq next (dired-move-to-filename))) + (while (and next (< next end)) + (beginning-of-line) + (forward-char 2) + (if (not visiblep) + (sr-mask-attributes (point) next) + (remove-text-properties (point) next '(invisible t)) + (remove-text-properties (point) next '(display))) + (forward-line 1) + (setq next (dired-move-to-filename)))))) + +(defun sr-toggle-attributes () + "Hide/Show the attributes of all files in the active pane." + (interactive) + (setq sr-show-file-attributes (not sr-show-file-attributes)) + (sr-display-attributes (point-min) (point-max) sr-show-file-attributes)) + +(defun sr-toggle-truncate-lines () + "Enable/Disable truncation of long lines in the active pane." + (interactive) + (if (sr-truncate-p) + (progn + (setq truncate-partial-width-windows (sr-truncate-v nil)) + (message "Sunrise: wrapping long lines")) + (progn + (setq truncate-partial-width-windows (sr-truncate-v t)) + (message "Sunrise: truncating long lines"))) + (sr-silently (dired-do-redisplay))) + +(defun sr-truncate-p () + "Return non-nil if `truncate-partial-width-windows' affects the current pane. +Used by `sr-toggle-truncate-lines'." + (if (numberp truncate-partial-width-windows) + (< 0 truncate-partial-width-windows) + truncate-partial-width-windows)) + +(defun sr-truncate-v (active) + "Return the appropriate value for `truncate-partial-width-widows'. +Depends on the Emacs version being used. Used by +`sr-toggle-truncate-lines'." + (or (and (version<= "23" emacs-version) + (or (and active 3000) 0)) + active)) + +(defun sr-sort-order (label option) + "Change the sorting order of the active pane. +Appends additional options to `dired-listing-switches' and +reverts the buffer." + (if (eq major-mode 'sr-virtual-mode) + (sr-sort-virtual option) + (progn + (put sr-selected-window 'sorting-order label) + (put sr-selected-window 'sorting-options option) + (let ((dired-listing-switches dired-listing-switches)) + (unless (string-match "^/ftp:" default-directory) + (setq dired-listing-switches sr-listing-switches)) + (dired-sort-other (concat dired-listing-switches option) t)) + (revert-buffer))) + (message "Sunrise: sorting entries by %s" label)) + +(defmacro sr-defun-sort-by (postfix options) + "Helper macro for defining `sr-sort-by-xxx' functions." + `(defun ,(intern (format "sr-sort-by-%s" postfix)) () + ,(format "Sorts the contents of the current Sunrise pane by %s." postfix) + (interactive) + (sr-sort-order ,(upcase postfix) ,options))) +(sr-defun-sort-by "name" "") +(sr-defun-sort-by "extension" "X") +(sr-defun-sort-by "time" "t") +(sr-defun-sort-by "size" "S") + +(defun sr-sort-by-number (&optional inhibit-label) + "Sort the contents of the current Sunrise pane numerically. +Displays entries containing unpadded numbers in a more logical +order than when sorted alphabetically by name." + (interactive) + (sr-sort-by-operation 'sr-numerical-sort-op (unless inhibit-label "NUMBER")) + (if (get sr-selected-window 'sorting-reverse) (sr-reverse-pane))) + +(defun sr-interactive-sort (order) + "Prompt for a new sorting order for the active pane and apply it." + (interactive "cSort by (n)ame, n(u)mber, (s)ize, (t)ime or e(x)tension? ") + (if (>= order 97) + (setq order (- order 32))) + (case order + (?U (sr-sort-by-number)) + (?T (sr-sort-by-time)) + (?S (sr-sort-by-size)) + (?X (sr-sort-by-extension)) + (t (sr-sort-by-name)))) + +(defun sr-reverse-pane (&optional interactively) + "Reverse the contents of the active pane." + (interactive "p") + (let ((line (line-number-at-pos)) + (reverse (get sr-selected-window 'sorting-reverse))) + (sr-sort-by-operation 'identity) + (when interactively + (put sr-selected-window 'sorting-reverse (not reverse)) + (goto-char (point-min)) (forward-line (1- line)) + (re-search-forward directory-listing-before-filename-regexp nil t)))) + +(defun sr-sort-virtual (option) + "Manage sorting of buffers in Sunrise VIRTUAL mode." + (let ((opt (string-to-char option)) (inhibit-read-only t) (beg) (end)) + (case opt + (?X (sr-end-of-buffer) + (setq end (point-at-eol)) + (sr-beginning-of-buffer) + (setq beg (point-at-bol)) + (sort-regexp-fields nil "^.*$" "[/.][^/.]+$" beg end)) + (?t (sr-sort-by-operation + (lambda (x) (sr-attribute-sort-op 5 t x)) "TIME")) + (?S (sr-sort-by-operation + (lambda (x) (sr-attribute-sort-op 7 t x)) "SIZE")) + (t (sr-sort-by-operation + (lambda (x) (sr-attribute-sort-op -1 nil x)) "NAME"))))) + +(defun sr-sort-by-operation (operation &optional label) + "General function for reordering the contents of a Sunrise pane. +OPERATION is a function that receives a list produced by +`sr-build-sort-lists', reorders it in some way, transforming it +into a list that can be passed to `sort-reorder', so the records +in the current buffer are reordered accordingly. The LABEL is a +string that will be used to set the sorting order of the current +pane and then displayed in the minibuffer; if it's not provided +or its value is nil then the ordering enforced by this function +is transient and can be undone by reverting the pane, or by +moving it to a different directory. See `sr-numerical-sort-op' +and `sr-attribute-sort-op' for examples of OPERATIONs." + (interactive) + (let ((messages (> (- (point-max) (point-min)) 50000)) + (focus (dired-get-filename 'verbatim t)) + (inhibit-read-only t)) + (if messages (message "Finding sort keys...")) + (let* ((sort-lists (sr-build-sort-lists)) + (old (reverse sort-lists)) + (beg) (end)) + (if messages (message "Sorting records...")) + (setq sort-lists (apply operation (list sort-lists))) + (if messages (message "Reordering buffer...")) + (save-excursion + (save-restriction + (sr-end-of-buffer) + (setq end (point-at-eol)) + (sr-beginning-of-buffer) + (setq beg (point-at-bol)) + (narrow-to-region beg end) + (sort-reorder-buffer sort-lists old))) + (if messages (message "Reordering buffer... Done"))) + (sr-highlight) + (if focus (sr-focus-filename focus)) + (when label + (put sr-selected-window 'sorting-order label) + (message "Sunrise: sorting entries by %s" label))) + nil) + +(defun sr-numerical-sort-op (sort-lists) + "Strategy used to numerically sort contents of a Sunrise pane. +Used by `sr-sort-by-operation'. See `sr-sort-by-number' for more +on this kind of sorting." + (mapcar + 'cddr + (sort + (sort + (mapcar + (lambda (x) + (let ((key (buffer-substring-no-properties (car x) (cddr x)))) + (append + (list key + (string-to-number (replace-regexp-in-string "^[^0-9]*" "" key)) + (cdr x)) + (cdr x)))) + sort-lists) + (lambda (a b) (string< (car a) (car b)))) + (lambda (a b) (< (cadr a) (cadr b)))))) + +(defun sr-attribute-sort-op (nth-attr as-number sort-lists) + "Strategy used to sort contents of a Sunrise pane according to file attributes. +Used by `sr-sort-by-operation'. See `file-attributes' for a list +of supported attributes and their positions. Directories are +forced to remain always on top. NTH-ATTR is the position of the +attribute to use for sorting, or -1 for the name of the file. +AS-NUMBER determines whether comparisons will be numeric or +alphabetical. SORT-LISTS is a list of positions obtained from +`sr-build-sort-lists'." + (let ((attributes (sr-files-attributes)) + (zero (if as-number 0 ""))) + (mapcar + 'cddr + (sort + (sort + (mapcar + (lambda (x) + (let* ((key (buffer-substring-no-properties (car x) (cddr x))) + (key (sr-chop ?/ (replace-regexp-in-string " -> .*$" "" key))) + (attrs (assoc-default key attributes)) + (index)) + (when attrs + (setq attrs (apply 'cons attrs) + index (or (nth (1+ nth-attr) attrs) zero)) + (append (list (cadr attrs) index (cdr x)) (cdr x))))) + sort-lists) + (lambda (a b) (sr-compare nth-attr (cadr b) (cadr a)))) + (lambda (a b) + (if (and (car a) (car b)) + (sr-compare nth-attr (cadr b) (cadr a)) + (and (car a) (not (stringp (car a)))))))))) + +(defun sr-build-sort-lists () + "Analyse contents of the current Sunrise pane for `sr-sort-by-operation'. +Builds a list of dotted lists of the form (a b . c) -- where 'a' +is the position at the start of the file name in an entry, while +'b' and 'c' are the start and end positions of the whole entry. +These lists are used by `sr-sort-by-operation' to sort the +contents of the pane in arbitrary ways." + (delq nil + (mapcar + (lambda (x) (and (atom (car x)) x)) + (save-excursion + (sr-beginning-of-buffer) + (beginning-of-line) + (sort-build-lists 'forward-line 'end-of-line 'dired-move-to-filename + nil))))) + +(defun sr-compare (mode a b) + "General comparison function, used to sort files in VIRTUAL buffers. +MODE must be a number; if it is less than 0, the direction of the +comparison is inverted: (sr-compare -1 a b) === (sr-compare 1 +b a). Compares numbers using `<', strings case-insensitively +using `string<' and lists recursively until the first two +elements that are non-equal are found." + (if (< mode 0) (let (tmp) (setq tmp a a b b tmp mode (abs mode)))) + (cond ((or (null a) (null b)) nil) + ((and (listp a) (listp b)) (if (= (car a) (car b)) + (sr-compare mode (cdr a) (cdr b)) + (sr-compare mode (car a) (car b)))) + ((and (stringp a) (stringp b)) (string< (downcase a) (downcase b))) + ((and (numberp a) (numberp b)) (< a b)) + (t nil))) + +(defun sr-scroll-up () + "Scroll the current pane or (if active) the viewer pane 1 line up." + (interactive) + (if (buffer-live-p other-window-scroll-buffer) + (save-selected-window + (sr-select-viewer-window) + (scroll-up 1)) + (scroll-up 1))) + +(defun sr-scroll-down () + "Scroll the current pane or (if active) the viewer pane 1 line down." + (interactive) + (if (buffer-live-p other-window-scroll-buffer) + (save-selected-window + (sr-select-viewer-window) + (scroll-down 1)) + (scroll-down 1))) + +(defun sr-scroll-quick-view () + "Scroll down the viewer window during a quick view." + (interactive) + (if other-window-scroll-buffer (scroll-other-window))) + +(defun sr-scroll-quick-view-down () + "Scroll down the viewer window during a quick view." + (interactive) + (if other-window-scroll-buffer (scroll-other-window-down nil))) + +(defun sr-undo () + "Restore selection as it was before the last file operation." + (interactive) + (dired-undo) + (sr-highlight)) + +;;; ============================================================================ +;;; Passive & synchronized navigation functions: + +(defun sr-sync () + "Toggle the Sunrise synchronized navigation feature." + (interactive) + (setq sr-synchronized (not sr-synchronized)) + (mapc 'sr-mark-sync (list sr-left-buffer sr-right-buffer)) + (message "Sunrise: sync navigation is now %s" (if sr-synchronized "ON" "OFF")) + (run-hooks 'sr-refresh-hook) + (sr-in-other (run-hooks 'sr-refresh-hook))) + +(defun sr-mark-sync (&optional buffer) + "Change `mode-name' depending on whether synchronized navigation is enabled." + (save-window-excursion + (if buffer + (switch-to-buffer buffer)) + (setq mode-name (concat "Sunrise " + (if sr-synchronized "SYNC-NAV" "Commander"))))) + +;; This advertises synchronized navigation in all new buffers: +(add-hook 'sr-mode-hook 'sr-mark-sync) + +(defun sr-next-line-other () + "Move the cursor down in the passive pane." + (interactive) + (sr-in-other (dired-next-line 1))) + +(defun sr-prev-line-other () + "Move the cursor up in the passive pane." + (interactive) + (sr-in-other (dired-next-line -1))) + +(defun sr-goto-dir-other (dir) + "Change the current directory in the passive pane to the given one." + (interactive (list (read-directory-name + "Change directory in PASSIVE pane (file or pattern): " + sr-other-directory))) + (sr-in-other (sr-goto-dir dir))) + +(defun sr-advertised-find-file-other () + "Open the file/directory selected in the passive pane." + (interactive) + (if sr-synchronized + (let ((target (sr-directory-name-proper (dired-get-filename)))) + (sr-change-window) + (if (file-directory-p target) + (sr-goto-dir (expand-file-name target)) + (if (y-or-n-p "Unable to synchronize. Disable sync navigation? ") + (sr-sync))) + (sr-change-window) + (sr-advertised-find-file)) + (sr-in-other (sr-advertised-find-file)))) + +(defun sr-mouse-advertised-find-file (e) + "Open the file/directory pointed to by the mouse." + (interactive "e") + (sr-mouse-change-window e) + (sr-advertised-find-file)) + +(defun sr-prev-subdir-other (&optional count) + "Go to the previous subdirectory in the passive pane." + (interactive "P") + (let ((count (or count 1))) + (sr-in-other (sr-dired-prev-subdir count)))) + +(defun sr-follow-file-other () + "Go to the directory of the selected file, but in the passive pane." + (interactive) + (let ((filename (dired-get-filename nil t))) + (sr-in-other (sr-follow-file filename)))) + +(defun sr-history-prev-other () + "Change to previous directory (if any) in the passive pane's history list." + (interactive) + (sr-in-other (sr-history-prev))) + +(defun sr-history-next-other () + "Change to the next directory (if any) in the passive pane's history list." + (interactive) + (sr-in-other (sr-history-next))) + +(defun sr-mark-other (arg) + "Mark the current (or next ARG) files in the passive pane." + (interactive "P") + (setq arg (or arg 1)) + (sr-in-other (dired-mark arg))) + +(defun sr-unmark-backward-other (arg) + (interactive "p") + (sr-in-other (dired-unmark-backward arg))) + +(defun sr-unmark-all-marks-other () + "Remove all marks from the passive pane." + (interactive) + (sr-in-other (dired-unmark-all-marks))) + +;;; ============================================================================ +;;; Progress feedback functions: + +(defun sr-progress-prompt (op-name) + "Build the default progress feedback message." + (concat "Sunrise: " op-name "... ")) + +(defun sr-make-progress-reporter (op-name totalsize) + "Make a new Sunrise progress reporter. +Prepends two integers (accumulator and scale) to a standard +progress reporter (built using `make-progress-reporter' from +subr.el): accumulator keeps the current state of the reporter, +and scale is used when the absolute value of 100% is bigger than +`most-positive-fixnum'." + (let ((accumulator 0) (scale 1) (maxval totalsize)) + (when (> totalsize most-positive-fixnum) + (setq scale (/ totalsize most-positive-fixnum)) + (setq maxval most-positive-fixnum)) + (list accumulator scale + (make-progress-reporter + (sr-progress-prompt op-name) 0 maxval 0 1 0.5)))) + +(defun sr-progress-reporter-update (reporter size) + "Update REPORTER (a Sunrise progress reporter) by adding SIZE to its state." + (let ((scale (cadr reporter))) + (setcar reporter (+ (truncate (/ size scale)) (car reporter))) + (progress-reporter-update (caddr reporter) (car reporter)))) + +(defun sr-progress-reporter-done (reporter) + "Print REPORTER's feedback message followed by \"done\" in echo area." + (progress-reporter-done (caddr reporter))) + +;;; ============================================================================ +;;; File manipulation functions: + +(defun sr-create-files (&optional qty) + "Interactively create empty file(s) with the given name or template. +Optional prefix argument specifies the number of files to create. +*NEVER* overwrites existing files. A template may contain one +%-sequence like those used by `format', but the only supported +specifiers are: d (decimal), x (hex) or o (octal)." + (interactive "p") + (let* ((qty (or (and (integerp qty) (< 0 qty) qty) 1)) + (prompt (if (>= 1 qty) "Create file: " + (format "Create %d files using template: " qty))) + (filename (read-file-name prompt)) (name)) + (with-temp-buffer + (if (>= 1 qty) + (unless (file-exists-p filename) (write-file filename)) + (unless (string-match "%[0-9]*[dox]" filename) + (setq filename (concat filename ".%d"))) + (setq filename (replace-regexp-in-string "%\\([^%]\\)" "%%\\1" filename) + filename (replace-regexp-in-string + "%%\\([0-9]*[dox]\\)" "%\\1" filename)) + (dotimes (n qty) + (setq name (format filename (1+ n))) + (unless (file-exists-p name) (write-file name))))) + (sr-revert-buffer))) + +(defun sr-editable-pane () + "Put the current pane in File Names Editing mode (`wdired-mode')." + (interactive) + (sr-graphical-highlight 'sr-editing-path-face) + (let* ((was-virtual (eq major-mode 'sr-virtual-mode)) + (major-mode 'dired-mode)) + (wdired-change-to-wdired-mode) + (if was-virtual + (set (make-local-variable 'sr-virtual-buffer) t))) + (run-hooks 'sr-refresh-hook)) + +(defun sr-readonly-pane (as-virtual) + "Put the current pane back in Sunrise mode." + (when as-virtual + (sr-virtual-mode) + (sr-force-passive-highlight t)) + (dired-build-subdir-alist) + (sr-revert-buffer)) + +(defun sr-terminate-wdired (fun) + "Restore the current pane's original mode after editing with WDired." + (ad-add-advice + fun + (ad-make-advice + (intern (concat "sr-advice-" (symbol-name fun))) nil t + `(advice + lambda () + (if (not sr-running) + ad-do-it + (let ((was-virtual (local-variable-p 'sr-virtual-buffer)) + (saved-point (point))) + (sr-save-aspect + (setq major-mode 'wdired-mode) + (letf (((symbol-function 'yes-or-no-p) (lambda (prompt) (ignore))) + ((symbol-function 'revert-buffer) + (lambda (&optional ignore-auto noconfirm preserve-modes) + (ignore)))) + ad-do-it) + (sr-readonly-pane was-virtual) + (goto-char saved-point)) + (sr-unhighlight 'sr-editing-path-face))))) + 'around 'last) + (ad-activate fun nil)) +(sr-terminate-wdired 'wdired-finish-edit) +(sr-terminate-wdired 'wdired-abort-changes) + +(defun sr-do-copy () + "Copy selected files and directories recursively to the passive pane." + (interactive) + (let* ((items (dired-get-marked-files nil)) + (vtarget (sr-virtual-target)) + (target (or vtarget sr-other-directory)) + (progress)) + (if (and (not vtarget) (sr-equal-dirs default-directory sr-other-directory)) + (dired-do-copy) + (when (sr-ask "Copy" target items #'y-or-n-p) + (if vtarget + (progn + (sr-copy-virtual) + (message "Done: %d items(s) copied" (length items))) + (progn + (setq progress (sr-make-progress-reporter + "copying" (sr-files-size items))) + (sr-clone items target #'copy-file progress ?C) + (sr-progress-reporter-done progress))) + (sr-silently (dired-unmark-all-marks)))))) + +(defun sr-do-symlink () + "Symlink selected files or directories from one pane to the other." + (interactive) + (if (sr-equal-dirs default-directory sr-other-directory) + (dired-do-symlink) + (sr-link #'make-symbolic-link "Symlink" dired-keep-marker-symlink))) + +(defun sr-do-relsymlink () + "Symlink selected files or directories from one pane to the other relatively. +See `dired-make-relative-symlink'." + (interactive) + (if (sr-equal-dirs default-directory sr-other-directory) + (dired-do-relsymlink) + (sr-link #'dired-make-relative-symlink + "RelSymLink" + dired-keep-marker-relsymlink))) + +(defun sr-do-hardlink () + "Same as `dired-do-hardlink', but refuse to hardlink files to VIRTUAL buffers." + (interactive) + (if (sr-virtual-target) + (error "Cannot hardlink files to a VIRTUAL buffer, try (C)opying instead") + (dired-do-hardlink))) + +(defun sr-do-rename () + "Move selected files and directories recursively from one pane to the other." + (interactive) + (when (sr-virtual-target) + (error "Cannot move files to a VIRTUAL buffer, try (C)opying instead")) + (if (sr-equal-dirs default-directory sr-other-directory) + (dired-do-rename) + (let ((marked (dired-get-marked-files))) + (when (sr-ask "Move" sr-other-directory marked #'y-or-n-p) + (let ((names (mapcar #'file-name-nondirectory marked)) + (progress (sr-make-progress-reporter "renaming" (length marked))) + (inhibit-read-only t)) + (sr-in-other + (progn + (sr-move-files marked default-directory progress) + (revert-buffer) + (when (eq major-mode 'sr-mode) + (dired-mark-remembered + (mapcar (lambda (x) (cons (expand-file-name x) ?R)) names)) + (sr-focus-filename (car names))))) + (sr-progress-reporter-done progress)) + (sr-silently (revert-buffer)))))) + +(defun sr-do-delete () + "Remove selected files from the file system." + (interactive) + (let* ((files (dired-get-marked-files)) + (mode (sr-ask "Delete" nil files #'sr-y-n-or-a-p)) + (deletion-mode (cond ((eq mode 'ALWAYS) 'always) + (mode 'top) + (t (error "(No deletions performed)"))))) + (mapc (lambda (x) + (message "Deleting %s" x) + (dired-delete-file x deletion-mode)) files) + (if (eq major-mode 'sr-virtual-mode) + (dired-do-kill-lines) + (revert-buffer)))) + +(defun sr-do-flagged-delete () + "Remove flagged files from the file system." + (interactive) + (let* ((dired-marker-char dired-del-marker) + (regexp (dired-marker-regexp)) ) + (if (save-excursion (goto-char (point-min)) + (re-search-forward regexp nil t)) + (sr-do-delete) + (message "(No deletions requested)")))) + +(defun sr-do-clone (&optional mode) + "Clone all selected items recursively into the passive pane." + (interactive "cClone as: (D)irectories only, (C)opies, (H)ardlinks,\ + (S)ymlinks or (R)elative symlinks? ") + + (if (sr-virtual-target) + (error "Cannot clone into a VIRTUAL buffer, try (C)opying instead")) + (if (sr-equal-dirs default-directory sr-other-directory) + (error "Cannot clone inside one single directory, please select a\ + different one in the passive pane")) + + (let ((target sr-other-directory) clone-op items progress) + (if (and mode (>= mode 97)) (setq mode (- mode 32))) + (setq clone-op + (case mode + (?D nil) + (?C #'copy-file) + (?H #'add-name-to-file) + (?S #'make-symbolic-link) + (?R #'dired-make-relative-symlink) + (t (error "Invalid cloning mode: %c" mode)))) + (setq items (dired-get-marked-files nil)) + (setq progress (sr-make-progress-reporter + "cloning" (sr-files-size items))) + (sr-clone items target clone-op progress ?K) + (dired-unmark-all-marks) + (message "Done: %d items(s) dispatched" (length items)))) + +(defun sr-fast-backup-files () + "Make backup copies of all marked files inside the same directory. +The extension to append to each filename can be controlled by +setting the value of the `sr-fast-backup-extension' custom +variable. Directories are not copied." + (interactive) + (let ((extension (if (listp sr-fast-backup-extension) + (eval sr-fast-backup-extension) + sr-fast-backup-extension))) + (dired-do-copy-regexp "$" extension)) + (revert-buffer)) + +(defun sr-clone (items target clone-op progress mark-char) + "Clone all given items (files and dirs) recursively into the passive pane." + (let ((names (mapcar #'file-name-nondirectory items)) + (inhibit-read-only t)) + (with-current-buffer (sr-other 'buffer) + (sr-clone-files items target clone-op progress)) + (when (window-live-p (sr-other 'window)) + (sr-in-other + (progn + (revert-buffer) + (when (memq major-mode '(sr-mode sr-virtual-mode)) + (dired-mark-remembered + (mapcar (lambda (x) (cons (expand-file-name x) mark-char)) names)) + (sr-focus-filename (car names)))))))) + +(defun sr-clone-files (file-paths target-dir clone-op progress &optional do-overwrite) + "Clone all files in FILE-PATHS to TARGET-DIR using CLONE-OP to clone the files. +FILE-PATHS should be a list of full paths." + (setq target-dir (replace-regexp-in-string "/?$" "/" target-dir)) + (mapc + (function + (lambda (f) + (sr-progress-reporter-update progress (nth 7 (file-attributes f))) + (let* ((name (file-name-nondirectory f)) + (target-file (concat target-dir name)) + (symlink-to (file-symlink-p (sr-chop ?/ f))) + (clone-args (list f target-file t))) + (cond + (symlink-to + (progn + (if (file-exists-p symlink-to) + (setq symlink-to (expand-file-name symlink-to))) + (make-symbolic-link symlink-to target-file do-overwrite))) + + ((file-directory-p f) + (let ((initial-path (file-name-directory f))) + (unless (file-symlink-p initial-path) + (sr-clone-directory + initial-path name target-dir clone-op progress do-overwrite)))) + + (clone-op + ;; (message "[[Cloning: %s => %s]]" f target-file) + (if (eq clone-op 'copy-file) + (setq clone-args + (append clone-args (list dired-copy-preserve-time)))) + (if (file-exists-p target-file) + (if (or (eq do-overwrite 'ALWAYS) + (setq do-overwrite (sr-ask-overwrite target-file))) + (apply clone-op clone-args)) + (apply clone-op clone-args))))))) + file-paths)) + +(defun sr-clone-directory (in-dir d to-dir clone-op progress do-overwrite) + "Clone directory IN-DIR/D and all its files recursively to TO-DIR. +IN-DIR/D => TO-DIR/D using CLONE-OP to clone the files." + (setq d (replace-regexp-in-string "/?$" "/" d)) + (if (string= "" d) + (setq to-dir (concat to-dir (sr-directory-name-proper in-dir)))) + (let* ((files-in-d (sr-list-of-contents (concat in-dir d))) + (file-paths-in-d + (mapcar (lambda (f) (concat in-dir d f)) files-in-d))) + (unless (file-exists-p (concat to-dir d)) + (make-directory (concat to-dir d))) + (sr-clone-files file-paths-in-d (concat to-dir d) clone-op progress do-overwrite))) + +(defsubst sr-move-op (file target target-dir progress do-overwrite) + "Helper function used by `sr-move-files' to rename files and directories." + (condition-case nil + (dired-rename-file file target do-overwrite) + (error + (sr-clone-directory file "" target-dir 'copy-file progress do-overwrite) + (dired-delete-file file 'always)))) + +(defun sr-move-files (file-path-list target-dir progress &optional do-overwrite) + "Move all files in FILE-PATH-LIST (list of full paths) to TARGET-DIR." + (mapc + (function + (lambda (f) + (if (file-directory-p f) + (progn + (setq f (replace-regexp-in-string "/?$" "/" f)) + (sr-progress-reporter-update progress 1) + (let* ((target (concat target-dir (sr-directory-name-proper f)))) + (if (file-exists-p target) + (when (or (eq do-overwrite 'ALWAYS) + (setq do-overwrite (sr-ask-overwrite target))) + (sr-move-op f target target-dir progress do-overwrite)) + (sr-move-op f target target-dir progress do-overwrite)))) + (let* ((name (file-name-nondirectory f)) + (target-file (concat target-dir name))) + ;; (message "Renaming: %s => %s" f target-file) + (sr-progress-reporter-update progress 1) + (if (file-exists-p target-file) + (if (or (eq do-overwrite 'ALWAYS) + (setq do-overwrite (sr-ask-overwrite target-file))) + (dired-rename-file f target-file t)) + (dired-rename-file f target-file t)) )))) + file-path-list)) + +(defun sr-link (creator action marker) + "Helper function for implementing `sr-do-symlink' and `sr-do-relsymlink'." + (if (sr-virtual-target) + (error "Cannot link files to a VIRTUAL buffer, try (C)opying instead.") + (dired-create-files creator action (dired-get-marked-files nil) + (lambda (from) + (setq from (sr-chop ?/ from)) + (if (file-directory-p from) + (setq from (sr-directory-name-proper from)) + (setq from (file-name-nondirectory from))) + (expand-file-name from sr-other-directory)) + marker))) + +(defun sr-virtual-target () + "If the passive pane is in VIRTUAL mode, return its name as a string. +Otherwise returns nil." + (save-window-excursion + (switch-to-buffer (sr-other 'buffer)) + (if (eq major-mode 'sr-virtual-mode) + (or (buffer-file-name) "Sunrise VIRTUAL buffer") + nil))) + +(defun sr-copy-virtual () + "Manage copying of files or directories to buffers in VIRTUAL mode." + (let ((fileset (dired-get-marked-files nil)) + (inhibit-read-only t) (beg)) + (sr-change-window) + (goto-char (point-max)) + (setq beg (point)) + (mapc (lambda (file) + (insert-char 32 2) + (setq file (dired-make-relative file default-directory) + file (sr-chop ?/ file)) + (insert-directory file sr-virtual-listing-switches)) + fileset) + (sr-display-attributes beg (point-at-eol) sr-show-file-attributes) + (unwind-protect + (delete-region (point) (line-end-position)) + (progn + (sr-change-window) + (dired-unmark-all-marks))))) + +(defun sr-ask (prompt target files function) + "Use FUNCTION to ask whether to do PROMPT on FILES with TARGET as destination." + (if (and files (listp files)) + (let* ((len (length files)) + (msg (if (< 1 len) + (format "* [%d items]" len) + (file-name-nondirectory (car files))))) + (if target + (setq msg (format "%s to %s" msg target))) + (funcall function (format "%s %s? " prompt msg))))) + +(defun sr-ask-overwrite (file-name) + "Ask whether to overwrite the given FILE-NAME." + (sr-y-n-or-a-p (format "File %s exists. OK to overwrite? " file-name))) + +(defun sr-y-n-or-a-p (prompt) + "Ask the user with PROMPT for an answer y/n/a ('a' stands for 'always'). +Returns t if the answer is y/Y, nil if the answer is n/N or the +symbol `ALWAYS' if the answer is a/A." + (setq prompt (concat prompt "([y]es, [n]o or [a]lways)")) + (let ((resp -1)) + (while (not (memq resp '(?y ?Y ?n ?N ?a ?A))) + (setq resp (read-event prompt)) + (setq prompt "Please answer [y]es, [n]o or [a]lways ")) + (if (>= resp 97) + (setq resp (- resp 32))) + (case resp + (?Y t) + (?A 'ALWAYS) + (t nil)))) + +(defun sr-overlapping-paths-p (dir1 dir2) + "Return non-nil if directory DIR2 is located inside directory DIR1." + (when (and dir1 dir2) + (setq dir1 (expand-file-name (file-name-as-directory dir1)) + dir2 (expand-file-name dir2)) + (if (>= (length dir2) (length dir1)) + (equal (substring dir2 0 (length dir1)) dir1) + nil))) + +(defun sr-list-of-contents (dir) + "Return the list of all files in DIR as a list of strings." + (sr-filter (function (lambda (x) (not (string-match "\\.\\.?/?$" x)))) + (directory-files dir))) + +(defun sr-list-of-directories (dir) + "Return the list of directories in DIR as a list of strings. +The list does not include the current directory and the parent directory." + (let ((result (sr-filter (function (lambda (x) + (file-directory-p (concat dir "/" x)))) + (sr-list-of-contents dir)))) + (mapcar (lambda (x) (concat x "/")) result))) + +(defun sr-list-of-files (dir) + "Return the list of regular files in DIR as a list of strings. +Broken links are *not* considered regular files." + (sr-filter + (function (lambda (x) (file-regular-p (concat dir "/" x)))) + (sr-list-of-contents dir))) + +(defun sr-filter (p x) + "Return the elements of the list X that satisfy the predicate P." + (let ((res-list nil)) + (while x + (if (apply p (list (car x))) + (setq res-list (cons (car x) res-list))) + (setq x (cdr x))) + (reverse res-list))) + +(defun sr-directory-name-proper (file-path) + "Return the proper name of the directory FILE-PATH, without initial path." + (if file-path + (let ( + (file-path-1 (substring file-path 0 (- (length file-path) 1))) + (lastchar (substring file-path (- (length file-path) 1))) + ) + (concat (file-name-nondirectory file-path-1) lastchar)))) + +;;; ============================================================================ +;;; Directory and file comparison functions: + +(defun sr-compare-panes () + "Compare the contents of Sunrise panes." + (interactive) + (let* ((file-alist1 (sr-files-attributes)) + (other (sr-other 'buffer)) + (file-alist2 (with-current-buffer other (sr-files-attributes))) + (progress + (sr-make-progress-reporter + "comparing" (+ (length file-alist1) (length file-alist2)))) + (predicate `(prog1 ,(sr-ask-compare-panes-predicate) + (sr-progress-reporter-update ',progress 1))) + (file-list1 (mapcar 'cadr (dired-file-set-difference + file-alist1 file-alist2 predicate))) + (file-list2 (mapcar 'cadr (dired-file-set-difference + file-alist2 file-alist1 predicate)))) + (sr-md5 nil) + (dired-mark-if (member (dired-get-filename nil t) file-list1) nil) + (with-current-buffer other + (dired-mark-if (member (dired-get-filename nil t) file-list2) nil)) + (message "Marked in pane1: %s files, in pane2: %s files" + (length file-list1) + (length file-list2)) + (sit-for 0.2))) + +(defun sr-ask-compare-panes-predicate () + "Prompt for the criterion to use for comparing the contents of the panes." + (let ((prompt "Compare by (d)ate, (s)ize, date_(a)nd_size, (n)ame \ +or (c)ontents? ") + (response -1)) + (while (not (memq response '(?d ?D ?s ?S ?a ?A ?n ?N ?c ?C))) + (setq response (read-event prompt)) + (setq prompt "Please select: Compare by (d)ate, (s)ize, date_(a)nd_size,\ + (n)ame or (c)ontents? ")) + (if (>= response 97) + (setq response (- response 32))) + (case response + (?D `(not (= mtime1 mtime2))) + (?S `(not (= size1 size2))) + (?N nil) + (?C `(not (string= (sr-md5 file1 t) (sr-md5 file2 t)))) + (t `(or (not (= mtime1 mtime2)) (not (= size1 size2))))))) + +(defun sr-files-attributes () + "Return a list of all file names and attributes in the current pane. +The list has the same form as the one returned by +`dired-files-attributes', but contains all the files currently +displayed in VIRTUAL panes." + (delq + nil + (mapcar + (lambda (file-name) + (unless (member file-name '("." "..")) + (let ((full-file-name (expand-file-name file-name default-directory))) + (list file-name full-file-name (file-attributes full-file-name))))) + (sr-pane-files)))) + +(defun sr-pane-files () + "Return the list of files in the current pane. +For VIRTUAL panes, returns the list of all files being currently +displayed." + (delq + nil + (if (eq major-mode 'sr-virtual-mode) + (sr-buffer-files (current-buffer)) + (directory-files default-directory)))) + +(defvar sr-md5 '(nil) "Memoization cache for the sr-md5 function.") +(defun sr-md5 (file-alist &optional memoize) + "Build and execute a shell command to calculate the MD5 checksum of a file. +Second element of FILE-ALIST is the absolute path of the file. If +MEMOIZE is non-nil, save the result into the `sr-md5' alist so it +can be reused the next time this function is called with the same +path. This cache can be cleared later calling `sr-md5' with nil +as its first argument." + (if (null file-alist) + (setq sr-md5 '(nil)) + (let* ((filename (cadr file-alist)) + (md5-digest (cdr (assoc filename sr-md5))) + (md5-command)) + (unless md5-digest + (setq md5-command + (replace-regexp-in-string + "%f" (format "\"%s\"" filename) sr-md5-shell-command)) + (setq md5-digest (shell-command-to-string md5-command)) + (if memoize + (push (cons filename md5-digest) sr-md5))) + md5-digest))) + +(defun sr-diff () + "Run `diff' on the top two marked files in both panes." + (interactive) + (eval (sr-diff-form 'diff)) + (sr-scrollable-viewer (get-buffer "*Diff*"))) + +(defun sr-ediff () + "Run `ediff' on the two top marked files in both panes." + (interactive) + (eval (sr-diff-form 'ediff))) + +(add-hook 'ediff-before-setup-windows-hook + (defun sr-ediff-before-setup-windows-function () + (setq sr-ediff-on t))) + +(add-hook 'ediff-quit-hook + (defun sr-ediff-quit-function () + (setq sr-ediff-on nil) + (when sr-running + (if (buffer-live-p sr-restore-buffer) + (switch-to-buffer sr-restore-buffer)) + (delete-other-windows) + (sr-setup-windows)))) + +(defun sr-diff-form (fun) + "Return the appropriate form to evaluate for comparing files using FUN." + (let ((this (sr-pop-mark)) (other nil)) + (unless this + (setq this (car (dired-get-marked-files t)))) + (if (sr-equal-dirs default-directory sr-other-directory) + (setq other (sr-pop-mark)) + (progn + (sr-change-window) + (setq other (sr-pop-mark)) + (sr-change-window) + (setq other (or other + (if (file-exists-p (concat sr-other-directory this)) + this + (file-name-nondirectory this)))))) + (setq this (concat default-directory this) + other (concat sr-other-directory other)) + (list fun this other))) + +(defun sr-pop-mark () + "Pop the first mark in the current Dired buffer." + (let ((result nil)) + (condition-case description + (save-excursion + (goto-char (point-min)) + (dired-next-marked-file 1) + (setq result (dired-get-filename t t)) + (dired-unmark 1)) + (error (message (cadr description)))) + result)) + +;;; ============================================================================ +;;; File search & analysis functions: + +(defun sr-process-kill () + "Kill the process running in the current buffer (if any)." + (interactive) + (let ((proc (get-buffer-process (current-buffer)))) + (and proc (eq (process-status proc) 'run) + (condition-case nil + (delete-process proc) + (error nil))))) + +(defvar sr-process-map (let ((map (make-sparse-keymap))) + (set-keymap-parent map sr-virtual-mode-map) + (define-key map "\C-c\C-k" 'sr-process-kill) + map) + "Local map used in Sunrise panes during find and locate operations.") + +(defun sr-find-decorate-buffer (find-items) + "Provide details on `sr-find' execution in the current buffer. +If the current find operation is done only in selected files and directories, +modify the info line of the buffer to reflect this. Additionally, display an +appropriate message in the minibuffer." + (rename-uniquely) + (when find-items + (let ((items-len (length find-items)) + (max-items-len (window-width)) + (inhibit-read-only t)) + (goto-char (point-min)) + (forward-line 1) + (when (re-search-forward "find \." nil t) + (if (> items-len max-items-len) + (setq find-items + (concat (substring find-items 0 max-items-len) " ..."))) + (replace-match (format "find %s" find-items))))) + (sr-beginning-of-buffer) + (sr-highlight) + (hl-line-mode 1) + (message (propertize "Sunrise find (C-c C-k to kill)" + 'face 'minibuffer-prompt))) + +(defun sr-find-apply (fun pattern) + "Helper function for functions `sr-find', `sr-find-name' and `sr-find-grep'." + (let* ((suffix (if (eq 'w32 window-system) " {} ;" " \\{\\} \\;")) + (find-ls-option + (cons + (concat "-exec ls -d " sr-virtual-listing-switches suffix) + "ls -ld")) + (sr-find-items (sr-quote-marked)) (dir)) + (when sr-find-items + (if (not (y-or-n-p "Find in marked items only? ")) + (setq sr-find-items nil) + (setq dir (directory-file-name (expand-file-name default-directory))) + (add-to-list 'file-name-handler-alist (cons dir 'sr-multifind-handler)))) + (sr-save-aspect + (sr-alternate-buffer (apply fun (list default-directory pattern))) + (sr-virtual-mode) + (use-local-map sr-process-map) + (sr-keep-buffer)) + (run-with-idle-timer 0.01 nil 'sr-find-decorate-buffer sr-find-items))) + +(defun sr-find (pattern) + "Run `find-dired' passing the current directory as first parameter." + (interactive "sRun find (with args): ") + (sr-find-apply 'find-dired pattern)) + +(defun sr-find-name (pattern) + "Run `find-name-dired' passing the current directory as first parameter." + (interactive "sFind name pattern: ") + (sr-find-apply 'find-name-dired pattern)) + +(defun sr-find-grep (pattern) + "Run `find-grep-dired' passing the current directory as first +parameter. Called with prefix asks for additional grep options." + (interactive "sFind files containing pattern: ") + (let ((find-grep-options + (if current-prefix-arg + (concat find-grep-options + " " + (read-string "Additional Grep Options: ")) + find-grep-options))) + (sr-find-apply 'find-grep-dired pattern))) + +(defadvice find-dired-sentinel + (after sr-advice-find-dired-sentinel (proc state)) + "If the current find operation was launched inside the Sunrise +Commander, create a new backup buffer on operation completion or +abort." + (with-current-buffer (process-buffer proc) + (when (eq 'sr-virtual-mode major-mode) + (sr-backup-buffer)))) +(ad-activate 'find-dired-sentinel) + +(defadvice find-dired-filter + (around sr-advice-find-dired-filter (proc string)) + "Disable the \"non-foolproof\" padding mechanism in `find-dired-filter' that +breaks Dired when using ls options that omit some columns (like g or G). Defined +by the Sunrise Commander." + (if (and (eq 'sr-virtual-mode major-mode) + (or (string-match "g" sr-virtual-listing-switches) + (string-match "G" sr-virtual-listing-switches))) + (let ((find-ls-option nil)) ad-do-it) + ad-do-it)) +(ad-activate 'find-dired-filter) + +(defun sr-multifind-handler (operation &rest args) + "Magic file name handler for manipulating the command executed by `find-dired' +when the user requests to perform the find operation on all currently marked +items (as opposed to the current default directory). Removes itself from the +`inhibit-file-name-handlers' every time it's executed." + (let ((inhibit-file-name-handlers + (cons 'sr-multifind-handler + (and (eq inhibit-file-name-operation operation) + inhibit-file-name-handlers))) + (inhibit-file-name-operation operation)) + (when (eq operation 'shell-command) + (setq file-name-handler-alist + (rassq-delete-all 'sr-multifind-handler file-name-handler-alist)) + (when sr-find-items + (setcar args (replace-regexp-in-string + "find \." (format "find %s" sr-find-items) (car args))))) + (apply operation args))) + +(defun sr-flatten-branch (&optional mode) + "Display a flat view of the items contained in the current directory and all +its subdirectories, sub-subdirectories and so on (recursively) in the active +pane." + (interactive "cFlatten branch showing: (E)verything, (D)irectories,\ + (N)on-directories or (F)iles only?") + (if (and mode (>= mode 97)) (setq mode (- mode 32))) + (case mode + (?E (sr-find-name "*")) + (?D (sr-find "-type d")) + (?N (sr-find "-not -type d")) + (?F (sr-find "-type f")))) + +(defun sr-prune-paths (regexp) + "Kill all lines (only the lines) in the current pane matching REGEXP." + (interactive "sPrune paths matching: ") + (save-excursion + (sr-beginning-of-buffer) + (while (if (string-match regexp (dired-get-filename t)) + (dired-kill-line) + (dired-next-line 1))))) + +(defun sr-locate-filter (locate-buffer search-string) + "Return a filter function for the background `locate' process." + `(lambda (process output) + (let ((inhibit-read-only t) + (search-regexp ,(regexp-quote search-string)) + (beg (point-max))) + (set-buffer ,locate-buffer) + (save-excursion + (mapc (lambda (x) + (when (and (string-match search-regexp x) (file-exists-p x)) + (goto-char (point-max)) + (insert-char 32 2) + (insert-directory x sr-virtual-listing-switches nil nil))) + (split-string output "[\r\n]" t)) + (sr-display-attributes beg (point-at-eol) sr-show-file-attributes))))) + +(defun sr-locate-sentinel (locate-buffer) + "Return a sentinel function for the background locate process. +Used to notify about the termination status of the process." + `(lambda (process status) + (let ((inhibit-read-only t)) + (set-buffer ,locate-buffer) + (goto-char (point-max)) + (insert "\n " locate-command " " status) + (forward-char -1) + (insert " at " (substring (current-time-string) 0 19)) + (forward-char 1)) + (sr-beginning-of-buffer) + (sr-highlight) + (hl-line-mode 1))) + +(defun sr-locate-prompt () + "Display the message that appears when a locate process is launched." + (message (propertize "Sunrise locate (C-c C-k to kill)" + 'face 'minibuffer-prompt))) + +(defvar locate-command) +(autoload 'locate-prompt-for-search-string "locate") +(defun sr-locate (search-string &optional _filter _arg) + "Run locate asynchronously and display the results in Sunrise virtual mode." + (interactive + (list (locate-prompt-for-search-string) nil current-prefix-arg)) + (let ((locate-buffer (create-file-buffer "*Sunrise Locate*")) + (process-connection-type nil) + (locate-process nil)) + (sr-save-aspect + (sr-alternate-buffer (switch-to-buffer locate-buffer)) + (cd "/") + (insert " " default-directory ":")(newline) + (insert " Results of: " locate-command " " search-string)(newline) + (sr-virtual-mode) + (set-process-filter + (setq locate-process + (start-process "Async Locate" nil locate-command search-string)) + (sr-locate-filter locate-buffer search-string)) + (set-process-sentinel locate-process (sr-locate-sentinel locate-buffer)) + (set-process-buffer locate-process locate-buffer) + (use-local-map sr-process-map) + (run-with-idle-timer 0.01 nil 'sr-locate-prompt)))) + +(defun sr-fuzzy-narrow () + "Interactively narrow contents of the current pane using fuzzy matching: + * press Delete or Backspace to revert the buffer to its previous state + * press Return, C-n or C-p to exit and accept the current narrowed state + * press Esc or C-g to abort the operation and revert the buffer + * use ! to prefix characters that should NOT appear beyond a given position. + Once narrowed and accepted, you can restore the original contents of the pane + by pressing g (`revert-buffer')." + (interactive) + (when sr-running + (sr-beginning-of-buffer) + (dired-change-marks ?* ?\t) + (let ((stack nil) (filter "") (regex "") (next-char nil) (inhibit-quit t)) + (labels ((read-next (f) (read-char (concat "Fuzzy narrow: " f)))) + (setq next-char (read-next filter)) + (sr-backup-buffer) + (while next-char + (case next-char + ((?\e ?\C-g) (setq next-char nil) (sr-revert-buffer)) + (?\C-n (setq next-char nil) (sr-beginning-of-buffer)) + (?\C-p (setq next-char nil) (sr-end-of-buffer)) + ((?\n ?\r) (setq next-char nil)) + ((?\b ?\d) + (revert-buffer) + (setq stack (cdr stack) filter (caar stack) regex (cdar stack)) + (unless stack (setq next-char nil))) + (t + (setq filter (concat filter (char-to-string next-char))) + (if (not (eq next-char sr-fuzzy-negation-character)) + (setq next-char (char-to-string next-char) + regex (if (string= "" regex) ".*" regex) + regex (concat regex (regexp-quote next-char) ".*")) + (setq next-char (char-to-string (read-next filter)) + filter (concat filter next-char) + regex (replace-regexp-in-string "\\.\\*\\'" "" regex) + regex (concat regex "[^"(regexp-quote next-char)"]*") + regex (replace-regexp-in-string "\\]\\*\\[\\^" "" regex))) + (setq stack (cons (cons filter regex) stack)))) + (when next-char + (dired-mark-files-regexp (concat "^" regex "$")) + (dired-toggle-marks) + (dired-do-kill-lines) + (setq next-char (read-next filter))))) + (dired-change-marks ?\t ?*)))) + +(defun sr-recent-files () + "Display the history of recent files in Sunrise virtual mode." + (interactive) + (if (not (featurep 'recentf)) + (error "ERROR: Feature recentf not available!")) + + (sr-save-aspect + (let ((dired-actual-switches dired-listing-switches)) + (sr-switch-to-clean-buffer "*Recent Files*") + (insert "Recently Visited Files: \n") + (dolist (file recentf-list) + (condition-case nil + (insert-directory file sr-virtual-listing-switches nil nil) + (error (ignore)))) + (sr-virtual-mode) + (sr-keep-buffer)))) + +(defun sr-recent-directories () + "Display the history of directories recently visited in the current pane." + (interactive) + (sr-save-aspect + (let ((hist (cdr (assoc sr-selected-window sr-history-registry))) + (dired-actual-switches dired-listing-switches) + (pane-name (capitalize (symbol-name sr-selected-window))) + (switches (concat sr-virtual-listing-switches " -d"))) + (sr-switch-to-clean-buffer (format "*%s Pane History*" pane-name)) + (insert (concat "Recent Directories in " pane-name " Pane: \n")) + (dolist (dir hist) + (condition-case nil + (when dir + (setq dir (sr-chop ?/ (expand-file-name dir))) + (insert-directory dir switches nil nil)) + (error (ignore)))) + (sr-virtual-mode)))) + +(defun sr-switch-to-clean-buffer (name) + (sr-alternate-buffer (switch-to-buffer name)) + (erase-buffer)) + +(defun sr-pure-virtual (&optional passive) + "Create a new empty buffer in Sunrise VIRTUAL mode. +If the optional argument PASSIVE is non-nil, creates the virtual +buffer in the passive pane." + (interactive "P") + (if passive + (progn + (sr-synchronize-panes) + (sr-in-other (sr-pure-virtual nil))) + (sr-save-aspect + (let* ((dir (directory-file-name (dired-current-directory))) + (buff (generate-new-buffer-name (buffer-name (current-buffer))))) + (sr-alternate-buffer (switch-to-buffer buff)) + (goto-char (point-min)) + (insert " " dir ":")(newline) + (insert " Pure VIRTUAL buffer: ")(newline) + (sr-virtual-mode) + (sr-keep-buffer))))) + +(defun sr-dired-do-apply (dired-fun) + "Helper function for implementing `sr-do-query-replace-regexp' and Co." + (let ((buff (current-buffer)) (orig sr-restore-buffer)) + (condition-case nil + (progn + (sr-quit) + (switch-to-buffer buff) + (call-interactively dired-fun) + (replace-buffer-in-windows buff) + (sr-bury-panes)) + (quit + (when orig (switch-to-buffer orig)) + (sunrise))))) + +(defun sr-do-query-replace-regexp () + "Force Sunrise to quit before executing `dired-do-query-replace-regexp'." + (interactive) + (sr-dired-do-apply 'dired-do-query-replace-regexp)) + +(defun sr-do-search () + "Force Sunrise to quit before executing `dired-do-search'." + (interactive) + (sr-dired-do-apply 'dired-do-search)) + +(defun sr-sticky-isearch-prompt () + "Display the message that appears when a sticky search is launched." + (message (propertize "Sunrise sticky I-search (C-g to exit): " + 'face 'minibuffer-prompt))) + +(defvar sr-sticky-isearch-commands + '(nil + ("\C-o" . dired-omit-mode) + ("\M-a" . sr-beginning-of-buffer) + ("\M-e" . sr-end-of-buffer) + ("\C-v" . scroll-up-command) + ("\M-v" . (lambda () (interactive) (scroll-up-command '-))) + ) "Keybindings installed in `isearch-mode' during a sticky search.") + +(defun sr-sticky-isearch-remap-commands (&optional restore) + "Remap `isearch-mode-map' commands using `sr-sticky-isearch-commands'. +Replace the bindings in our table with the previous ones from `isearch-mode-map' +so we can restore them when the current sticky search operation finishes." + (when (eq restore (car sr-sticky-isearch-commands)) + (setcar sr-sticky-isearch-commands (not restore)) + (mapc (lambda (entry) + (let* ((binding (car entry)) + (old-command (lookup-key isearch-mode-map binding)) + (new-command (cdr entry))) + (define-key isearch-mode-map binding new-command) + (setcdr entry old-command))) + (cdr sr-sticky-isearch-commands)))) + +(defun sr-sticky-isearch (&optional backward) + "Concatenate Isearch operations to allow fast file system navigation. +Search continues until C-g is pressed (to abort) or Return is +pressed on a regular file (to end the operation and visit that +file)." + (set (make-local-variable 'search-nonincremental-instead) nil) + (add-hook 'isearch-mode-end-hook 'sr-sticky-post-isearch) + (sr-sticky-isearch-remap-commands) + (if backward + (isearch-backward nil t) + (isearch-forward nil t)) + (run-hooks 'sr-refresh-hook) + (run-with-idle-timer 0.01 nil 'sr-sticky-isearch-prompt)) + +(defun sr-sticky-isearch-forward () + "Start a sticky forward search in the current pane." + (interactive) + (sr-sticky-isearch)) + +(defun sr-sticky-isearch-backward () + "Start a sticky backward search in the current pane." + (interactive) + (sr-sticky-isearch t)) + +(defun sr-sticky-post-isearch () + "`isearch-mode-end-hook' function for Sunrise sticky Isearch operations." + (and + (dired-get-filename nil t) + (let* ((filename (expand-file-name (dired-get-filename nil t))) + (is-dir (or (file-directory-p filename) + (sr-avfs-dir filename) + (sr-virtual-directory-p filename)))) + (cond ((or isearch-mode-end-hook-quit (not is-dir)) + (progn + (remove-hook 'isearch-mode-end-hook 'sr-sticky-post-isearch) + (kill-local-variable 'search-nonincremental-instead) + (sr-sticky-isearch-remap-commands t) + (isearch-done) + (if isearch-mode-end-hook-quit + (run-hooks 'sr-refresh-hook) + (sr-find-file filename)))) + (t + (progn + (sr-find-file filename) + (set (make-local-variable 'search-nonincremental-instead) nil) + (isearch-forward nil t) + (run-with-idle-timer 0.01 nil 'sr-sticky-isearch-prompt))))))) + +(defun sr-show-files-info (&optional deref-symlinks) + "Enhanced version of `dired-show-file-type' from diredâaux. +If at most one item is marked, print the filetype of the current +item according to the \"file\" command, including its size in bytes. +If more than one item is marked, print the total size in +bytes (calculated recursively) of all marked items." + (interactive "P") + (message "Calculating total size of selection... (C-g to abort)") + (let* ((selection (dired-get-marked-files t)) + (size (sr-size-format (sr-files-size selection))) + (items (length selection)) (label) (regex)) + (if (>= 1 items) + (progn + (setq selection (car selection) + label (file-name-nondirectory selection) + regex (concat "^.*" label "[:;]") + label (concat label ":")) + (dired-show-file-type selection deref-symlinks) + (message + "%s (%s bytes)" + (replace-regexp-in-string regex label (current-message)) size)) + (message "%s bytes in %d selected items" size items)) + (sit-for 0.5))) + +(eval-when-compile + (defsubst sr-size-attr (file) + "Helper function for `sr-files-size'." + (float (or (nth 7 (file-attributes file)) 0)))) + +(defun sr-files-size (files) + "Recursively calculate the total size of all FILES. +FILES should be a list of paths." + (let ((result 0)) + (mapc + (lambda (x) (setq result (+ x result))) + (mapcar (lambda (f) (cond ((string-match "\\.\\./?$" f) 0) + ((string-match "\\./?$" f) (sr-size-attr f)) + ((file-symlink-p f) (sr-size-attr f)) + ((file-directory-p f) (sr-directory-size f)) + (t (float (sr-size-attr f))))) + files)) + result)) + +(defun sr-directory-size (directory) + "Recursively calculate the total size of the given DIRECTORY." + (sr-files-size (directory-files directory t nil t))) + +(defun sr-size-format (size) + "Return integer representation of SIZE (a float) as a string. +Uses comma as the thousands separator." + (let* ((num (replace-regexp-in-string "\\..*$" "" (number-to-string size))) + (digits (reverse (split-string num "" t))) + result) + (dotimes (n (length digits)) + (when (and (< 0 n) (zerop (% n 3))) + (setq result (concat "," result))) + (setq result (concat (pop digits) result))) + result)) + +;;; ============================================================================ +;;; TI (Terminal Integration) and CLEX (Command Line EXpansion) functions: + +;;;###autoload +(defun sr-term (&optional cd newterm program) + "Run terminal in a new buffer or switch to an existing one. +If the optional argument CD is non-nil, directory is changed to +the current one in the active pane. A non-nil NEWTERM argument +forces the creation of a new terminal. If PROGRAM is provided +and exists in `exec-path', then it will be used instead of the +default `sr-terminal-program'." + (interactive) + (let ((aterm (car sr-ti-openterms))) + (if (and (null program) + (or (eq major-mode 'eshell-mode) + (and (buffer-live-p aterm) + (with-current-buffer aterm + (eq major-mode 'eshell-mode))))) + (setq program "eshell") + (setq program (or program sr-terminal-program)))) + (if (memq major-mode '(sr-mode sr-virtual-mode sr-tree-mode)) + (hl-line-mode 1)) + (if (string= program "eshell") + (sr-term-eshell cd newterm) + (sr-term-extern cd newterm program))) + +;;;###autoload +(defun sr-term-cd () + "Run terminal in a new buffer or switch to an existing one. +cd's to the current directory of the active pane." + (interactive) + (sr-term t)) + +;;;###autoload +(defun sr-term-cd-newterm () + "Open a NEW terminal (don't switch to an existing one). +cd's to the current directory of the active pane." + (interactive) + (sr-term t t)) + +;;;###autoload +(defun sr-term-cd-program (&optional program) + "Open a NEW terminal using PROGRAM as the shell." + (interactive "sShell program to use: ") + (sr-term t t program)) + +(defmacro sr-term-excursion (newterm form &optional is-external) + "Take care of the common mechanics of launching or switching to a terminal. +Helper macro." + `(let* ((start-buffer (current-buffer)) + (new-term (or (null sr-ti-openterms) ,newterm)) + (next-buffer (or (cadr (memq start-buffer sr-ti-openterms)) + (car sr-ti-openterms))) + (new-name) (is-line-mode)) + (sr-select-viewer-window t) + (if (not new-term) + (switch-to-buffer next-buffer) + (when next-buffer + (with-current-buffer next-buffer + (setq is-line-mode (and (boundp 'sr-term-line-minor-mode) + (symbol-value 'sr-term-line-minor-mode))))) + ,form + (if ,is-external (sr-term-char-mode)) + (if is-line-mode (sr-term-line-mode)) + (when (memq (current-buffer) sr-ti-openterms) + (rename-uniquely) + (setq new-name (buffer-name)) + ,form) + (when new-name + (message "Sunrise: previous terminal renamed to %s" new-name)) + (push (current-buffer) sr-ti-openterms)))) + +(defun sr-term-line-mode () + "Switch the current terminal to line mode. +Apply additional Sunrise keybindings for terminal integration." + (interactive) + (term-line-mode) + (sr-term-line-minor-mode 1)) + +(defun sr-term-char-mode () + "Switch the current terminal to character mode. +Bind C-j and C-k to Sunrise terminal integration commands." + (interactive) + (term-char-mode) + (sr-term-line-minor-mode 0) + (sr-term-char-minor-mode 1)) + +(defun sr-term-extern (&optional cd newterm program) + "Implementation of `sr-term' for external terminal programs. +See `sr-term' for a description of the arguments." + (let* ((program (if program (executable-find program))) + (program (or program sr-terminal-program)) + (dir (expand-file-name (sr-choose-cd-target))) + (aterm (car sr-ti-openterms)) + (cd (or cd (null sr-ti-openterms))) + (line-mode (if (buffer-live-p aterm) + (with-current-buffer aterm (term-in-line-mode))))) + (sr-term-excursion newterm (term program) t) + (sr-term-char-mode) + (when (or line-mode (term-in-line-mode)) + (sr-term-line-mode)) + (when cd + (term-send-raw-string + (concat "cd " (shell-quote-wildcard-pattern dir) " +"))))) + +(defun sr-term-eshell (&optional cd newterm) + "Implementation of `sr-term' when using `eshell'." + (let ((dir (expand-file-name (sr-choose-cd-target))) + (cd (or cd (null sr-ti-openterms)))) + (sr-term-excursion newterm (eshell)) + (when cd + (insert (concat "cd " (shell-quote-wildcard-pattern dir))) + (eshell-send-input)) + (sr-term-line-mode))) + +(defmacro sr-ti (form) + "Evaluate FORM in the context of the selected pane. +Helper macro for implementing terminal integration in Sunrise." + `(if sr-running + (progn + (sr-select-window sr-selected-window) + (hl-line-unhighlight) + (unwind-protect + ,form + (when sr-running + (sr-select-viewer-window)))))) + +(defun sr-ti-previous-line () + "Move one line backward on active pane from the terminal window." + (interactive) + (sr-ti (forward-line -1))) + +(defun sr-ti-next-line () + "Move one line forward on active pane from the terminal window." + (interactive) + (sr-ti (forward-line 1))) + +(defun sr-ti-select () + "Run `dired-advertised-find-file' on active pane from the terminal window." + (interactive) + (sr-ti (sr-advertised-find-file))) + +(defun sr-ti-mark () + "Run `dired-mark' on active pane from the terminal window." + (interactive) + (sr-ti (dired-mark 1))) + +(defun sr-ti-unmark () + "Run `dired-unmark-backward' on active pane from the terminal window." + (interactive) + (sr-ti (dired-unmark-backward 1))) + +(defun sr-ti-prev-subdir (&optional count) + "Run `dired-prev-subdir' on active pane from the terminal window." + (interactive "P") + (let ((count (or count 1))) + (sr-ti (sr-dired-prev-subdir count)))) + +(defun sr-ti-unmark-all-marks () + "Remove all marks on active pane from the terminal window." + (interactive) + (sr-ti (dired-unmark-all-marks))) + +(defun sr-ti-change-window () + "Switch focus to the currently active pane." + (interactive) + (sr-select-window sr-selected-window)) + +(defun sr-ti-change-pane () + "Change selection of active pane to passive one." + (interactive) + (sr-ti (sr-change-window))) + +(add-hook + 'kill-buffer-hook + (defun sr-ti-cleanup-openterms () + "Remove the current buffer from the list of open terminals." + (setq sr-ti-openterms (delete (current-buffer) sr-ti-openterms)))) + +(defun sr-ti-revert-buffer () + "Refresh the currently active pane." + (interactive) + (let ((dir default-directory)) + (if (not (sr-equal-dirs dir sr-this-directory)) + (sr-ti (sr-goto-dir dir)) + (sr-ti (sr-revert-buffer))))) + +(defun sr-ti-lock-panes () + "Resize and lock the panes at standard position from the command line." + (interactive) + (sr-ti (sr-lock-panes))) + +(defun sr-ti-min-lock-panes () + "Minimize the panes from the command line." + (interactive) + (sr-ti (sr-min-lock-panes))) + +(defun sr-ti-max-lock-panes () + "Maximize the panes from the command line." + (interactive) + (sr-ti (sr-max-lock-panes))) + +(defmacro sr-clex (pane form) + "Evaluate FORM in the context of PANE. +Helper macro for implementing command line expansion in Sunrise." + `(save-window-excursion + (setq pane (if (atom pane) pane (eval pane))) + (select-window (symbol-value (sr-symbol ,pane 'window))) + ,form)) + +(defun sr-clex-marked (pane) + "Return a string containing the list of marked files in PANE." + (sr-clex + pane + (mapconcat 'shell-quote-wildcard-pattern (dired-get-marked-files) " "))) + +(defun sr-clex-file (pane) + "Return the file currently selected in PANE." + (sr-clex + pane + (concat (shell-quote-wildcard-pattern (dired-get-filename)) " "))) + +(defun sr-clex-marked-nodir (pane) + "Return a list of basenames of all the files currently marked in PANE." + (sr-clex + pane + (mapconcat 'shell-quote-wildcard-pattern + (dired-get-marked-files 'no-dir) " "))) + +(defun sr-clex-dir (pane) + "Return the current directory of the given pane." + (sr-clex + pane + (concat (shell-quote-wildcard-pattern default-directory) " "))) + +(defun sr-clex-start () + "Start a new CLEX operation. +Puts `sr-clex-commit' into local `after-change-functions'." + (interactive) + (if sr-clex-on + (progn + (setq sr-clex-on nil) + (delete-overlay sr-clex-hotchar-overlay)) + (progn + (insert-char ?% 1) + (if sr-running + (progn + (add-hook 'after-change-functions 'sr-clex-commit nil t) + (setq sr-clex-on t) + (setq sr-clex-hotchar-overlay (make-overlay (point) (1- (point)))) + (overlay-put sr-clex-hotchar-overlay 'face 'sr-clex-hotchar-face) + (message + "Sunrise: CLEX is now ON for keys: m f n d a p M F N D A P %%")))))) + +(defun sr-clex-commit (&optional _beg _end _range) + "Commit the current CLEX operation (if any). +This function is added to the local `after-change-functions' list +by `sr-clex-start'." + (interactive) + (if sr-clex-on + (progn + (setq sr-clex-on nil) + (delete-overlay sr-clex-hotchar-overlay) + (let* ((xchar (char-before)) + (expansion (case xchar + (?m (sr-clex-marked 'left)) + (?f (sr-clex-file 'left)) + (?n (sr-clex-marked-nodir 'left)) + (?d (sr-clex-dir 'left)) + (?M (sr-clex-marked 'right)) + (?F (sr-clex-file 'right)) + (?N (sr-clex-marked-nodir 'right)) + (?D (sr-clex-dir 'right)) + (?a (sr-clex-marked '(sr-this))) + (?A (sr-clex-dir '(sr-this))) + (?p (sr-clex-marked '(sr-other))) + (?P (sr-clex-dir '(sr-other))) + (t nil)))) + (if expansion + (progn + (delete-char -2) + (insert expansion))))))) + +(define-minor-mode sr-term-char-minor-mode + "Sunrise Commander terminal add-on for character (raw) mode." + nil nil + '(("\C-c\C-j" . sr-term-line-mode) + ("\C-c\C-k" . sr-term-char-mode) + ("\C-c\t" . sr-ti-change-window) + ("\C-ct" . sr-term) + ("\C-cT" . sr-term-cd) + ("\C-c\C-t" . sr-term-cd-newterm) + ("\C-c\M-t" . sr-term-cd-program) + ("\C-c;" . sr-follow-viewer) + ("\C-c\\" . sr-ti-lock-panes) + ("\C-c{" . sr-ti-min-lock-panes) + ("\C-c}" . sr-ti-max-lock-panes))) + +(define-minor-mode sr-term-line-minor-mode + "Sunrise Commander terminal add-on for line (cooked) mode." + nil nil + '(([M-up] . sr-ti-previous-line) + ([A-up] . sr-ti-previous-line) + ("\M-P" . sr-ti-previous-line) + ([M-down] . sr-ti-next-line) + ([A-down] . sr-ti-next-line) + ("\M-N" . sr-ti-next-line) + ("\M-\C-m" . sr-ti-select) + ("\C-\M-j" . sr-ti-select) + ([M-return] . sr-ti-select) + ([S-M-return] . sr-ti-select) + ("\M-M" . sr-ti-mark) + ([M-backspace] . sr-ti-unmark) + ("\M-\d" . sr-ti-unmark) + ("\M-J" . sr-ti-prev-subdir) + ("\M-U" . sr-ti-unmark-all-marks) + ([C-tab] . sr-ti-change-window) + ([M-tab] . sr-ti-change-pane) + ("\C-c\t" . sr-ti-change-window) + ("\C-ct" . sr-term) + ("\C-cT" . sr-term-cd) + ("\C-c\C-t" . sr-term-cd-newterm) + ("\C-c\M-t" . sr-term-cd-program) + ("\C-c;" . sr-follow-viewer) + ("\M-\S-g" . sr-ti-revert-buffer) + ("%" . sr-clex-start) + ("\t" . term-dynamic-complete) + ("\C-c\\" . sr-ti-lock-panes) + ("\C-c{" . sr-ti-min-lock-panes) + ("\C-c}" . sr-ti-max-lock-panes)) + :group 'sunrise) + +(defadvice term-sentinel (around sr-advice-term-sentinel (proc msg) activate) + "Take care of killing Sunrise Commander terminal buffers on exit." + (if (and (or sr-term-char-minor-mode sr-term-line-minor-mode) + sr-terminal-kill-buffer-on-exit + (memq (process-status proc) '(signal exit))) + (let ((buffer (process-buffer proc))) + ad-do-it + (bury-buffer buffer) + (kill-buffer buffer)) + ad-do-it)) + +;;; ============================================================================ +;;; Desktop support: + +(defun sr-pure-virtual-p (&optional buffer) + "Return t if BUFFER (or the current buffer if nil) is purely virtual. +Purely virtual means it is not attached to any directory or any +file in the file system." + (with-current-buffer (if (bufferp buffer) buffer (current-buffer)) + (not (or (eq 'sr-mode major-mode) + (and (eq 'sr-virtual-mode major-mode) + buffer-file-truename + (file-exists-p buffer-file-truename)))))) + +(defun sr-desktop-save-buffer (desktop-dir) + "Return the additional data for saving a Sunrise buffer to a desktop file." + (unless (sr-pure-virtual-p) + (apply + 'append + (delq nil + (list + (if (eq major-mode 'sr-virtual-mode) + (list 'dirs buffer-file-truename) + (cons 'dirs (dired-desktop-buffer-misc-data desktop-dir))) + (if (eq (current-buffer) sr-left-buffer) (cons 'left t)) + (if (eq (current-buffer) sr-right-buffer) (cons 'right t)) + (if (eq major-mode 'sr-virtual-mode) (cons 'virtual t)))) + (mapcar (lambda (fun) + (funcall fun desktop-dir)) + sr-desktop-save-handlers)))) + +(defun sr-desktop-restore-buffer (desktop-buffer-file-name + desktop-buffer-name + desktop-buffer-misc) + "Restore a Sunrise (normal or VIRTUAL) buffer from its desktop file data." + (let* ((sr-running t) + (misc-data (cdr (assoc 'dirs desktop-buffer-misc))) + (is-virtual (assoc 'virtual desktop-buffer-misc)) + (buffer + (if (not is-virtual) + (with-current-buffer + (dired-restore-desktop-buffer desktop-buffer-file-name + desktop-buffer-name + misc-data) + (sr-mode) + (current-buffer)) + (desktop-restore-file-buffer (car misc-data) + desktop-buffer-name + misc-data)))) + (with-current-buffer buffer + (when is-virtual (set-visited-file-name nil t)) + (mapc (lambda (side) + (when (cdr (assq side desktop-buffer-misc)) + (set (sr-symbol side 'buffer) buffer) + (set (sr-symbol side 'directory) default-directory))) + '(left right)) + (mapc (lambda (fun) + (funcall fun + desktop-buffer-file-name + desktop-buffer-name + desktop-buffer-misc)) + sr-desktop-restore-handlers)) + buffer)) + +(defun sr-reset-state () + "Reset some environment variables that control the Sunrise behavior. +Used for desktop support." + (setq sr-left-directory "~/" sr-right-directory "~/" + sr-this-directory "~/" sr-other-directory "~/") + (if sr-running (sr-quit)) + nil) + +;; These register the previous functions in the desktop framework: +(add-to-list 'desktop-buffer-mode-handlers + '(sr-mode . sr-desktop-restore-buffer)) +(add-to-list 'desktop-buffer-mode-handlers + '(sr-virtual-mode . sr-desktop-restore-buffer)) + +;; This initializes (and sometimes starts) Sunrise after desktop restoration: +(add-hook 'desktop-after-read-hook + (defun sr-desktop-after-read-function () + (unless (assoc 'sr-running desktop-globals-to-clear) + (add-to-list 'desktop-globals-to-clear + '(sr-running . (sr-reset-state)))) + (if (memq major-mode '(sr-mode sr-virtual-mode sr-tree-mode)) + (sunrise)))) + +;;; ============================================================================ +;;; Miscellaneous functions: + +(defun sr-buffer-files (buffer-or-name) + "Return the list of all file names currently displayed in the given buffer." + (with-current-buffer buffer-or-name + (save-excursion + (let ((result nil)) + (sr-beginning-of-buffer) + (while (not (eobp)) + (setq result (cons (dired-get-filename t t) result)) + (forward-line 1)) + (reverse result))))) + +(defun sr-keep-buffer (&optional side) + "Keep the currently displayed buffer in SIDE (left or right) window. +Keeps it there even if it does not belong to the panel's history +ring. If SIDE is nil, use the value of `sr-selected-window' +instead. Useful for maintaining the contents of the pane during +layout switching." + (let* ((side (or side sr-selected-window)) + (window (symbol-value (sr-symbol side 'window)))) + (set (sr-symbol side 'buffer) (window-buffer window)))) + +(defun sr-scrollable-viewer (buffer) + "Set the `other-window-scroll-buffer' variable to BUFFER. +Doing so allows to scroll the given buffer directly from the active pane." + (setq other-window-scroll-buffer buffer) + (if buffer + (message "QUICK VIEW: Press C-e/C-y to scroll, Space/M-Space to page, and C-u v (or C-u o) to dismiss"))) + +(defun sr-describe-mode () + "Call `describe-mode' and make the resulting buffer C-M-v scrollable." + (interactive) + (describe-mode) + (sr-scrollable-viewer (get-buffer "*Help*")) + (sr-select-window sr-selected-window)) + +(defun sr-equal-dirs (dir1 dir2) + "Return non-nil if the two paths DIR1 and DIR2 represent the same directory." + (string= (expand-file-name (concat (directory-file-name dir1) "/")) + (expand-file-name (concat (directory-file-name dir2) "/")))) + +(defun sr-summary () + "Summarize basic Sunrise commands and show recent Dired errors." + (interactive) + (dired-why) + (message "C-opy, R-ename, K-lone, D-elete, v-iew, e-X-ecute, Ff-ollow, \ +Jj-ump, q-uit, m-ark, u-nmark, h-elp")) + +(defun sr-restore-point-if-same-buffer () + "Synchronize point position if the same buffer is displayed in both panes." + (let ((this-win)(other-win)(point)) + (when (and (eq sr-left-buffer sr-right-buffer) + (window-live-p (setq other-win (sr-other 'window)))) + (setq this-win (selected-window)) + (setq point (point)) + (select-window other-win) + (goto-char point) + (select-window this-win)))) + +(defun sr-mark-toggle () + "Toggle the mark on the current file or directory." + (interactive) + (when (dired-get-filename t t) + (if (eq ? (char-after (line-beginning-position))) + (dired-mark 1) + (dired-unmark 1)))) + +(defun sr-assoc-key (name alist test) + "Return the key in ALIST matched by NAME according to TEST." + (let (head (tail alist) found) + (while (and tail (not found)) + (setq head (caar tail) + found (and (apply test (list head name)) head) + tail (cdr tail))) + found)) + +(defun sr-quote-marked () + "Return current pane's selected entries quoted and space-separated as a string." + (let ((marked (dired-get-marked-files t nil nil t))) + (if (< (length marked) 2) + (setq marked nil) + (if (eq t (car marked)) (setq marked (cdr marked))) + (format "\"%s\"" (mapconcat 'identity marked "\" \""))))) + +(defun sr-fix-listing-switches() + "Work around a bug in Dired that makes `dired-move-to-filename' misbehave +when any of the options -p or -F is used with ls." + (mapc (lambda (sym) + (let ((val (replace-regexp-in-string "\\(?:^\\| \\)-[pF]*\\(?: \\|$\\)" " " (symbol-value sym)))) + (while (string-match "\\(?:^\\| \\)-[^- ]*[pF]" val) + (setq val (replace-regexp-in-string "\\(\\(?:^\\| \\)-[^- ]*\\)[pF]\\([^ ]*\\)" "\\1\\2" val))) + (set sym val))) + '(sr-listing-switches sr-virtual-listing-switches)) + (remove-hook 'sr-init-hook 'sr-fix-listing-switches)) +(add-hook 'sr-init-hook 'sr-fix-listing-switches) + +(defun sr-chop (char path) + "Remove all trailing instances of character CHAR from the string PATH." + (while (and (< 1 (length path)) + (eq (string-to-char (substring path -1)) char)) + (setq path (substring path 0 -1))) + path) + +;;; ============================================================================ +;;; Advice + +(defun sr-ad-enable (regexp &optional function) + "Put all or FUNCTION-specific advice matching REGEXP into effect. +If provided, only update FUNCTION itself, otherwise all functions +with advice matching REGEXP." + (if function + (progn (ad-enable-advice function 'any regexp) + (ad-activate function)) + (ad-enable-regexp regexp) + (ad-activate-regexp regexp))) + +(defun sr-ad-disable (regexp &optional function) + "Stop all FUNCTION-specific advice matching REGEXP from taking effect. +If provided, only update FUNCTION itself, otherwise all functions +with advice matching REGEXP." + (if function + (progn (ad-disable-advice function 'any regexp) + (ad-update function)) + (ad-disable-regexp regexp) + (ad-update-regexp regexp))) + +(defun sunrise-commander-unload-function () + (sr-ad-disable "^sr-advice-")) + +;;; ============================================================================ +;;; Font-Lock colors & styles: + +(defmacro sr-rainbow (symbol spec regexp) + `(progn + (defface ,symbol '((t ,spec)) "Sunrise rainbow face" :group 'sunrise) + ,@(mapcar (lambda (m) + `(font-lock-add-keywords ',m '((,regexp 1 ',symbol)))) + '(sr-mode sr-virtual-mode)))) + +(sr-rainbow sr-html-face (:foreground "DarkOliveGreen") "\\(^[^!].[^d].*\\.x?html?$\\)") +(sr-rainbow sr-xml-face (:foreground "DarkGreen") "\\(^[^!].[^d].*\\.\\(xml\\|xsd\\|xslt?\\|wsdl\\)$\\)") +(sr-rainbow sr-log-face (:foreground "brown") "\\(^[^!].[^d].*\\.log$\\)") +(sr-rainbow sr-compressed-face (:foreground "magenta") "\\(^[^!].[^d].*\\.\\(zip\\|bz2\\|t?[gx]z\\|[zZ]\\|[jwers]?ar\\|xpi\\|apk\\|xz\\)$\\)") +(sr-rainbow sr-packaged-face (:foreground "DarkMagenta") "\\(^[^!].[^d].*\\.\\(deb\\|rpm\\)$\\)") +(sr-rainbow sr-encrypted-face (:foreground "DarkOrange1") "\\(^[^!].[^d].*\\.\\(gpg\\|pgp\\)$\\)") + +(sr-rainbow sr-directory-face (:inherit dired-directory :bold t) "\\(^[^!].d.*\\)") +(sr-rainbow sr-symlink-face (:inherit dired-symlink :italic t) "\\(^[^!].l.*[^/]$\\)") +(sr-rainbow sr-symlink-directory-face (:inherit dired-directory :italic t) "\\(^[^!].l.*/$\\)") +(sr-rainbow sr-alt-marked-dir-face (:foreground "DeepPink" :bold t) "\\(^[^ *!D].d.*$\\)") +(sr-rainbow sr-alt-marked-file-face (:foreground "DeepPink") "\\(^[^ *!D].[^d].*$\\)") +(sr-rainbow sr-marked-dir-face (:inherit dired-marked) "\\(^[*!D].d.*$\\)") +(sr-rainbow sr-marked-file-face (:inherit dired-marked :bold nil) "\\(^[*!D].[^d].*$\\)") +(sr-rainbow sr-broken-link-face (:inherit dired-warning :italic t) "\\(^[!].l.*$\\)") + +(provide 'sunrise-commander) + +;;; sunrise-commander.el ends here diff --git a/emacs/twittering-mode b/emacs/twittering-mode new file mode 160000 index 0000000..ab64c73 --- /dev/null +++ b/emacs/twittering-mode @@ -0,0 +1 @@ +Subproject commit ab64c73b393e7ed1a28ca2bf15e13958996a52df diff --git a/emacs/verilog-mode.el b/emacs/verilog-mode.el new file mode 100644 index 0000000..ed966f0 --- /dev/null +++ b/emacs/verilog-mode.el @@ -0,0 +1,10137 @@ +;; verilog-mode.el --- major mode for editing verilog source in Emacs +;; +;; $Id: verilog-mode.el 344 2007-07-10 15:49:18Z wsnyder $ + +;; Copyright (C) 1996-2007 Free Software Foundation, Inc. + +;; Author: Michael McNamara (mac@verilog.com) +;; http://www.verilog.com +;; +;; AUTO features, signal, modsig; by: Wilson Snyder +;; (wsnyder@wsnyder.org) +;; http://www.veripool.com +;; 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 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. + +;;; Commentary: + +;; This mode borrows heavily from the Pascal-mode and the cc-mode of emacs + +;; USAGE +;; ===== + +;; A major mode for editing Verilog HDL source code. When you have +;; entered Verilog mode, you may get more info by pressing C-h m. You +;; may also get online help describing various functions by: C-h f +;; <Name of function you want described> + +;; You can get step by step help in installing this file by going to +;; <http://www.verilog.com/emacs_install.html> + +;; The short list of installation instructions are: To set up +;; automatic verilog mode, put this file in your load path, and put +;; the following in code (please un comment it first!) in your +;; .emacs, or in your site's site-load.el + +; (autoload 'verilog-mode "verilog-mode" "Verilog mode" t ) +; (setq auto-mode-alist (cons '("\\.v\\'" . verilog-mode) auto-mode-alist)) +; (setq auto-mode-alist (cons '("\\.dv\\'" . verilog-mode) auto-mode-alist)) + +;; If you want to customize Verilog mode to fit your needs better, +;; you may add these lines (the values of the variables presented +;; here are the defaults). Note also that if you use an emacs that +;; supports custom, it's probably better to use the custom menu to +;; edit these. +;; +;; Be sure to examine at the help for verilog-auto, and the other +;; verilog-auto-* functions for some major coding time savers. +;; +; ;; User customization for Verilog mode +; (setq verilog-indent-level 3 +; verilog-indent-level-module 3 +; verilog-indent-level-declaration 3 +; verilog-indent-level-behavioral 3 +; verilog-indent-level-directive 1 +; verilog-case-indent 2 +; verilog-auto-newline t +; verilog-auto-indent-on-newline t +; verilog-tab-always-indent t +; verilog-auto-endcomments t +; verilog-minimum-comment-distance 40 +; verilog-indent-begin-after-if t +; verilog-auto-lineup '(all) +; verilog-linter "my_lint_shell_command" +; ) + +;; KNOWN BUGS / BUG REPORTS +;; ======================= +;; This is beta code, and likely has bugs. Please report any and all +;; bugs to me at mac@verilog.com. Use +;; verilog-submit-bug-report to submit a report. +;; + +;;; History: +;; +;; +;;; Code: + +(provide 'verilog-mode) + +;; This variable will always hold the version number of the mode +(defconst verilog-mode-version (substring "$$Revision: 344 $$" 12 -3) + "Version of this verilog mode.") +(defconst verilog-mode-release-date (substring "$$Date: 2007-07-10 08:49:18 -0700 (Tue, 10 Jul 2007) $$" 8 -3) + "Version of this verilog mode.") + +(defconst verilog-running-on-xemacs (string-match "XEmacs" emacs-version)) +(defun verilog-version () + "Inform caller of the version of this file." + (interactive) + (message (concat "Using verilog-mode version " verilog-mode-version) )) + +;; Insure we have certain packages, and deal with it if we don't +(if (fboundp 'eval-when-compile) + (eval-when-compile + (require 'verilog-mode) + (condition-case nil + (require 'imenu) + (error nil)) + (condition-case nil + (require 'reporter) + (error nil)) + (condition-case nil + (require 'easymenu) + (error nil)) + (condition-case nil + (require 'regexp-opt) + (error nil)) + (condition-case nil + (load "skeleton") ;; bug in 19.28 through 19.30 skeleton.el, not provided. + (error nil)) + (condition-case nil + (require 'vc) + (error nil)) + (condition-case nil + (if (fboundp 'when) + nil ;; fab + (defmacro when (var &rest body) + (` (cond ( (, var) (,@ body)))))) + (error nil)) + (condition-case nil + (if (fboundp 'unless) + nil ;; fab + (defmacro unless (var &rest body) + (` (if (, var) nil (,@ body))))) + (error nil)) + (condition-case nil + (if (fboundp 'store-match-data) + nil ;; fab + (defmacro store-match-data (&rest args) nil)) + (error nil)) + (condition-case nil + (if (boundp 'current-menubar) + nil ;; great + (progn + (defmacro set-buffer-menubar (&rest args) nil) + (defmacro add-submenu (&rest args) nil)) + ) + (error nil)) + (condition-case nil + (if (fboundp 'zmacs-activate-region) + nil ;; great + (defmacro zmacs-activate-region (&rest args) nil)) + (error nil)) + (condition-case nil + (if (fboundp 'char-before) + nil ;; great + (defmacro char-before (&rest body) + (` (char-after (1- (point)))))) + (error nil)) + ;; Requires to define variables that would be "free" warnings + (condition-case nil + (require 'font-lock) + (error nil)) + (condition-case nil + (require 'compile) + (error nil)) + (condition-case nil + (require 'custom) + (error nil)) + (condition-case nil + (require 'dinotrace) + (error nil)) + (condition-case nil + (if (fboundp 'dinotrace-unannotate-all) + nil ;; great + (defun dinotrace-unannotate-all (&rest args) nil)) + (error nil)) + (condition-case nil + (if (fboundp 'customize-apropos) + nil ;; great + (defun customize-apropos (&rest args) nil)) + (error nil)) + (condition-case nil + (if (fboundp 'match-string-no-properties) + nil ;; great + (defsubst match-string-no-properties (num &optional string) + "Return string of text matched by last search, without text properties. +NUM specifies which parenthesized expression in the last regexp. + Value is nil if NUMth pair didn't match, or there were less than NUM pairs. +Zero means the entire text matched by the whole regexp or whole string. +STRING should be given if the last search was by `string-match' on STRING." + (if (match-beginning num) + (if string + (let ((result + (substring string (match-beginning num) (match-end num)))) + (set-text-properties 0 (length result) nil result) + result) + (buffer-substring-no-properties (match-beginning num) + (match-end num) + (current-buffer) + ))))) + (error nil)) + (if (and (featurep 'custom) (fboundp 'custom-declare-variable)) + nil ;; We've got what we needed + ;; We have the old custom-library, hack around it! + (defmacro defgroup (&rest args) nil) + (defmacro customize (&rest args) + (message "Sorry, Customize is not available with this version of emacs")) + (defmacro defcustom (var value doc &rest args) + (` (defvar (, var) (, value) (, doc)))) + ) + (if (fboundp 'defface) + nil ; great! + (defmacro defface (var value doc &rest args) + (` (make-face (, var)))) + ) + + (if (and (featurep 'custom) (fboundp 'customize-group)) + nil ;; We've got what we needed + ;; We have an intermediate custom-library, hack around it! + (defmacro customize-group (var &rest args) + (`(customize (, var) ))) + ) + + )) +;; Provide a regular expression optimization routine, using regexp-opt +;; if provided by the user's elisp libraries +(eval-and-compile + (if (fboundp 'regexp-opt) + ;; regexp-opt is defined, does it take 3 or 2 arguments? + (if (fboundp 'function-max-args) + (case (function-max-args `regexp-opt) + ( 3 ;; It takes 3 + (condition-case nil ; Hide this defun from emacses + ;with just a two input regexp + (defun verilog-regexp-opt (a b) + "Deal with differing number of required arguments for `regexp-opt'. + Call 'regexp-opt' on A and B." + (regexp-opt a b 't) + ) + (error nil)) + ) + ( 2 ;; It takes 2 + (defun verilog-regexp-opt (a b) + "Call 'regexp-opt' on A and B." + (regexp-opt a b)) + ) + ( t nil)) + ;; We can't tell; assume it takes 2 + (defun verilog-regexp-opt (a b) + "Call 'regexp-opt' on A and B." + (regexp-opt a b)) + ) + ;; There is no regexp-opt, provide our own + (defun verilog-regexp-opt (strings &optional paren shy) + (let ((open (if paren "\\(" "")) (close (if paren "\\)" ""))) + (concat open (mapconcat 'regexp-quote strings "\\|") close))) + )) + +(eval-when-compile + (defun verilog-regexp-words (a) + "Call 'regexp-opt' with word delimiters." + (concat "\\<" (verilog-regexp-opt a t) "\\>"))) + +(defun verilog-regexp-words (a) + "Call 'regexp-opt' with word delimiters for the words A." + (concat "\\<" (verilog-regexp-opt a t) "\\>")) + +(defun verilog-customize () + "Link to customize screen for Verilog." + (interactive) + (customize-group 'verilog-mode)) + +(defun verilog-font-customize () + "Link to customize fonts used for Verilog." + (interactive) + (customize-apropos "font-lock-*" 'faces)) + +(defgroup verilog-mode nil + "Facilitates easy editing of Verilog source text" + :group 'languages) + +; (defgroup verilog-mode-fonts nil +; "Facilitates easy customization fonts used in Verilog source text" +; :link '(customize-apropos "font-lock-*" 'faces) +; :group 'verilog-mode) + +(defgroup verilog-mode-indent nil + "Customize indentation and highlighting of verilog source text" + :group 'verilog-mode) + +(defgroup verilog-mode-actions nil + "Customize actions on verilog source text" + :group 'verilog-mode) + +(defgroup verilog-mode-auto nil + "Customize AUTO actions when expanding verilog source text" + :group 'verilog-mode) + +(defcustom verilog-linter + "echo 'No verilog-linter set, see \"M-x describe-variable verilog-linter\"'" + "*Unix program and arguments to call to run a lint checker on verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defcustom verilog-coverage + "echo 'No verilog-coverage set, see \"M-x describe-variable verilog-coverage\"'" + "*Program and arguments to use to annotate for coverage verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defcustom verilog-simulator + "echo 'No verilog-simulator set, see \"M-x describe-variable verilog-simulator\"'" + "*Program and arguments to use to interpret verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defcustom verilog-compiler + "echo 'No verilog-compiler set, see \"M-x describe-variable verilog-compiler\"'" + "*Program and arguments to use to compile verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defvar verilog-tool 'verilog-linter + "Which tool to use for building compiler-command. +Either nil, `verilog-linter, `verilog-coverage, `verilog-simulator, or +`verilog-compiler. Alternatively use the \"Choose Compilation Action\" +menu. See `verilog-set-compile-command' for more information.") + +(defcustom verilog-highlight-translate-off nil + "*Non-nil means background-highlight code excluded from translation. +That is, all code between \"// synopsys translate_off\" and +\"// synopsys translate_on\" is highlighted using a different background color +\(face `verilog-font-lock-translate-off-face'). + +Note: This will slow down on-the-fly fontification (and thus editing). + +Note: Activate the new setting in a Verilog buffer by re-fontifying it (menu +entry \"Fontify Buffer\"). XEmacs: turn off and on font locking." + :type 'boolean + :group 'verilog-mode-indent) + +(defcustom verilog-indent-level 3 + "*Indentation of Verilog statements with respect to containing block." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-level-module 3 + "*Indentation of Module level Verilog statements. (eg always, initial) +Set to 0 to get initial and always statements lined up on the left side of +your screen." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-level-declaration 3 + "*Indentation of declarations with respect to containing block. +Set to 0 to get them list right under containing block." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-declaration-macros nil + "*How to treat macro expansions in a declaration. +If nil, indent as: + input [31:0] a; + input `CP; + output c; +If non nil, treat as: + input [31:0] a; + input `CP ; + output c;" + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-indent-lists t + "*How to treat indenting items in a list. +If t (the default), indent as: + always @( posedge a or + reset ) begin + +If nil, treat as: + always @( posedge a or + reset ) begin" + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-indent-level-behavioral 3 + "*Absolute indentation of first begin in a task or function block. +Set to 0 to get such code to start at the left side of the screen." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-level-directive 1 + "*Indentation to add to each level of `ifdef declarations. +Set to 0 to have all directives start at the left side of the screen." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-cexp-indent 2 + "*Indentation of Verilog statements split across lines." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-case-indent 2 + "*Indentation for case statements." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-auto-newline t + "*True means automatically newline after semicolons." + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-auto-indent-on-newline t + "*True means automatically indent line after newline." + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-tab-always-indent t + "*True means TAB should always re-indent the current line. +Nil means TAB will only reindent when at the beginning of the line." + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-tab-to-comment nil + "*True means TAB moves to the right hand column in preparation for a comment." + :group 'verilog-mode-actions + :type 'boolean) + +(defcustom verilog-indent-begin-after-if t + "*If true, indent begin statements following if, else, while, for and repeat. +Otherwise, line them up." + :group 'verilog-mode-indent + :type 'boolean ) + + +(defcustom verilog-align-ifelse nil + "*If true, align `else' under matching `if'. +Otherwise else is lined up with first character on line holding matching if." + :group 'verilog-mode-indent + :type 'boolean ) + +(defcustom verilog-minimum-comment-distance 10 + "*Minimum distance (in lines) between begin and end required before a comment. +Setting this variable to zero results in every end acquiring a comment; the +default avoids too many redundant comments in tight quarters" + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-auto-lineup '(declaration) + "*Algorithm for lining up statements on multiple lines. + +If this list contains the symbol 'all', then all line ups described below +are done. + +If this list contains the symbol 'declaration', then declarations are lined up +with any preceding declarations, taking into account widths and the like, so +for example the code: + reg [31:0] a; + reg b; +would become + reg [31:0] a; + reg b; + +If this list contains the symbol 'assignment', then assignments are lined up +with any preceding assignments, so for example the code + a_long_variable = b + c; + d = e + f; +would become + a_long_variable = b + c; + d = e + f;" + +;; The following is not implemented: +;If this list contains the symbol 'case', then case items are lined up +;with any preceding case items, so for example the code +; case (a) begin +; a_long_state : a = 3; +; b: a = 4; +; endcase +;would become +; case (a) begin +; a_long_state : a = 3; +; b : a = 4; +; endcase +; + + :group 'verilog-mode-indent + :type 'list ) + +(defcustom verilog-auto-endcomments t + "*True means insert a comment /* ... */ after 'end's. +The name of the function or case will be set between the braces." + :group 'verilog-mode-actions + :type 'boolean ) + +(defcustom verilog-auto-read-includes nil + "*True means to automatically read includes before AUTOs. +This will do a `verilog-read-defines' and `verilog-read-includes' before +each AUTO expansion. This makes it easier to embed defines and includes, +but can result in very slow reading times if there are many or large +include files." + :group 'verilog-mode-actions + :type 'boolean ) + +(defcustom verilog-auto-save-policy nil + "*Non-nil indicates action to take when saving a Verilog buffer with AUTOs. +A value of `force' will always do a \\[verilog-auto] automatically if +needed on every save. A value of `detect' will do \\[verilog-auto] +automatically when it thinks necessary. A value of `ask' will query the +user when it thinks updating is needed. + +You should not rely on the 'ask or 'detect policies, they are safeguards +only. They do not detect when AUTOINSTs need to be updated because a +sub-module's port list has changed." + :group 'verilog-mode-actions + :type '(choice (const nil) (const ask) (const detect) (const force))) + +(defcustom verilog-auto-star-expand t + "*Non-nil indicates to expand a SystemVerilog .* instance ports. +They will be expanded in the same way as if there was a AUTOINST in the +instantiation. See also `verilog-auto-star' and `verilog-auto-star-save'." + :group 'verilog-mode-actions + :type 'boolean) + +(defcustom verilog-auto-star-save nil + "*Non-nil indicates to save to disk SystemVerilog .* instance expansions. +Nil indicates direct connections will be removed before saving. Only +meaningful to those created due to `verilog-auto-star-expand' being set. + +Instead of setting this, you may want to use /*AUTOINST*/, which will +always be saved." + :group 'verilog-mode-actions + :type 'boolean) + +(defvar verilog-auto-update-tick nil + "Modification tick at which autos were last performed.") + +(defvar verilog-auto-last-file-locals nil + "Text from file-local-variables during last evaluation.") + +(defvar verilog-error-regexp-add-didit nil) +(defvar verilog-error-regexp nil) +(setq verilog-error-regexp-add-didit nil + verilog-error-regexp + '( + ; SureLint +;; ("[^\n]*\\[\\([^:]+\\):\\([0-9]+\\)\\]" 1 2) + ; Most SureFire tools + ("\\(WARNING\\|ERROR\\|INFO\\)[^:]*: \\([^,]+\\), \\(line \\|\\)\\([0-9]+\\):" 2 4 ) + ("\ +\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)\\([) \t]\\|\ +:\\([^0-9\n]\\|\\([0-9]+:\\)\\)\\)" 1 2 5) + ; xsim + ; Error! in file /homes/mac/Axis/Xsim/test.v at line 13 [OBJ_NOT_DECLARED] + ("\\(Error\\|Warning\\).*in file (\\([^ \t]+\\) at line *\\([0-9]+\\))" 2 3) + ; vcs + ("\\(Error\\|Warning\\):[^(]*(\\([^ \t]+\\) line *\\([0-9]+\\))" 2 3) + ("Warning:.*(port.*(\\([^ \t]+\\) line \\([0-9]+\\))" 1 2) + ("\\(Error\\|Warning\\):[\n.]*\\([^ \t]+\\) *\\([0-9]+\\):" 2 3) + ("syntax error:.*\n\\([^ \t]+\\) *\\([0-9]+\\):" 1 2) + ; Verilator + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 3 4) + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 3 4) + ; vxl + ("\\(Error\\|Warning\\)!.*\n?.*\"\\([^\"]+\\)\", \\([0-9]+\\)" 2 3) + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+\\([0-9]+\\):.*$" 1 2) ; vxl + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+line[ \t]+\\([0-9]+\\):.*$" 1 2) + ; nc-verilog + (".*\\*[WE],[0-9A-Z]+ (\\([^ \t,]+\\),\\([0-9]+\\)|" 1 2) + ; Leda + ("In file \\([^ \t]+\\)[ \t]+line[ \t]+\\([0-9]+\\):\n[^\n]*\n[^\n]*\n\\[\\(Warning\\|Error\\|Failure\\)\\][^\n]*" 1 2) + ) +; "*List of regexps for verilog compilers, like verilint. See compilation-error-regexp-alist for the formatting." +) + +(defvar verilog-error-font-lock-keywords + '( + ("[^\n]*\\[\\([^:]+\\):\\([0-9]+\\)\\]" 1 bold t) + ("[^\n]*\\[\\([^:]+\\):\\([0-9]+\\)\\]" 2 bold t) + + ("\\(WARNING\\|ERROR\\|INFO\\): \\([^,]+\\), line \\([0-9]+\\):" 2 bold t) + ("\\(WARNING\\|ERROR\\|INFO\\): \\([^,]+\\), line \\([0-9]+\\):" 3 bold t) + + ("\ +\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)\\([) \t]\\|\ +:\\([^0-9\n]\\|\\([0-9]+:\\)\\)\\)" 1 bold t) + ("\ +\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)\\([) \t]\\|\ +:\\([^0-9\n]\\|\\([0-9]+:\\)\\)\\)" 1 bold t) + + ("\\(Error\\|Warning\\):[^(]*(\\([^ \t]+\\) line *\\([0-9]+\\))" 2 bold t) + ("\\(Error\\|Warning\\):[^(]*(\\([^ \t]+\\) line *\\([0-9]+\\))" 3 bold t) + + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 3 bold t) + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 4 bold t) + + ("Warning:.*(port.*(\\([^ \t]+\\) line \\([0-9]+\\))" 1 bold t) + ("Warning:.*(port.*(\\([^ \t]+\\) line \\([0-9]+\\))" 1 bold t) + + ("\\(Error\\|Warning\\):[\n.]*\\([^ \t]+\\) *\\([0-9]+\\):" 2 bold t) + ("\\(Error\\|Warning\\):[\n.]*\\([^ \t]+\\) *\\([0-9]+\\):" 3 bold t) + + ("syntax error:.*\n\\([^ \t]+\\) *\\([0-9]+\\):" 1 bold t) + ("syntax error:.*\n\\([^ \t]+\\) *\\([0-9]+\\):" 2 bold t) + ; vxl + ("\\(Error\\|Warning\\)!.*\n?.*\"\\([^\"]+\\)\", \\([0-9]+\\)" 2 bold t) + ("\\(Error\\|Warning\\)!.*\n?.*\"\\([^\"]+\\)\", \\([0-9]+\\)" 2 bold t) + + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+\\([0-9]+\\):.*$" 1 bold t) + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+\\([0-9]+\\):.*$" 2 bold t) + + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+line[ \t]+\\([0-9]+\\):.*$" 1 bold t) + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+line[ \t]+\\([0-9]+\\):.*$" 2 bold t) + ; nc-verilog + (".*[WE],[0-9A-Z]+ (\\([^ \t,]+\\),\\([0-9]+\\)|" 1 bold t) + (".*[WE],[0-9A-Z]+ (\\([^ \t,]+\\),\\([0-9]+\\)|" 2 bold t) + ; Leda + ("In file \\([^ \t]+\\)[ \t]+line[ \t]+\\([0-9]+\\):\n[^\n]*\n[^\n]*\n\\[\\(Warning\\|Error\\|Failure\\)\\][^\n]*" 1 bold t) + ("In file \\([^ \t]+\\)[ \t]+line[ \t]+\\([0-9]+\\):\n[^\n]*\n[^\n]*\n\\[\\(Warning\\|Error\\|Failure\\)\\][^\n]*" 2 bold t) + ) + "*Keywords to also highlight in Verilog *compilation* buffers." + ) + +(defcustom verilog-library-flags '("") + "*List of standard Verilog arguments to use for /*AUTOINST*/. +These arguments are used to find files for `verilog-auto', and match +the flags accepted by a standard Verilog-XL simulator. + + -f filename Reads more `verilog-library-flags' from the filename. + +incdir+dir Adds the directory to `verilog-library-directories'. + -Idir Adds the directory to `verilog-library-directories'. + -y dir Adds the directory to `verilog-library-directories'. + +libext+.v Adds the extensions to `verilog-library-extensions'. + -v filename Adds the filename to `verilog-library-files'. + + filename Adds the filename to `verilog-library-files'. + This is not recommended, -v is a better choice. + +You might want these defined in each file; put at the *END* of your file +something like: + + // Local Variables: + // verilog-library-flags:(\"-y dir -y otherdir\") + // End: + +Verilog-mode attempts to detect changes to this local variable, but they +are only insured to be correct when the file is first visited. Thus if you +have problems, use \\[find-alternate-file] RET to have these take effect. + +See also the variables mentioned above." + :group 'verilog-mode-auto + :type '(repeat string)) + +(defcustom verilog-library-directories '(".") + "*List of directories when looking for files for /*AUTOINST*/. +The directory may be relative to the current file, or absolute. +Environment variables are also expanded in the directory names. +Having at least the current directory is a good idea. + +You might want these defined in each file; put at the *END* of your file +something like: + + // Local Variables: + // verilog-library-directories:(\".\" \"subdir\" \"subdir2\") + // End: + +Verilog-mode attempts to detect changes to this local variable, but they +are only insured to be correct when the file is first visited. Thus if you +have problems, use \\[find-alternate-file] RET to have these take effect. + +See also `verilog-library-flags', `verilog-library-files' +and `verilog-library-extensions'." + :group 'verilog-mode-auto + :type '(repeat file)) + +(defcustom verilog-library-files '() + "*List of files to search for modules when looking for AUTOINST files. +This is a complete path, usually to a technology file with many standard +cells defined in it. + +You might want these defined in each file; put at the *END* of your file +something like: + + // Local Variables: + // verilog-library-files:(\"/some/path/technology.v\" \"/some/path/tech2.v\") + // End: + +Verilog-mode attempts to detect changes to this local variable, but they +are only insured to be correct when the file is first visited. Thus if you +have problems, use \\[find-alternate-file] RET to have these take effect. + +See also `verilog-library-flags', `verilog-library-directories'." + :group 'verilog-mode-auto + :type '(repeat directory)) + +(defcustom verilog-library-extensions '(".v") + "*List of extensions to use when looking for files for /*AUTOINST*/. +See also `verilog-library-flags', `verilog-library-directories'." + :type '(repeat string) + :group 'verilog-mode-auto) + +(defcustom verilog-active-low-regexp nil + "*If set, treat signals matching this regexp as active low. +This is used for AUTORESET and AUTOTIEOFF. For proper behavior, +you will probably also need `verilog-auto-reset-widths' set." + :group 'verilog-mode-auto + :type 'string) + +(defcustom verilog-auto-sense-include-inputs nil + "*If true, AUTOSENSE should include all inputs. +If nil, only inputs that are NOT output signals in the same block are +included." + :type 'boolean + :group 'verilog-mode-auto) + +(defcustom verilog-auto-sense-defines-constant nil + "*If true, AUTOSENSE should assume all defines represent constants. +When true, the defines will not be included in sensitivity lists. To +maintain compatibility with other sites, this should be set at the bottom +of each verilog file that requires it, rather then being set globally." + :type 'boolean + :group 'verilog-mode-auto) + +(defcustom verilog-auto-reset-widths t + "*If true, AUTORESET should determine the width of signals. +This is then used to set the width of the zero (32'h0 for example). This +is required by some lint tools that aren't smart enough to ignore widths of +the constant zero. This may result in ugly code when parameters determine +the MSB or LSB of a signal inside a AUTORESET." + :type 'boolean + :group 'verilog-mode-auto) + +(defcustom verilog-assignment-delay "" + "*Text used for delays in delayed assignments. Add a trailing space if set." + :type 'string + :group 'verilog-mode-auto) + +(defcustom verilog-auto-inst-vector t + "*If true, when creating default ports with AUTOINST, use bus subscripts. +If nil, skip the subscript when it matches the entire bus as declared in +the module (AUTOWIRE signals always are subscripted, you must manually +declare the wire to have the subscripts removed.) Nil may speed up some +simulators, but is less general and harder to read, so avoid." + :group 'verilog-mode-auto + :type 'boolean ) + +(defcustom verilog-auto-inst-template-numbers nil + "*If true, when creating templated ports with AUTOINST, add a comment. +The comment will add the line number of the template that was used for that +port declaration. Setting this aids in debugging, but nil is suggested for +regular use to prevent large numbers of merge conflicts." + :group 'verilog-mode-auto + :type 'boolean ) + +(defvar verilog-auto-inst-column 40 + "Column number for first part of auto-inst.") + +(defcustom verilog-auto-input-ignore-regexp nil + "*If set, when creating AUTOINPUT list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-auto-inout-ignore-regexp nil + "*If set, when creating AUTOINOUT list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-auto-output-ignore-regexp nil + "*If set, when creating AUTOOUTPUT list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-auto-unused-ignore-regexp nil + "*If set, when creating AUTOUNUSED list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-typedef-regexp nil + "*If non-nil, regular expression that matches Verilog-2001 typedef names. +For example, \"_t$\" matches typedefs named with _t, as in the C language." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-mode-hook 'verilog-set-compile-command + "*Hook (List of functions) run after verilog mode is loaded." + :type 'hook + :group 'verilog-mode) + +(defcustom verilog-auto-hook nil + "*Hook run after `verilog-mode' updates AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-before-auto-hook nil + "*Hook run before `verilog-mode' updates AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-delete-auto-hook nil + "*Hook run after `verilog-mode' deletes AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-before-delete-auto-hook nil + "*Hook run before `verilog-mode' deletes AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-getopt-flags-hook nil + "*Hook run after `verilog-getopt-flags' determines the Verilog option lists." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-before-getopt-flags-hook nil + "*Hook run before `verilog-getopt-flags' determines the Verilog option lists." + :type 'hook + :group 'verilog-mode-auto) + +(defvar verilog-imenu-generic-expression + '((nil "^\\s-*\\(\\(m\\(odule\\|acromodule\\)\\)\\|primitive\\)\\s-+\\([a-zA-Z0-9_.:]+\\)" 4) + ("*Vars*" "^\\s-*\\(reg\\|wire\\)\\s-+\\(\\|\\[[^]]+\\]\\s-+\\)\\([A-Za-z0-9_]+\\)" 3)) + "Imenu expression for Verilog-mode. See `imenu-generic-expression'.") + +;; +;; provide a verilog-header function. +;; Customization variables: +;; +(defvar verilog-date-scientific-format nil + "*If non-nil, dates are written in scientific format (e.g. 1997/09/17). +If nil, in European format (e.g. 17.09.1997). The brain-dead American +format (e.g. 09/17/1997) is not supported.") + +(defvar verilog-company nil + "*Default name of Company for verilog header. +If set will become buffer local.") + +(defvar verilog-project nil + "*Default name of Project for verilog header. +If set will become buffer local.") + +(define-abbrev-table 'verilog-mode-abbrev-table ()) + +(defvar verilog-mode-map () + "Keymap used in Verilog mode.") +(if verilog-mode-map + () + (setq verilog-mode-map (make-sparse-keymap)) + (define-key verilog-mode-map ";" 'electric-verilog-semi) + (define-key verilog-mode-map [(control 59)] 'electric-verilog-semi-with-comment) + (define-key verilog-mode-map ":" 'electric-verilog-colon) + ;;(define-key verilog-mode-map "=" 'electric-verilog-equal) + (define-key verilog-mode-map "\`" 'electric-verilog-tick) + (define-key verilog-mode-map "\t" 'electric-verilog-tab) + (define-key verilog-mode-map "\r" 'electric-verilog-terminate-line) + ;; backspace/delete key bindings + (define-key verilog-mode-map [backspace] 'backward-delete-char-untabify) + (unless (boundp 'delete-key-deletes-forward) ; XEmacs variable + (define-key verilog-mode-map [delete] 'delete-char) + (define-key verilog-mode-map [(meta delete)] 'kill-word)) + (define-key verilog-mode-map "\M-\C-b" 'electric-verilog-backward-sexp) + (define-key verilog-mode-map "\M-\C-f" 'electric-verilog-forward-sexp) + (define-key verilog-mode-map "\M-\r" `electric-verilog-terminate-and-indent) + (define-key verilog-mode-map "\M-\t" 'verilog-complete-word) + (define-key verilog-mode-map "\M-?" 'verilog-show-completions) + (define-key verilog-mode-map [(meta control h)] 'verilog-mark-defun) + (define-key verilog-mode-map "\C-c\`" 'verilog-lint-off) + (define-key verilog-mode-map "\C-c\*" 'verilog-delete-auto-star-implicit) + (define-key verilog-mode-map "\C-c\C-r" 'verilog-label-be) + (define-key verilog-mode-map "\C-c\C-i" 'verilog-pretty-declarations) + (define-key verilog-mode-map "\C-c=" 'verilog-pretty-expr) + (define-key verilog-mode-map "\C-c\C-b" 'verilog-submit-bug-report) + (define-key verilog-mode-map "\M-*" 'verilog-star-comment) + (define-key verilog-mode-map "\C-c\C-c" 'verilog-comment-region) + (define-key verilog-mode-map "\C-c\C-u" 'verilog-uncomment-region) + (define-key verilog-mode-map "\M-\C-a" 'verilog-beg-of-defun) + (define-key verilog-mode-map "\M-\C-e" 'verilog-end-of-defun) + (define-key verilog-mode-map "\C-c\C-d" 'verilog-goto-defun) + (define-key verilog-mode-map "\C-c\C-k" 'verilog-delete-auto) + (define-key verilog-mode-map "\C-c\C-a" 'verilog-auto) + (define-key verilog-mode-map "\C-c\C-s" 'verilog-auto-save-compile) + (define-key verilog-mode-map "\C-c\C-z" 'verilog-inject-auto) + (define-key verilog-mode-map "\C-c\C-e" 'verilog-expand-vector) + (define-key verilog-mode-map "\C-c\C-h" 'verilog-header) + ) + +;; menus +(defvar verilog-xemacs-menu + '("Verilog" + ("Choose Compilation Action" + ["None" + (progn + (setq verilog-tool nil) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool nil)] + ["Lint" + (progn + (setq verilog-tool 'verilog-linter) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-linter)] + ["Coverage" + (progn + (setq verilog-tool 'verilog-coverage) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-coverage)] + ["Simulator" + (progn + (setq verilog-tool 'verilog-simulator) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-simulator)] + ["Compiler" + (progn + (setq verilog-tool 'verilog-compiler) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-compiler)] + ) + ("Move" + ["Beginning of function" verilog-beg-of-defun t] + ["End of function" verilog-end-of-defun t] + ["Mark function" verilog-mark-defun t] + ["Goto function/module" verilog-goto-defun t] + ["Move to beginning of block" electric-verilog-backward-sexp t] + ["Move to end of block" electric-verilog-forward-sexp t] + ) + ("Comments" + ["Comment Region" verilog-comment-region t] + ["UnComment Region" verilog-uncomment-region t] + ["Multi-line comment insert" verilog-star-comment t] + ["Lint error to comment" verilog-lint-off t] + ) + "----" + ["Compile" compile t] + ["AUTO, Save, Compile" verilog-auto-save-compile t] + ["Next Compile Error" next-error t] + ["Ignore Lint Warning at point" verilog-lint-off t] + "----" + ["Line up declarations around point" verilog-pretty-declarations t] + ["Line up equations around point" verilog-pretty-expr t] + ["Redo/insert comments on every end" verilog-label-be t] + ["Expand [x:y] vector line" verilog-expand-vector t] + ["Insert begin-end block" verilog-insert-block t] + ["Complete word" verilog-complete-word t] + "----" + ["Recompute AUTOs" verilog-auto t] + ["Kill AUTOs" verilog-delete-auto t] + ["Inject AUTOs" verilog-inject-auto t] + ("AUTO Help..." + ["AUTO General" (describe-function 'verilog-auto) t] + ["AUTO Library Flags" (describe-variable 'verilog-library-flags) t] + ["AUTO Library Path" (describe-variable 'verilog-library-directories) t] + ["AUTO Library Files" (describe-variable 'verilog-library-files) t] + ["AUTO Library Extensions" (describe-variable 'verilog-library-extensions) t] + ["AUTO `define Reading" (describe-function 'verilog-read-defines) t] + ["AUTO `include Reading" (describe-function 'verilog-read-includes) t] + ["AUTOARG" (describe-function 'verilog-auto-arg) t] + ["AUTOASCIIENUM" (describe-function 'verilog-auto-ascii-enum) t] + ["AUTOINOUTMODULE" (describe-function 'verilog-auto-inout-module) t] + ["AUTOINOUT" (describe-function 'verilog-auto-inout) t] + ["AUTOINPUT" (describe-function 'verilog-auto-input) t] + ["AUTOINST" (describe-function 'verilog-auto-inst) t] + ["AUTOINST (.*)" (describe-function 'verilog-auto-star) t] + ["AUTOINSTPARAM" (describe-function 'verilog-auto-inst-param) t] + ["AUTOOUTPUT" (describe-function 'verilog-auto-output) t] + ["AUTOOUTPUTEVERY" (describe-function 'verilog-auto-output-every) t] + ["AUTOREG" (describe-function 'verilog-auto-reg) t] + ["AUTOREGINPUT" (describe-function 'verilog-auto-reg-input) t] + ["AUTORESET" (describe-function 'verilog-auto-reset) t] + ["AUTOSENSE" (describe-function 'verilog-auto-sense) t] + ["AUTOTIEOFF" (describe-function 'verilog-auto-tieoff) t] + ["AUTOUNUSED" (describe-function 'verilog-auto-unused) t] + ["AUTOWIRE" (describe-function 'verilog-auto-wire) t] + ) + "----" + ["Submit bug report" verilog-submit-bug-report t] + ["Version and FAQ" verilog-faq t] + ["Customize Verilog Mode..." verilog-customize t] + ["Customize Verilog Fonts & Colors" verilog-font-customize t] + ) + "Emacs menu for VERILOG mode." + ) +(defvar verilog-statement-menu + '("Statements" + ["Header" verilog-sk-header t] + ["Comment" verilog-sk-comment t] + "----" + ["Module" verilog-sk-module t] + ["Primitive" verilog-sk-primitive t] + "----" + ["Input" verilog-sk-input t] + ["Output" verilog-sk-output t] + ["Inout" verilog-sk-inout t] + ["Wire" verilog-sk-wire t] + ["Reg" verilog-sk-reg t] + ["Define thing under point as a register" verilog-sk-define-signal t] + "----" + ["Initial" verilog-sk-initial t] + ["Always" verilog-sk-always t] + ["Function" verilog-sk-function t] + ["Task" verilog-sk-task t] + ["Specify" verilog-sk-specify t] + ["Generate" verilog-sk-generate t] + "----" + ["Begin" verilog-sk-begin t] + ["If" verilog-sk-if t] + ["(if) else" verilog-sk-else-if t] + ["For" verilog-sk-for t] + ["While" verilog-sk-while t] + ["Fork" verilog-sk-fork t] + ["Repeat" verilog-sk-repeat t] + ["Case" verilog-sk-case t] + ["Casex" verilog-sk-casex t] + ["Casez" verilog-sk-casez t] + ) + "Menu for statement templates in Verilog." + ) + +(easy-menu-define verilog-menu verilog-mode-map "Menu for Verilog mode" + verilog-xemacs-menu) +(easy-menu-define verilog-stmt-menu verilog-mode-map "Menu for statement templates in Verilog." + verilog-statement-menu) + +(defvar verilog-mode-abbrev-table nil + "Abbrev table in use in Verilog-mode buffers.") + +(define-abbrev-table 'verilog-mode-abbrev-table ()) + +;; compilation program +(defun verilog-set-compile-command () + "Function to compute shell command to compile verilog. + +This reads `verilog-tool' and sets `compile-command'. This specifies the +program that executes when you type \\[compile] or +\\[verilog-auto-save-compile]. + +By default `verilog-tool' uses a Makefile if one exists in the current +directory. If not, it is set to the `verilog-linter', `verilog-coverage', +`verilog-simulator', or `verilog-compiler' variables, as selected with the +Verilog -> \"Choose Compilation Action\" menu. + +You should set `verilog-tool' or the other variables to the path and +arguments for your Verilog simulator. For example: + \"vcs -p123 -O\" +or a string like: + \"(cd /tmp; surecov %s)\". + +In the former case, the path to the current buffer is concat'ed to the +value of `verilog-tool'; in the later, the path to the current buffer is +substituted for the %s. + +Where __FILE__ appears in the string, the buffer-file-name of the current +buffer, without the directory portion, will be substituted." + (interactive) + (cond + ((or (file-exists-p "makefile") ;If there is a makefile, use it + (file-exists-p "Makefile")) + (make-local-variable 'compile-command) + (setq compile-command "make ")) + (t + (make-local-variable 'compile-command) + (setq compile-command + (if verilog-tool + (if (string-match "%s" (eval verilog-tool)) + (format (eval verilog-tool) (or buffer-file-name "")) + (concat (eval verilog-tool) " " (or buffer-file-name ""))) + "")))) + (verilog-modify-compile-command)) + +(defun verilog-modify-compile-command () + "Replace meta-information in `compile-command'. +Where __FILE__ appears in the string, the current buffer's file-name, +without the directory portion, will be substituted." + (when (string-match "\\b__FILE__\\b" compile-command) + (make-local-variable 'compile-command) + (setq compile-command + (verilog-string-replace-matches + "\\b__FILE__\\b" (file-name-nondirectory (buffer-file-name)) + t t compile-command)))) + +(defun verilog-error-regexp-add () + "Add the messages to the `compilation-error-regexp-alist'. +Called by `compilation-mode-hook'. This allows \\[next-error] to find the errors." + (if (not verilog-error-regexp-add-didit) + (progn + (setq verilog-error-regexp-add-didit t) + (setq-default compilation-error-regexp-alist + (append verilog-error-regexp + (default-value 'compilation-error-regexp-alist))) + ;; Could be buffer local at this point; maybe also in let; change all three + (setq compilation-error-regexp-alist (default-value 'compilation-error-regexp-alist)) + (set (make-local-variable 'compilation-error-regexp-alist) + (default-value 'compilation-error-regexp-alist)) + ))) + +(add-hook 'compilation-mode-hook 'verilog-error-regexp-add) + +(defconst verilog-directive-re + ;; "`case" "`default" "`define" "`define" "`else" "`endfor" "`endif" + ;; "`endprotect" "`endswitch" "`endwhile" "`for" "`format" "`if" "`ifdef" + ;; "`ifndef" "`include" "`let" "`protect" "`switch" "`timescale" + ;; "`time_scale" "`undef" "`while" + "\\<`\\(case\\|def\\(ault\\|ine\\(\\)?\\)\\|e\\(lse\\|nd\\(for\\|if\\|protect\\|switch\\|while\\)\\)\\|for\\(mat\\)?\\|i\\(f\\(def\\|ndef\\)?\\|nclude\\)\\|let\\|protect\\|switch\\|time\\(_scale\\|scale\\)\\|undef\\|while\\)\\>") + +(defconst verilog-directive-begin + "\\<`\\(for\\|i\\(f\\|fdef\\|fndef\\)\\|switch\\|while\\)\\>") + +(defconst verilog-directive-middle + "\\<`\\(else\\|default\\|case\\)\\>") + +(defconst verilog-directive-end + "`\\(endfor\\|endif\\|endswitch\\|endwhile\\)\\>") + +(defconst verilog-directive-re-1 + (concat "[ \t]*" verilog-directive-re)) + +;; +;; Regular expressions used to calculate indent, etc. +;; +(defconst verilog-symbol-re "\\<[a-zA-Z_][a-zA-Z_0-9.]*\\>") +(defconst verilog-case-re "\\(\\<case[xz]?\\>\\|\\<randcase\\>\\)") +;; Want to match +;; aa : +;; aa,bb : +;; a[34:32] : +;; a, +;; b : + +(defconst verilog-no-indent-begin-re + "\\<\\(if\\|else\\|while\\|for\\|repeat\\|always\\|always_comb\\|always_ff\\|always_latch\\)\\>") + +(defconst verilog-ends-re + ;; Parenthesis indicate type of keyword found + (concat + "\\(\\<else\\>\\)\\|" ; 1 + "\\(\\<if\\>\\)\\|" ; 2 + "\\(\\<end\\>\\)\\|" ; 3 + "\\(\\<endcase\\>\\)\\|" ; 4 + "\\(\\<endfunction\\>\\)\\|" ; 5 + "\\(\\<endtask\\>\\)\\|" ; 6 + "\\(\\<endspecify\\>\\)\\|" ; 7 + "\\(\\<endtable\\>\\)\\|" ; 8 + "\\(\\<endgenerate\\>\\)\\|" ; 9 + "\\(\\<join\\(_any\\|_none\\)?\\>\\)\\|" ; 10 + "\\(\\<endclass\\>\\)\\|" ; 11 + "\\(\\<endgroup\\>\\)" ; 12 + )) + +(defconst verilog-auto-end-comment-lines-re + ;; Matches to names in this list cause auto-end-commentation + ;; + ;; "macromodule" "module" "primitive" "interface" "end" "endcase" "endfunction" + ;; "endtask" "endmodule" "endprimitive" "endinterface" "endspecify" "endtable" "join" + ;; "begin" "else" `{directives} + (concat "\\(" + verilog-directive-re "\\)\\|\\(" + (eval-when-compile + (verilog-regexp-words + `( "begin" + "else" + "end" + "endcase" + "endclass" + "endgroup" + "endfunction" + "endmodule" + "endprogram" + "endprimitive" + "endinterface" + "endpackage" + "endsequence" + "endspecify" + "endtable" + "endtask" + "join" + "join_any" + "join_none" + "module" + "macromodule" + "primitive" + "interface" + "package"))) + "\\)")) + +;;; NOTE: verilog-leap-to-head expects that verilog-end-block-re and +;;; verilog-end-block-ordered-re matches exactly the same strings. +(defconst verilog-end-block-ordered-re + ;; Parenthesis indicate type of keyword found + (concat "\\(\\<endcase\\>\\)\\|" ; 1 + "\\(\\<end\\>\\)\\|" ; 2 + "\\(\\<end" ; 3, but not used + "\\(" ; 4, but not used + "\\(function\\)\\|" ; 5 + "\\(task\\)\\|" ; 6 + "\\(module\\)\\|" ; 7 + "\\(primitive\\)\\|" ; 8 + "\\(interface\\)\\|" ; 9 + "\\(package\\)\\|" ; 10 + "\\(class\\)\\|" ; 11 + "\\(group\\)\\|" ; 12 + "\\(program\\)\\|" ; 13 + "\\(sequence\\)\\|" ; 14 + "\\)\\>\\)")) +(defconst verilog-end-block-re + (eval-when-compile + (verilog-regexp-words + + `("end" ;; closes begin + "endcase" ;; closes any of case, casex casez or randcase + "join" "join_any" "join_none" ;; closes fork + "endclass" + "endtable" + "endspecify" + "endfunction" + "endgenerate" + "endtask" + "endgroup" + "endproperty" + "endinterface" + "endpackage" + "endprogram" + "endsequence" + ) + ))) + + +(defconst verilog-endcomment-reason-re + ;; Parenthesis indicate type of keyword found + (concat + "\\(\\<fork\\>\\)\\|" + "\\(\\<begin\\>\\)\\|" + "\\(\\<if\\>\\)\\|" + "\\(\\<else\\>\\)\\|" + "\\(\\<end\\>.*\\<else\\>\\)\\|" + "\\(\\<task\\>\\)\\|" + "\\(\\<function\\>\\)\\|" + "\\(\\<initial\\>\\)\\|" + "\\(\\<interface\\>\\)\\|" + "\\(\\<package\\>\\)\\|" + "\\(\\<final\\>\\)\\|" + "\\(\\<always\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(\\<always_comb\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(\\<always_ff\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(\\<always_latch\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(@\\)\\|" + "\\(\\<while\\>\\)\\|" + "\\(\\<for\\(ever\\)?\\>\\)\\|" + "\\(\\<repeat\\>\\)\\|\\(\\<wait\\>\\)\\|" + "#")) + +(defconst verilog-named-block-re "begin[ \t]*:") + +;; These words begin a block which can occur inside a module which should be indented, +;; and closed with the respective word from the end-block list + +(defconst verilog-beg-block-re + (eval-when-compile + (verilog-regexp-words + `("begin" + "case" "casex" "casez" "randcase" + "generate" + "fork" + "function" + "property" + "specify" + "table" + "task" + )))) +;; These are the same words, in a specific order in the regular +;; expression so that matching will work nicely for +;; verilog-forward-sexp and verilog-calc-indent + +(defconst verilog-beg-block-re-ordered + ( concat "\\<" + "\\(begin\\)\\|" ;1 + "\\(randcase\\|case[xz]?\\)\\|" ; 2 + "\\(fork\\)\\|" ;3 + "\\(class\\)\\|" ;4 + "\\(table\\)\\|" ;5 + "\\(specify\\)\\|" ;6 + "\\(function\\)\\|" ;7 + "\\(task\\)\\|" ;8 + "\\(generate\\)\\|" ;9 + "\\(covergroup\\)\\|" ;10 + "\\(property\\)\\|" ;11 + "\\(\\(rand\\)?sequence\\)" ;12 + "\\>")) + +(defconst verilog-end-block-ordered-rry + [ "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<endcase\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" + "\\(\\<randcase\\>\\|\\<case[xz]?\\>\\)\\|\\(\\<endcase\\>\\)" + "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" + "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" + "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" + "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" + "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" + "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" + "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" + "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" + "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" + "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" + ] ) + +(defconst verilog-nameable-item-re + (eval-when-compile + (verilog-regexp-words + `("begin" + "fork" + "join" "join_any" "join_none" + "end" + "endcase" + "endconfig" + "endclass" + "endfunction" + "endgenerate" + "endmodule" + "endprimative" + "endinterface" + "endpackage" + "endspecify" + "endtable" + "endtask" ) + ))) + +(defconst verilog-declaration-opener + (eval-when-compile + (verilog-regexp-words + `("module" "begin" "task" "function")))) + +(defconst verilog-declaration-re + (eval-when-compile + (verilog-regexp-words + `("assign" "defparam" "event" "inout" "input" "integer" "localparam" "output" + "parameter" "real" "realtime" "reg" "supply" "supply0" "supply1" "time" + "tri" "tri0" "tri1" "triand" "trior" "trireg" "wand" "wire" "typedef" + "struct" "logic" "bit" "genvar" "wor")))) +(defconst verilog-range-re "\\(\\[[^]]*\\]\\s-*\\)+") +(defconst verilog-optional-signed-re "\\s-*\\(signed\\)?") +(defconst verilog-optional-signed-range-re + (concat + "\\s-*\\(\\<\\(reg\\|wire\\)\\>\\s-*\\)?\\(\\<signed\\>\\s-*\\)?\\(" verilog-range-re "\\)?")) +(defconst verilog-macroexp-re "`\\sw+") + +(defconst verilog-delay-re "#\\s-*\\(\\([0-9_]+\\('s?[hdxbo][0-9a-fA-F_xz]+\\)?\\)\\|\\(([^()]*)\\)\\|\\(\\sw+\\)\\)") +(defconst verilog-declaration-re-2-no-macro + (concat "\\s-*" verilog-declaration-re + "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)" +; "\\|\\(" verilog-macroexp-re "\\)" + "\\)?")) +(defconst verilog-declaration-re-2-macro + (concat "\\s-*" verilog-declaration-re + "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)" + "\\|\\(" verilog-macroexp-re "\\)" + "\\)?")) +(defconst verilog-declaration-re-1-macro + (concat "^" verilog-declaration-re-2-macro)) +; (concat +; "^\\s-*\\<\\(in\\(?:out\\|put\\|teger\\)\\|output\\|re\\(?:al\\(?:time\\)?\\|g\\)\\|t\\(?:ime\\|ri\\(?:and\\|or\\|reg\\|[01]\\)?\\|ypedef\\)\\|w\\(?:and\\|ire\\|or\\)\\)\\>" +; "\\s-*" +; "\\(" +; "\\(" +; "\\(\\<\\(reg\\|wire\\)\\>\\s-*\\)?" +; "\\(\\<signed\\>\\s-*\\)?" +; "\\(\\(\\[[^]]*\\]\\)+\\)?" +; "\\)" +; "\\|" +; "\\(#\\s-*\\(" +; "\\([0-9_]+\\('s?[hdxbo][0-9a-fA-F_xz]+\\)?\\)" +; "\\|\\(([^()]*)\\)" +; "\\|\\(\\sw+\\)" +; "\\)" +; "\\)" +; "\\|\\(`\\sw+\\)\\)?" +; )) + +(defconst verilog-declaration-re-1-no-macro (concat "^" verilog-declaration-re-2-no-macro)) +(defconst verilog-defun-re + (eval-when-compile (verilog-regexp-words `("macromodule" "module" "class" "program" "interface" "package" "primitive" "config")))) +(defconst verilog-end-defun-re + (eval-when-compile (verilog-regexp-words `("endmodule" "endclass" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig")))) +(defconst verilog-zero-indent-re + (concat verilog-defun-re "\\|" verilog-end-defun-re)) + +(defconst verilog-behavioral-block-beg-re + (concat "\\(\\<initial\\>\\|\\<final\\>\\|\\<always\\>\\|\\<always_comb\\>\\|\\<always_ff\\>\\|" + "\\<always_latch\\>\\|\\<function\\>\\|\\<task\\>\\)")) + +(defconst verilog-indent-re + (eval-when-compile + (verilog-regexp-words + `( + "always" "always_latch" "always_ff" "always_comb" + "begin" "end" + "case" "casex" "casez" "randcase" "endcase" + "class" "endclass" + "config" "endconfig" + "covergroup" "endgroup" + "fork" "join" "join_any" "join_none" + "function" "endfunction" + "final" + "generate" "endgenerate" + "initial" + "interface" "endinterface" + "module" "macromodule" "endmodule" + "package" "endpackage" + "primitive" "endprimative" + "program" "endprogram" + "property" "endproperty" + "sequence" "randsequence" "endsequence" + "specify" "endspecify" + "table" "endtable" + "task" "endtask" + "`case" + "`default" + "`define" "`undef" + "`if" "`ifdef" "`ifndef" "`else" "`endif" + "`while" "`endwhile" + "`for" "`endfor" + "`format" + "`include" + "`let" + "`protect" "`endprotect" + "`switch" "`endswitch" + "`timescale" + "`time_scale" + )))) + +(defconst verilog-defun-level-re + (eval-when-compile + (verilog-regexp-words + `( + "module" "macromodule" "primitive" "class" "program" "initial" "final" "always" "always_comb" + "always_ff" "always_latch" "endtask" "endfunction" "interface" "package" + "config")))) + +(defconst verilog-defun-level-not-generate-re + (eval-when-compile + (verilog-regexp-words + `( + "module" "macromodule" "primitive" "class" "program" "interface" "package" "config")))) + +(defconst verilog-cpp-level-re + (eval-when-compile + (verilog-regexp-words + `( + "endmodule" "endprimitive" "endinterface" "endpackage" "endprogram" "endclass" + )))) + +(defconst verilog-complete-reg + (concat + "\\(extern\\s-+\\|virtual\\s-+\\|protected\\s-+\\)*\\(function\\|task\\)\\|" + "\\(typedef\\s-+\\)*\\(struct\\|union\\|class\\)\\|" + (eval-when-compile + (verilog-regexp-words + `( + "always" "assign" "always_latch" "always_ff" "always_comb" "constraint" + "import" "initial" "final" "repeat" "case" "casex" "casez" "randcase" "while" + "if" "for" "forever" "else" "parameter" "do" "foreach" + ))))) + +(defconst verilog-end-statement-re + (concat "\\(" verilog-beg-block-re "\\)\\|\\(" + verilog-end-block-re "\\)")) + +(defconst verilog-endcase-re + (concat verilog-case-re "\\|" + "\\(endcase\\)\\|" + verilog-defun-re + )) + +(defconst verilog-exclude-str-start "/* -----\\/----- EXCLUDED -----\\/-----" + "String used to mark beginning of excluded text.") +(defconst verilog-exclude-str-end " -----/\\----- EXCLUDED -----/\\----- */" + "String used to mark end of excluded text.") + +(defconst verilog-keywords + '( "`case" "`default" "`define" "`else" "`endfor" "`endif" + "`endprotect" "`endswitch" "`endwhile" "`for" "`format" "`if" "`ifdef" + "`ifndef" "`include" "`let" "`protect" "`switch" "`timescale" + "`time_scale" "`undef" "`while" + + "alias" "always" "always_comb" "always_ff" "always_latch" "and" + "assert" "assign" "assume" "automatic" "before" "begin" "bind" + "bins" "binsof" "bit" "break" "buf" "bufif0" "bufif1" "byte" + "case" "casex" "casez" "cell" "chandle" "class" "clocking" "cmos" + "config" "const" "constraint" "context" "continue" "cover" + "covergroup" "coverpoint" "cross" "deassign" "default" "defparam" + "design" "disable" "dist" "do" "edge" "else" "end" "endcase" + "endclass" "endclocking" "endconfig" "endfunction" "endgenerate" + "endgroup" "endinterface" "endmodule" "endpackage" "endprimitive" + "endprogram" "endproperty" "endspecify" "endsequence" "endtable" + "endtask" "enum" "event" "expect" "export" "extends" "extern" + "final" "first_match" "for" "force" "foreach" "forever" "fork" + "forkjoin" "function" "generate" "genvar" "highz0" "highz1" "if" + "iff" "ifnone" "ignore_bins" "illegal_bins" "import" "incdir" + "include" "initial" "inout" "input" "inside" "instance" "int" + "integer" "interface" "intersect" "join" "join_any" "join_none" + "large" "liblist" "library" "local" "localparam" "logic" + "longint" "macromodule" "matches" "medium" "modport" "module" + "nand" "negedge" "new" "nmos" "nor" "noshowcancelled" "not" + "notif0" "notif1" "null" "or" "output" "package" "packed" + "parameter" "pmos" "posedge" "primitive" "priority" "program" + "property" "protected" "pull0" "pull1" "pulldown" "pullup" + "pulsestyle_onevent" "pulsestyle_ondetect" "pure" "rand" "randc" + "randcase" "randsequence" "rcmos" "real" "realtime" "ref" "reg" + "release" "repeat" "return" "rnmos" "rpmos" "rtran" "rtranif0" + "rtranif1" "scalared" "sequence" "shortint" "shortreal" + "showcancelled" "signed" "small" "solve" "specify" "specparam" + "static" "string" "strong0" "strong1" "struct" "super" "supply0" + "supply1" "table" "tagged" "task" "this" "throughout" "time" + "timeprecision" "timeunit" "tran" "tranif0" "tranif1" "tri" + "tri0" "tri1" "triand" "trior" "trireg" "type" "typedef" "union" + "unique" "unsigned" "use" "var" "vectored" "virtual" "void" + "wait" "wait_order" "wand" "weak0" "weak1" "while" "wildcard" + "wire" "with" "within" "wor" "xnor" "xor" + ) + "List of Verilog keywords.") + + +(defconst verilog-emacs-features + ;; Documentation at the bottom + (let ((major (and (boundp 'emacs-major-version) + emacs-major-version)) + (minor (and (boundp 'emacs-minor-version) + emacs-minor-version)) + flavor comments flock-syntax) + ;; figure out version numbers if not already discovered + (and (or (not major) (not minor)) + (string-match "\\([0-9]+\\).\\([0-9]+\\)" emacs-version) + (setq major (string-to-int (substring emacs-version + (match-beginning 1) + (match-end 1))) + minor (string-to-int (substring emacs-version + (match-beginning 2) + (match-end 2))))) + (if (not (and major minor)) + (error "Cannot figure out the major and minor version numbers")) + ;; calculate the major version + (cond + ((= major 4) (setq major 'v18)) ;Epoch 4 + ((= major 18) (setq major 'v18)) ;Emacs 18 + ((= major 19) (setq major 'v19 ;Emacs 19 + flavor (if (or (string-match "Lucid" emacs-version) + (string-match "XEmacs" emacs-version)) + 'XEmacs 'FSF))) + ((> major 19) (setq major 'v20 + flavor (if (or (string-match "Lucid" emacs-version) + (string-match "XEmacs" emacs-version)) + 'XEmacs 'FSF))) + ;; I don't know + (t (error "Cannot recognize major version number: %s" major))) + ;; XEmacs 19 uses 8-bit modify-syntax-entry flags, as do all + ;; patched Emacs 19, Emacs 18, Epoch 4's. Only Emacs 19 uses a + ;; 1-bit flag. Let's be as smart as we can about figuring this + ;; out. + (if (or (eq major 'v20) (eq major 'v19)) + (let ((table (copy-syntax-table))) + (modify-syntax-entry ?a ". 12345678" table) + (cond + ;; XEmacs pre 20 and Emacs pre 19.30 use vectors for syntax tables. + ((vectorp table) + (if (= (logand (lsh (aref table ?a) -16) 255) 255) + (setq comments '8-bit) + (setq comments '1-bit))) + ;; XEmacs 20 is known to be 8-bit + ((eq flavor 'XEmacs) (setq comments '8-bit)) + ;; Emacs 19.30 and beyond are known to be 1-bit + ((eq flavor 'FSF) (setq comments '1-bit)) + ;; Don't know what this is + (t (error "Couldn't figure out syntax table format")) + )) + ;; Emacs 18 has no support for dual comments + (setq comments 'no-dual-comments)) + ;; determine whether to use old or new font lock syntax + ;; We can assume 8-bit syntax table emacsen support new syntax, otherwise + ;; look for version > 19.30 + (setq flock-syntax + (if (or (equal comments '8-bit) + (equal major 'v20) + (and (equal major 'v19) (> minor 30))) + 'flock-syntax-after-1930 + 'flock-syntax-before-1930)) + ;; lets do some minimal sanity checking. + (if (or + ;; Emacs before 19.6 had bugs + (and (eq major 'v19) (eq flavor 'XEmacs) (< minor 6)) + ;; Emacs 19 before 19.21 has known bugs + (and (eq major 'v19) (eq flavor 'FSF) (< minor 21)) + ) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "The version of Emacs that you are running, %s, +has known bugs in its syntax parsing routines which will affect the +performance of verilog-mode. You should strongly consider upgrading to the +latest available version. verilog-mode may continue to work, after a +fashion, but strange indentation errors could be encountered." + emacs-version)))) + ;; Emacs 18, with no patch is not too good + (if (and (eq major 'v18) (eq comments 'no-dual-comments)) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "The version of Emacs 18 you are running, %s, +has known deficiencies in its ability to handle the dual verilog +(and C++) comments, (e.g. the // and /* */ comments). This will +not be much of a problem for you if you only use the /* */ comments, +but you really should strongly consider upgrading to one of the latest +Emacs 19's. In Emacs 18, you may also experience performance degradations. +Emacs 19 has some new built-in routines which will speed things up for you. +Because of these inherent problems, verilog-mode is not supported +on emacs-18." + emacs-version)))) + ;; Emacs 18 with the syntax patches are no longer supported + (if (and (eq major 'v18) (not (eq comments 'no-dual-comments))) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "You are running a syntax patched Emacs 18 variant. While this should +work for you, you may want to consider upgrading to Emacs 19. +The syntax patches are no longer supported either for verilog-mode.")))) + (list major comments flock-syntax)) + "A list of features extant in the Emacs you are using. +There are many flavors of Emacs out there, each with different +features supporting those needed by `verilog-mode'. Here's the current +supported list, along with the values for this variable: + + Vanilla Emacs 18/Epoch 4: (v18 no-dual-comments flock-syntax-before-1930) + Emacs 18/Epoch 4 (patch2): (v18 8-bit flock-syntax-after-1930) + XEmacs (formerly Lucid) 19: (v19 8-bit flock-syntax-after-1930) + XEmacs 20: (v20 8-bit flock-syntax-after-1930) + Emacs 19.1-19.30: (v19 8-bit flock-syntax-before-1930) + Emacs 19.31-19.xx: (v19 8-bit flock-syntax-after-1930) + Emacs20 : (v20 1-bit flock-syntax-after-1930).") + +(defconst verilog-comment-start-regexp "//\\|/\\*" + "Dual comment value for `comment-start-regexp'.") + +(defun verilog-populate-syntax-table (table) + "Populate the syntax TABLE." + (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?% "." table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?` "w" table) + (modify-syntax-entry ?_ "w" table) + (modify-syntax-entry ?\' "." table) +) + +(defun verilog-setup-dual-comments (table) + "Set up TABLE to handle block and line style comments." + (cond + ((memq '8-bit verilog-emacs-features) + ;; XEmacs (formerly Lucid) has the best implementation + (modify-syntax-entry ?/ ". 1456" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + ) + ((memq '1-bit verilog-emacs-features) + ;; Emacs 19 does things differently, but we can work with it + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + ) + )) + +(defvar verilog-mode-syntax-table nil + "Syntax table used in `verilog-mode' buffers.") + +(defconst verilog-font-lock-keywords nil + "Default highlighting for Verilog mode.") + +(defconst verilog-font-lock-keywords-1 nil + "Subdued level highlighting for Verilog mode.") + +(defconst verilog-font-lock-keywords-2 nil + "Medium level highlighting for Verilog mode. +See also `verilog-font-lock-extra-types'.") + +(defconst verilog-font-lock-keywords-3 nil + "Gaudy level highlighting for Verilog mode. +See also `verilog-font-lock-extra-types'.") +(defvar verilog-font-lock-translate-off-face + 'verilog-font-lock-translate-off-face + "Font to use for translated off regions.") +(defface verilog-font-lock-translate-off-face + '((((class color) + (background light)) + (:background "gray90" :italic t )) + (((class color) + (background dark)) + (:background "gray10" :italic t )) + (((class grayscale) (background light)) + (:foreground "DimGray" :italic t)) + (((class grayscale) (background dark)) + (:foreground "LightGray" :italic t)) + (t (:italis t))) + "Font lock mode face used to background highlight translate-off regions." + :group 'font-lock-highlighting-faces) + +(defvar verilog-font-lock-p1800-face + 'verilog-font-lock-p1800-face + "Font to use for p1800 keywords.") +(defface verilog-font-lock-p1800-face + '((((class color) + (background light)) + (:foreground "DarkOrange3" :bold t )) + (((class color) + (background dark)) + (:foreground "orange1" :bold t )) + (t (:italic t))) + "Font lock mode face used to highlight P1800 keywords." + :group 'font-lock-highlighting-faces) + +(defvar verilog-font-lock-ams-face + 'verilog-font-lock-ams-face + "Font to use for Analog/Mixed Signal keywords.") +(defface verilog-font-lock-ams-face + '((((class color) + (background light)) + (:foreground "Purple" :bold t )) + (((class color) + (background dark)) + (:foreground "orange1" :bold t )) + (t (:italic t))) + "Font lock mode face used to highlight P1800 keywords." + :group 'font-lock-highlighting-faces) + +(let* ((verilog-type-font-keywords + (eval-when-compile + (verilog-regexp-opt + '( + "and" "bit" "buf" "bufif0" "bufif1" "cmos" "defparam" + "event" "genvar" "inout" "input" "integer" "localparam" + "logic" "nand" "nmos" "not" "notif0" "notif1" "or" + "output" "parameter" "pmos" "pull0" "pull1" "pullup" + "rcmos" "real" "realtime" "reg" "rnmos" "rpmos" "rtran" + "rtranif0" "rtranif1" "signed" "struct" "supply" + "supply0" "supply1" "time" "tran" "tranif0" "tranif1" + "tri" "tri0" "tri1" "triand" "trior" "trireg" "typedef" + "vectored" "wand" "wire" "wor" "xnor" "xor" + ) nil ))) + + (verilog-pragma-keywords + (eval-when-compile + (verilog-regexp-opt + '("surefire" "synopsys" "rtl_synthesis" "verilint" ) nil + ))) + + (verilog-p1800-keywords + (eval-when-compile + (verilog-regexp-opt + '("alias" "assert" "assume" "automatic" "before" "bind" + "bins" "binsof" "break" "byte" "cell" "chandle" "class" + "clocking" "config" "const" "constraint" "context" "continue" + "cover" "covergroup" "coverpoint" "cross" "deassign" "design" + "dist" "do" "edge" "endclass" "endclocking" "endconfig" + "endgroup" "endprogram" "endproperty" "endsequence" "enum" + "expect" "export" "extends" "extern" "first_match" "foreach" + "forkjoin" "genvar" "highz0" "highz1" "ifnone" "ignore_bins" + "illegal_bins" "import" "incdir" "include" "inside" "instance" + "int" "intersect" "large" "liblist" "library" "local" "longint" + "matches" "medium" "modport" "new" "noshowcancelled" "null" + "packed" "program" "property" "protected" "pull0" "pull1" + "pulsestyle_onevent" "pulsestyle_ondetect" "pure" "rand" "randc" + "randcase" "randsequence" "ref" "release" "return" "scalared" + "sequence" "shortint" "shortreal" "showcancelled" "small" "solve" + "specparam" "static" "string" "strong0" "strong1" "struct" + "super" "tagged" "this" "throughout" "timeprecision" "timeunit" + "type" "union" "unsigned" "use" "var" "virtual" "void" + "wait_order" "weak0" "weak1" "wildcard" "with" "within" + ) nil ))) + + (verilog-ams-keywords + (eval-when-compile + (verilog-regexp-opt + '("above" "abs" "absdelay" "acos" "acosh" "ac_stim" + "aliasparam" "analog" "analysis" "asin" "asinh" "atan" "atan2" "atanh" + "branch" "ceil" "connectmodule" "connectrules" "cos" "cosh" "ddt" + "ddx" "discipline" "driver_update" "enddiscipline" "endconnectrules" + "endnature" "endparamset" "exclude" "exp" "final_step" "flicker_noise" + "floor" "flow" "from" "ground" "hypot" "idt" "idtmod" "inf" + "initial_step" "laplace_nd" "laplace_np" "laplace_zd" "laplace_zp" + "last_crossing" "limexp" "ln" "log" "max" "min" "nature" + "net_resolution" "noise_table" "paramset" "potential" "pow" "sin" + "sinh" "slew" "sqrt" "tan" "tanh" "timer" "transition" "white_noise" + "wreal" "zi_nd" "zi_np" "zi_zd" ) nil ))) + + (verilog-font-keywords + (eval-when-compile + (verilog-regexp-opt + '( + "assign" "begin" "case" "casex" "casez" "randcase" "deassign" + "default" "disable" "else" "end" "endcase" "endfunction" + "endgenerate" "endinterface" "endmodule" "endprimitive" + "endspecify" "endtable" "endtask" "final" "for" "force" "return" "break" + "continue" "forever" "fork" "function" "generate" "if" "iff" "initial" + "interface" "join" "join_any" "join_none" "macromodule" "module" "negedge" + "package" "endpackage" "always" "always_comb" "always_ff" + "always_latch" "posedge" "primitive" "priority" "release" + "repeat" "specify" "table" "task" "unique" "wait" "while" + "class" "program" "endclass" "endprogram" + ) nil )))) + + (setq verilog-font-lock-keywords + (list + ;; Fontify all builtin keywords + (concat "\\<\\(" verilog-font-keywords "\\|" + ;; And user/system tasks and functions + "\\$[a-zA-Z][a-zA-Z0-9_\\$]*" + "\\)\\>") + ;; Fontify all types + (cons (concat "\\<\\(" verilog-type-font-keywords "\\)\\>") + 'font-lock-type-face) + ;; Fontify IEEE-P1800 keywords + (cons (concat "\\<\\(" verilog-p1800-keywords "\\)\\>") + 'verilog-font-lock-p1800-face) + ;; Fontify Verilog-AMS keywords + (cons (concat "\\<\\(" verilog-ams-keywords "\\)\\>") + 'verilog-font-lock-ams-face) + + )) + + (setq verilog-font-lock-keywords-1 + (append verilog-font-lock-keywords + (list + ;; Fontify module definitions + (list + "\\<\\(\\(macro\\)?module\\|primitive\\|class\\|program\\|interface\\|package\\|task\\)\\>\\s-*\\(\\sw+\\)" + '(1 font-lock-keyword-face) + '(3 font-lock-function-name-face 'prepend)) + ;; Fontify function definitions + (list + (concat "\\<function\\>\\s-+\\(integer\\|real\\(time\\)?\\|time\\)\\s-+\\(\\sw+\\)" ) + '(1 font-lock-keyword-face) + '(3 font-lock-reference-face prepend) + ) + '("\\<function\\>\\s-+\\(\\[[^]]+\\]\\)\\s-+\\(\\sw+\\)" + (1 font-lock-keyword-face) + (2 font-lock-reference-face append) + ) + '("\\<function\\>\\s-+\\(\\sw+\\)" + 1 'font-lock-reference-face append) + ))) + + (setq verilog-font-lock-keywords-2 + (append verilog-font-lock-keywords-1 + (list + ;; Fontify pragmas + (concat "\\(//\\s-*" verilog-pragma-keywords "\\s-.*\\)") + ;; Fontify escaped names + '("\\(\\\\\\S-*\\s-\\)" 0 font-lock-function-name-face) + ;; Fontify macro definitions/ uses + '("`\\s-*[A-Za-z][A-Za-z0-9_]*" 0 font-lock-preprocessor-face) + ;; Fontify delays/numbers + '("\\(@\\)\\|\\(#\\s-*\\(\\(\[0-9_.\]+\\('s?[hdxbo][0-9a-fA-F_xz]*\\)?\\)\\|\\(([^()]+)\\|\\sw+\\)\\)\\)" + 0 font-lock-type-face append) + ;; Fontify instantiation names + '("\\([A-Za-z][A-Za-z0-9_]+\\)\\s-*(" 1 font-lock-function-name-face) + + ))) + + (setq verilog-font-lock-keywords-3 + (append verilog-font-lock-keywords-2 + (when verilog-highlight-translate-off + (list + ;; Fontify things in translate off regions + '(verilog-match-translate-off (0 'verilog-font-lock-translate-off-face prepend)) + ))) + ) + ) + + + +(defun verilog-inside-comment-p () + "Check if point inside a nested comment." + (save-excursion + (let ((st-point (point)) hitbeg) + (or (search-backward "//" (verilog-get-beg-of-line) t) + (if (progn + ;; This is for tricky case //*, we keep searching if /* is proceeded by // on same line + (while (and (setq hitbeg (search-backward "/*" nil t)) + (progn (forward-char 1) (search-backward "//" (verilog-get-beg-of-line) t)))) + hitbeg) + (not (search-forward "*/" st-point t))))))) + +(defun verilog-declaration-end () + (search-forward ";")) + +(defun verilog-point-text (&optional pointnum) + "Return text describing where POINTNUM or current point is (for errors). +Use filename, if current buffer being edited shorten to just buffer name." + (concat (or (and (equal (window-buffer (selected-window)) (current-buffer)) + (buffer-name)) + buffer-file-name + (buffer-name)) + ":" (int-to-string (count-lines (point-min) (or pointnum (point)))))) + +(defun electric-verilog-backward-sexp () + "Move backward over a sexp." + (interactive) + ;; before that see if we are in a comment + (verilog-backward-sexp) +) +(defun electric-verilog-forward-sexp () + "Move backward over a sexp." + (interactive) + ;; before that see if we are in a comment + (verilog-forward-sexp) +) +;;;used by hs-minor-mode +(defun verilog-forward-sexp-function (arg) + (if (< arg 0) + (verilog-backward-sexp) + (verilog-forward-sexp))) + + +(defun verilog-backward-sexp () + (let ((reg) + (elsec 1) + (found nil) + (st (point)) + ) + (if (not (looking-at "\\<")) + (forward-word -1)) + (cond + ((verilog-skip-backward-comment-or-string) + ) + ((looking-at "\\<else\\>") + (setq reg (concat + verilog-end-block-re + "\\|\\(\\<else\\>\\)" + "\\|\\(\\<if\\>\\)" + )) + (while (and (not found) + (verilog-re-search-backward reg nil 'move)) + (cond + ((match-end 1) ; matched verilog-end-block-re + ; try to leap back to matching outward block by striding across + ; indent level changing tokens then immediately + ; previous line governs indentation. + (verilog-leap-to-head)) + ((match-end 2) ; else, we're in deep + (setq elsec (1+ elsec))) + ((match-end 3) ; found it + (setq elsec (1- elsec)) + (if (= 0 elsec) + ;; Now previous line describes syntax + (setq found 't) + )) + ) + ) + ) + ((looking-at verilog-end-block-re) + (verilog-leap-to-head)) + ((looking-at "\\(endmodule\\>\\)\\|\\(\\<endprimitive\\>\\)\\|\\(\\<endclass\\>\\)\\|\\(\\<endprogram\\>\\)\\|\\(\\<endinterface\\>\\)\\|\\(\\<endpackage\\>\\)") + (cond + ((match-end 1) + (verilog-re-search-backward "\\<\\(macro\\)?module\\>" nil 'move)) + ((match-end 2) + (verilog-re-search-backward "\\<primitive\\>" nil 'move)) + ((match-end 3) + (verilog-re-search-backward "\\<class\\>" nil 'move)) + ((match-end 4) + (verilog-re-search-backward "\\<program\\>" nil 'move)) + ((match-end 5) + (verilog-re-search-backward "\\<interface\\>" nil 'move)) + ((match-end 6) + (verilog-re-search-backward "\\<package\\>" nil 'move)) + (t + (goto-char st) + (backward-sexp 1)))) + (t + (goto-char st) + (backward-sexp)) + ) ;; cond + )) + +(defun verilog-forward-sexp () + (let ((reg) + (md 2) + (st (point))) + (if (not (looking-at "\\<")) + (forward-word -1)) + (cond + ((verilog-skip-forward-comment-or-string) + (verilog-forward-syntactic-ws) + ) + ((looking-at verilog-beg-block-re-ordered);; begin|case|fork|class|table|specify|function|task|generate|covergroup|property|sequence + (cond + ((match-end 1) ; end + ;; Search forward for matching begin + (setq reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)" )) + ((match-end 2) ; endcase + ;; Search forward for matching case + (setq reg "\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" ) + ) + ((match-end 3) ; join + ;; Search forward for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" )) + ((match-end 4) ; endclass + ;; Search forward for matching class + (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" )) + ((match-end 5) ; endtable + ;; Search forward for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )) + ((match-end 6) ; endspecify + ;; Search forward for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )) + ((match-end 7) ; endfunction + ;; Search forward for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )) + ((match-end 8) ; endtask + ;; Search forward for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )) + ((match-end 9) ; endgenerate + ;; Search forward for matching generate + (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" )) + ((match-end 10) ; endgroup + ;; Search forward for matching covergroup + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" )) + ((match-end 11) ; endproperty + ;; Search forward for matching property + (setq reg "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" )) + ((match-end 12) ; endsequence + ;; Search forward for matching sequence + (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" ) + (setq md 3) ; 3 to get to endsequence in the reg above + ) + + ) + (if (forward-word 1) + (catch 'skip + (let ((nest 1)) + (while (verilog-re-search-forward reg nil 'move) + (cond + ((match-end md) ; the closer in reg + (setq nest (1- nest)) + (if (= 0 nest) + (throw 'skip 1))) + ((match-end 1) ; begin + (setq nest (1+ nest))))) + ))) + ) + ((looking-at (concat + "\\(\\<\\(macro\\)?module\\>\\)\\|" + "\\(\\<primitive\\>\\)\\|" + "\\(\\<class\\>\\)\\|" + "\\(\\<program\\>\\)\\|" + "\\(\\<interface\\>\\)\\|" + "\\(\\<package\\>\\)")) + (cond + ((match-end 1) + (verilog-re-search-forward "\\<endmodule\\>" nil 'move)) + ((match-end 2) + (verilog-re-search-forward "\\<endprimitive\\>" nil 'move)) + ((match-end 3) + (verilog-re-search-forward "\\<endclass\\>" nil 'move)) + ((match-end 4) + (verilog-re-search-forward "\\<endprogram\\>" nil 'move)) + ((match-end 5) + (verilog-re-search-forward "\\<endinterface\\>" nil 'move)) + ((match-end 6) + (verilog-re-search-forward "\\<endpackage\\>" nil 'move)) + (t + (goto-char st) + (if (= (following-char) ?\) ) + (forward-char 1) + (forward-sexp 1))))) + (t + (goto-char st) + (if (= (following-char) ?\) ) + (forward-char 1) + (forward-sexp 1))) + ) ;; cond + )) + +(defun verilog-declaration-beg () + (verilog-re-search-backward verilog-declaration-re (bobp) t)) + +;; +;; Macros +;; + +(defsubst verilog-string-replace-matches (from-string to-string fixedcase literal string) + "Replace occurrences of FROM-STRING with TO-STRING. +FIXEDCASE and LITERAL as in `replace-match`. STRING is what to replace. +The case (verilog-string-replace-matches \"o\" \"oo\" nil nil \"foobar\") +will break, as the o's continuously replace. xa -> x works ok though." + ;; Hopefully soon to a emacs built-in + (let ((start 0)) + (while (string-match from-string string start) + (setq string (replace-match to-string fixedcase literal string) + start (min (length string) (match-end 0)))) + string)) + +(defsubst verilog-string-remove-spaces (string) + "Remove spaces surrounding STRING." + (save-match-data + (setq string (verilog-string-replace-matches "^\\s-+" "" nil nil string)) + (setq string (verilog-string-replace-matches "\\s-+$" "" nil nil string)) + string)) + +(defsubst verilog-re-search-forward (REGEXP BOUND NOERROR) + ; checkdoc-params: (REGEXP BOUND NOERROR) + "Like `re-search-forward', but skips over match in comments or strings." + (store-match-data '(nil nil)) + (while (and + (re-search-forward REGEXP BOUND NOERROR) + (and (verilog-skip-forward-comment-or-string) + (progn + (store-match-data '(nil nil)) + (if BOUND + (< (point) BOUND) + t) + )))) + (match-end 0)) + +(defsubst verilog-re-search-backward (REGEXP BOUND NOERROR) + ; checkdoc-params: (REGEXP BOUND NOERROR) + "Like `re-search-backward', but skips over match in comments or strings." + (store-match-data '(nil nil)) + (while (and + (re-search-backward REGEXP BOUND NOERROR) + (and (verilog-skip-backward-comment-or-string) + (progn + (store-match-data '(nil nil)) + (if BOUND + (> (point) BOUND) + t) + )))) + (match-end 0)) + +(defsubst verilog-re-search-forward-quick (regexp bound noerror) + "Like `verilog-re-search-forward', including use of REGEXP BOUND and NOERROR, +but trashes match data and is faster for REGEXP that doesn't match often. +This may at some point use text properties to ignore comments, +so there may be a large up front penalty for the first search." + (let (pt) + (while (and (not pt) + (re-search-forward regexp bound noerror)) + (if (not (verilog-inside-comment-p)) + (setq pt (match-end 0)))) + pt)) + +(defsubst verilog-re-search-backward-quick (regexp bound noerror) + ; checkdoc-params: (REGEXP BOUND NOERROR) + "Like `verilog-re-search-backward', including use of REGEXP BOUND and NOERROR, +but trashes match data and is faster for REGEXP that doesn't match often. +This may at some point use text properties to ignore comments, +so there may be a large up front penalty for the first search." + (let (pt) + (while (and (not pt) + (re-search-backward regexp bound noerror)) + (if (not (verilog-inside-comment-p)) + (setq pt (match-end 0)))) + pt)) + +(defsubst verilog-get-beg-of-line (&optional arg) + (save-excursion + (beginning-of-line arg) + (point))) + +(defsubst verilog-get-end-of-line (&optional arg) + (save-excursion + (end-of-line arg) + (point))) + +(defsubst verilog-within-string () + (save-excursion + (nth 3 (parse-partial-sexp (verilog-get-beg-of-line) (point))))) + +(require 'font-lock) +(defvar verilog-need-fld 1) +(defvar font-lock-defaults-alist nil) ;In case we are XEmacs + +(defun verilog-font-lock-init () + "Initialize fontification." + ;; highlight keywords and standardized types, attributes, enumeration + ;; values, and subprograms + (setq verilog-font-lock-keywords-3 + (append verilog-font-lock-keywords-2 + (when verilog-highlight-translate-off + (list + ;; Fontify things in translate off regions + '(verilog-match-translate-off (0 'verilog-font-lock-translate-off-face prepend)) + )) + ) + ) + (put 'verilog-mode 'font-lock-defaults + '((verilog-font-lock-keywords + verilog-font-lock-keywords-1 + verilog-font-lock-keywords-2 + verilog-font-lock-keywords-3 + ) + nil ;; nil means highlight strings & comments as well as keywords + nil ;; nil means keywords must match case + nil ;; syntax table handled elsewhere + verilog-beg-of-defun ;; function to move to beginning of reasonable region to highlight + )) + (if verilog-need-fld + (let ((verilog-mode-defaults + '((verilog-font-lock-keywords + verilog-font-lock-keywords-1 + verilog-font-lock-keywords-2 + verilog-font-lock-keywords-3 + ) + nil ;; nil means highlight strings & comments as well as keywords + nil ;; nil means keywords must match case + nil ;; syntax table handled elsewhere + verilog-beg-of-defun ;; function to move to beginning of reasonable region to highlight + ))) + (setq font-lock-defaults-alist + (append + font-lock-defaults-alist + (list (cons 'verilog-mode verilog-mode-defaults)))) + (setq verilog-need-fld 0)))) + +;; initialize fontification for Verilog Mode +(verilog-font-lock-init) +;; start up message +(defconst verilog-startup-message-lines + '("Please use \\[verilog-submit-bug-report] to report bugs." + "Visit http://www.verilog.com to check for updates" + )) +(defconst verilog-startup-message-displayed t) +(defun verilog-display-startup-message () + (if (not verilog-startup-message-displayed) + (if (sit-for 5) + (let ((lines verilog-startup-message-lines)) + (message "verilog-mode version %s, released %s; type \\[describe-mode] for help" + verilog-mode-version verilog-mode-release-date) + (setq verilog-startup-message-displayed t) + (while (and (sit-for 4) lines) + (message (substitute-command-keys (car lines))) + (setq lines (cdr lines))))) + (message ""))) +;; +;; +;; Mode +;; + +;;###autoload +(defun verilog-mode () + "Major mode for editing Verilog code. +\\<verilog-mode-map> +See \\[describe-function] verilog-auto (\\[verilog-auto]) for details on how +AUTOs can improve coding efficiency. + +Use \\[verilog-faq] for a pointer to frequently asked questions. + +NEWLINE, TAB indents for Verilog code. +Delete converts tabs to spaces as it moves back. + +Supports highlighting. + +Turning on Verilog mode calls the value of the variable `verilog-mode-hook' +with no args, if that value is non-nil. + +Variables controlling indentation/edit style: + + variable `verilog-indent-level' (default 3) + Indentation of Verilog statements with respect to containing block. + `verilog-indent-level-module' (default 3) + 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' (default 3) + Indentation of declarations with respect to containing block. + Set to 0 to get them list right under containing block. + `verilog-indent-level-behavioral' (default 3) + 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' (default 1) + Indentation of `ifdef/`endif blocks + `verilog-cexp-indent' (default 1) + Indentation of Verilog statements broken across lines i.e.: + if (a) + begin + `verilog-case-indent' (default 2) + Indentation for case statements. + `verilog-auto-newline' (default nil) + Non-nil means automatically newline after semicolons and the punctuation + mark after an end. + `verilog-auto-indent-on-newline' (default t) + Non-nil means automatically indent line after newline + `verilog-tab-always-indent' (default t) + 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' (default t) + 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' (default t) + 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' (default 10) + 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' (default `(all)) + List of contexts where auto lineup of code should be done. + +Variables controlling other actions: + + `verilog-linter' (default surelint) + Unix program to call to run the lint checker. This is the default + command for \\[compile-command] and \\[verilog-auto-save-compile]. + +See \\[customize] for the complete list of variables. + +AUTO expansion functions are, in part: + + \\[verilog-auto] Expand AUTO statements. + \\[verilog-delete-auto] Remove the AUTOs. + \\[verilog-inject-auto] Insert AUTOs for the first time. + +Some other functions are: + + \\[verilog-complete-word] Complete word with appropriate possibilities. + \\[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, etc statements. + + \\[verilog-comment-region] Put marked area in a comment. + \\[verilog-uncomment-region] Uncomment an area commented with \\[verilog-comment-region]. + \\[verilog-insert-block] Insert begin ... end;. + \\[verilog-star-comment] Insert /* ... */. + + \\[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-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. + \\[verilog-sk-define-signal] Define signal under point as a register at the top of the module. + +All key bindings can be seen in a Verilog-buffer with \\[describe-bindings]. +Key bindings specific to `verilog-mode-map' are: + +\\{verilog-mode-map}" + (interactive) + (kill-all-local-variables) + (use-local-map verilog-mode-map) + (setq major-mode 'verilog-mode) + (setq mode-name "Verilog") + (setq local-abbrev-table verilog-mode-abbrev-table) + (setq verilog-mode-syntax-table (make-syntax-table)) + (verilog-populate-syntax-table verilog-mode-syntax-table) + ;; add extra comment syntax + (verilog-setup-dual-comments verilog-mode-syntax-table) + (set-syntax-table verilog-mode-syntax-table) + (make-local-variable 'indent-line-function) + (setq indent-line-function 'verilog-indent-line-relative) + (setq comment-indent-function 'verilog-comment-indent) + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments nil) + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'comment-multi-line) + (make-local-variable 'comment-start-skip) + (setq comment-start "// " + comment-end "" + comment-start-skip "/\\*+ *\\|// *" + comment-multi-line nil) + ;; Set up for compilation + (setq verilog-which-tool 1) + (setq verilog-tool 'verilog-linter) + (verilog-set-compile-command) + (when (boundp 'hack-local-variables-hook) ;; Also modify any file-local-variables + (add-hook 'hack-local-variables-hook 'verilog-modify-compile-command t)) + + ;; Setting up things for font-lock + (if verilog-running-on-xemacs + (progn + (if (and current-menubar + (not (assoc "Verilog" current-menubar))) + (progn + ;; (set-buffer-menubar (copy-sequence current-menubar)) + (add-submenu nil verilog-xemacs-menu) + (add-submenu nil verilog-stmt-menu) + ) + ) + )) + ;; Stuff for GNU emacs + (make-local-variable 'font-lock-defaults) + ;;------------------------------------------------------------ + ;; now hook in 'verilog-colorize-include-files (eldo-mode.el&spice-mode.el) + ;; all buffer local: + (make-local-hook 'font-lock-mode-hook) + (make-local-hook 'font-lock-after-fontify-buffer-hook); doesn't exist in emacs 20 + (add-hook 'font-lock-mode-hook 'verilog-colorize-include-files-buffer t t) + (add-hook 'font-lock-after-fontify-buffer-hook 'verilog-colorize-include-files-buffer t t) ; not in emacs 20 + (make-local-hook 'after-change-functions) + (add-hook 'after-change-functions 'verilog-colorize-include-files t t) + + ;; Tell imenu how to handle verilog. + (make-local-variable 'imenu-generic-expression) + (setq imenu-generic-expression verilog-imenu-generic-expression) + ;; hideshow support + (unless (assq 'verilog-mode hs-special-modes-alist) + (setq hs-special-modes-alist + (cons '(verilog-mode-mode "\\<begin\\>" "\\<end\\>" nil + verilog-forward-sexp-function) + hs-special-modes-alist))) + ;; Display version splash information. + (verilog-display-startup-message) + + ;; Stuff for autos + (add-hook 'write-contents-hooks 'verilog-auto-save-check) ; already local +;; (verilog-auto-reeval-locals t) ; Save locals in case user changes them +;; (verilog-getopt-flags) + (run-hooks 'verilog-mode-hook)) + + +;; +;; Electric functions +;; +(defun electric-verilog-terminate-line (&optional arg) + "Terminate line and indent next line. +With optional ARG, remove existing end of line comments." + (interactive) + ;; before that see if we are in a comment + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ; Inside // comment + (if (eolp) + (progn + (delete-horizontal-space) + (newline)) + (progn + (newline) + (insert-string "// ") + (beginning-of-line))) + (verilog-indent-line)) + ((nth 4 state) ; Inside any comment (hence /**/) + (newline) + (verilog-more-comment)) + ((eolp) + ;; First, check if current line should be indented + (if (save-excursion + (delete-horizontal-space) + (beginning-of-line) + (skip-chars-forward " \t") + (if (looking-at verilog-auto-end-comment-lines-re) + (let ((indent-str (verilog-indent-line))) + ;; Maybe we should set some endcomments + (if verilog-auto-endcomments + (verilog-set-auto-endcomments indent-str arg)) + (end-of-line) + (delete-horizontal-space) + (if arg + () + (newline)) + nil) + (progn + (end-of-line) + (delete-horizontal-space) + 't + ) + ) + ) + ;; see if we should line up assignments + (progn + (if (or (memq 'all verilog-auto-lineup) + (memq 'assignments verilog-auto-lineup)) + (verilog-pretty-expr) + ) + (newline) + ) + (forward-line 1) + ) + ;; Indent next line + (if verilog-auto-indent-on-newline + (verilog-indent-line)) + ) + (t + (newline)) + ))) + +(defun electric-verilog-terminate-and-indent () + "Insert a newline and indent for the next statement." + (interactive) + (electric-verilog-terminate-line 1)) + +(defun electric-verilog-semi () + "Insert `;' character and reindent the line." + (interactive) + (insert last-command-char) + + (if (or (verilog-in-comment-or-string-p) + (verilog-in-escaped-name-p)) + () + (save-excursion + (beginning-of-line) + (verilog-forward-ws&directives) + (verilog-indent-line) + ) + (if (and verilog-auto-newline + (not (verilog-parenthesis-depth))) + (electric-verilog-terminate-line)))) + +(defun electric-verilog-semi-with-comment () + "Insert `;' character, reindent the line and indent for comment." + (interactive) + (insert "\;") + (save-excursion + (beginning-of-line) + (verilog-indent-line)) + (indent-for-comment)) + +(defun electric-verilog-colon () + "Insert `:' and do all indentations except line indent on this line." + (interactive) + (insert last-command-char) + ;; Do nothing if within string. + (if (or + (verilog-within-string) + (not (verilog-in-case-region-p))) + () + (save-excursion + (let ((p (point)) + (lim (progn (verilog-beg-of-statement) (point)))) + (goto-char p) + (verilog-backward-case-item lim) + (verilog-indent-line))) +;; (let ((verilog-tab-always-indent nil)) +;; (verilog-indent-line)) + )) + +;;(defun electric-verilog-equal () +;; "Insert `=', and do indentation if within block." +;; (interactive) +;; (insert last-command-char) +;; Could auto line up expressions, but not yet +;; (if (eq (car (verilog-calculate-indent)) 'block) +;; (let ((verilog-tab-always-indent nil)) +;; (verilog-indent-command))) +;; ) + +(defun electric-verilog-tick () + "Insert back-tick, and indent to column 0 if this is a CPP directive." + (interactive) + (insert last-command-char) + (save-excursion + (if (progn + (beginning-of-line) + (looking-at verilog-directive-re-1)) + (verilog-indent-line)))) + +(defun electric-verilog-tab () + "Function called when TAB is pressed in Verilog mode." + (interactive) + ;; If verilog-tab-always-indent, indent the beginning of the line. + (if (or verilog-tab-always-indent + (save-excursion + (skip-chars-backward " \t") + (bolp))) + (let* ((oldpnt (point)) + (boi-point + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (verilog-indent-line) + (back-to-indentation) + (point)))) + (if (< (point) boi-point) + (back-to-indentation) + (cond ((not verilog-tab-to-comment)) + ((not (eolp)) + (end-of-line)) + (t + (indent-for-comment) + (when (and (eolp) (= oldpnt (point))) + ; kill existing comment + (beginning-of-line) + (re-search-forward comment-start-skip oldpnt 'move) + (goto-char (match-beginning 0)) + (skip-chars-backward " \t") + (kill-region (point) oldpnt) + )))) + ) + (progn (insert "\t")))) + + + +;; +;; Interactive functions +;; + +(defun verilog-indent-buffer () + "Indent-region the entire buffer as Verilog code. +To call this from the command line, see \\[verilog-batch-indent]." + (interactive) + (verilog-mode) + (indent-region (point-min) (point-max) nil)) + +(defun verilog-insert-block () + "Insert Verilog begin ... end; block in the code with right indentation." + (interactive) + (verilog-indent-line) + (insert "begin") + (electric-verilog-terminate-line) + (save-excursion + (electric-verilog-terminate-line) + (insert "end") + (beginning-of-line) + (verilog-indent-line))) + +(defun verilog-star-comment () + "Insert Verilog star comment at point." + (interactive) + (verilog-indent-line) + (insert "/*") + (save-excursion + (newline) + (insert " */")) + (newline) + (insert " * ")) + +(defun verilog-insert-indices (MAX) + "Insert a set of indices at into the rectangle. +The upper left corner is defined by the current point. Indices always +begin with 0 and extend to the MAX - 1. If no prefix arg is given, the +user is prompted for a value. The indices are surrounded by square brackets +[]. For example, the following code with the point located after the first +'a' gives: + + a = b a[ 0] = b + a = b a[ 1] = b + a = b a[ 2] = b + a = b a[ 3] = b + a = b ==> insert-indices ==> a[ 4] = b + a = b a[ 5] = b + a = b a[ 6] = b + a = b a[ 7] = b + a = b a[ 8] = b" + + (interactive "NMAX?") + (save-excursion + (let ((n 0)) + (while (< n MAX) + (save-excursion + (insert (format "[%3d]" n))) + (next-line 1) + (setq n (1+ n)))))) + + +(defun verilog-generate-numbers (MAX) + "Insert a set of generated numbers into a rectangle. +The upper left corner is defined by point. The numbers are padded to three +digits, starting with 000 and extending to (MAX - 1). If no prefix argument +is supplied, then the user is prompted for the MAX number. consider the +following code fragment: + + buf buf buf buf000 + buf buf buf buf001 + buf buf buf buf002 + buf buf buf buf003 + buf buf ==> insert-indices ==> buf buf004 + buf buf buf buf005 + buf buf buf buf006 + buf buf buf buf007 + buf buf buf buf008" + + (interactive "NMAX?") + (save-excursion + (let ((n 0)) + (while (< n MAX) + (save-excursion + (insert (format "%3.3d" n))) + (next-line 1) + (setq n (1+ n)))))) + +(defun verilog-mark-defun () + "Mark the current verilog function (or procedure). +This puts the mark at the end, and point at the beginning." + (interactive) + (push-mark (point)) + (verilog-end-of-defun) + (push-mark (point)) + (verilog-beg-of-defun) + (zmacs-activate-region)) + +(defun verilog-comment-region (start end) + ; checkdoc-params: (start end) + "Put the region into a Verilog comment. +The comments that are in this area are \"deformed\": +`*)' becomes `!(*' and `}' becomes `!{'. +These deformed comments are returned to normal if you use +\\[verilog-uncomment-region] to undo the commenting. + +The commented area starts with `verilog-exclude-str-start', and ends with +`verilog-exclude-str-end'. But if you change these variables, +\\[verilog-uncomment-region] won't recognize the comments." + (interactive "r") + (save-excursion + ;; Insert start and endcomments + (goto-char end) + (if (and (save-excursion (skip-chars-forward " \t") (eolp)) + (not (save-excursion (skip-chars-backward " \t") (bolp)))) + (forward-line 1) + (beginning-of-line)) + (insert verilog-exclude-str-end) + (setq end (point)) + (newline) + (goto-char start) + (beginning-of-line) + (insert verilog-exclude-str-start) + (newline) + ;; Replace end-comments within commented area + (goto-char end) + (save-excursion + (while (re-search-backward "\\*/" start t) + (replace-match "*-/" t t))) + (save-excursion + (let ((s+1 (1+ start))) + (while (re-search-backward "/\\*" s+1 t) + (replace-match "/-*" t t)))) + )) + +(defun verilog-uncomment-region () + "Uncomment a commented area; change deformed comments back to normal. +This command does nothing if the pointer is not in a commented +area. See also `verilog-comment-region'." + (interactive) + (save-excursion + (let ((start (point)) + (end (point))) + ;; Find the boundaries of the comment + (save-excursion + (setq start (progn (search-backward verilog-exclude-str-start nil t) + (point))) + (setq end (progn (search-forward verilog-exclude-str-end nil t) + (point)))) + ;; Check if we're really inside a comment + (if (or (equal start (point)) (<= end (point))) + (message "Not standing within commented area.") + (progn + ;; Remove endcomment + (goto-char end) + (beginning-of-line) + (let ((pos (point))) + (end-of-line) + (delete-region pos (1+ (point)))) + ;; Change comments back to normal + (save-excursion + (while (re-search-backward "\\*-/" start t) + (replace-match "*/" t t))) + (save-excursion + (while (re-search-backward "/-\\*" start t) + (replace-match "/*" t t))) + ;; Remove start comment + (goto-char start) + (beginning-of-line) + (let ((pos (point))) + (end-of-line) + (delete-region pos (1+ (point))))))))) + +(defun verilog-beg-of-defun () + "Move backward to the beginning of the current function or procedure." + (interactive) + (verilog-re-search-backward verilog-defun-re nil 'move)) + +(defun verilog-end-of-defun () + "Move forward to the end of the current function or procedure." + (interactive) + (verilog-re-search-forward verilog-end-defun-re nil 'move)) + +(defun verilog-get-beg-of-defun (&optional warn) + (save-excursion + (cond ((verilog-re-search-forward-quick verilog-defun-re nil t) + (point)) + (t + (error "%s: Can't find module beginning" (verilog-point-text)) + (point-max))))) +(defun verilog-get-end-of-defun (&optional warn) + (save-excursion + (cond ((verilog-re-search-forward-quick verilog-end-defun-re nil t) + (point)) + (t + (error "%s: Can't find endmodule" (verilog-point-text)) + (point-max))))) + +(defun verilog-label-be (&optional arg) + "Label matching begin ... end, fork ... join and case ... endcase statements. +With ARG, first kill any existing labels." + (interactive) + (let ((cnt 0) + (oldpos (point)) + (b (progn + (verilog-beg-of-defun) + (point-marker))) + (e (progn + (verilog-end-of-defun) + (point-marker))) + ) + (goto-char (marker-position b)) + (if (> (- e b) 200) + (message "Relabeling module...")) + (while (and + (> (marker-position e) (point)) + (verilog-re-search-forward + (concat + "\\<end\\(\\(function\\)\\|\\(task\\)\\|\\(module\\)\\|\\(primitive\\)\\|\\(interface\\)\\|\\(package\\)\\|\\(case\\)\\)?\\>" + "\\|\\(`endif\\)\\|\\(`else\\)") + nil 'move)) + (goto-char (match-beginning 0)) + (let ((indent-str (verilog-indent-line))) + (verilog-set-auto-endcomments indent-str 't) + (end-of-line) + (delete-horizontal-space) + ) + (setq cnt (1+ cnt)) + (if (= 9 (% cnt 10)) + (message "%d..." cnt)) + ) + (goto-char oldpos) + (if (or + (> (- e b) 200) + (> cnt 20)) + (message "%d lines auto commented" cnt)) + )) + +(defun verilog-beg-of-statement () + "Move backward to beginning of statement." + (interactive) + (while (save-excursion + (not (looking-at verilog-complete-reg)) + (verilog-backward-syntactic-ws) + (not (or + (bolp) + (= (preceding-char) ?\;) + (save-excursion + (verilog-backward-token) + (looking-at verilog-end-block-re)) + ))) + (skip-chars-backward " \t") + (verilog-backward-token)) + (let ((last (point))) + (while (progn + (setq last (point)) + (and (not (looking-at verilog-complete-reg)) + (verilog-continued-line)))) + (goto-char last) + (verilog-forward-syntactic-ws))) + +(defun verilog-beg-of-statement-1 () + "Move backward to beginning of statement." + (interactive) + (let ((pt (point))) + + (while (and (not (looking-at verilog-complete-reg)) + (setq pt (point)) + (verilog-backward-token) + (not (looking-at verilog-complete-reg)) + (verilog-backward-syntactic-ws) + (setq pt (point)) + (not (bolp)) + (not (= (preceding-char) ?\;)))) +; (while (progn +; (setq pt (point)) +; (and (not (looking-at verilog-complete-reg)) +; (not (= (preceding-char) ?\;)) +; (verilog-continued-line)))) + (goto-char pt) + (verilog-forward-ws&directives))) + +(defun verilog-end-of-statement () + "Move forward to end of current statement." + (interactive) + (let ((nest 0) pos) + (or (looking-at verilog-beg-block-re) + ;; Skip to end of statement + (setq pos (catch 'found + (while t + (forward-sexp 1) + (verilog-skip-forward-comment-or-string) + (cond ((looking-at "[ \t]*;") + (skip-chars-forward "^;") + (forward-char 1) + (throw 'found (point))) + ((save-excursion + (forward-sexp -1) + (looking-at verilog-beg-block-re)) + (goto-char (match-beginning 0)) + (throw 'found nil)) + ((eobp) + (throw 'found (point)))))))) + (if (not pos) + ;; Skip a whole block + (catch 'found + (while t + (verilog-re-search-forward verilog-end-statement-re nil 'move) + (setq nest (if (match-end 1) + (1+ nest) + (1- nest))) + (cond ((eobp) + (throw 'found (point))) + ((= 0 nest) + (throw 'found (verilog-end-of-statement)))))) + pos))) + +(defun verilog-in-case-region-p () + "Return TRUE if in a case region; +more specifically, point @ in the line foo : @ begin" + (interactive) + (save-excursion + (if (and + (progn (verilog-forward-syntactic-ws) + (looking-at "\\<begin\\>")) + (progn (verilog-backward-syntactic-ws) + (= (preceding-char) ?\:))) + (catch 'found + (let ((nest 1)) + (while t + (verilog-re-search-backward + (concat "\\(\\<module\\>\\)\\|\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|" + "\\(\\<endcase\\>\\)\\>") + nil 'move) + (cond + ((match-end 3) + (setq nest (1+ nest))) + ((match-end 2) + (if (= nest 1) + (throw 'found 1)) + (setq nest (1- nest))) + (t + (throw 'found (= nest 0))) + )))) + nil))) +(defun verilog-in-struct-region-p () + "Return TRUE if in a struct region; +more specifically, in a list after a struct|union keyword" + (interactive) + (save-excursion + (let* ((state (parse-partial-sexp (point-min) (point))) + (depth (nth 0 state))) + (if depth + (progn (backward-up-list depth) + (verilog-beg-of-statement) + (looking-at "\\<typedef\\>?\\s-*\\<struct\\|union\\>") + ) + ) + ) + ) + ) + +(defun verilog-in-generate-region-p () + "Return TRUE if in a generate region; +more specifically, after a generate and before an endgenerate" + (interactive) + (let ((lim (save-excursion (verilog-beg-of-defun) (point))) + (nest 1) + ) + (save-excursion + (while (and + (/= nest 0) + (verilog-re-search-backward "\\<\\(generate\\)\\|\\(endgenerate\\)\\>" lim 'move) + (cond + ((match-end 1) ; generate + (setq nest (1- nest))) + ((match-end 2) ; endgenerate + (setq nest (1+ nest))) + )) + )) + (= nest 0) )) ; return nest + +(defun verilog-in-fork-region-p () + "Return true if between a fork and join." + (interactive) + (let ((lim (save-excursion (verilog-beg-of-defun) (point))) + (nest 1) + ) + (save-excursion + (while (and + (/= nest 0) + (verilog-re-search-backward "\\<\\(fork\\)\\|\\(join\\(_any\\|_none\\)?\\)\\>" lim 'move) + (cond + ((match-end 1) ; fork + (setq nest (1- nest))) + ((match-end 2) ; join + (setq nest (1+ nest))) + )) + )) + (= nest 0) )) ; return nest + +(defun verilog-backward-case-item (lim) + "Skip backward to nearest enclosing case item. +Limit search to point LIM." + (interactive) + (let ((str 'nil) + (lim1 + (progn + (save-excursion + (verilog-re-search-backward verilog-endcomment-reason-re + lim 'move) + (point))))) + ;; Try to find the real : + (if (save-excursion (search-backward ":" lim1 t)) + (let ((colon 0) + b e ) + (while + (and + (< colon 1) + (verilog-re-search-backward "\\(\\[\\)\\|\\(\\]\\)\\|\\(:\\)" + lim1 'move)) + (cond + ((match-end 1) ;; [ + (setq colon (1+ colon)) + (if (>= colon 0) + (error "%s: unbalanced [" (verilog-point-text)))) + ((match-end 2) ;; ] + (setq colon (1- colon))) + + ((match-end 3) ;; : + (setq colon (1+ colon))) + )) + ;; Skip back to beginning of case item + (skip-chars-backward "\t ") + (verilog-skip-backward-comment-or-string) + (setq e (point)) + (setq b + (progn + (if + (verilog-re-search-backward + "\\<\\(case[zx]?\\)\\>\\|;\\|\\<end\\>" nil 'move) + (progn + (cond + ((match-end 1) + (goto-char (match-end 1)) + (verilog-forward-ws&directives) + (if (looking-at "(") + (progn + (forward-sexp) + (verilog-forward-ws&directives))) + (point)) + (t + (goto-char (match-end 0)) + (verilog-forward-ws&directives) + (point)) + )) + (error "Malformed case item") + ))) + (setq str (buffer-substring b e)) + (if + (setq e + (string-match + "[ \t]*\\(\\(\n\\)\\|\\(//\\)\\|\\(/\\*\\)\\)" str)) + (setq str (concat (substring str 0 e) "..."))) + str) + 'nil))) + + +;; +;; Other functions +;; + +(defun kill-existing-comment () + "Kill auto comment on this line." + (save-excursion + (let* ( + (e (progn + (end-of-line) + (point))) + (b (progn + (beginning-of-line) + (search-forward "//" e t)))) + (if b + (delete-region (- b 2) e))))) + +(defconst verilog-directive-nest-re + (concat "\\(`else\\>\\)\\|" + "\\(`endif\\>\\)\\|" + "\\(`if\\>\\)\\|" + "\\(`ifdef\\>\\)\\|" + "\\(`ifndef\\>\\)")) +(defun verilog-set-auto-endcomments (indent-str kill-existing-comment) + "Add ending comment with given INDENT-STR. +With KILL-EXISTING-COMMENT, remove what was there before. +Insert `// case: 7 ' or `// NAME ' on this line if appropriate. +Insert `// case expr ' if this line ends a case block. +Insert `// ifdef FOO ' if this line ends code conditional on FOO. +Insert `// NAME ' if this line ends a function, task, module, primitive or interface named NAME." + (save-excursion + (cond + (; Comment close preprocessor directives + (and + (looking-at "\\(`endif\\)\\|\\(`else\\)") + (or kill-existing-comment + (not (save-excursion + (end-of-line) + (search-backward "//" (verilog-get-beg-of-line) t))))) + (let ((nest 1) b e + m + (else (if (match-end 2) "!" " ")) + ) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (save-excursion + (backward-sexp 1) + (while (and (/= nest 0) + (verilog-re-search-backward verilog-directive-nest-re nil 'move)) + (cond + ((match-end 1) ; `else + (if (= nest 1) + (setq else "!"))) + ((match-end 2) ; `endif + (setq nest (1+ nest))) + ((match-end 3) ; `if + (setq nest (1- nest))) + ((match-end 4) ; `ifdef + (setq nest (1- nest))) + ((match-end 5) ; `ifndef + (setq nest (1- nest))) + )) + (if (match-end 0) + (setq + m (buffer-substring + (match-beginning 0) + (match-end 0)) + b (progn + (skip-chars-forward "^ \t") + (verilog-forward-syntactic-ws) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point) + )))) + (if b + (if (> (count-lines (point) b) verilog-minimum-comment-distance) + (insert (concat " // " else m " " (buffer-substring b e)))) + (progn + (insert " // unmatched `else or `endif") + (ding 't)) + ))) + + (; Comment close case/class/function/task/module and named block + (and (looking-at "\\<end") + (or kill-existing-comment + (not (save-excursion + (end-of-line) + (search-backward "//" (verilog-get-beg-of-line) t))))) + (let ((type (car indent-str))) + (unless (eq type 'declaration) + (unless (looking-at (concat "\\(" verilog-end-block-ordered-re "\\)[ \t]*:")) ;; ignore named ends + (if (looking-at verilog-end-block-ordered-re) + (cond + (;- This is a case block; search back for the start of this case + (match-end 1) ;; of verilog-end-block-ordered-re + + (let ((err 't) + (str "UNMATCHED!!")) + (save-excursion + (verilog-leap-to-head) + (cond + ((looking-at "\\<randcase\\>") + (setq str "randcase") + (setq err nil) + ) + ((match-end 0) + (goto-char (match-end 1)) + (if nil + (let (s f) + (setq s (match-beginning 1)) + (setq f (progn (end-of-line) + (point))) + (setq str (buffer-substring s f))) + (setq err nil)) + (setq str (concat (buffer-substring (match-beginning 1) (match-end 1)) + " " + (verilog-get-expr)))))) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (insert (concat " // " str )) + (if err (ding 't)) + )) + + (;- This is a begin..end block + (match-end 2) ;; of verilog-end-block-ordered-re + (let ((str " // UNMATCHED !!") + (err 't) + (here (point)) + there + cntx + ) + (save-excursion + (verilog-leap-to-head) + (setq there (point)) + (if (not (match-end 0)) + (progn + (goto-char here) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (insert str) + (ding 't) + ) + (let ((lim + (save-excursion (verilog-beg-of-defun) (point))) + (here (point)) + ) + (cond + (;-- handle named block differently + (looking-at verilog-named-block-re) + (search-forward ":") + (setq there (point)) + (setq str (verilog-get-expr)) + (setq err nil) + (setq str (concat " // block: " str ))) + + ((verilog-in-case-region-p) ;-- handle case item differently + (goto-char here) + (setq str (verilog-backward-case-item lim)) + (setq there (point)) + (setq err nil) + (setq str (concat " // case: " str ))) + + (;- try to find "reason" for this begin + (cond + (; + (eq here (progn + (verilog-backward-token) + (verilog-beg-of-statement-1) + (point))) + (setq err nil) + (setq str "")) + ((looking-at verilog-endcomment-reason-re) + (setq there (match-end 0)) + (setq cntx (concat + (buffer-substring (match-beginning 0) (match-end 0)) " ")) + (cond + (;- begin + (match-end 2) + (setq err nil) + (save-excursion + (if (and (verilog-continued-line) + (looking-at "\\<repeat\\>\\|\\<wait\\>\\|\\<always\\>")) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq str + (concat " // " + (buffer-substring (match-beginning 0) (match-end 0)) " " + (verilog-get-expr)))) + (setq str "")))) + + (;- else + (match-end 4) + (let ((nest 0) + ( reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<if\\>\\)") + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest))) + ((match-end 2) ; end + (setq nest (1+ nest))) + ((match-end 3) + (if (= 0 nest) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // else: !if" str )) + (throw 'skip 1)) + ))) + )))) + + (;- end else + (match-end 5) + (goto-char there) + (let ((nest 0) + ( reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<if\\>\\)") + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest))) + ((match-end 2) ; end + (setq nest (1+ nest))) + ((match-end 3) + (if (= 0 nest) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // else: !if" str )) + (throw 'skip 1)) + ))) + )))) + + (;- task/function/initial et cetera + t + (match-end 0) + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // " cntx str ))) + + (;-- otherwise... + (setq str " // auto-endcomment confused ")) + )) + + ((and + (verilog-in-case-region-p) ;-- handle case item differently + (progn + (setq there (point)) + (goto-char here) + (setq str (verilog-backward-case-item lim)))) + (setq err nil) + (setq str (concat " // case: " str ))) + + ((verilog-in-fork-region-p) + (setq err nil) + (setq str " // fork branch" )) + + ((looking-at "\\<end\\>") + ;; HERE + (forward-word 1) + (verilog-forward-syntactic-ws) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // " cntx str ))) + + )))) + (goto-char here) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (if (or err + (> (count-lines here there) verilog-minimum-comment-distance)) + (insert str)) + (if err (ding 't)) + )))) + (;- this is endclass, which can be nested + (match-end 11) ;; of verilog-end-block-ordered-re + ;;(goto-char there) + (let ((nest 0) + ( reg "\\<\\(class\\)\\|\\(endclass\\)\\|\\(package\\|primitive\\|\\(macro\\)?module\\)\\>") + string + ) + (save-excursion + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 3) ; endclass + (ding 't) + (setq string "unmatched endclass") + (throw 'skip 1)) + + ((match-end 2) ; endclass + (setq nest (1+ nest))) + + ((match-end 1) ; class + (setq nest (1- nest)) + (if (< nest 0) + (progn + (goto-char (match-end 0)) + (let (b e) + (setq b (progn + (skip-chars-forward "^ \t") + (verilog-forward-ws&directives) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))) + (setq string (buffer-substring b e))) + (throw 'skip 1)))) + )))) + (end-of-line) + (insert (concat " // " string ))) + ) + + (;- this is end{function,generate,task,module,primitive,table,generate} + ;- which can not be nested. + t + (let (string reg (width nil)) + (end-of-line) + (if kill-existing-comment + (save-match-data + (kill-existing-comment))) + (delete-horizontal-space) + (backward-sexp) + (cond + ((match-end 5) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<function\\>\\)\\|\\(\\<\\(endfunction\\|task\\|\\(macro\\)?module\\|primitive\\)\\>\\)") + (setq width "\\(\\s-*\\(\\[[^]]*\\]\\)\\|\\(real\\(time\\)?\\)\\|\\(integer\\)\\|\\(time\\)\\)?") + ) + ((match-end 6) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<task\\>\\)\\|\\(\\<\\(endtask\\|function\\|\\(macro\\)?module\\|primitive\\)\\>\\)")) + ((match-end 7) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<\\(macro\\)?module\\>\\)\\|\\<endmodule\\>")) + ((match-end 8) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<primitive\\>\\)\\|\\(\\<\\(endprimitive\\|package\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 9) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<interface\\>\\)\\|\\(\\<\\(endinterface\\|package\\|primitive\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 10) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<package\\>\\)\\|\\(\\<\\(endpackage\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 11) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<class\\>\\)\\|\\(\\<\\(endclass\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 12) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<\\(endcovergroup\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 13) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<program\\>\\)\\|\\(\\<\\(endprogram\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 14) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<\\(endsequence\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ) + (let (b e) + (save-excursion + (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) + (setq b (progn + (skip-chars-forward "^ \t") + (verilog-forward-ws&directives) + (if (and width (looking-at width)) + (progn + (goto-char (match-end 0)) + (verilog-forward-ws&directives) + )) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))) + (setq string (buffer-substring b e))) + (t + (ding 't) + (setq string "unmatched end(function|task|module|primitive|interface|package|class)"))))) + (end-of-line) + (insert (concat " // " string ))) + )))))))))) + +(defun verilog-get-expr() + "Grab expression at point, e.g, case ( a | b & (c ^d))" + (let* ((b (progn + (verilog-forward-syntactic-ws) + (skip-chars-forward " \t") + (point))) + (e (let ((par 1)) + (cond + ((looking-at "@") + (forward-char 1) + (verilog-forward-syntactic-ws) + (if (looking-at "(") + (progn + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\((\\)\\|\\()\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))))) + (point)) + ((looking-at "(") + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\((\\)\\|\\()\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))) + (point)) + ((looking-at "\\[") + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\(\\[\\)\\|\\(\\]\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))) + (verilog-forward-syntactic-ws) + (skip-chars-forward "^ \t\n\f") + (point)) + ((looking-at "/[/\\*]") + b) + ('t + (skip-chars-forward "^: \t\n\f") + (point) + )))) + (str (buffer-substring b e))) + (if (setq e (string-match "[ \t]*\\(\\(\n\\)\\|\\(//\\)\\|\\(/\\*\\)\\)" str)) + (setq str (concat (substring str 0 e) "..."))) + str)) + +(defun verilog-expand-vector () + "Take a signal vector on the current line and expand it to multiple lines. +Useful for creating tri's and other expanded fields." + (interactive) + (verilog-expand-vector-internal "[" "]")) + +(defun verilog-expand-vector-internal (bra ket) + "Given BRA, the start brace and KET, the end brace, expand one line into many lines." + (save-excursion + (forward-line 0) + (let ((signal-string (buffer-substring (point) + (progn + (end-of-line) (point))))) + (if (string-match (concat "\\(.*\\)" + (regexp-quote bra) + "\\([0-9]*\\)\\(:[0-9]*\\|\\)\\(::[0-9---]*\\|\\)" + (regexp-quote ket) + "\\(.*\\)$") signal-string) + (let* ((sig-head (match-string 1 signal-string)) + (vec-start (string-to-int (match-string 2 signal-string))) + (vec-end (if (= (match-beginning 3) (match-end 3)) + vec-start + (string-to-int (substring signal-string (1+ (match-beginning 3)) (match-end 3))))) + (vec-range (if (= (match-beginning 4) (match-end 4)) + 1 + (string-to-int (substring signal-string (+ 2 (match-beginning 4)) (match-end 4))))) + (sig-tail (match-string 5 signal-string)) + vec) + ;; Decode vectors + (setq vec nil) + (if (< vec-range 0) + (let ((tmp vec-start)) + (setq vec-start vec-end + vec-end tmp + vec-range (- vec-range)))) + (if (< vec-end vec-start) + (while (<= vec-end vec-start) + (setq vec (append vec (list vec-start))) + (setq vec-start (- vec-start vec-range))) + (while (<= vec-start vec-end) + (setq vec (append vec (list vec-start))) + (setq vec-start (+ vec-start vec-range)))) + ;; + ;; Delete current line + (delete-region (point) (progn (forward-line 0) (point))) + ;; + ;; Expand vector + (while vec + (insert (concat sig-head bra (int-to-string (car vec)) ket sig-tail "\n")) + (setq vec (cdr vec))) + (delete-char -1) + ;; + ))))) + +(defun verilog-strip-comments () + "Strip all comments from the verilog code." + (interactive) + (goto-char (point-min)) + (while (re-search-forward "//" nil t) + (if (verilog-within-string) + (re-search-forward "\"" nil t) + (if (verilog-in-star-comment-p) + (re-search-forward "\*/" nil t) + (let ((bpt (- (point) 2))) + (end-of-line) + (delete-region bpt (point)))))) + ;; + (goto-char (point-min)) + (while (re-search-forward "/\\*" nil t) + (if (verilog-within-string) + (re-search-forward "\"" nil t) + (let ((bpt (- (point) 2))) + (re-search-forward "\\*/") + (delete-region bpt (point)))))) + +(defun verilog-one-line () + "Convert structural verilog instances to occupy one line." + (interactive) + (goto-char (point-min)) + (while (re-search-forward "\\([^;]\\)[ \t]*\n[ \t]*" nil t) + (replace-match "\\1 " nil nil))) + +(defun verilog-linter-name () + "Return name of linter, either surelint or verilint." + (let ((compile-word1 (verilog-string-replace-matches "\\s .*$" "" nil nil + compile-command)) + (lint-word1 (verilog-string-replace-matches "\\s .*$" "" nil nil + verilog-linter))) + (cond ((equal compile-word1 "surelint") `surelint) + ((equal compile-word1 "verilint") `verilint) + ((equal lint-word1 "surelint") `surelint) + ((equal lint-word1 "verilint") `verilint) + (t `surelint)))) ;; back compatibility + +(defun verilog-lint-off () + "Convert a Verilog linter warning line into a disable statement. +For example: + pci_bfm_null.v, line 46: Unused input: pci_rst_ +becomes a comment for the appropriate tool. + +The first word of the `compile-command' or `verilog-linter' +variables are used to determine which product is being used. + +See \\[verilog-surelint-off] and \\[verilog-verilint-off]." + (interactive) + (let ((linter (verilog-linter-name))) + (cond ((equal linter `surelint) + (verilog-surelint-off)) + ((equal linter `verilint) + (verilog-verilint-off)) + (t (error "Linter name not set"))))) + +(defun verilog-surelint-off () + "Convert a SureLint warning line into a disable statement. +Run from Verilog source window; assumes there is a *compile* buffer +with point set appropriately. + +For example: + WARNING [STD-UDDONX]: xx.v, line 8: output out is never assigned. +becomes: + // surefire lint_line_off UDDONX" + (interactive) + (save-excursion + (switch-to-buffer compilation-last-buffer) + (beginning-of-line) + (when + (looking-at "\\(INFO\\|WARNING\\|ERROR\\) \\[[^-]+-\\([^]]+\\)\\]: \\([^,]+\\), line \\([0-9]+\\): \\(.*\\)$") + (let* ((code (match-string 2)) + (file (match-string 3)) + (line (match-string 4)) + (buffer (get-file-buffer file)) + dir filename) + (unless buffer + (progn + (setq buffer + (and (file-exists-p file) + (find-file-noselect file))) + (or buffer + (let* ((pop-up-windows t)) + (let ((name (expand-file-name + (read-file-name + (format "Find this error in: (default %s) " + file) + dir file t)))) + (if (file-directory-p name) + (setq name (expand-file-name filename name))) + (setq buffer + (and (file-exists-p name) + (find-file-noselect name)))))))) + (switch-to-buffer buffer) + (goto-line (string-to-number line)) + (end-of-line) + (catch 'already + (cond + ((verilog-in-slash-comment-p) + (re-search-backward "//") + (cond + ((looking-at "// surefire lint_off_line ") + (goto-char (match-end 0)) + (let ((lim (save-excursion (end-of-line) (point)))) + (if (re-search-forward code lim 'move) + (throw 'already t) + (insert-string (concat " " code))))) + (t + ))) + ((verilog-in-star-comment-p) + (re-search-backward "/\*") + (insert-string (format " // surefire lint_off_line %6s" code )) + ) + (t + (insert-string (format " // surefire lint_off_line %6s" code )) + ))))))) + +(defun verilog-verilint-off () + "Convert a Verilint warning line into a disable statement. + +For example: + (W240) pci_bfm_null.v, line 46: Unused input: pci_rst_ +becomes: + //Verilint 240 off // WARNING: Unused input" + (interactive) + (save-excursion + (beginning-of-line) + (when (looking-at "\\(.*\\)([WE]\\([0-9A-Z]+\\)).*,\\s +line\\s +[0-9]+:\\s +\\([^:\n]+\\):?.*$") + (replace-match (format + ;; %3s makes numbers 1-999 line up nicely + "\\1//Verilint %3s off // WARNING: \\3" + (match-string 2))) + (beginning-of-line) + (verilog-indent-line)))) + +(defun verilog-auto-save-compile () + "Update automatics with \\[verilog-auto], save the buffer, and compile." + (interactive) + (verilog-auto) ; Always do it for safety + (save-buffer) + (compile compile-command)) + + + +;; +;; Batch +;; + +(defmacro verilog-batch-error-wrapper (&rest body) + "Execute BODY and add error prefix to any errors found. +This lets programs calling batch mode to easily extract error messages." + (` (condition-case err + (progn (,@ body)) + (error + (error "%%Error: %s%s" (error-message-string err) + (if verilog-running-on-xemacs "\n" "")))))) ;; xemacs forgets to add a newline + +(defun verilog-batch-execute-func (funref) + "Internal processing of a batch command, running FUNREF on all command arguments." + (verilog-batch-error-wrapper + ;; General globals needed + (setq make-backup-files nil) + (setq-default make-backup-files nil) + (setq enable-local-variables t) + (setq enable-local-eval t) + ;; Make sure any sub-files we read get proper mode + (setq default-major-mode `verilog-mode) + ;; Ditto files already read in + (mapcar '(lambda (buf) + (when (buffer-file-name buf) + (save-excursion + (set-buffer buf) + (verilog-mode)))) + (buffer-list)) + ;; Process the files + (mapcar '(lambda (buf) + (when (buffer-file-name buf) + (save-excursion + (if (not (file-exists-p (buffer-file-name buf))) + (error (concat "File not found: " (buffer-file-name buf)))) + (message (concat "Processing " (buffer-file-name buf))) + (set-buffer buf) + (funcall funref) + (save-buffer)))) + (buffer-list)))) + +(defun verilog-batch-auto () + "For use with --batch, perform automatic expansions as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, updates automatics +with \\[verilog-auto] on all command-line files, and saves the buffers. +For proper results, multiple filenames need to be passed on the command +line in bottom-up order." + (unless noninteractive + (error "Use verilog-batch-auto only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-auto)) + +(defun verilog-batch-delete-auto () + "For use with --batch, perform automatic deletion as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, deletes automatics +with \\[verilog-delete-auto] on all command-line files, and saves the buffers." + (unless noninteractive + (error "Use verilog-batch-delete-auto only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-delete-auto)) + +(defun verilog-batch-inject-auto () + "For use with --batch, perform automatic injection as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, injects new automatics +with \\[verilog-inject-auto] on all command-line files, and saves the buffers. +For proper results, multiple filenames need to be passed on the command +line in bottom-up order." + (unless noninteractive + (error "Use verilog-batch-inject-auto only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-inject-auto)) + +(defun verilog-batch-indent () + "For use with --batch, reindent an a entire file as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, calls +\\[verilog-indent-buffer] on all command-line files, and saves the buffers." + (unless noninteractive + (error "Use verilog-batch-indent only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-indent-buffer)) + + +;; +;; Indentation +;; +(defconst verilog-indent-alist + '((block . (+ ind verilog-indent-level)) + (case . (+ ind verilog-case-indent)) + (cparenexp . (+ ind verilog-indent-level)) + (cexp . (+ ind verilog-cexp-indent)) + (defun . verilog-indent-level-module) + (declaration . verilog-indent-level-declaration) + (directive . (verilog-calculate-indent-directive)) + (tf . verilog-indent-level) + (behavioral . (+ verilog-indent-level-behavioral verilog-indent-level-module)) + (statement . ind) + (cpp . 0) + (comment . (verilog-comment-indent)) + (unknown . 3) + (string . 0))) + +(defun verilog-continued-line-1 (lim) + "Return true if this is a continued line. +Set point to where line starts. Limit search to point LIM." + (let ((continued 't)) + (if (eq 0 (forward-line -1)) + (progn + (end-of-line) + (verilog-backward-ws&directives lim) + (if (bobp) + (setq continued nil) + (setq continued (verilog-backward-token)))) + (setq continued nil)) + continued)) + +(defun verilog-calculate-indent () + "Calculate the indent of the current Verilog line. +Examine previous lines. Once a line is found that is definitive as to the +type of the current line, return that lines' indent level and its +type. Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." + (save-excursion + (let* ((starting_position (point)) + (par 0) + (begin (looking-at "[ \t]*begin\\>")) + (lim (save-excursion (verilog-re-search-backward "\\(\\<begin\\>\\)\\|\\(\\<module\\>\\)" nil t))) + (type (catch 'nesting + ;; Keep working backwards until we can figure out + ;; what type of statement this is. + ;; Basically we need to figure out + ;; 1) if this is a continuation of the previous line; + ;; 2) are we in a block scope (begin..end) + + ;; if we are in a comment, done. + (if (verilog-in-star-comment-p) + (throw 'nesting 'comment)) + + ;; if we have a directive, done. + (if (save-excursion (beginning-of-line) (looking-at verilog-directive-re-1)) + (throw 'nesting 'directive)) + + ;; if we are in a parenthesized list, and the user likes to indent these, return. + (if (verilog-in-paren) + (if verilog-indent-lists + (progn (setq par 1) + (throw 'nesting 'block)) + () + ) + ) + + ;; See if we are continuing a previous line + (while t + ;; trap out if we crawl off the top of the buffer + (if (bobp) (throw 'nesting 'cpp)) + + (if (verilog-continued-line-1 lim) + (let ((sp (point))) + (if (and + (not (looking-at verilog-complete-reg)) + (verilog-continued-line-1 lim)) + (progn (goto-char sp) + (throw 'nesting 'cexp)) + + (goto-char sp)) + + (if (and begin + (not verilog-indent-begin-after-if) + (looking-at verilog-no-indent-begin-re)) + (progn + (beginning-of-line) + (skip-chars-forward " \t") + (throw 'nesting 'statement)) + (progn + (throw 'nesting 'cexp)))) + ;; not a continued line + (goto-char starting_position)) + + (if (looking-at "\\<else\\>") + ;; search back for governing if, striding across begin..end pairs + ;; appropriately + (let ((elsec 1)) + (while (verilog-re-search-backward verilog-ends-re nil 'move) + (cond + ((match-end 1) ; else, we're in deep + (setq elsec (1+ elsec))) + ((match-end 2) ; if + (setq elsec (1- elsec)) + (if (= 0 elsec) + (if verilog-align-ifelse + (throw 'nesting 'statement) + (progn ;; back up to first word on this line + (beginning-of-line) + (verilog-forward-syntactic-ws) + (throw 'nesting 'statement))))) + (t ; endblock + ; try to leap back to matching outward block by striding across + ; indent level changing tokens then immediately + ; previous line governs indentation. + (let (( reg) (nest 1)) +;; verilog-ends => else|if|end|join(_any|_none|)|endcase|endclass|endtable|endspecify|endfunction|endtask|endgenerate|endgroup + (cond + ((match-end 3) ; end + ;; Search back for matching begin + (setq reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)" )) + ((match-end 4) ; endcase + ;; Search back for matching case + (setq reg "\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" )) + ((match-end 5) ; endfunction + ;; Search back for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )) + ((match-end 6) ; endtask + ;; Search back for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )) + ((match-end 7) ; endspecify + ;; Search back for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )) + ((match-end 8) ; endtable + ;; Search back for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )) + ((match-end 9) ; endgenerate + ;; Search back for matching generate + (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" )) + ((match-end 10) ; joins + ;; Search back for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|none\\)?\\>\\)" )) + ((match-end 11) ; class + ;; Search back for matching class + (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" )) + ((match-end 12) ; covergroup + ;; Search back for matching covergroup + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" )) + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest)) + (if (= 0 nest) + (throw 'skip 1))) + ((match-end 2) ; end + (setq nest (1+ nest))))) + ) + )) + )))) + (throw 'nesting (verilog-calc-1)) + ) + );; catch nesting + );; type + ) + ;; Return type of block and indent level. + (if (not type) + (setq type 'cpp)) + (if (> par 0) ; Unclosed Parenthesis + (list 'cparenexp par) + (cond + ((eq type 'case) + (list type (verilog-case-indent-level))) + ((eq type 'statement) + (list type (current-column))) + ((eq type 'defun) + (list type 0)) + (t + (list type (verilog-current-indent-level))))) + ))) +(defun verilog-wai () + "Show matching nesting block for debugging." + (interactive) + (save-excursion + (let ((nesting (verilog-calc-1))) + (message "You are at nesting %s" nesting)))) + +(defun verilog-calc-1 () + (catch 'nesting + (while (verilog-re-search-backward verilog-indent-re nil 'move) + (cond + ((looking-at verilog-beg-block-re-ordered) + (cond + ((match-end 2) (throw 'nesting 'case)) + ;; need to conside typedef struct here... + ((looking-at "\\<class\\|struct\\|function\\|task\\|property\\>") + ; *sigh* These words have an optional prefix: + ; extern {virtual|protected}? function a(); + ; assert property (p_1); + ; typedef class foo; + ; and we don't want to confuse this with + ; function a(); + ; property + ; ... + ; endfunction + (let ((here (point))) + (save-excursion + (verilog-beg-of-statement) + (if (= (point) here) + (throw 'nesting 'block)) + ))) + (t (throw 'nesting 'block)))) + + ((looking-at verilog-end-block-re) + (verilog-leap-to-head) + (if (verilog-in-case-region-p) + (progn + (verilog-leap-to-case-head) + (if (looking-at verilog-case-re) + (throw 'nesting 'case))))) + + ((looking-at (if (verilog-in-generate-region-p) + verilog-defun-level-not-generate-re + verilog-defun-level-re)) + (throw 'nesting 'defun)) + + ((looking-at verilog-cpp-level-re) + (throw 'nesting 'cpp)) + + ((bobp) + (throw 'nesting 'cpp)) + )))) + +(defun verilog-calculate-indent-directive () + "Return indentation level for directive. +For speed, the searcher looks at the last directive, not the indent +of the appropriate enclosing block." + (let ((base -1) ;; Indent of the line that determines our indentation + (ind 0) ;; Relative offset caused by other directives (like `endif on same line as `else) + ) + ;; Start at current location, scan back for another directive + + (save-excursion + (beginning-of-line) + (while (and (< base 0) + (verilog-re-search-backward verilog-directive-re nil t)) + (cond ((save-excursion (skip-chars-backward " \t") (bolp)) + (setq base (current-indentation)) + )) + (cond ((and (looking-at verilog-directive-end) (< base 0)) ;; Only matters when not at BOL + (setq ind (- ind verilog-indent-level-directive))) + ((and (looking-at verilog-directive-middle) (>= base 0)) ;; Only matters when at BOL + (setq ind (+ ind verilog-indent-level-directive))) + ((looking-at verilog-directive-begin) + (setq ind (+ ind verilog-indent-level-directive))))) + ;; Adjust indent to starting indent of critical line + (setq ind (max 0 (+ ind base)))) + + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (cond ((or (looking-at verilog-directive-middle) + (looking-at verilog-directive-end)) + (setq ind (max 0 (- ind verilog-indent-level-directive)))))) + ind)) + +(defun verilog-leap-to-case-head () + (let ((nest 1)) + (while (/= 0 nest) + (verilog-re-search-backward "\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" nil 'move) + (cond + ((match-end 1) + (setq nest (1- nest))) + ((match-end 2) + (setq nest (1+ nest))) + ((bobp) + (ding 't) + (setq nest 0)))))) + +(defun verilog-leap-to-head () + "Move point to the head of this block; jump from end to matching begin, +from endcase to matching case, and so on." + (let ((reg nil) + snest + (nest 1)) + (cond + ((looking-at "\\<end\\>") + ;; 1: Search back for matching begin + (setq reg (concat "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|" + "\\(\\<endcase\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" ))) + ((looking-at "\\<endcase\\>") + ;; 2: Search back for matching case + (setq reg "\\(\\<randcase\\>\\|\\<case[xz]?\\>\\)\\|\\(\\<endcase\\>\\)" )) + ((looking-at "\\<join\\(_any\\|_none\\)?\\>") + ;; 3: Search back for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" )) + ((looking-at "\\<endclass\\>") + ;; 4: Search back for matching class + (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" )) + ((looking-at "\\<endtable\\>") + ;; 5: Search back for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )) + ((looking-at "\\<endspecify\\>") + ;; 6: Search back for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )) + ((looking-at "\\<endfunction\\>") + ;; 7: Search back for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )) + ((looking-at "\\<endgenerate\\>") + ;; 8: Search back for matching generate + (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" )) + ((looking-at "\\<endtask\\>") + ;; 9: Search back for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )) + ((looking-at "\\<endgroup\\>") + ;; 10: Search back for matching covergroup + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" )) + ((looking-at "\\<endproperty\\>") + ;; 11: Search back for matching property + (setq reg "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" )) + ((looking-at "\\<endinterface\\>") + ;; 12: Search back for matching interface + (setq reg "\\(\\<interface\\>\\)\\|\\(\\<endinterface\\>\\)" )) + ((looking-at "\\<endsequence\\>") + ;; 12: Search back for matching interface + (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" )) + ) + (if reg + (catch 'skip + (let (sreg) + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest)) + (if (= 0 nest) + ;; Now previous line describes syntax + (throw 'skip 1)) + (if (and snest + (= snest nest)) + (setq reg sreg))) + ((match-end 2) ; end + (setq nest (1+ nest))) + ((match-end 3) + ;; endcase, jump to case + (setq snest nest) + (setq nest (1+ nest)) + (setq sreg reg) + (setq reg "\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" )) + ((match-end 4) + ;; join, jump to fork + (setq snest nest) + (setq nest (1+ nest)) + (setq sreg reg) + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" )) + ))))))) + +(defun verilog-continued-line () + "Return true if this is a continued line. +Set point to where line starts" + (let ((continued 't)) + (if (eq 0 (forward-line -1)) + (progn + (end-of-line) + (verilog-backward-ws&directives) + (if (bobp) + (setq continued nil) + (while (and continued + (save-excursion + (skip-chars-backward " \t") + (not (bolp)))) + (setq continued (verilog-backward-token)) + ) ;; while + )) + (setq continued nil)) + continued)) + +(defun verilog-backward-token () + "Step backward token, returning true if we are now at an end of line token." + (verilog-backward-syntactic-ws) + (cond + ((bolp) + nil) + (;-- Anything ending in a ; is complete + (= (preceding-char) ?\;) + nil) + (;-- constraint foo { a = b } + ; is a complete statement. *sigh* + (= (preceding-char) ?\}) + (progn + (backward-char) + (backward-up-list 1) + (verilog-backward-syntactic-ws) + (forward-word -1) ; label for the (possible) constraint + (verilog-backward-syntactic-ws) + (forward-word -1) + (not (looking-at "\\<constraint\\>"))) + ) + (;-- Could be 'case (foo)' or 'always @(bar)' which is complete + ; also could be simply '@(foo)' + ; or foo u1 #(a=8) + ; (b, ... which ISN'T complete + ;;;; Do we need this??? + (= (preceding-char) ?\)) + (progn + (backward-char) + (backward-up-list 1) + (verilog-backward-syntactic-ws) + (let ((back (point))) + (forward-word -1) + (cond + ((looking-at "\\<\\(always\\(_latch\\|_ff\\|_comb\\)?\\|case\\(\\|[xz]\\)\\|for\\(\\|ever\\)\\|i\\(f\\|nitial\\)\\|repeat\\|while\\)\\>") + (not (looking-at "\\<randcase\\>\\|\\<case[xz]?\\>[^:]"))) + (t + (goto-char back) + (cond + ((= (preceding-char) ?\@) + (backward-char) + (save-excursion + (verilog-backward-token) + (not (looking-at "\\<\\(always\\(_latch\\|_ff\\|_comb\\)?\\|initial\\|while\\)\\>")))) + ((= (preceding-char) ?\#) + t) + (t t)) + ))))) + + (;-- any of begin|initial|while are complete statements; 'begin : foo' is also complete + t + (forward-word -1) + (cond + ((looking-at "\\(else\\)\\|\\(initial\\>\\)\\|\\(always\\(_latch\\|_ff\\|_comb\\)?\\>\\)") + t) + ((looking-at verilog-indent-re) + nil) + (t + (let + ((back (point))) + (verilog-backward-syntactic-ws) + (cond + ((= (preceding-char) ?\:) + (backward-char) + (verilog-backward-syntactic-ws) + (backward-sexp) + (if (looking-at verilog-nameable-item-re ) + nil + t) + ) + ((= (preceding-char) ?\#) + (backward-char) + t) + ((= (preceding-char) ?\`) + (backward-char) + t) + + (t + (goto-char back) + t) + ))))))) + +(defun verilog-backward-syntactic-ws (&optional bound) + "Backward skip over syntactic whitespace for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-min))) (here bound) ) + (if (< bound (point)) + (progn + (narrow-to-region bound (point)) + (while (/= here (point)) + (setq here (point)) + (verilog-skip-backward-comments) + ))) + )) + t) + +(defun verilog-forward-syntactic-ws (&optional bound) + "Forward skip over syntactic whitespace for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-max))) + (here bound) + ) + (if (> bound (point)) + (progn + (narrow-to-region (point) bound) + (while (/= here (point)) + (setq here (point)) + (forward-comment (buffer-size)) + ))) + ))) + +(defun verilog-backward-ws&directives (&optional bound) + "Backward skip over syntactic whitespace and compiler directives for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-min))) + (here bound) + (p nil) ) + (if (< bound (point)) + (progn + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ;; in // comment + (verilog-re-search-backward "//" nil 'move) + (skip-chars-backward "/")) + ((nth 4 state) ;; in /* */ comment + (verilog-re-search-backward "/\*" nil 'move)))) + (narrow-to-region bound (point)) + (while (/= here (point)) + (setq here (point)) + (verilog-skip-backward-comments) + (setq p + (save-excursion + (beginning-of-line) + (cond + ((verilog-within-translate-off) + (verilog-back-to-start-translate-off (point-min))) + ((looking-at verilog-directive-re-1) + (point)) + (t + nil)))) + (if p (goto-char p)) + ))) + ))) + +(defun verilog-forward-ws&directives (&optional bound) + "Forward skip over syntactic whitespace and compiler directives for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-max))) + (here bound) + jump + ) + (if (> bound (point)) + (progn + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ;; in // comment + (verilog-re-search-forward "//" nil 'move)) + ((nth 4 state) ;; in /* */ comment + (verilog-re-search-forward "/\*" nil 'move)))) + (narrow-to-region (point) bound) + (while (/= here (point)) + (setq here (point) + jump nil) + (forward-comment (buffer-size)) + (save-excursion + (beginning-of-line) + (if (looking-at verilog-directive-re-1) + (setq jump t))) + (if jump + (beginning-of-line 2)) + ))) + ))) + +(defun verilog-in-comment-p () + "Return true if in a star or // comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (or (nth 4 state) (nth 7 state)))) + +(defun verilog-in-star-comment-p () + "Return true if in a star comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (and + (nth 4 state) ; t if in a comment of style a // or b /**/ + (not + (nth 7 state) ; t if in a comment of style b /**/ + )))) + +(defun verilog-in-slash-comment-p () + "Return true if in a slash comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (nth 7 state))) + +(defun verilog-in-comment-or-string-p () + "Return true if in a string or comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (or (nth 3 state) (nth 4 state) (nth 7 state)))) ; Inside string or comment) + +(defun verilog-in-escaped-name-p () + "Return true if in an escaped name." + (save-excursion + (backward-char) + (skip-chars-backward "^ \t\n\f") + (if (= (char-after (point) ) ?\\ ) + t + nil))) + +(defun verilog-in-paren () + "Return true if in a parenthetical expression." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (/= 0 (nth 0 state)))) + +(defun verilog-parenthesis-depth () + "Return non zero if in parenthetical-expression." + (save-excursion + (nth 1 (parse-partial-sexp (point-min) (point))))) + + +(defun verilog-skip-forward-comment-or-string () + "Return true if in a string or comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 3 state) ;Inside string + (goto-char (nth 3 state)) + t) + ((nth 7 state) ;Inside // comment + (forward-line 1) + t) + ((nth 4 state) ;Inside any comment (hence /**/) + (search-forward "*/")) + (t + nil)))) + +(defun verilog-skip-backward-comment-or-string () + "Return true if in a string or comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 3 state) ;Inside string + (search-backward "\"") + t) + ((nth 7 state) ;Inside // comment + (search-backward "//") + (skip-chars-backward "/") + t) + ((nth 4 state) ;Inside /* */ comment + (search-backward "/*") + t) + (t + nil)))) + +(defun verilog-skip-backward-comments () + "Return true if a comment was skipped." + (let ((more t)) + (while more + (setq more + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ;Inside // comment + (search-backward "//") + (skip-chars-backward "/") + (skip-chars-backward " \t\n\f") + t) + ((nth 4 state) ;Inside /* */ comment + (search-backward "/*") + (skip-chars-backward " \t\n\f") + t) + ((and (not (bobp)) + (= (char-before) ?\/) + (= (char-before (1- (point))) ?\*) + ) + (goto-char (- (point) 2)) + t) + (t + (skip-chars-backward " \t\n\f") + nil))))))) + +(defun verilog-skip-forward-comment-p () + "If in comment, move to end and return true." + (let (state) + (progn + (setq state + (save-excursion + (parse-partial-sexp (point-min) (point)))) + (cond + ((nth 3 state) + t) + ((nth 7 state) ;Inside // comment + (end-of-line) + (forward-char 1) + t) + ((nth 4 state) ;Inside any comment + t) + (t + nil))))) + +(defun verilog-indent-line-relative () + "Cheap version of indent line. +Only look at a few lines to determine indent level." + (interactive) + (let ((indent-str) + (sp (point))) + (if (looking-at "^[ \t]*$") + (cond ;- A blank line; No need to be too smart. + ((bobp) + (setq indent-str (list 'cpp 0))) + ((verilog-continued-line) + (let ((sp1 (point))) + (if (verilog-continued-line) + (progn (goto-char sp) + (setq indent-str (list 'statement (verilog-current-indent-level)))) + (goto-char sp1) + (setq indent-str (list 'block (verilog-current-indent-level))))) + (goto-char sp)) + ((goto-char sp) + (setq indent-str (verilog-calculate-indent)))) + (progn (skip-chars-forward " \t") + (setq indent-str (verilog-calculate-indent)))) + (verilog-do-indent indent-str))) + +(defun verilog-indent-line () + "Indent for special part of code." + (verilog-do-indent (verilog-calculate-indent))) + +(defun verilog-do-indent (indent-str) + (let ((type (car indent-str)) + (ind (car (cdr indent-str)))) + (cond + (; handle continued exp + (eq type 'cexp) + (let ((here (point))) + (verilog-backward-syntactic-ws) + (cond + ((or + (= (preceding-char) ?\,) + (= (preceding-char) ?\]) + (save-excursion + (verilog-beg-of-statement-1) + (looking-at verilog-declaration-re))) + (let* ( fst + (val + (save-excursion + (backward-char 1) + (verilog-beg-of-statement-1) + (setq fst (point)) + (if (looking-at verilog-declaration-re) + (progn ;; we have multiple words + (goto-char (match-end 0)) + (skip-chars-forward " \t") + (cond + ((and verilog-indent-declaration-macros + (= (following-char) ?\`)) + (progn + (forward-char 1) + (forward-word 1) + (skip-chars-forward " \t"))) + ((= (following-char) ?\[) + (progn + (forward-char 1) + (backward-up-list -1) + (skip-chars-forward " \t"))) + ) + (current-column)) + (progn + (goto-char fst) + (+ (current-column) verilog-cexp-indent)) + )))) + (goto-char here) + (indent-line-to val)) + ) + ((= (preceding-char) ?\) ) + (goto-char here) + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + (indent-line-to val))) + (t + (goto-char here) + (let ((val)) + (verilog-beg-of-statement-1) + (if (and (< (point) here) + (verilog-re-search-forward "=[ \\t]*" here 'move)) + (setq val (current-column)) + (setq val (eval (cdr (assoc type verilog-indent-alist))))) + (goto-char here) + (indent-line-to val))) + ))) + + (; handle inside parenthetical expressions + (eq type 'cparenexp) + (let ((val (save-excursion + (backward-up-list 1) + (forward-char 1) + (skip-chars-forward " \t") + (current-column)))) + (indent-line-to val) + (if (and (not (verilog-in-struct-region-p)) + (looking-at verilog-declaration-re)) + (verilog-indent-declaration ind)) + )) + + (;-- Handle the ends + (looking-at verilog-end-block-re ) + (let ((val (if (eq type 'statement) + (- ind verilog-indent-level) + ind))) + (indent-line-to val))) + + (;-- Case -- maybe line 'em up + (and (eq type 'case) (not (looking-at "^[ \t]*$"))) + (progn + (cond + ((looking-at "\\<endcase\\>") + (indent-line-to ind)) + (t + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + (indent-line-to val)))))) + + (;-- defun + (and (eq type 'defun) + (looking-at verilog-zero-indent-re)) + (indent-line-to 0)) + + (;-- declaration + (and (or + (eq type 'defun) + (eq type 'block)) + (looking-at verilog-declaration-re)) + (verilog-indent-declaration ind)) + + (;-- Everything else + t + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + (indent-line-to val))) + ) + (if (looking-at "[ \t]+$") + (skip-chars-forward " \t")) + indent-str ; Return indent data + )) + +(defun verilog-current-indent-level () + "Return the indent-level the current statement has." + (save-excursion + (let (par-pos) + (beginning-of-line) + (setq par-pos (verilog-parenthesis-depth)) + (while par-pos + (goto-char par-pos) + (beginning-of-line) + (setq par-pos (verilog-parenthesis-depth))) + (skip-chars-forward " \t") + (current-column)))) + +(defun verilog-case-indent-level () + "Return the indent-level the current statement has. +Do not count named blocks or case-statements." + (save-excursion + (skip-chars-forward " \t") + (cond + ((looking-at verilog-named-block-re) + (current-column)) + ((and (not (looking-at verilog-case-re)) + (looking-at "^[^:;]+[ \t]*:")) + (verilog-re-search-forward ":" nil t) + (skip-chars-forward " \t") + (current-column)) + (t + (current-column))))) + +(defun verilog-indent-comment () + "Indent current line as comment." + (let* ((stcol + (cond + ((verilog-in-star-comment-p) + (save-excursion + (re-search-backward "/\\*" nil t) + (1+(current-column)))) + (comment-column + comment-column ) + (t + (save-excursion + (re-search-backward "//" nil t) + (current-column))) + ))) + (indent-line-to stcol) + stcol)) + +(defun verilog-more-comment () + "Make more comment lines like the previous." + (let* ((star 0) + (stcol + (cond + ((verilog-in-star-comment-p) + (save-excursion + (setq star 1) + (re-search-backward "/\\*" nil t) + (1+(current-column)))) + (comment-column + comment-column ) + (t + (save-excursion + (re-search-backward "//" nil t) + (current-column))) + ))) + (progn + (indent-to stcol) + (if (and star + (save-excursion + (forward-line -1) + (skip-chars-forward " \t") + (looking-at "\*"))) + (insert "* "))))) + +(defun verilog-comment-indent (&optional arg) + "Return the column number the line should be indented to. +ARG is ignored, for `comment-indent-function' compatibility." + (cond + ((verilog-in-star-comment-p) + (save-excursion + (re-search-backward "/\\*" nil t) + (1+(current-column)))) + ( comment-column + comment-column ) + (t + (save-excursion + (re-search-backward "//" nil t) + (current-column))))) + +;; + +(defun verilog-pretty-declarations () + "Line up declarations around point." + (interactive) + (save-excursion + (if (progn + (verilog-beg-of-statement-1) + (looking-at verilog-declaration-re)) + (let* ((m1 (make-marker)) + (e) (r) + (here (point)) + (start + (progn + (verilog-beg-of-statement-1) + (while (looking-at verilog-declaration-re) + (beginning-of-line) + (setq e (point)) + (verilog-backward-syntactic-ws) + (backward-char) + (verilog-beg-of-statement-1)) ;Ack, need to grok `define + e)) + (end + (progn + (goto-char here) + (verilog-end-of-statement) + (setq e (point)) ;Might be on last line + (verilog-forward-syntactic-ws) + (while (looking-at verilog-declaration-re) + (beginning-of-line) + (verilog-end-of-statement) + (setq e (point)) + (verilog-forward-syntactic-ws)) + e)) + (edpos (set-marker (make-marker) end)) + (ind) + (base-ind + (progn + (goto-char start) + (verilog-do-indent (verilog-calculate-indent)) + (verilog-forward-ws&directives) + (current-column))) + ) + (goto-char end) + (goto-char start) + (if (> (- end start) 100) + (message "Lining up declarations..(please stand by)")) + ;; Get the beginning of line indent first + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (cond + ( (save-excursion (skip-chars-backward " \t") + (bolp)) + (verilog-forward-ws&directives) + (indent-line-to base-ind) + (verilog-forward-ws&directives) + (verilog-re-search-forward "[ \t\n\f]" e 'move) + ) + (t + (just-one-space) + (verilog-re-search-forward "[ \t\n\f]" e 'move) + ) + ) + ) + ;;(forward-line)) + ;; Now find biggest prefix + (setq ind (verilog-get-lineup-indent start edpos)) + ;; Now indent each line. + (goto-char start) + (while (progn (setq e (marker-position edpos)) + (setq r (- e (point))) + (> r 0)) + (setq e (point)) + (message "%d" r) + (cond + ((or (and verilog-indent-declaration-macros + (looking-at verilog-declaration-re-1-macro)) + (looking-at verilog-declaration-re-1-no-macro)) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[#`]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (just-one-space) + (indent-to ind)) + (progn + (just-one-space) + (indent-to ind)) + ))) + ((verilog-continued-line-1 start) + (goto-char e) + (indent-line-to ind)) + (t ; Must be comment or white space + (goto-char e) + (verilog-forward-ws&directives) + (forward-line -1)) + ) + (forward-line 1)) + (message ""))))) + +(defun verilog-pretty-expr (&optional myre) + "Line up expressions around point." + (interactive "sRegular Expression: (<?=) ") + (save-excursion + (if (or (eq myre nil) + (string-equal myre "")) + (setq myre "<=")) + (setq myre (concat "\\(^[^;" myre "]*\\)\\([" myre "]\\)")) + (beginning-of-line) + (if (and (not (looking-at (concat "^\\s-*" verilog-complete-reg))) + (looking-at myre)) + (let* ((here (point)) + (e) (r) + (start + (progn + (beginning-of-line) + (setq e (point)) + (verilog-backward-syntactic-ws) + (beginning-of-line) + (while (and (not(looking-at (concat "^\\s-*" verilog-complete-reg))) + (looking-at myre)) + (setq e (point)) + (verilog-backward-syntactic-ws) + (beginning-of-line) + ) ;Ack, need to grok `define + e)) + (end + (progn + (goto-char here) + (end-of-line) + (setq e (point)) ;Might be on last line + (verilog-forward-syntactic-ws) + (beginning-of-line) + (while (and (not(looking-at (concat "^\\s-*" verilog-complete-reg))) + (looking-at myre)) + (end-of-line) + (setq e (point)) + (verilog-forward-syntactic-ws) + (beginning-of-line) + ) + e)) + (edpos (set-marker (make-marker) end)) + (ind) + ) + (goto-char start) + (verilog-do-indent (verilog-calculate-indent)) + (if (> (- end start) 100) + (message "Lining up expressions..(please stand by)")) + + ;; Set indent to minimum throughout region + (while (< (point) (marker-position edpos)) + (beginning-of-line) + (verilog-just-one-space myre) + (end-of-line) + (verilog-forward-syntactic-ws) + ) + + ;; Now find biggest prefix + (setq ind (verilog-get-lineup-indent-2 myre start edpos)) + + ;; Now indent each line. + (goto-char start) + (while (progn (setq e (marker-position edpos)) + (setq r (- e (point))) + (> r 0)) + (setq e (point)) + (message "%d" r) + (cond + ((looking-at myre) + (goto-char (match-end 1)) + (if (eq (char-after) ?=) + (indent-to (1+ ind)) ; line up the = of the <= with surrounding = + (indent-to ind) + ) + ) + ((verilog-continued-line-1 start) + (goto-char e) + (indent-line-to ind)) + (t ; Must be comment or white space + (goto-char e) + (verilog-forward-ws&directives) + (forward-line -1)) + ) + (forward-line 1)) + (message "") + )))) + +(defun verilog-just-one-space (myre) + "Remove extra spaces around regular expression MYRE." + (interactive) + (if (and (not(looking-at verilog-complete-reg)) + (looking-at myre)) + (let ((p1 (match-end 1)) + (p2 (match-end 2))) + (progn + (goto-char p2) + (if (looking-at "\\s-") (just-one-space) ) + (goto-char p1) + (forward-char -1) + (if (looking-at "\\s-") (just-one-space)) + ) + )) + (message "")) + +(defun verilog-indent-declaration (baseind) + "Indent current lines as declaration. +Line up the variable names based on previous declaration's indentation. +BASEIND is the base indent to offset everything." + (interactive) + (let ((pos (point-marker)) + (lim (save-excursion + ;; (verilog-re-search-backward verilog-declaration-opener nil 'move) + (verilog-re-search-backward "\\(\\<begin\\>\\)\\|\\(\\<module\\>\\)\\|\\(\\<task\\>\\)" nil 'move) + (point))) + (ind) + (val) + (m1 (make-marker)) + ) + (setq val (+ baseind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (indent-line-to val) + + ;; Use previous declaration (in this module) as template. + (if (or (memq 'all verilog-auto-lineup) + (memq 'declaration verilog-auto-lineup)) + (if (verilog-re-search-backward (or (and verilog-indent-declaration-macros + verilog-declaration-re-1-macro) + verilog-declaration-re-1-no-macro) lim t) + (progn + (goto-char (match-end 0)) + (skip-chars-forward " \t") + (setq ind (current-column)) + (goto-char pos) + (setq val (+ baseind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (indent-line-to val) + (if (and verilog-indent-declaration-macros + (looking-at verilog-declaration-re-2-macro)) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[#`]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (just-one-space) + (indent-to ind) + ) + (if (/= (current-column) ind) + (progn + (just-one-space) + (indent-to ind)) + ))) + (if (looking-at verilog-declaration-re-2-no-macro) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[`#]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (just-one-space) + (indent-to ind)) + (if (/= (current-column) ind) + (progn + (just-one-space) + (indent-to ind)) + ))) + ))) + ) + ) + (goto-char pos) + ) + ) + +(defun verilog-get-lineup-indent (b edpos) + "Return the indent level that will line up several lines within the region. +Region is defined by B and EDPOS." + (save-excursion + (let ((ind 0) e) + (goto-char b) + ;; Get rightmost position + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (if (verilog-re-search-forward (or (and verilog-indent-declaration-macros + verilog-declaration-re-1-macro) + verilog-declaration-re-1-no-macro) e 'move) + (progn + (goto-char (match-end 0)) + (verilog-backward-syntactic-ws) + (if (> (current-column) ind) + (setq ind (current-column))) + (goto-char (match-end 0))))) + (if (> ind 0) + (1+ ind) + ;; No lineup-string found + (goto-char b) + (end-of-line) + (skip-chars-backward " \t") + (1+ (current-column)))))) + +(defun verilog-get-lineup-indent-2 (myre b edpos) + "Return the indent level that will line up several lines within the region." + (save-excursion + (let ((ind 0) e) + (goto-char b) + ;; Get rightmost position + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (if (verilog-re-search-forward myre e 'move) + (progn + (goto-char (match-end 0)) + (verilog-backward-syntactic-ws) + (if (> (current-column) ind) + (setq ind (current-column))) + (goto-char (match-end 0))))) + (if (> ind 0) + (1+ ind) + ;; No lineup-string found + (goto-char b) + (end-of-line) + (skip-chars-backward " \t") + (1+ (current-column)))))) + +(defun verilog-comment-depth (type val) + "A useful mode debugging aide. TYPE and VAL are comments for insertion." + (save-excursion + (let + ((b (prog2 + (beginning-of-line) + (point-marker) + (end-of-line))) + (e (point-marker))) + (if (re-search-backward " /\\* \[#-\]# \[a-zA-Z\]+ \[0-9\]+ ## \\*/" b t) + (progn + (replace-match " /* -# ## */") + (end-of-line)) + (progn + (end-of-line) + (insert " /* ## ## */")))) + (backward-char 6) + (insert + (format "%s %d" type val)))) + +;; +;; +;; Completion +;; +(defvar verilog-str nil) +(defvar verilog-all nil) +(defvar verilog-pred nil) +(defvar verilog-buffer-to-use nil) +(defvar verilog-flag nil) +(defvar verilog-toggle-completions nil + "*True means \\<verilog-mode-map>\\[verilog-complete-word] should try all possible completions one by one. +Repeated use of \\[verilog-complete-word] will show you all of them. +Normally, when there is more than one possible completion, +it displays a list of all possible completions.") + + +(defvar verilog-type-keywords + '( + "and" "buf" "bufif0" "bufif1" "cmos" "defparam" "inout" "input" + "integer" "localparam" "logic" "nand" "nmos" "nor" "not" "notif0" + "notif1" "or" "output" "parameter" "pmos" "pull0" "pull1" "pullup" + "rcmos" "real" "realtime" "reg" "rnmos" "rpmos" "rtran" "rtranif0" + "rtranif1" "time" "tran" "tranif0" "tranif1" "tri" "tri0" "tri1" + "triand" "trior" "trireg" "wand" "wire" "wor" "xnor" "xor" + ) + "*Keywords for types used when completing a word in a declaration or parmlist. +\(eg. integer, real, reg...)") + +(defvar verilog-cpp-keywords + '("module" "macromodule" "primitive" "timescale" "define" "ifdef" "ifndef" "else" + "endif") + "*Keywords to complete when at first word of a line in declarative scope. +\(eg. initial, always, begin, assign.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-defun-keywords + (append + '( + "always" "always_comb" "always_ff" "always_latch" "assign" + "begin" "end" "generate" "endgenerate" "module" "endmodule" + "specify" "endspecify" "function" "endfunction" "initial" "final" + "task" "endtask" "primitive" "endprimitive" + ) + verilog-type-keywords) + "*Keywords to complete when at first word of a line in declarative scope. +\(eg. initial, always, begin, assign.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-block-keywords + '( + "begin" "break" "case" "continue" "else" "end" "endfunction" + "endgenerate" "endinterface" "endpackage" "endspecify" "endtask" + "for" "fork" "if" "join" "join_any" "join_none" "repeat" "return" + "while") + "*Keywords to complete when at first word of a line in behavioral scope. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-tf-keywords + '("begin" "break" "fork" "join" "join_any" "join_none" "case" "end" "endtask" "endfunction" "if" "else" "for" "while" "repeat") + "*Keywords to complete when at first word of a line in a task or function. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-case-keywords + '("begin" "fork" "join" "join_any" "join_none" "case" "end" "endcase" "if" "else" "for" "repeat") + "*Keywords to complete when at first word of a line in case scope. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-separator-keywords + '("else" "then" "begin") + "*Keywords to complete when NOT standing at the first word of a statement. +\(eg. else, then.) +Variables and function names defined within the +Verilog program are completed runtime and should not be added to this list.") + +(defun verilog-string-diff (str1 str2) + "Return index of first letter where STR1 and STR2 differs." + (catch 'done + (let ((diff 0)) + (while t + (if (or (> (1+ diff) (length str1)) + (> (1+ diff) (length str2))) + (throw 'done diff)) + (or (equal (aref str1 diff) (aref str2 diff)) + (throw 'done diff)) + (setq diff (1+ diff)))))) + +;; Calculate all possible completions for functions if argument is `function', +;; completions for procedures if argument is `procedure' or both functions and +;; procedures otherwise. + +(defun verilog-func-completion (type) + "Build regular expression for module/task/function names. +TYPE is 'module, 'tf for task or function, or t if unknown." + (if (string= verilog-str "") + (setq verilog-str "[a-zA-Z_]")) + (let ((verilog-str (concat (cond + ((eq type 'module) "\\<\\(module\\)\\s +") + ((eq type 'tf) "\\<\\(task\\|function\\)\\s +") + (t "\\<\\(task\\|function\\|module\\)\\s +")) + "\\<\\(" verilog-str "[a-zA-Z0-9_.]*\\)\\>")) + match) + + (if (not (looking-at verilog-defun-re)) + (verilog-re-search-backward verilog-defun-re nil t)) + (forward-char 1) + + ;; Search through all reachable functions + (goto-char (point-min)) + (while (verilog-re-search-forward verilog-str (point-max) t) + (progn (setq match (buffer-substring (match-beginning 2) + (match-end 2))) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + (if (match-beginning 0) + (goto-char (match-beginning 0))))) + +(defun verilog-get-completion-decl (end) + "Macro for searching through current declaration (var, type or const) +for matches of `str' and adding the occurrence tp `all' through point END." + (let ((re (or (and verilog-indent-declaration-macros + verilog-declaration-re-2-macro) + verilog-declaration-re-2-no-macro)) + decl-end match) + ;; Traverse lines + (while (and (< (point) end) + (verilog-re-search-forward re end t)) + ;; Traverse current line + (setq decl-end (save-excursion (verilog-declaration-end))) + (while (and (verilog-re-search-forward verilog-symbol-re decl-end t) + (not (match-end 1))) + (setq match (buffer-substring (match-beginning 0) (match-end 0))) + (if (string-match (concat "\\<" verilog-str) match) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + (forward-line 1) + ) + ) + verilog-all + ) + +(defun verilog-type-completion () + "Calculate all possible completions for types." + (let ((start (point)) + goon) + ;; Search for all reachable type declarations + (while (or (verilog-beg-of-defun) + (setq goon (not goon))) + (save-excursion + (if (and (< start (prog1 (save-excursion (verilog-end-of-defun) + (point)) + (forward-char 1))) + (verilog-re-search-forward + "\\<type\\>\\|\\<\\(begin\\|function\\|procedure\\)\\>" + start t) + (not (match-end 1))) + ;; Check current type declaration + (verilog-get-completion-decl start)))))) + +(defun verilog-var-completion () + "Calculate all possible completions for variables (or constants)." + (let ((start (point))) + ;; Search for all reachable var declarations + (verilog-beg-of-defun) + (save-excursion + ;; Check var declarations + (verilog-get-completion-decl start)))) + +(defun verilog-keyword-completion (keyword-list) + "Give list of all possible completions of keywords in KEYWORD-LIST." + (mapcar '(lambda (s) + (if (string-match (concat "\\<" verilog-str) s) + (if (or (null verilog-pred) + (funcall verilog-pred s)) + (setq verilog-all (cons s verilog-all))))) + keyword-list)) + + +(defun verilog-completion (verilog-str verilog-pred verilog-flag) + "Function passed to `completing-read', `try-completion' or `all-completions'. +Called to get completion on VERILOG-STR. If VERILOG-PRED is non-nil, it +must be a function to be called for every match to check if this should +really be a match. If VERILOG-FLAG is t, the function returns a list of all +possible completions. If VERILOG-FLAG is nil it returns a string, the +longest possible completion, or t if STR is an exact match. If VERILOG-FLAG +is 'lambda, the function returns t if STR is an exact match, nil +otherwise." + (save-excursion + (let ((verilog-all nil)) + ;; Set buffer to use for searching labels. This should be set + ;; within functions which use verilog-completions + (set-buffer verilog-buffer-to-use) + + ;; Determine what should be completed + (let ((state (car (verilog-calculate-indent)))) + (cond ((eq state 'defun) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'module) + (verilog-keyword-completion verilog-defun-keywords)) + + ((eq state 'behavioral) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'module) + (verilog-keyword-completion verilog-defun-keywords)) + + ((eq state 'block) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-block-keywords)) + + ((eq state 'case) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-case-keywords)) + + ((eq state 'tf) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-tf-keywords)) + + ((eq state 'cpp) + (save-excursion (verilog-var-completion)) + (verilog-keyword-completion verilog-cpp-keywords)) + + ((eq state 'cparenexp) + (save-excursion (verilog-var-completion))) + + (t;--Anywhere else + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'both) + (verilog-keyword-completion verilog-separator-keywords)))) + + ;; Now we have built a list of all matches. Give response to caller + (verilog-completion-response)))) + +(defun verilog-completion-response () + (cond ((or (equal verilog-flag 'lambda) (null verilog-flag)) + ;; This was not called by all-completions + (if (null verilog-all) + ;; Return nil if there was no matching label + nil + ;; Get longest string common in the labels + (let* ((elm (cdr verilog-all)) + (match (car verilog-all)) + (min (length match)) + tmp) + (if (string= match verilog-str) + ;; Return t if first match was an exact match + (setq match t) + (while (not (null elm)) + ;; Find longest common string + (if (< (setq tmp (verilog-string-diff match (car elm))) min) + (progn + (setq min tmp) + (setq match (substring match 0 min)))) + ;; Terminate with match=t if this is an exact match + (if (string= (car elm) verilog-str) + (progn + (setq match t) + (setq elm nil)) + (setq elm (cdr elm))))) + ;; If this is a test just for exact match, return nil ot t + (if (and (equal verilog-flag 'lambda) (not (equal match 't))) + nil + match)))) + ;; If flag is t, this was called by all-completions. Return + ;; list of all possible completions + (verilog-flag + verilog-all))) + +(defvar verilog-last-word-numb 0) +(defvar verilog-last-word-shown nil) +(defvar verilog-last-completions nil) + +(defun verilog-complete-word () + "Complete word at current point. +\(See also `verilog-toggle-completions', `verilog-type-keywords', +and `verilog-separator-keywords'.)" + (interactive) + (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) + (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) + (verilog-str (buffer-substring b e)) + ;; The following variable is used in verilog-completion + (verilog-buffer-to-use (current-buffer)) + (allcomp (if (and verilog-toggle-completions + (string= verilog-last-word-shown verilog-str)) + verilog-last-completions + (all-completions verilog-str 'verilog-completion))) + (match (if verilog-toggle-completions + "" (try-completion + verilog-str (mapcar '(lambda (elm) + (cons elm 0)) allcomp))))) + ;; Delete old string + (delete-region b e) + + ;; Toggle-completions inserts whole labels + (if verilog-toggle-completions + (progn + ;; Update entry number in list + (setq verilog-last-completions allcomp + verilog-last-word-numb + (if (>= verilog-last-word-numb (1- (length allcomp))) + 0 + (1+ verilog-last-word-numb))) + (setq verilog-last-word-shown (elt allcomp verilog-last-word-numb)) + ;; Display next match or same string if no match was found + (if (not (null allcomp)) + (insert "" verilog-last-word-shown) + (insert "" verilog-str) + (message "(No match)"))) + ;; The other form of completion does not necessarily do that. + + ;; Insert match if found, or the original string if no match + (if (or (null match) (equal match 't)) + (progn (insert "" verilog-str) + (message "(No match)")) + (insert "" match)) + ;; Give message about current status of completion + (cond ((equal match 't) + (if (not (null (cdr allcomp))) + (message "(Complete but not unique)") + (message "(Sole completion)"))) + ;; Display buffer if the current completion didn't help + ;; on completing the label. + ((and (not (null (cdr allcomp))) (= (length verilog-str) + (length match))) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list allcomp)) + ;; Wait for a key press. Then delete *Completion* window + (momentary-string-display "" (point)) + (delete-window (get-buffer-window (get-buffer "*Completions*"))) + ))))) + +(defun verilog-show-completions () + "Show all possible completions at current point." + (interactive) + (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) + (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) + (verilog-str (buffer-substring b e)) + ;; The following variable is used in verilog-completion + (verilog-buffer-to-use (current-buffer)) + (allcomp (if (and verilog-toggle-completions + (string= verilog-last-word-shown verilog-str)) + verilog-last-completions + (all-completions verilog-str 'verilog-completion)))) + ;; Show possible completions in a temporary buffer. + (with-output-to-temp-buffer "*Completions*" + (display-completion-list allcomp)) + ;; Wait for a key press. Then delete *Completion* window + (momentary-string-display "" (point)) + (delete-window (get-buffer-window (get-buffer "*Completions*"))))) + + +(defun verilog-get-default-symbol () + "Return symbol around current point as a string." + (save-excursion + (buffer-substring (progn + (skip-chars-backward " \t") + (skip-chars-backward "a-zA-Z0-9_") + (point)) + (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))))) + +(defun verilog-build-defun-re (str &optional arg) + "Return function/task/module starting with STR as regular expression. +With optional second ARG non-nil, STR is the complete name of the instruction." + (if arg + (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "\\)\\>") + (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "[a-zA-Z0-9_]*\\)\\>"))) + +(defun verilog-comp-defun (verilog-str verilog-pred verilog-flag) + "Function passed to `completing-read', `try-completion' or `all-completions'. +Returns a completion on any function name based on VERILOG-STR prefix. If +VERILOG-PRED is non-nil, it must be a function to be called for every match +to check if this should really be a match. If VERILOG-FLAG is t, the +function returns a list of all possible completions. If it is nil it +returns a string, the longest possible completion, or t if VERILOG-STR is +an exact match. If VERILOG-FLAG is 'lambda, the function returns t if +VERILOG-STR is an exact match, nil otherwise." + (save-excursion + (let ((verilog-all nil) + match) + + ;; Set buffer to use for searching labels. This should be set + ;; within functions which use verilog-completions + (set-buffer verilog-buffer-to-use) + + (let ((verilog-str verilog-str)) + ;; Build regular expression for functions + (if (string= verilog-str "") + (setq verilog-str (verilog-build-defun-re "[a-zA-Z_]")) + (setq verilog-str (verilog-build-defun-re verilog-str))) + (goto-char (point-min)) + + ;; Build a list of all possible completions + (while (verilog-re-search-forward verilog-str nil t) + (setq match (buffer-substring (match-beginning 2) (match-end 2))) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + + ;; Now we have built a list of all matches. Give response to caller + (verilog-completion-response)))) + +(defun verilog-goto-defun () + "Move to specified Verilog module/task/function. +The default is a name found in the buffer around point. +If search fails, other files are checked based on +`verilog-library-flags'." + (interactive) + (let* ((default (verilog-get-default-symbol)) + ;; The following variable is used in verilog-comp-function + (verilog-buffer-to-use (current-buffer)) + (label (if (not (string= default "")) + ;; Do completion with default + (completing-read (concat "Label: (default " default ") ") + 'verilog-comp-defun nil nil "") + ;; There is no default value. Complete without it + (completing-read "Label: " + 'verilog-comp-defun nil nil ""))) + pt) + ;; If there was no response on prompt, use default value + (if (string= label "") + (setq label default)) + ;; Goto right place in buffer if label is not an empty string + (or (string= label "") + (progn + (save-excursion + (goto-char (point-min)) + (setq pt (re-search-forward (verilog-build-defun-re label t) nil t))) + (when pt + (goto-char pt) + (beginning-of-line)) + pt) + (verilog-goto-defun-file label) + ))) + +;; Eliminate compile warning +(eval-when-compile + (if (not (boundp 'occur-pos-list)) + (defvar occur-pos-list nil "Backward compatibility occur positions."))) + +(defun verilog-showscopes () + "List all scopes in this module." + (interactive) + (let ((buffer (current-buffer)) + (linenum 1) + (nlines 0) + (first 1) + (prevpos (point-min)) + (final-context-start (make-marker)) + (regexp "\\(module\\s-+\\w+\\s-*(\\)\\|\\(\\w+\\s-+\\w+\\s-*(\\)") + ) + (with-output-to-temp-buffer "*Occur*" + (save-excursion + (message (format "Searching for %s ..." regexp)) + ;; Find next match, but give up if prev match was at end of buffer. + (while (and (not (= prevpos (point-max))) + (verilog-re-search-forward regexp nil t)) + (goto-char (match-beginning 0)) + (beginning-of-line) + (save-match-data + (setq linenum (+ linenum (count-lines prevpos (point))))) + (setq prevpos (point)) + (goto-char (match-end 0)) + (let* ((start (save-excursion + (goto-char (match-beginning 0)) + (forward-line (if (< nlines 0) nlines (- nlines))) + (point))) + (end (save-excursion + (goto-char (match-end 0)) + (if (> nlines 0) + (forward-line (1+ nlines)) + (forward-line 1)) + (point))) + (tag (format "%3d" linenum)) + (empty (make-string (length tag) ?\ )) + tem) + (save-excursion + (setq tem (make-marker)) + (set-marker tem (point)) + (set-buffer standard-output) + (setq occur-pos-list (cons tem occur-pos-list)) + (or first (zerop nlines) + (insert "--------\n")) + (setq first nil) + (insert-buffer-substring buffer start end) + (backward-char (- end start)) + (setq tem (if (< nlines 0) (- nlines) nlines)) + (while (> tem 0) + (insert empty ?:) + (forward-line 1) + (setq tem (1- tem))) + (let ((this-linenum linenum)) + (set-marker final-context-start + (+ (point) (- (match-end 0) (match-beginning 0)))) + (while (< (point) final-context-start) + (if (null tag) + (setq tag (format "%3d" this-linenum))) + (insert tag ?:))))))) + (set-buffer-modified-p nil)))) + + +;; Highlight helper functions +(defconst verilog-directive-regexp "\\(translate\\|coverage\\|lint\\)_") +(defun verilog-within-translate-off () + "Return point if within translate-off region, else nil." + (and (save-excursion + (re-search-backward + (concat "//\\s-*.*\\s-*" verilog-directive-regexp "\\(on\\|off\\)\\>") + nil t)) + (equal "off" (match-string 2)) + (point))) + +(defun verilog-start-translate-off (limit) + "Return point before translate-off directive if before LIMIT, else nil." + (when (re-search-forward + (concat "//\\s-*.*\\s-*" verilog-directive-regexp "off\\>") + limit t) + (match-beginning 0))) + +(defun verilog-back-to-start-translate-off (limit) + "Return point before translate-off directive if before LIMIT, else nil." + (when (re-search-backward + (concat "//\\s-*.*\\s-*" verilog-directive-regexp "off\\>") + limit t) + (match-beginning 0))) + +(defun verilog-end-translate-off (limit) + "Return point after translate-on directive if before LIMIT, else nil." + + (re-search-forward (concat + "//\\s-*.*\\s-*" verilog-directive-regexp "on\\>") limit t)) + +(defun verilog-match-translate-off (limit) + "Match a translate-off block, setting `match-data' and returning t, else nil. +Bound search by LIMIT." + (when (< (point) limit) + (let ((start (or (verilog-within-translate-off) + (verilog-start-translate-off limit))) + (case-fold-search t)) + (when start + (let ((end (or (verilog-end-translate-off limit) limit))) + (set-match-data (list start end)) + (goto-char end)))))) + +(defun verilog-font-lock-match-item (limit) + "Match, and move over, any declaration item after point. +Bound search by LIMIT. Adapted from +`font-lock-match-c-style-declaration-item-and-skip-to-next'." + (condition-case nil + (save-restriction + (narrow-to-region (point-min) limit) + ;; match item + (when (looking-at "\\s-*\\([a-zA-Z]\\w*\\)") + (save-match-data + (goto-char (match-end 1)) + ;; move to next item + (if (looking-at "\\(\\s-*,\\)") + (goto-char (match-end 1)) + (end-of-line) t)))) + (error nil))) + + +;; Added by Subbu Meiyappan for Header + +(defun verilog-header () + "Insert a standard Verilog file header." + (interactive) + (let ((start (point))) + (insert "\ +//----------------------------------------------------------------------------- +// Title : <title> +// Project : <project> +//----------------------------------------------------------------------------- +// File : <filename> +// Author : <author> +// Created : <credate> +// Last modified : <moddate> +//----------------------------------------------------------------------------- +// Description : +// <description> +//----------------------------------------------------------------------------- +// Copyright (c) <copydate> by <company> This model is the confidential and +// proprietary property of <company> and the possession or use of this +// file requires a written license from <company>. +//------------------------------------------------------------------------------ +// Modification history : +// <modhist> +//----------------------------------------------------------------------------- + +") + (goto-char start) + (search-forward "<filename>") + (replace-match (buffer-name) t t) + (search-forward "<author>") (replace-match "" t t) + (insert (user-full-name)) + (insert " <" (user-login-name) "@" (system-name) ">") + (search-forward "<credate>") (replace-match "" t t) + (insert-date) + (search-forward "<moddate>") (replace-match "" t t) + (insert-date) + (search-forward "<copydate>") (replace-match "" t t) + (insert-year) + (search-forward "<modhist>") (replace-match "" t t) + (insert-date) + (insert " : created") + (goto-char start) + (let (string) + (setq string (read-string "title: ")) + (search-forward "<title>") + (replace-match string t t) + (setq string (read-string "project: " verilog-project)) + (make-variable-buffer-local 'verilog-project) + (setq verilog-project string) + (search-forward "<project>") + (replace-match string t t) + (setq string (read-string "Company: " verilog-company)) + (make-variable-buffer-local 'verilog-company) + (setq verilog-company string) + (search-forward "<company>") + (replace-match string t t) + (search-forward "<company>") + (replace-match string t t) + (search-forward "<company>") + (replace-match string t t) + (search-backward "<description>") + (replace-match "" t t) + ))) + +;; verilog-header Uses the insert-date function + +(defun insert-date () + "Insert date from the system." + (interactive) + (let ((timpos)) + (setq timpos (point)) + (if verilog-date-scientific-format + (shell-command "date \"+@%Y/%m/%d\"" t) + (shell-command "date \"+@%d.%m.%Y\"" t)) + (search-forward "@") + (delete-region timpos (point)) + (end-of-line)) + (delete-char 1)) + +(defun insert-year () + "Insert year from the system." + (interactive) + (let ((timpos)) + (setq timpos (point)) + (shell-command "date \"+@%Y\"" t) + (search-forward "@") + (delete-region timpos (point)) + (end-of-line)) + (delete-char 1)) + + +;; +;; Signal list parsing +;; + +;; Elements of a signal list +(defsubst verilog-sig-name (sig) + (car sig)) +(defsubst verilog-sig-bits (sig) + (nth 1 sig)) +(defsubst verilog-sig-comment (sig) + (nth 2 sig)) +(defsubst verilog-sig-memory (sig) + (nth 3 sig)) +(defsubst verilog-sig-enum (sig) + (nth 4 sig)) +(defsubst verilog-sig-signed (sig) + (nth 5 sig)) +(defsubst verilog-sig-type (sig) + (nth 6 sig)) +(defsubst verilog-sig-multidim (sig) + (nth 7 sig)) +(defsubst verilog-sig-multidim-string (sig) + (if (verilog-sig-multidim sig) + (let ((str "") (args (verilog-sig-multidim sig))) + (while args + (setq str (concat str (car args))) + (setq args (cdr args))) + str))) +(defsubst verilog-sig-width (sig) + (verilog-make-width-expression (verilog-sig-bits sig))) + +(defsubst verilog-alw-get-inputs (sigs) + (nth 2 sigs)) +(defsubst verilog-alw-get-outputs (sigs) + (nth 0 sigs)) +(defsubst verilog-alw-get-uses-delayed (sigs) + (nth 3 sigs)) + +(defun verilog-signals-not-in (in-list not-list) + "Return list of signals in IN-LIST that aren't also in NOT-LIST. +Signals must be in standard (base vector) form." + (let (out-list) + (while in-list + (if (not (assoc (car (car in-list)) not-list)) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list))) +;;(verilog-signals-not-in '(("A" "") ("B" "") ("DEL" "[2:3]")) '(("DEL" "") ("EXT" ""))) + +(defun verilog-signals-in (in-list other-list) + "Return list of signals in IN-LIST that are also in OTHER-LIST. +Signals must be in standard (base vector) form." + (let (out-list) + (while in-list + (if (assoc (car (car in-list)) other-list) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list))) +;;(verilog-signals-in '(("A" "") ("B" "") ("DEL" "[2:3]")) '(("DEL" "") ("EXT" ""))) + +(defun verilog-signals-memory (in-list) + "Return list of signals in IN-LIST that are memoried (multidimensional)." + (let (out-list) + (while in-list + (if (nth 3 (car in-list)) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + out-list)) +;;(verilog-signals-memory '(("A" nil nil "[3:0]")) '(("B" nil nil nil))) + +(defun verilog-signals-sort-compare (a b) + "Compare signal A and B for sorting." + (string< (car a) (car b))) + +(defun verilog-signals-not-params (in-list) + "Return list of signals in IN-LIST that aren't parameters or numeric constants." + (let (out-list) + (while in-list + (unless (boundp (intern (concat "vh-" (car (car in-list))))) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list))) + +(defun verilog-signals-combine-bus (in-list) + "Return a list of signals in IN-LIST, with busses combined. +Duplicate signals are also removed. For example A[2] and A[1] become A[2:1]." + (let (combo + out-list + sig highbit lowbit ; Temp information about current signal + sv-name sv-highbit sv-lowbit ; Details about signal we are forming + sv-comment sv-memory sv-enum sv-signed sv-type sv-multidim sv-busstring + bus) + ;; Shove signals so duplicated signals will be adjacent + (setq in-list (sort in-list `verilog-signals-sort-compare)) + (while in-list + (setq sig (car in-list)) + ;; No current signal; form from existing details + (unless sv-name + (setq sv-name (verilog-sig-name sig) + sv-highbit nil + sv-busstring nil + sv-comment (verilog-sig-comment sig) + sv-memory (verilog-sig-memory sig) + sv-enum (verilog-sig-enum sig) + sv-signed (verilog-sig-signed sig) + sv-type (verilog-sig-type sig) + sv-multidim (verilog-sig-multidim sig) + combo "" + )) + ;; Extract bus details + (setq bus (verilog-sig-bits sig)) + (cond ((and bus + (or (and (string-match "\\[\\([0-9]+\\):\\([0-9]+\\)\\]" bus) + (setq highbit (string-to-int (match-string 1 bus)) + lowbit (string-to-int (match-string 2 bus)))) + (and (string-match "\\[\\([0-9]+\\)\\]" bus) + (setq highbit (string-to-int (match-string 1 bus)) + lowbit highbit)))) + ;; Combine bits in bus + (if sv-highbit + (setq sv-highbit (max highbit sv-highbit) + sv-lowbit (min lowbit sv-lowbit)) + (setq sv-highbit highbit + sv-lowbit lowbit))) + (bus + ;; String, probably something like `preproc:0 + (setq sv-busstring bus))) + ;; Peek ahead to next signal + (setq in-list (cdr in-list)) + (setq sig (car in-list)) + (cond ((and sig (equal sv-name (verilog-sig-name sig))) + ;; Combine with this signal + (if (and sv-busstring (not (equal sv-busstring (verilog-sig-bits sig)))) + (message (concat "Warning, can't merge into single bus " + sv-name bus + ", the AUTOs may be wrong"))) + (if (verilog-sig-comment sig) (setq combo ", ...")) + (setq sv-memory (or sv-memory (verilog-sig-memory sig)) + sv-enum (or sv-enum (verilog-sig-enum sig)) + sv-signed (or sv-signed (verilog-sig-signed sig)) + sv-type (or sv-type (verilog-sig-type sig)) + sv-multidim (or sv-multidim (verilog-sig-multidim sig)))) + ;; Doesn't match next signal, add to que, zero in prep for next + ;; Note sig may also be nil for the last signal in the list + (t + (setq out-list + (cons (list sv-name + (or sv-busstring + (if sv-highbit + (concat "[" (int-to-string sv-highbit) ":" (int-to-string sv-lowbit) "]"))) + (concat sv-comment combo) + sv-memory sv-enum sv-signed sv-type sv-multidim) + out-list) + sv-name nil))) + ) + ;; + out-list)) + +(defun verilog-sig-tieoff (sig &optional no-width) + "Return tieoff expression for given SIGNAL, with appropriate width. +Ignore width if optional NO-WIDTH is set." + (let* ((width (if no-width nil (verilog-sig-width sig)))) + (concat + (if (and verilog-active-low-regexp + (string-match verilog-active-low-regexp (verilog-sig-name sig))) + "~" "") + (cond ((not width) + "0") + ((string-match "^[0-9]+$" width) + (concat width (if (verilog-sig-signed sig) "'sh0" "'h0"))) + (t + (concat "{" width "{1'b0}}")))))) + +;; +;; Port/Wire/Etc Reading +;; + +(defun verilog-read-inst-backward-name () + "Internal. Move point back to beginning of inst-name." + (verilog-backward-open-paren) + (let (done) + (while (not done) + (verilog-re-search-backward-quick "\\()\\|\\b[a-zA-Z0-9`_\$]\\|\\]\\)" nil nil) ; ] isn't word boundary + (cond ((looking-at ")") + (verilog-backward-open-paren)) + (t (setq done t))))) + (while (looking-at "\\]") + (verilog-backward-open-bracket) + (verilog-re-search-backward-quick "\\(\\b[a-zA-Z0-9`_\$]\\|\\]\\)" nil nil)) + (skip-chars-backward "a-zA-Z0-9`_$")) + +(defun verilog-read-inst-module () + "Return module_name when point is inside instantiation." + (save-excursion + (verilog-read-inst-backward-name) + ;; Skip over instantiation name + (verilog-re-search-backward-quick "\\(\\b[a-zA-Z0-9`_\$]\\|)\\)" nil nil) ; ) isn't word boundary + ;; Check for parameterized instantiations + (when (looking-at ")") + (verilog-backward-open-paren) + (verilog-re-search-backward-quick "\\b[a-zA-Z0-9`_\$]" nil nil)) + (skip-chars-backward "a-zA-Z0-9'_$") + (looking-at "[a-zA-Z0-9`_\$]+") + ;; Important: don't use match string, this must work with emacs 19 font-lock on + (buffer-substring-no-properties (match-beginning 0) (match-end 0)))) + +(defun verilog-read-inst-name () + "Return instance_name when point is inside instantiation." + (save-excursion + (verilog-read-inst-backward-name) + (looking-at "[a-zA-Z0-9`_\$]+") + ;; Important: don't use match string, this must work with emacs 19 font-lock on + (buffer-substring-no-properties (match-beginning 0) (match-end 0)))) + +(defun verilog-read-module-name () + "Return module name when after its ( or ;." + (save-excursion + (re-search-backward "[(;]") + (verilog-re-search-backward-quick "\\b[a-zA-Z0-9`_\$]" nil nil) + (skip-chars-backward "a-zA-Z0-9`_$") + (looking-at "[a-zA-Z0-9`_\$]+") + ;; Important: don't use match string, this must work with emacs 19 font-lock on + (buffer-substring-no-properties (match-beginning 0) (match-end 0)))) + +(defun verilog-read-auto-params (num-param &optional max-param) + "Return parameter list inside auto. +Optional NUM-PARAM and MAX-PARAM check for a specific number of parameters." + (let ((olist)) + (save-excursion + ;; /*AUTOPUNT("parameter", "parameter")*/ + (search-backward "(") + (while (looking-at "(?\\s *\"\\([^\"]*\\)\"\\s *,?") + (setq olist (cons (match-string 1) olist)) + (goto-char (match-end 0)))) + (or (eq nil num-param) + (<= num-param (length olist)) + (error "%s: Expected %d parameters" (verilog-point-text) num-param)) + (if (eq max-param nil) (setq max-param num-param)) + (or (eq nil max-param) + (>= max-param (length olist)) + (error "%s: Expected <= %d parameters" (verilog-point-text) max-param)) + (nreverse olist))) + +(defun verilog-read-decls () + "Compute signal declaration information for the current module at point. +Return a array of [outputs inouts inputs wire reg assign const]." + (let ((end-mod-point (or (verilog-get-end-of-defun t) (point-max))) + (functask 0) (paren 0) + sigs-in sigs-out sigs-inout sigs-wire sigs-reg sigs-assign sigs-const sigs-gparam + vec expect-signal keywd newsig rvalue enum io signed typedefed multidim) + (save-excursion + (verilog-beg-of-defun) + (setq sigs-const (verilog-read-auto-constants (point) end-mod-point)) + (while (< (point) end-mod-point) + ;;(if dbg (setq dbg (cons (format "Pt %s Vec %s Kwd'%s'\n" (point) vec keywd) dbg))) + (cond + ((looking-at "//") + (if (looking-at "[^\n]*synopsys\\s +enum\\s +\\([a-zA-Z0-9_]+\\)") + (setq enum (match-string 1))) + (search-forward "\n")) + ((looking-at "/\\*") + (forward-char 2) + (if (looking-at "[^*]*synopsys\\s +enum\\s +\\([a-zA-Z0-9_]+\\)") + (setq enum (match-string 1))) + (or (search-forward "*/") + (error "%s: Unmatched /* */, at char %d" (verilog-point-text) (point)))) + ((looking-at "(\\*") + (forward-char 2) + (or (looking-at "\\s-*)") ; It's a "always @ (*)" + (search-forward "*)") + (error "%s: Unmatched (* *), at char %d" (verilog-point-text) (point)))) + ((eq ?\" (following-char)) + (or (re-search-forward "[^\\]\"" nil t) ;; don't forward-char first, since we look for a non backslash first + (error "%s: Unmatched quotes, at char %d" (verilog-point-text) (point)))) + ((eq ?\; (following-char)) + (setq vec nil io nil expect-signal nil newsig nil paren 0 rvalue nil) + (forward-char 1)) + ((eq ?= (following-char)) + (setq rvalue t newsig nil) + (forward-char 1)) + ((and rvalue + (cond ((and (eq ?, (following-char)) + (eq paren 0)) + (setq rvalue nil) + (forward-char 1) + t) + ;; ,'s can occur inside {} & funcs + ((looking-at "[{(]") + (setq paren (1+ paren)) + (forward-char 1) + t) + ((looking-at "[})]") + (setq paren (1- paren)) + (forward-char 1) + t) + ))) + ((looking-at "\\s-*\\(\\[[^]]+\\]\\)") + (goto-char (match-end 0)) + (cond (newsig ; Memory, not just width. Patch last signal added's memory (nth 3) + (setcar (cdr (cdr (cdr newsig))) (match-string 1))) + (vec ;; Multidimensional + (setq multidim (cons vec multidim)) + (setq vec (verilog-string-replace-matches + "\\s-+" "" nil nil (match-string 1)))) + (t ;; Bit width + (setq vec (verilog-string-replace-matches + "\\s-+" "" nil nil (match-string 1)))))) + ;; Normal or escaped identifier -- note we remember the \ if escaped + ((looking-at "\\s-*\\([a-zA-Z0-9`_$]+\\|\\\\[^ \t\n\f]+\\)") + (goto-char (match-end 0)) + (setq keywd (match-string 1)) + (when (string-match "^\\\\" keywd) + (setq keywd (concat keywd " "))) ;; Escaped ID needs space at end + (cond ((equal keywd "input") + (setq vec nil enum nil rvalue nil newsig nil signed nil typedefed nil multidim nil io t expect-signal 'sigs-in)) + ((equal keywd "output") + (setq vec nil enum nil rvalue nil newsig nil signed nil typedefed nil multidim nil io t expect-signal 'sigs-out)) + ((equal keywd "inout") + (setq vec nil enum nil rvalue nil newsig nil signed nil typedefed nil multidim nil io t expect-signal 'sigs-inout)) + ((or (equal keywd "wire") + (equal keywd "tri") + (equal keywd "tri0") + (equal keywd "tri1")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil expect-signal 'sigs-wire))) + ((or (equal keywd "reg") + (equal keywd "trireg")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil expect-signal 'sigs-reg))) + ((equal keywd "assign") + (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil expect-signal 'sigs-assign)) + ((or (equal keywd "supply0") + (equal keywd "supply1") + (equal keywd "supply") + (equal keywd "localparam")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil expect-signal 'sigs-const))) + ((or (equal keywd "parameter")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil expect-signal 'sigs-gparam))) + ((equal keywd "signed") + (setq signed "signed")) + ((or (equal keywd "function") + (equal keywd "task")) + (setq functask (1+ functask))) + ((or (equal keywd "endfunction") + (equal keywd "endtask")) + (setq functask (1- functask))) + ((or (equal keywd "`ifdef") + (equal keywd "`ifndef")) + (setq rvalue t)) + ((verilog-typedef-name-p keywd) + (setq typedefed keywd)) + ((and expect-signal + (eq functask 0) + (not (member keywd verilog-keywords)) + (not rvalue)) + ;; Add new signal to expect-signal's variable + (setq newsig (list keywd vec nil nil enum signed typedefed multidim)) + (set expect-signal (cons newsig + (symbol-value expect-signal)))))) + (t + (forward-char 1))) + (skip-syntax-forward " ")) + ;; Return arguments + (vector (nreverse sigs-out) + (nreverse sigs-inout) + (nreverse sigs-in) + (nreverse sigs-wire) + (nreverse sigs-reg) + (nreverse sigs-assign) + (nreverse sigs-const) + (nreverse sigs-gparam) + )))) + +(defvar sigs-in nil) ; Prevent compile warning +(defvar sigs-inout nil) ; Prevent compile warning +(defvar sigs-out nil) ; Prevent compile warning + +(defun verilog-read-sub-decls-sig (submodi comment port sig vec multidim) + "For verilog-read-sub-decls-line, add a signal." + (let (portdata) + (when sig + (setq port (verilog-symbol-detick-denumber port)) + (setq sig (verilog-symbol-detick-denumber sig)) + (if sig (setq sig (verilog-string-replace-matches "^[---+~!|&]+" "" nil nil sig))) + (if vec (setq vec (verilog-symbol-detick-denumber vec))) + (if multidim (setq multidim (mapcar `verilog-symbol-detick-denumber multidim))) + (unless (or (not sig) + (equal sig "")) ;; Ignore .foo(1'b1) assignments + (cond ((setq portdata (assoc port (verilog-modi-get-inouts submodi))) + (setq sigs-inout (cons (list sig vec (concat "To/From " comment) nil nil + (verilog-sig-signed portdata) + (verilog-sig-type portdata) + multidim) + sigs-inout))) + ((setq portdata (assoc port (verilog-modi-get-outputs submodi))) + (setq sigs-out (cons (list sig vec (concat "From " comment) nil nil + (verilog-sig-signed portdata) + (verilog-sig-type portdata) + multidim) + sigs-out))) + ((setq portdata (assoc port (verilog-modi-get-inputs submodi))) + (setq sigs-in (cons (list sig vec (concat "To " comment) nil nil + (verilog-sig-signed portdata) + (verilog-sig-type portdata) + multidim) + sigs-in))) + ;; (t -- warning pin isn't defined.) ; Leave for lint tool + ))))) + +(defun verilog-read-sub-decls-line (submodi comment) + "For read-sub-decls, read lines of port defs until none match anymore. +Return the list of signals found, using submodi to look up each port." + (let (done port sig vec multidim) + (save-excursion + (forward-line 1) + (while (not done) + ;; Get port name + (cond ((looking-at "\\s-*\\.\\s-*\\([a-zA-Z0-9`_$]*\\)\\s-*(\\s-*") + (setq port (match-string 1)) + (goto-char (match-end 0))) + ((looking-at "\\s-*\\.\\s-*\\(\\\\[^ \t\n\f]*\\)\\s-*(\\s-*") + (setq port (concat (match-string 1) " ")) ;; escaped id's need trailing space + (goto-char (match-end 0))) + ((looking-at "\\s-*\\.[^(]*(") + (setq port nil) ;; skip this line + (goto-char (match-end 0))) + (t + (setq port nil done t))) ;; Unknown, ignore rest of line + ;; Get signal name + (when port + (setq multidim nil) + (cond ((looking-at "\\(\\\\[^ \t\n\f]*\\)\\s-*)") + (setq sig (concat (match-string 1) " ") ;; escaped id's need trailing space + vec nil)) + ; We intentionally ignore (non-escaped) signals with .s in them + ; this prevents AUTOWIRE etc from noticing hierarchical sigs. + ((looking-at "\\([^[({).]*\\)\\s-*)") + (setq sig (verilog-string-remove-spaces (match-string 1)) + vec nil)) + ((looking-at "\\([^[({).]*\\)\\s-*\\(\\[[^]]+\\]\\)\\s-*)") + (setq sig (verilog-string-remove-spaces (match-string 1)) + vec (match-string 2))) + ((looking-at "\\([^[({).]*\\)\\s-*/\\*\\(\\[[^*]+\\]\\)\\*/\\s-*)") + (setq sig (verilog-string-remove-spaces (match-string 1)) + vec nil) + (let ((parse (match-string 2))) + (while (string-match "^\\(\\[[^]]+\\]\\)\\(.*\\)$" parse) + (when vec (setq multidim (cons vec multidim))) + (setq vec (match-string 1 parse)) + (setq parse (match-string 2 parse))))) + ((looking-at "{\\(.*\\)}.*\\s-*)") + (let ((mlst (split-string (match-string 1) ",")) + mstr) + (while (setq mstr (pop mlst)) + ;;(unless noninteractive (message "sig: %s " mstr)) + (cond + ((string-match "\\(['`a-zA-Z0-9_$]+\\)\\s-*$" mstr) + (setq sig (verilog-string-remove-spaces (match-string 1 mstr)) + vec nil) + ;;(unless noninteractive (message "concat sig1: %s %s" mstr (match-string 1 mstr))) + ) + ((string-match "\\([^[({).]+\\)\\s-*\\(\\[[^]]+\\]\\)\\s-*" mstr) + (setq sig (verilog-string-remove-spaces (match-string 1 mstr)) + vec (match-string 2 mstr)) + ;;(unless noninteractive (message "concat sig2: '%s' '%s' '%s'" mstr (match-string 1 mstr) (match-string 2 mstr))) + ) + (t + (setq sig nil))) + ;; Process signals + (verilog-read-sub-decls-sig submodi comment port sig vec multidim)))) + (t + (setq sig nil))) + ;; Process signals + (verilog-read-sub-decls-sig submodi comment port sig vec multidim)) + ;; + (forward-line 1))))) + +(defun verilog-read-sub-decls () + "Internally parse signals going to modules under this module. +Return a array of [ outputs inouts inputs ] signals for modules that are +instantiated in this module. For example if declare A A (.B(SIG)) and SIG +is a output, then SIG will be included in the list. + +This only works on instantiations created with /*AUTOINST*/ converted by +\\[verilog-auto-inst]. Otherwise, it would have to read in the whole +component library to determine connectivity of the design. + +One work around for this problem is to manually create // Inputs and // +Outputs comments above subcell signals, for example: + + module1 instance1x ( + // Outputs + .out (out), + // Inputs + .in (in));" + (save-excursion + (let ((end-mod-point (verilog-get-end-of-defun t)) + st-point end-inst-point + ;; below 3 modified by verilog-read-sub-decls-line + sigs-out sigs-inout sigs-in) + (verilog-beg-of-defun) + (while (re-search-forward "\\(/\\*AUTOINST\\*/\\|\\.\\*\\)" end-mod-point t) + (save-excursion + (goto-char (match-beginning 0)) + (unless (verilog-inside-comment-p) + ;; Attempt to snarf a comment + (let* ((submod (verilog-read-inst-module)) + (inst (verilog-read-inst-name)) + (comment (concat inst " of " submod ".v")) submodi) + (when (setq submodi (verilog-modi-lookup submod t)) + ;; This could have used a list created by verilog-auto-inst + ;; However I want it to be runnable even on user's manually added signals + (verilog-backward-open-paren) + (setq end-inst-point (save-excursion (forward-sexp 1) (point)) + st-point (point)) + (while (re-search-forward "\\s *(?\\s *// Outputs" end-inst-point t) + (verilog-read-sub-decls-line submodi comment)) ;; Modifies sigs-out + (goto-char st-point) + (while (re-search-forward "\\s *// Inouts" end-inst-point t) + (verilog-read-sub-decls-line submodi comment)) ;; Modifies sigs-inout + (goto-char st-point) + (while (re-search-forward "\\s *// Inputs" end-inst-point t) + (verilog-read-sub-decls-line submodi comment)) ;; Modifies sigs-in + ))))) + ;; Combine duplicate bits + ;;(setq rr (vector sigs-out sigs-inout sigs-in)) + (vector (verilog-signals-combine-bus (nreverse sigs-out)) + (verilog-signals-combine-bus (nreverse sigs-inout)) + (verilog-signals-combine-bus (nreverse sigs-in)))))) + +(defun verilog-read-inst-pins () + "Return a array of [ pins ] for the current instantiation at point. +For example if declare A A (.B(SIG)) then B will be included in the list." + (save-excursion + (let ((end-mod-point (point)) ;; presume at /*AUTOINST*/ point + pins pin) + (verilog-backward-open-paren) + (while (re-search-forward "\\.\\([^(,) \t\n\f]*\\)\\s-*" end-mod-point t) + (setq pin (match-string 1)) + (unless (verilog-inside-comment-p) + (setq pins (cons (list pin) pins)) + (when (looking-at "(") + (forward-sexp 1)))) + (vector pins)))) + +(defun verilog-read-arg-pins () + "Return a array of [ pins ] for the current argument declaration at point." + (save-excursion + (let ((end-mod-point (point)) ;; presume at /*AUTOARG*/ point + pins pin) + (verilog-backward-open-paren) + (while (re-search-forward "\\([a-zA-Z0-9$_.%`]+\\)" end-mod-point t) + (setq pin (match-string 1)) + (unless (verilog-inside-comment-p) + (setq pins (cons (list pin) pins)))) + (vector pins)))) + +(defun verilog-read-auto-constants (beg end-mod-point) + "Return a list of AUTO_CONSTANTs used in the region from BEG to END-MOD-POINT." + ;; Insert new + (save-excursion + (let (sig-list tpl-end-pt) + (goto-char beg) + (while (re-search-forward "\\<AUTO_CONSTANT" end-mod-point t) + (if (not (looking-at "\\s *(")) + (error "%s: Missing () after AUTO_CONSTANT" (verilog-point-text))) + (search-forward "(" end-mod-point) + (setq tpl-end-pt (save-excursion + (backward-char 1) + (forward-sexp 1) ;; Moves to paren that closes argdecl's + (backward-char 1) + (point))) + (while (re-search-forward "\\s-*\\([\"a-zA-Z0-9$_.%`]+\\)\\s-*,*" tpl-end-pt t) + (setq sig-list (cons (list (match-string 1) nil nil) sig-list)))) + sig-list))) + +(defun verilog-read-auto-lisp (start end) + "Look for and evaluate a AUTO_LISP between START and END." + (save-excursion + (goto-char start) + (while (re-search-forward "\\<AUTO_LISP(" end t) + (backward-char) + (let* ((beg-pt (prog1 (point) + (forward-sexp 1))) ;; Closing paren + (end-pt (point))) + (eval-region beg-pt end-pt nil))))) + +(eval-when-compile + ;; These are passed in a let, not global + (if (not (boundp 'sigs-in)) + (defvar sigs-in nil) (defvar sigs-out nil) + (defvar got-sig nil) (defvar got-rvalue nil) (defvar uses-delayed nil))) + +(defun verilog-read-always-signals-recurse + (exit-keywd rvalue ignore-next) + "Recursive routine for parentheses/bracket matching. +EXIT-KEYWD is expression to stop at, nil if top level. +RVALUE is true if at right hand side of equal. +IGNORE-NEXT is true to ignore next token, fake from inside case statement." + (let* ((semi-rvalue (equal "endcase" exit-keywd)) ;; true if after a ; we are looking for rvalue + keywd last-keywd sig-tolk sig-last-tolk gotend end-else-check) + ;;(if dbg (setq dbg (concat dbg (format "Recursion %S %S %S\n" exit-keywd rvalue ignore-next)))) + (while (not (or (eobp) gotend)) + (cond + ((looking-at "//") + (search-forward "\n")) + ((looking-at "/\\*") + (or (search-forward "*/") + (error "%s: Unmatched /* */, at char %d" (verilog-point-text) (point)))) + ((looking-at "(\\*") + (or (looking-at "(\\*\\s-*)") ; It's a "always @ (*)" + (search-forward "*)") + (error "%s: Unmatched (* *), at char %d" (verilog-point-text) (point)))) + (t (setq keywd (buffer-substring-no-properties + (point) + (save-excursion (when (eq 0 (skip-chars-forward "a-zA-Z0-9$_.%`")) + (forward-char 1)) + (point))) + sig-last-tolk sig-tolk + sig-tolk nil) + ;;(if dbg (setq dbg (concat dbg (format "\tPt %S %S\t%S %S %S\n" (point) keywd rvalue ignore-next end-else-check)))) + (cond + ((equal keywd "\"") + (or (re-search-forward "[^\\]\"" nil t) + (error "%s: Unmatched quotes, at char %d" (verilog-point-text) (point)))) + ;; else at top level loop, keep parsing + ((and end-else-check (equal keywd "else")) + ;;(if dbg (setq dbg (concat dbg (format "\tif-check-else %s\n" keywd)))) + ;; no forward movement, want to see else in lower loop + (setq end-else-check nil)) + ;; End at top level loop + ((and end-else-check (looking-at "[^ \t\n\f]")) + ;;(if dbg (setq dbg (concat dbg (format "\tif-check-else-other %s\n" keywd)))) + (setq gotend t)) + ;; Final statement? + ((and exit-keywd (equal keywd exit-keywd)) + (setq gotend t) + (forward-char (length keywd))) + ;; Standard tokens... + ((equal keywd ";") + (setq ignore-next nil rvalue semi-rvalue) + ;; Final statement at top level loop? + (when (not exit-keywd) + ;;(if dbg (setq dbg (concat dbg (format "\ttop-end-check %s\n" keywd)))) + (setq end-else-check t)) + (forward-char 1)) + ((equal keywd "'") + (if (looking-at "'s?[hdxbo][0-9a-fA-F_xz? \t]*") + (goto-char (match-end 0)) + (forward-char 1))) + ((equal keywd ":") ;; Case statement, begin/end label, x?y:z + (cond ((equal "endcase" exit-keywd) ;; case x: y=z; statement next + (setq ignore-next nil rvalue nil)) + ((not rvalue) ;; begin label + (setq ignore-next t rvalue nil))) + (forward-char 1)) + ((equal keywd "=") + (if (eq (char-before) ?< ) + (setq uses-delayed 1)) + (setq ignore-next nil rvalue t) + (forward-char 1)) + ((equal keywd "?") + (forward-char 1) + (verilog-read-always-signals-recurse ":" rvalue nil)) + ((equal keywd "[") + (forward-char 1) + (verilog-read-always-signals-recurse "]" t nil)) + ((equal keywd "(") + (forward-char 1) + (cond (sig-last-tolk ;; Function call; zap last signal + (setq got-sig nil))) + (cond ((equal last-keywd "for") + (verilog-read-always-signals-recurse ";" nil nil) + (verilog-read-always-signals-recurse ";" t nil) + (verilog-read-always-signals-recurse ")" nil nil)) + (t (verilog-read-always-signals-recurse ")" t nil)))) + ((equal keywd "begin") + (skip-syntax-forward "w_") + (verilog-read-always-signals-recurse "end" nil nil) + ;;(if dbg (setq dbg (concat dbg (format "\tgot-end %s\n" exit-keywd)))) + (setq ignore-next nil rvalue semi-rvalue) + (if (not exit-keywd) (setq end-else-check t))) + ((or (equal keywd "case") + (equal keywd "casex") + (equal keywd "casez")) + (skip-syntax-forward "w_") + (verilog-read-always-signals-recurse "endcase" t nil) + (setq ignore-next nil rvalue semi-rvalue) + (if (not exit-keywd) (setq gotend t))) ;; top level begin/end + ((string-match "^[$`a-zA-Z_]" keywd) ;; not exactly word constituent + (cond ((or (equal keywd "`ifdef") + (equal keywd "`ifndef")) + (setq ignore-next t)) + ((or ignore-next + (member keywd verilog-keywords) + (string-match "^\\$" keywd)) ;; PLI task + (setq ignore-next nil)) + (t + (setq keywd (verilog-symbol-detick-denumber keywd)) + (if got-sig (if got-rvalue + (setq sigs-in (cons got-sig sigs-in)) + (setq sigs-out (cons got-sig sigs-out)))) + (setq got-rvalue rvalue + got-sig (if (or (not keywd) + (assoc keywd (if got-rvalue sigs-in sigs-out))) + nil (list keywd nil nil)) + sig-tolk t))) + (skip-chars-forward "a-zA-Z0-9$_.%`")) + (t + (forward-char 1))) + ;; End of non-comment token + (setq last-keywd keywd) + )) + (skip-syntax-forward " ")) + ;;(if dbg (setq dbg (concat dbg (format "ENDRecursion %s\n" exit-keywd)))) + )) + +(defun verilog-read-always-signals () + "Parse always block at point and return list of (outputs inout inputs)." + ;; Insert new + (save-excursion + (let* (;;(dbg "") + sigs-in sigs-out + got-sig got-rvalue + uses-delayed) ;; Found signal/rvalue; push if not function + (search-forward ")") + (verilog-read-always-signals-recurse nil nil nil) + ;; Return what was found + (if got-sig (if got-rvalue + (setq sigs-in (cons got-sig sigs-in)) + (setq sigs-out (cons got-sig sigs-out)))) + ;;(if dbg (message dbg)) + (list sigs-out nil sigs-in uses-delayed)))) + +(defun verilog-read-instants () + "Parse module at point and return list of ( ( file instance ) ... )." + (verilog-beg-of-defun) + (let* ((end-mod-point (verilog-get-end-of-defun t)) + (state nil) + (instants-list nil)) + (save-excursion + (while (< (point) end-mod-point) + ;; Stay at level 0, no comments + (while (progn + (setq state (parse-partial-sexp (point) end-mod-point 0 t nil)) + (or (> (car state) 0) ; in parens + (nth 5 state) ; comment + )) + (forward-line 1)) + (beginning-of-line) + (if (looking-at "^\\s-*\\([a-zA-Z0-9`_$]+\\)\\s-+\\([a-zA-Z0-9`_$]+\\)\\s-*(") + ;;(if (looking-at "^\\(.+\\)$") + (let ((module (match-string 1)) + (instant (match-string 2))) + (if (not (member module verilog-keywords)) + (setq instants-list (cons (list module instant) instants-list))))) + (forward-line 1) + )) + instants-list)) + + +(defun verilog-read-auto-template (module) + "Look for a auto_template for the instantiation of the given MODULE. +If found returns the signal name connections. Return REGEXP and +list of ( (signal_name connection_name)... )" + (save-excursion + ;; Find beginning + (let ((tpl-regexp "\\([0-9]+\\)") + (lineno 0) + (templateno 0) + tpl-sig-list tpl-wild-list tpl-end-pt rep) + (cond ((or + (re-search-backward (concat "^\\s-*/?\\*?\\s-*" module "\\s-+AUTO_TEMPLATE") nil t) + (progn + (goto-char (point-min)) + (re-search-forward (concat "^\\s-*/?\\*?\\s-*" module "\\s-+AUTO_TEMPLATE") nil t))) + (goto-char (match-end 0)) + ;; Parse "REGEXP" + ;; We reserve @"..." for future lisp expressions that evaluate once-per-AUTOINST + (when (looking-at "\\s-*\"\\([^\"]*)\\)\"") + (setq tpl-regexp (match-string 1)) + (goto-char (match-end 0))) + (search-forward "(") + ;; Parse lines in the template + (when verilog-auto-inst-template-numbers + (save-excursion + (goto-char (point-min)) + (while (search-forward "AUTO_TEMPLATE" nil t) + (setq templateno (1+ templateno))))) + (setq tpl-end-pt (save-excursion + (backward-char 1) + (forward-sexp 1) ;; Moves to paren that closes argdecl's + (backward-char 1) + (point))) + ;; + (while (< (point) tpl-end-pt) + (cond ((looking-at "\\s-*\\.\\([a-zA-Z0-9`_$]+\\)\\s-*(\\(.*\\))\\s-*\\(,\\|)\\s-*;\\)") + (setq tpl-sig-list (cons (list + (match-string-no-properties 1) + (match-string-no-properties 2) + templateno lineno) + tpl-sig-list)) + (goto-char (match-end 0))) + ;; Regexp form?? + ((looking-at + ;; Regexp bug in xemacs disallows ][ inside [], and wants + last + "\\s-*\\.\\(\\([a-zA-Z0-9`_$+@^.*?|---]+\\|[][]\\|\\\\[()|]\\)+\\)\\s-*(\\(.*\\))\\s-*\\(,\\|)\\s-*;\\)") + (setq rep (match-string-no-properties 3)) + (goto-char (match-end 0)) + (setq tpl-wild-list + (cons (list + (concat "^" + (verilog-string-replace-matches "@" "\\\\([0-9]+\\\\)" nil nil + (match-string 1)) + "$") + rep + templateno lineno) + tpl-wild-list))) + ((looking-at "[ \t\f]+") + (goto-char (match-end 0))) + ((looking-at "\n") + (setq lineno (1+ lineno)) + (goto-char (match-end 0))) + ((looking-at "//") + (search-forward "\n")) + ((looking-at "/\\*") + (forward-char 2) + (or (search-forward "*/") + (error "%s: Unmatched /* */, at char %d" (verilog-point-text) (point)))) + (t + (error "%s: AUTO_TEMPLATE parsing error: %s" + (verilog-point-text) + (progn (looking-at ".*$") (match-string 0)))) + )) + ;; Return + (vector tpl-regexp + (list tpl-sig-list tpl-wild-list))) + ;; If no template found + (t (vector tpl-regexp nil)))))) +;;(progn (find-file "auto-template.v") (verilog-read-auto-template "ptl_entry")) + +(defun verilog-set-define (defname defvalue &optional buffer enumname) + "Set the definition DEFNAME to the DEFVALUE in the given BUFFER. +Optionally associate it with the specified enumeration ENUMNAME." + (save-excursion + (set-buffer (or buffer (current-buffer))) + (let ((mac (intern (concat "vh-" defname)))) + ;;(message "Define %s=%s" defname defvalue) (sleep-for 1) + ;; Need to define to a constant if no value given + (set (make-variable-buffer-local mac) + (if (equal defvalue "") "1" defvalue))) + (if enumname + (let ((enumvar (intern (concat "venum-" enumname)))) + ;;(message "Define %s=%s" defname defvalue) (sleep-for 1) + (make-variable-buffer-local enumvar) + (add-to-list enumvar defname))) + )) + +(defun verilog-read-defines (&optional filename recurse subcall) + "Read `defines and parameters for the current file, or optional FILENAME. +If the filename is provided, `verilog-library-flags' will be used to +resolve it. If optional RECURSE is non-nil, recurse through `includes. + +Parameters must be simple assignments to constants, or have their own +\"parameter\" label rather then a list of parameters. Thus: + + parameter X = 5, Y = 10; // Ok + parameter X = {1'b1, 2'h2}; // Ok + parameter X = {1'b1, 2'h2}, Y = 10; // Bad, make into 2 parameter lines + +Defines must be simple text substitutions, one on a line, starting +at the beginning of the line. Any ifdefs or multiline comments around the +define are ignored. + +Defines are stored inside Emacs variables using the name vh-{definename}. + +This function is useful for setting vh-* variables. The file variables +feature can be used to set defines that `verilog-mode' can see; put at the +*END* of your file something like: + + // Local Variables: + // vh-macro:\"macro_definition\" + // End: + +If macros are defined earlier in the same file and you want their values, +you can read them automatically (provided `enable-local-eval' is on): + + // Local Variables: + // eval:(verilog-read-defines) + // eval:(verilog-read-defines \"group_standard_includes.v\") + // End: + +Note these are only read when the file is first visited, you must use +\\[find-alternate-file] RET to have these take effect after editing them! + +If you want to disable the \"Process `eval' or hook local variables\" +warning message, you need to add to your .emacs file: + + (setq enable-local-eval t)" + (let ((origbuf (current-buffer))) + (save-excursion + (unless subcall (verilog-getopt-flags)) + (when filename + (let ((fns (verilog-library-filenames filename (buffer-file-name)))) + (if fns + (set-buffer (find-file-noselect (car fns))) + (error (concat (verilog-point-text) + ": Can't find verilog-read-defines file: " filename))))) + (when recurse + (goto-char (point-min)) + (while (re-search-forward "^\\s-*`include\\s-+\\([^ \t\n\f]+\\)" nil t) + (let ((inc (verilog-string-replace-matches "\"" "" nil nil (match-string-no-properties 1)))) + (unless (verilog-inside-comment-p) + (verilog-read-defines inc recurse t))))) + ;; Read `defines + ;; note we don't use verilog-re... it's faster this way, and that + ;; function has problems when comments are at the end of the define + (goto-char (point-min)) + (while (re-search-forward "^\\s-*`define\\s-+\\([a-zA-Z0-9_$]+\\)\\s-+\\(.*\\)$" nil t) + (let ((defname (match-string-no-properties 1)) + (defvalue (match-string-no-properties 2))) + (setq defvalue (verilog-string-replace-matches "\\s-*/[/*].*$" "" nil nil defvalue)) + (verilog-set-define defname defvalue origbuf))) + ;; Hack: Read parameters + (goto-char (point-min)) + (while (re-search-forward + "^\\s-*\\(parameter\\|localparam\\)\\(\\(\\s-*\\[[^]]*\\]\\|\\)\\s-+\\([a-zA-Z0-9_$]+\\)\\s-*=\\s-*\\([^;,]*\\),?\\|\\)\\s-*" nil t) + (let ((var (match-string-no-properties 4)) + (val (match-string-no-properties 5)) + enumname) + ;; The primary way of getting defines is verilog-read-decls + ;; However, that isn't called yet for included files, so we'll add another scheme + (if (looking-at "[^\n]*synopsys\\s +enum\\s +\\([a-zA-Z0-9_]+\\)") + (setq enumname (match-string-no-properties 1))) + (if var + (verilog-set-define var val origbuf enumname)) + (forward-comment 999) + (while (looking-at "\\s-*,?\\s-*\\([a-zA-Z0-9_$]+\\)\\s-*=\\s-*\\([^;,]*\\),?\\s-*") + (verilog-set-define (match-string-no-properties 1) (match-string-no-properties 2) origbuf enumname) + (goto-char (match-end 0)) + (forward-comment 999)))) + ))) + +(defun verilog-read-includes () + "Read `includes for the current file. +This will find all of the `includes which are at the beginning of lines, +ignoring any ifdefs or multiline comments around them. +`verilog-read-defines' is then performed on the current and each included +file. + +It is often useful put at the *END* of your file something like: + + // Local Variables: + // eval:(verilog-read-defines) + // eval:(verilog-read-includes) + // End: + +Note includes are only read when the file is first visited, you must use +\\[find-alternate-file] RET to have these take effect after editing them! + +It is good to get in the habit of including all needed files in each .v +file that needs it, rather then waiting for compile time. This will aid +this process, Verilint, and readability. To prevent defining the same +variable over and over when many modules are compiled together, put a test +around the inside each include file: + +foo.v (a include): + `ifdef _FOO_V // include if not already included + `else + `define _FOO_V + ... contents of file + `endif // _FOO_V" +;;slow: (verilog-read-defines nil t)) + (save-excursion + (verilog-getopt-flags) + (goto-char (point-min)) + (while (re-search-forward "^\\s-*`include\\s-+\\([^ \t\n\f]+\\)" nil t) + (let ((inc (verilog-string-replace-matches "\"" "" nil nil (match-string 1)))) + (verilog-read-defines inc nil t))))) + +(defun verilog-read-signals (&optional start end) + "Return a simple list of all possible signals in the file. +Bounded by optional region from START to END. Overly aggressive but fast. +Some macros and such are also found and included. For dinotrace.el" + (let (sigs-all keywd) + (progn;save-excursion + (goto-char (or start (point-min))) + (setq end (or end (point-max))) + (while (re-search-forward "[\"/a-zA-Z_.%`]" end t) + (forward-char -1) + (cond + ((looking-at "//") + (search-forward "\n")) + ((looking-at "/\\*") + (search-forward "*/")) + ((looking-at "(\\*") + (or (looking-at "(\\*\\s-*)") ; It's a "always @ (*)" + (search-forward "*)"))) + ((eq ?\" (following-char)) + (re-search-forward "[^\\]\"")) ;; don't forward-char first, since we look for a non backslash first + ((looking-at "\\s-*\\([a-zA-Z0-9$_.%`]+\\)") + (goto-char (match-end 0)) + (setq keywd (match-string-no-properties 1)) + (or (member keywd verilog-keywords) + (member keywd sigs-all) + (setq sigs-all (cons keywd sigs-all)))) + (t (forward-char 1))) + ) + ;; Return list + sigs-all))) + +;; +;; Argument file parsing +;; + +(defun verilog-getopt (arglist) + "Parse -f, -v etc arguments in ARGLIST list or string." + (unless (listp arglist) (setq arglist (list arglist))) + (let ((space-args '()) + arg next-param) + ;; Split on spaces, so users can pass whole command lines + (while arglist + (setq arg (car arglist) + arglist (cdr arglist)) + (while (string-match "^\\([^ \t\n\f]+\\)[ \t\n\f]*\\(.*$\\)" arg) + (setq space-args (append space-args + (list (match-string-no-properties 1 arg)))) + (setq arg (match-string 2 arg)))) + ;; Parse arguments + (while space-args + (setq arg (car space-args) + space-args (cdr space-args)) + (cond + ;; Need another arg + ((equal arg "-f") + (setq next-param arg)) + ((equal arg "-v") + (setq next-param arg)) + ((equal arg "-y") + (setq next-param arg)) + ;; +libext+(ext1)+(ext2)... + ((string-match "^\\+libext\\+\\(.*\\)" arg) + (setq arg (match-string 1 arg)) + (while (string-match "\\([^+]+\\)\\+?\\(.*\\)" arg) + (verilog-add-list-unique `verilog-library-extensions + (match-string 1 arg)) + (setq arg (match-string 2 arg)))) + ;; + ((or (string-match "^-D\\([^+=]*\\)[+=]\\(.*\\)" arg) ;; -Ddefine=val + (string-match "^-D\\([^+=]*\\)\\(\\)" arg) ;; -Ddefine + (string-match "^\\+define\\([^+=]*\\)[+=]\\(.*\\)" arg) ;; +define+val + (string-match "^\\+define\\([^+=]*\\)\\(\\)" arg)) ;; +define+define + (verilog-set-define (match-string 1 arg) (match-string 2 arg))) + ;; + ((or (string-match "^\\+incdir\\+\\(.*\\)" arg) ;; +incdir+dir + (string-match "^-I\\(.*\\)" arg)) ;; -Idir + (verilog-add-list-unique `verilog-library-directories + (match-string 1 arg))) + ;; Ignore + ((equal "+librescan" arg)) + ((string-match "^-U\\(.*\\)" arg)) ;; -Udefine + ;; Second parameters + ((equal next-param "-f") + (setq next-param nil) + (verilog-getopt-file arg)) + ((equal next-param "-v") + (setq next-param nil) + (verilog-add-list-unique `verilog-library-files arg)) + ((equal next-param "-y") + (setq next-param nil) + (verilog-add-list-unique `verilog-library-directories arg)) + ;; Filename + ((string-match "^[^-+]" arg) + (verilog-add-list-unique `verilog-library-files arg)) + ;; Default - ignore; no warning + ) + ) + ) + ) +;;(verilog-getopt (list "+libext+.a+.b" "+incdir+foodir" "+define+a+aval" "-f" "otherf" "-v" "library" "-y" "dir")) + +(defun verilog-getopt-file (filename) + "Read verilog options from the specified FILENAME." + (save-excursion + (let ((fns (verilog-library-filenames filename (buffer-file-name))) + (orig-buffer (current-buffer)) + line) + (if fns + (set-buffer (find-file-noselect (car fns))) + (error (concat (verilog-point-text) + "Can't find verilog-getopt-file -f file: " filename))) + (goto-char (point-min)) + (while (not (eobp)) + (setq line (buffer-substring (point) + (save-excursion (end-of-line) (point)))) + (forward-line 1) + (when (string-match "//" line) + (setq line (substring line 0 (match-beginning 0)))) + (save-excursion + (set-buffer orig-buffer) ; Variables are buffer-local, so need right context. + (verilog-getopt line)))))) + +(defun verilog-getopt-flags () + "Convert `verilog-library-flags' into standard library variables." + ;; If the flags are local, then all the outputs should be local also + (when (local-variable-p `verilog-library-flags (current-buffer)) + (make-variable-buffer-local 'verilog-library-extensions) + (make-variable-buffer-local 'verilog-library-directories) + (make-variable-buffer-local 'verilog-library-files) + (make-variable-buffer-local 'verilog-library-flags)) + ;; Allow user to customize + (run-hooks 'verilog-before-getopt-flags-hook) + ;; Process arguments + (verilog-getopt verilog-library-flags) + ;; Allow user to customize + (run-hooks 'verilog-getopt-flags-hook)) + +(defun verilog-add-list-unique (varref object) + "Append to VARREF list the given OBJECT, +unless it is already a member of the variable's list" + (unless (member object (symbol-value varref)) + (set varref (append (symbol-value varref) (list object)))) + varref) +;;(progn (setq l '()) (verilog-add-list-unique `l "a") (verilog-add-list-unique `l "a") l) + + +;; +;; Module name lookup +;; + +(defun verilog-module-inside-filename-p (module filename) + "Return point if MODULE is specified inside FILENAME, else nil. +Allows version control to check out the file if need be." + (and (or (file-exists-p filename) + (and + (condition-case nil + (fboundp 'vc-backend) + (error nil)) + (vc-backend filename))) + (let (pt) + (save-excursion + (set-buffer (find-file-noselect filename)) + (goto-char (point-min)) + (while (and + ;; It may be tempting to look for verilog-defun-re, don't, it slows things down a lot! + (verilog-re-search-forward-quick "\\<module\\>" nil t) + (verilog-re-search-forward-quick "[(;]" nil t)) + (if (equal module (verilog-read-module-name)) + (setq pt (point)))) + pt)))) + +(defun verilog-is-number (symbol) + "Return true if SYMBOL is number-like." + (or (string-match "^[0-9 \t:]+$" symbol) + (string-match "^[---]*[0-9]+$" symbol) + (string-match "^[0-9 \t]+'s?[hdxbo][0-9a-fA-F_xz? \t]*$" symbol) + )) + +(defun verilog-symbol-detick (symbol wing-it) + "Return a expanded SYMBOL name without any defines. +If the variable vh-{symbol} is defined, return that value. +If undefined, and WING-IT, return just SYMBOL without the tick, else nil." + (while (and symbol (string-match "^`" symbol)) + (setq symbol (substring symbol 1)) + (setq symbol + (if (boundp (intern (concat "vh-" symbol))) + ;; Emacs has a bug where boundp on a buffer-local variable in only one + ;; buffer returns t in another. This can confuse, so check for nil. + (let ((val (eval (intern (concat "vh-" symbol))))) + (if (eq val nil) + (if wing-it symbol nil) + val)) + (if wing-it symbol nil)))) + symbol) +;;(verilog-symbol-detick "`mod" nil) + +(defun verilog-symbol-detick-denumber (symbol) + "Return SYMBOL with defines converted and any numbers dropped to nil." + (when (string-match "^`" symbol) + ;; This only will work if the define is a simple signal, not + ;; something like a[b]. Sorry, it should be substituted into the parser + (setq symbol + (verilog-string-replace-matches + "\[[^0-9: \t]+\]" "" nil nil + (or (verilog-symbol-detick symbol nil) + (if verilog-auto-sense-defines-constant + "0" + symbol))))) + (if (verilog-is-number symbol) + nil + symbol)) + +(defun verilog-expand-dirnames (&optional dirnames) + "Return a list of existing directories given a list of wildcarded DIRNAMES. +Or, just the existing dirnames themselves if there are no wildcards." + (interactive) + (unless dirnames (error "`verilog-library-directories' should include at least '.'")) + (setq dirnames (reverse dirnames)) ; not nreverse + (let ((dirlist nil) + pattern dirfile dirfiles dirname root filename rest) + (while dirnames + (setq dirname (substitute-in-file-name (car dirnames)) + dirnames (cdr dirnames)) + (cond ((string-match (concat "^\\(\\|[/\\]*[^*?]*[/\\]\\)" ;; root + "\\([^/\\]*[*?][^/\\]*\\)" ;; filename with *? + "\\(.*\\)") ;; rest + dirname) + (setq root (match-string 1 dirname) + filename (match-string 2 dirname) + rest (match-string 3 dirname) + pattern filename) + ;; now replace those * and ? with .+ and . + ;; use ^ and /> to get only whole file names + ;;verilog-string-replace-matches + (setq pattern (verilog-string-replace-matches "[*]" ".+" nil nil pattern) + pattern (verilog-string-replace-matches "[?]" "." nil nil pattern) + + ;; Unfortunately allows abc/*/rtl to match abc/rtl + ;; because abc/.. shows up in dirfiles. Solutions welcome. + dirfiles (if (file-directory-p root) ; Ignore version control external + (directory-files root t pattern nil))) + (while dirfiles + (setq dirfile (expand-file-name (concat (car dirfiles) rest)) + dirfiles (cdr dirfiles)) + (if (file-directory-p dirfile) + (setq dirlist (cons dirfile dirlist)))) + ) + ;; Defaults + (t + (if (file-directory-p dirname) + (setq dirlist (cons dirname dirlist)))) + )) + dirlist)) +;;(verilog-expand-dirnames (list "." ".." "nonexist" "../*" "/home/wsnyder/*/v")) + +(defun verilog-library-filenames (filename current &optional check-ext) + "Return a search path to find the given FILENAME name. +Uses the CURRENT filename, `verilog-library-directories' and +`verilog-library-extensions' variables to build the path. +With optional CHECK-EXT also check `verilog-library-extensions'." + (let ((ckdir (verilog-expand-dirnames verilog-library-directories)) + fn outlist) + (while ckdir + (let ((ckext (if check-ext verilog-library-extensions `("")))) + (while ckext + (setq fn (expand-file-name + (concat filename (car ckext)) + (expand-file-name (car ckdir) (file-name-directory current)))) + (if (file-exists-p fn) + (setq outlist (cons fn outlist))) + (setq ckext (cdr ckext)))) + (setq ckdir (cdr ckdir))) + (nreverse outlist))) + +(defun verilog-module-filenames (module current) + "Return a search path to find the given MODULE name. +Uses the CURRENT filename, `verilog-library-extensions', +`verilog-library-directories' and `verilog-library-files' +variables to build the path." + ;; Return search locations for it + (append (list current) ; first, current buffer + (verilog-library-filenames module current t) + verilog-library-files)) ; finally, any libraries + +;; +;; Module Information +;; +;; Many of these functions work on "modi" a module information structure +;; A modi is: [module-name-string file-name begin-point] + +(defvar verilog-cache-enabled t + "If true, enable caching of signals, etc. Set to nil for debugging to make things SLOW!") + +(defvar verilog-modi-cache-list nil + "Cache of ((Module Function) Buf-Tick Buf-Modtime Func-Returns)... +For speeding up verilog-modi-get-* commands. +Buffer-local.") + +(defvar verilog-modi-cache-preserve-tick nil + "Modification tick after which the cache is still considered valid. +Use verilog-preserve-cache's to set") +(defvar verilog-modi-cache-preserve-buffer nil + "Modification tick after which the cache is still considered valid. +Use verilog-preserve-cache's to set") + +(defun verilog-modi-current () + "Return the modi structure for the module currently at point." + (let* (name pt) + ;; read current module's name + (save-excursion + (verilog-re-search-backward-quick verilog-defun-re nil nil) + (verilog-re-search-forward-quick "(" nil nil) + (setq name (verilog-read-module-name)) + (setq pt (point))) + ;; return + (vector name (or (buffer-file-name) (current-buffer)) pt))) + +(defvar verilog-modi-lookup-last-mod nil "Cache of last module looked up.") +(defvar verilog-modi-lookup-last-modi nil "Cache of last modi returned.") +(defvar verilog-modi-lookup-last-current nil "Cache of last `current-buffer' looked up.") +(defvar verilog-modi-lookup-last-tick nil "Cache of last `buffer-modified-tick' looked up.") + +(defun verilog-modi-lookup (module allow-cache) + "Find the file and point at which MODULE is defined. +If ALLOW-CACHE is set, check and remember cache of previous lookups. +Return modi if successful, else print message." + (let* ((current (or (buffer-file-name) (current-buffer)))) + (cond ((and verilog-modi-lookup-last-modi + verilog-cache-enabled + allow-cache + (equal verilog-modi-lookup-last-mod module) + (equal verilog-modi-lookup-last-current current) + (equal verilog-modi-lookup-last-tick (buffer-modified-tick))) + ;; ok as is + ) + (t (let* ((realmod (verilog-symbol-detick module t)) + (orig-filenames (verilog-module-filenames realmod current)) + (filenames orig-filenames) + pt) + (while (and filenames (not pt)) + (if (not (setq pt (verilog-module-inside-filename-p realmod (car filenames)))) + (setq filenames (cdr filenames)))) + (cond (pt (setq verilog-modi-lookup-last-modi + (vector realmod (car filenames) pt))) + (t (setq verilog-modi-lookup-last-modi nil) + (error (concat (verilog-point-text) + ": Can't locate " module " module definition" + (if (not (equal module realmod)) + (concat " (Expanded macro to " realmod ")") + "") + "\n Check the verilog-library-directories variable." + "\n I looked in (if not listed, doesn't exist):\n\t" (mapconcat 'concat orig-filenames "\n\t")))) + ) + (setq verilog-modi-lookup-last-mod module + verilog-modi-lookup-last-current current + verilog-modi-lookup-last-tick (buffer-modified-tick))))) + verilog-modi-lookup-last-modi + )) + +(defsubst verilog-modi-name (modi) + (aref modi 0)) +(defsubst verilog-modi-file-or-buffer (modi) + (aref modi 1)) +(defsubst verilog-modi-point (modi) + (aref modi 2)) + +(defun verilog-modi-filename (modi) + "Filename of MODI, or name of buffer if its never been saved." + (if (bufferp (verilog-modi-file-or-buffer modi)) + (or (buffer-file-name (verilog-modi-file-or-buffer modi)) + (buffer-name (verilog-modi-file-or-buffer modi))) + (verilog-modi-file-or-buffer modi))) + +(defun verilog-modi-goto (modi) + "Move point/buffer to specified MODI." + (or modi (error "Passed unfound modi to goto, check earlier")) + (set-buffer (if (bufferp (verilog-modi-file-or-buffer modi)) + (verilog-modi-file-or-buffer modi) + (find-file-noselect (verilog-modi-file-or-buffer modi)))) + (or (equal major-mode `verilog-mode) ;; Put into verilog mode to get syntax + (verilog-mode)) + (goto-char (verilog-modi-point modi))) + +(defun verilog-goto-defun-file (module) + "Move point to the file at which a given MODULE is defined." + (interactive "sGoto File for Module: ") + (let* ((modi (verilog-modi-lookup module nil))) + (when modi + (verilog-modi-goto modi) + (switch-to-buffer (current-buffer))))) + +(defun verilog-modi-cache-results (modi function) + "Run on MODI the given FUNCTION. Locate the module in a file. +Cache the output of function so next call may have faster access." + (let (func-returns fass) + (save-excursion + (verilog-modi-goto modi) + (if (and (setq fass (assoc (list (verilog-modi-name modi) function) + verilog-modi-cache-list)) + ;; Destroy caching when incorrect; Modified or file changed + (not (and verilog-cache-enabled + (or (equal (buffer-modified-tick) (nth 1 fass)) + (and verilog-modi-cache-preserve-tick + (<= verilog-modi-cache-preserve-tick (nth 1 fass)) + (equal verilog-modi-cache-preserve-buffer (current-buffer)))) + (equal (visited-file-modtime) (nth 2 fass))))) + (setq verilog-modi-cache-list nil + fass nil)) + (cond (fass + ;; Found + (setq func-returns (nth 3 fass))) + (t + ;; Read from file + ;; Clear then restore any hilighting to make emacs19 happy + (let ((fontlocked (when (and (memq 'v19 verilog-emacs-features) + (boundp 'font-lock-mode) + font-lock-mode) + (font-lock-mode nil) + t))) + (setq func-returns (funcall function)) + (when fontlocked (font-lock-mode t))) + ;; Cache for next time + (make-variable-buffer-local 'verilog-modi-cache-list) + (setq verilog-modi-cache-list + (cons (list (list (verilog-modi-name modi) function) + (buffer-modified-tick) + (visited-file-modtime) + func-returns) + verilog-modi-cache-list))) + )) + ;; + func-returns)) + +(defun verilog-modi-cache-add (modi function element sig-list) + "Add function return results to the module cache. +Update MODI's cache for given FUNCTION so that the return ELEMENT of that +function now contains the additional SIG-LIST parameters." + (let (fass) + (save-excursion + (verilog-modi-goto modi) + (if (setq fass (assoc (list (verilog-modi-name modi) function) + verilog-modi-cache-list)) + (let ((func-returns (nth 3 fass))) + (aset func-returns element + (append sig-list (aref func-returns element)))))))) + +(defmacro verilog-preserve-cache (&rest body) + "Execute the BODY forms, allowing cache preservation within BODY. +This means that changes to the buffer will not result in the cache being +flushed. If the changes affect the modsig state, they must call the +modsig-cache-add-* function, else the results of later calls may be +incorrect. Without this, changes are assumed to be adding/removing signals +and invalidating the cache." + `(let ((verilog-modi-cache-preserve-tick (buffer-modified-tick)) + (verilog-modi-cache-preserve-buffer (current-buffer))) + (progn ,@body))) + +(defsubst verilog-modi-get-decls (modi) + (verilog-modi-cache-results modi 'verilog-read-decls)) + +(defsubst verilog-modi-get-sub-decls (modi) + (verilog-modi-cache-results modi 'verilog-read-sub-decls)) + +;; Signal reading for given module +;; Note these all take modi's - as returned from the verilog-modi-current function +(defsubst verilog-modi-get-outputs (modi) + (aref (verilog-modi-get-decls modi) 0)) +(defsubst verilog-modi-get-inouts (modi) + (aref (verilog-modi-get-decls modi) 1)) +(defsubst verilog-modi-get-inputs (modi) + (aref (verilog-modi-get-decls modi) 2)) +(defsubst verilog-modi-get-wires (modi) + (aref (verilog-modi-get-decls modi) 3)) +(defsubst verilog-modi-get-regs (modi) + (aref (verilog-modi-get-decls modi) 4)) +(defsubst verilog-modi-get-assigns (modi) + (aref (verilog-modi-get-decls modi) 5)) +(defsubst verilog-modi-get-consts (modi) + (aref (verilog-modi-get-decls modi) 6)) +(defsubst verilog-modi-get-gparams (modi) + (aref (verilog-modi-get-decls modi) 7)) +(defsubst verilog-modi-get-sub-outputs (modi) + (aref (verilog-modi-get-sub-decls modi) 0)) +(defsubst verilog-modi-get-sub-inouts (modi) + (aref (verilog-modi-get-sub-decls modi) 1)) +(defsubst verilog-modi-get-sub-inputs (modi) + (aref (verilog-modi-get-sub-decls modi) 2)) + + +(defun verilog-signals-matching-enum (in-list enum) + "Return all signals in IN-LIST matching the given ENUM." + (let (out-list) + (while in-list + (if (equal (verilog-sig-enum (car in-list)) enum) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + ;; New scheme + (let* ((enumvar (intern (concat "venum-" enum))) + (enumlist (and (boundp enumvar) (eval enumvar)))) + (while enumlist + (add-to-list 'out-list (list (car enumlist))) + (setq enumlist (cdr enumlist)))) + (nreverse out-list))) + +(defun verilog-signals-not-matching-regexp (in-list regexp) + "Return all signals in IN-LIST not matching the given REGEXP, if non-nil." + (if (not regexp) + in-list + (let (out-list) + (while in-list + (if (not (string-match regexp (verilog-sig-name (car in-list)))) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list)))) + +;; Combined +(defun verilog-modi-get-signals (modi) + (append + (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi) + (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-assigns modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi))) + +(defun verilog-modi-get-ports (modi) + (append + (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi))) + +(defsubst verilog-modi-cache-add-outputs (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 0 sig-list)) +(defsubst verilog-modi-cache-add-inouts (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 1 sig-list)) +(defsubst verilog-modi-cache-add-inputs (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 2 sig-list)) +(defsubst verilog-modi-cache-add-wires (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 3 sig-list)) +(defsubst verilog-modi-cache-add-regs (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 4 sig-list)) + +(defun verilog-signals-from-signame (signame-list) + "Return signals in standard form from SIGNAME-LIST, a simple list of signal names." + (mapcar (function (lambda (name) (list name nil nil))) + signame-list)) + +;; +;; Auto creation utilities +;; + +(defun verilog-auto-search-do (search-for func) + "Search for the given auto text SEARCH-FOR, and perform FUNC where it occurs." + (goto-char (point-min)) + (while (search-forward search-for nil t) + (if (not (save-excursion + (goto-char (match-beginning 0)) + (verilog-inside-comment-p))) + (funcall func)))) + +(defun verilog-auto-re-search-do (search-for func) + "Search for the given auto text SEARCH-FOR, and perform FUNC where it occurs." + (goto-char (point-min)) + (while (re-search-forward search-for nil t) + (if (not (save-excursion + (goto-char (match-beginning 0)) + (verilog-inside-comment-p))) + (funcall func)))) + +(defun verilog-insert-one-definition (sig type indent-pt) + "Print out a definition for SIGNAL of the given TYPE, +with appropriate INDENT-PT indentation." + (indent-to indent-pt) + (insert type) + (when (verilog-sig-signed sig) + (insert " " (verilog-sig-signed sig))) + (when (verilog-sig-multidim sig) + (insert " " (verilog-sig-multidim-string sig))) + (when (verilog-sig-bits sig) + (insert " " (verilog-sig-bits sig))) + (indent-to (max 24 (+ indent-pt 16))) + (unless (= (char-syntax (preceding-char)) ?\ ) + (insert " ")) ; Need space between "]name" if indent-to did nothing + (insert (verilog-sig-name sig))) + +(defun verilog-insert-definition (sigs direction indent-pt v2k &optional dont-sort) + "Print out a definition for a list of SIGS of the given DIRECTION, +with appropriate INDENT-PT indentation. If V2K, use Verilog 2001 I/O +format. Sort unless DONT-SORT. DIRECTION is normally wire/reg/output." + (or dont-sort + (setq sigs (sort (copy-alist sigs) `verilog-signals-sort-compare))) + (while sigs + (let ((sig (car sigs))) + (verilog-insert-one-definition + sig + ;; Want "type x" or "output type x", not "wire type x" + (cond ((verilog-sig-type sig) + (concat + (if (not (equal direction "wire")) + (concat direction " ")) + (verilog-sig-type sig))) + (t direction)) + indent-pt) + (insert (if v2k "," ";")) + (if (or (not (verilog-sig-comment sig)) + (equal "" (verilog-sig-comment sig))) + (insert "\n") + (indent-to (max 48 (+ indent-pt 40))) + (insert (concat "// " (verilog-sig-comment sig) "\n"))) + (setq sigs (cdr sigs))))) + +(eval-when-compile + (if (not (boundp 'indent-pt)) + (defvar indent-pt nil "Local used by insert-indent"))) + +(defun verilog-insert-indent (&rest stuff) + "Indent to position stored in local `indent-pt' variable, then insert STUFF. +Presumes that any newlines end a list element." + (let ((need-indent t)) + (while stuff + (if need-indent (indent-to indent-pt)) + (setq need-indent nil) + (insert (car stuff)) + (setq need-indent (string-match "\n$" (car stuff)) + stuff (cdr stuff))))) +;;(let ((indent-pt 10)) (verilog-insert-indent "hello\n" "addon" "there\n")) + +(defun verilog-repair-open-comma () + "If backwards-from-point is other then a open parenthesis insert comma." + (save-excursion + (verilog-backward-syntactic-ws) + (when (save-excursion + (backward-char 1) + (and (not (looking-at "[(,]")) + (progn + (verilog-re-search-backward "[(`]" nil t) + (looking-at "(")))) + (insert ",")))) + +(defun verilog-repair-close-comma () + "If point is at a comma followed by a close parenthesis, fix it. +This repairs those mis-inserted by a AUTOARG." + ;; It would be much nicer if Verilog allowed extra commas like Perl does! + (save-excursion + (verilog-forward-close-paren) + (backward-char 1) + (verilog-backward-syntactic-ws) + (backward-char 1) + (when (looking-at ",") + (delete-char 1)))) + +(defun verilog-get-list (start end) + "Return the elements of a comma separated list between START and END." + (interactive) + (let ((my-list (list)) + my-string) + (save-excursion + (while (< (point) end) + (when (re-search-forward "\\([^,{]+\\)" end t) + (setq my-string (verilog-string-remove-spaces (match-string 1))) + (setq my-list (nconc my-list (list my-string) )) + (goto-char (match-end 0)))) + my-list))) + +(defun verilog-make-width-expression (range-exp) + "Return an expression calculating the length of a range [x:y] in RANGE-EXP." + ;; strip off the [] + (cond ((not range-exp) + "1") + (t + (if (string-match "^\\[\\(.*\\)\\]$" range-exp) + (setq range-exp (match-string 1 range-exp))) + (cond ((not range-exp) + "1") + ((string-match "^\\s *\\([0-9]+\\)\\s *:\\s *\\([0-9]+\\)\\s *$" range-exp) + (int-to-string (1+ (abs (- (string-to-int (match-string 1 range-exp)) + (string-to-int (match-string 2 range-exp))))))) + ((string-match "^\\(.*\\)\\s *:\\s *\\(.*\\)\\s *$" range-exp) + (concat "(1+(" (match-string 1 range-exp) + ")" + (if (equal "0" (match-string 2 range-exp)) ;; Don't bother with -(0) + "" + (concat "-(" (match-string 2 range-exp) ")")) + ")")) + (t nil))))) +;;(verilog-make-width-expression "`A:`B") + +(defun verilog-typedef-name-p (variable-name) + "Return true if the VARIABLE-NAME is a type definition." + (when verilog-typedef-regexp + (string-match verilog-typedef-regexp variable-name))) + +;; +;; Auto deletion +;; + +(defun verilog-delete-autos-lined () + "Delete autos that occupy multiple lines, between begin and end comments." + (let ((pt (point))) + (forward-line 1) + (when (and + (looking-at "\\s-*// Beginning") + (search-forward "// End of automatic" nil t)) + ;; End exists + (end-of-line) + (delete-region pt (point)) + (forward-line 1)) + )) + +(defun verilog-forward-close-paren () + "Find the close parenthesis that match the current point, +ignore other close parenthesis with matching open parens" + (let ((parens 1)) + (while (> parens 0) + (unless (verilog-re-search-forward-quick "[()]" nil t) + (error "%s: Mismatching ()" (verilog-point-text))) + (cond ((= (preceding-char) ?\( ) + (setq parens (1+ parens))) + ((= (preceding-char) ?\) ) + (setq parens (1- parens))))))) + +(defun verilog-backward-open-paren () + "Find the open parenthesis that match the current point, +ignore other open parenthesis with matching close parens" + (let ((parens 1)) + (while (> parens 0) + (unless (verilog-re-search-backward-quick "[()]" nil t) + (error "%s: Mismatching ()" (verilog-point-text))) + (cond ((= (following-char) ?\) ) + (setq parens (1+ parens))) + ((= (following-char) ?\( ) + (setq parens (1- parens))))))) + +(defun verilog-backward-open-bracket () + "Find the open bracket that match the current point, +ignore other open bracket with matching close bracket" + (let ((parens 1)) + (while (> parens 0) + (unless (verilog-re-search-backward-quick "[][]" nil t) + (error "%s: Mismatching []" (verilog-point-text))) + (cond ((= (following-char) ?\] ) + (setq parens (1+ parens))) + ((= (following-char) ?\[ ) + (setq parens (1- parens))))))) + +(defun verilog-delete-to-paren () + "Delete the automatic inst/sense/arg created by autos. +Deletion stops at the matching end parenthesis." + (delete-region (point) + (save-excursion + (verilog-backward-open-paren) + (forward-sexp 1) ;; Moves to paren that closes argdecl's + (backward-char 1) + (point)))) + +(defun verilog-auto-star-safe () + "Return if a .* AUTOINST is safe to delete or expand. +It was created by the AUTOS themselves, or by the user." + (and verilog-auto-star-expand + (looking-at "[ \t\n\f,]*\\([)]\\|// \\(Outputs\\|Inouts\\|Inputs\\)\\)"))) + +(defun verilog-delete-auto-star-all () + "Delete a .* AUTOINST, if it is safe." + (when (verilog-auto-star-safe) + (verilog-delete-to-paren))) + +(defun verilog-delete-auto-star-implicit () + "Delete all .* implicit connections created by `verilog-auto-star'. +This function will be called automatically at save unless +`verilog-auto-star-save' is set, any non-templated expanded pins will be +removed." + (interactive) + (let (paren-pt indent have-close-paren) + (save-excursion + (goto-char (point-min)) + ;; We need to match these even outside of comments. + ;; For reasonable performance, we don't check if inside comments, sorry. + (while (re-search-forward "// Implicit \\.\\*" nil t) + (setq paren-pt (point)) + (beginning-of-line) + (setq have-close-paren + (save-excursion + (when (search-forward ");" paren-pt t) + (setq indent (current-indentation)) + t))) + (delete-region (point) (+ 1 paren-pt)) ; Nuke line incl CR + (when have-close-paren + ;; Delete extra commentary + (save-excursion + (while (progn + (forward-line -1) + (looking-at "\\s *//\\s *\\(Outputs\\|Inouts\\|Inputs\\)\n")) + (delete-region (match-beginning 0) (match-end 0)))) + ;; If it is simple, we can put the ); on the same line as the last text + (let ((rtn-pt (point))) + (save-excursion + (while (progn (backward-char 1) + (looking-at "[ \t\n\f]"))) + (when (looking-at ",") + (delete-region (+ 1 (point)) rtn-pt)))) + (when (bolp) + (indent-to indent)) + (insert ");\n") + ;; Still need to kill final comma - always is one as we put one after the .* + (re-search-backward ",") + (delete-char 1)))))) + +(defun verilog-delete-auto () + "Delete the automatic outputs, regs, and wires created by \\[verilog-auto]. +Use \\[verilog-auto] to re-insert the updated AUTOs. + +The hooks `verilog-before-delete-auto-hook' and `verilog-delete-auto-hook' are +called before and after this function, respectively." + (interactive) + (save-excursion + (if (buffer-file-name) + (find-file-noselect (buffer-file-name))) ;; To check we have latest version + ;; Allow user to customize + (run-hooks 'verilog-before-delete-auto-hook) + + ;; Remove those that have multi-line insertions + (verilog-auto-re-search-do "/\\*AUTO\\(OUTPUTEVERY\\|CONCATCOMMENT\\|WIRE\\|REG\\|DEFINEVALUE\\|REGINPUT\\|INPUT\\|OUTPUT\\|INOUT\\|RESET\\|TIEOFF\\|UNUSED\\)\\*/" + 'verilog-delete-autos-lined) + ;; Remove those that have multi-line insertions with parameters + (verilog-auto-re-search-do "/\\*AUTO\\(INOUTMODULE\\|ASCIIENUM\\)([^)]*)\\*/" + 'verilog-delete-autos-lined) + ;; Remove those that are in parenthesis + (verilog-auto-re-search-do "/\\*\\(AS\\|AUTO\\(ARG\\|CONCATWIDTH\\|INST\\|INSTPARAM\\|SENSE\\)\\)\\*/" + 'verilog-delete-to-paren) + ;; Do .* instantiations, but avoid removing any user pins by looking for our magic comments + (verilog-auto-re-search-do "\\.\\*" + 'verilog-delete-auto-star-all) + ;; Remove template comments ... anywhere in case was pasted after AUTOINST removed + (goto-char (point-min)) + (while (re-search-forward "\\s-*// \\(Templated\\|Implicit \\.\\*\\)[ \tLT0-9]*$" nil t) + (replace-match "")) + + ;; Final customize + (run-hooks 'verilog-delete-auto-hook))) + +;; +;; Auto inject +;; + +(defun verilog-inject-auto () + "Examine legacy non-AUTO code and insert AUTOs in appropriate places. + +Any always @ blocks with sensitivity lists that match computed lists will +be replaced with /*AS*/ comments. + +Any cells will get /*AUTOINST*/ added to the end of the pin list. Pins with +have identical names will be deleted. + +Argument lists will not be deleted, /*AUTOARG*/ will only be inserted to +support adding new ports. You may wish to delete older ports yourself. + +For example: + + module ex_inject (i, o); + input i; + input j; + output o; + always @ (i or j) + o = i | j; + cell cell (.foobar(baz), + .j(j)); + endmodule + +Typing \\[verilog-inject-auto] will make this into: + + module ex_inject (i, o/*AUTOARG*/ + // Inputs + j); + input i; + output o; + always @ (/*AS*/i or j) + o = i | j; + cell cell (.foobar(baz), + /*AUTOINST*/ + // Outputs + .j(j)); + endmodule" + (interactive) + (verilog-auto t)) + +(defun verilog-inject-arg () + "Inject AUTOARG into new code. See `verilog-inject-auto'." + ;; Presume one module per file. + (save-excursion + (goto-char (point-min)) + (while (verilog-re-search-forward-quick "\\<module\\>" nil t) + (let ((endmodp (save-excursion + (verilog-re-search-forward-quick "\\<endmodule\\>" nil t) + (point)))) + ;; See if there's already a comment .. inside a comment so not verilog-re-search + (when (not (re-search-forward "/\\*AUTOARG\\*/" endmodp t)) + (verilog-re-search-forward-quick ";" nil t) + (backward-char 1) + (verilog-backward-syntactic-ws) + (backward-char 1) ; Moves to paren that closes argdecl's + (when (looking-at ")") + (insert "/*AUTOARG*/"))))))) + +(defun verilog-inject-sense () + "Inject AUTOSENSE into new code. See `verilog-inject-auto'." + (save-excursion + (goto-char (point-min)) + (while (verilog-re-search-forward-quick "\\<always\\s *@\\s *(" nil t) + (let ((start-pt (point)) + (modi (verilog-modi-current)) + pre-sigs + got-sigs) + (backward-char 1) + (forward-sexp 1) + (backward-char 1) ;; End ) + (when (not (verilog-re-search-backward "/\\*\\(AUTOSENSE\\|AS\\)\\*/" start-pt t)) + (setq pre-sigs (verilog-signals-from-signame + (verilog-read-signals start-pt (point))) + got-sigs (verilog-auto-sense-sigs modi nil)) + (when (not (or (verilog-signals-not-in pre-sigs got-sigs) ; Both are equal? + (verilog-signals-not-in got-sigs pre-sigs))) + (delete-region start-pt (point)) + (insert "/*AS*/"))))))) + +(defun verilog-inject-inst () + "Inject AUTOINST into new code. See `verilog-inject-auto'." + (save-excursion + (goto-char (point-min)) + ;; It's hard to distinguish modules; we'll instead search for pins. + (while (verilog-re-search-forward-quick "\\.\\s *[a-zA-Z0-9`_\$]+\\s *(\\s *[a-zA-Z0-9`_\$]+\\s *)" nil t) + (verilog-backward-open-paren) ;; Inst start + (cond + ((= (preceding-char) ?\#) ;; #(...) parameter section, not pin. Skip. + (forward-char 1) + (verilog-forward-close-paren)) ;; Parameters done + (t + (forward-char 1) + (let ((indent-pt (+ (current-column))) + (end-pt (save-excursion (verilog-forward-close-paren) (point)))) + (cond ((verilog-re-search-forward "\\(/\\*AUTOINST\\*/\\|\\.\\*\\)" end-pt t) + (goto-char end-pt)) ;; Already there, continue search with next instance + (t + ;; Delete identical interconnect + (let ((case-fold-search nil)) ;; So we don't convert upper-to-lower, etc + (while (verilog-re-search-forward "\\.\\s *\\([a-zA-Z0-9`_\$]+\\)*\\s *(\\s *\\1\\s *)\\s *" end-pt t) + (delete-region (match-beginning 0) (match-end 0)) + (setq end-pt (- end-pt (- (match-end 0) (match-beginning 0)))) ;; Keep it correct + (while (or (looking-at "[ \t\n\f,]+") + (looking-at "//[^\n]*")) + (delete-region (match-beginning 0) (match-end 0)) + (setq end-pt (- end-pt (- (match-end 0) (match-beginning 0))))))) + (verilog-forward-close-paren) + (backward-char 1) + ;; Not verilog-re-search, as we don't want to strip comments + (while (re-search-backward "[ \t\n\f]+" (- (point) 1) t) + (delete-region (match-beginning 0) (match-end 0))) + (insert "\n") + (indent-to indent-pt) + (insert "/*AUTOINST*/"))))))))) + +;; +;; Auto save +;; + +(defun verilog-auto-save-check () + "On saving see if we need auto update." + (cond ((not verilog-auto-save-policy)) ; disabled + ((not (save-excursion + (save-match-data + (let ((case-fold-search nil)) + (goto-char (point-min)) + (re-search-forward "AUTO" nil t)))))) + ((eq verilog-auto-save-policy 'force) + (verilog-auto)) + ((not (buffer-modified-p))) + ((eq verilog-auto-update-tick (buffer-modified-tick))) ; up-to-date + ((eq verilog-auto-save-policy 'detect) + (verilog-auto)) + (t + (when (yes-or-no-p "AUTO statements not recomputed, do it now? ") + (verilog-auto)) + ;; Don't ask again if didn't update + (set (make-local-variable 'verilog-auto-update-tick) (buffer-modified-tick)) + )) + (when (not verilog-auto-star-save) + (verilog-delete-auto-star-implicit)) + nil) ;; Always return nil -- we don't write the file ourselves + +(defun verilog-auto-read-locals () + "Return file local variable segment at bottom of file." + (save-excursion + (goto-char (point-max)) + (if (re-search-backward "Local Variables:" nil t) + (buffer-substring-no-properties (point) (point-max)) + ""))) + +(defun verilog-auto-reeval-locals (&optional force) + "Read file local variable segment at bottom of file if it has changed. +If FORCE, always reread it." + (make-variable-buffer-local 'verilog-auto-last-file-locals) + (let ((curlocal (verilog-auto-read-locals))) + (when (or force (not (equal verilog-auto-last-file-locals curlocal))) + (setq verilog-auto-last-file-locals curlocal) + ;; Note this may cause this function to be recursively invoked. + ;; The above when statement will prevent it from recursing forever. + (hack-local-variables) + t))) + +;; +;; Auto creation +;; + +(defun verilog-auto-arg-ports (sigs message indent-pt) + "Print a list of ports for a AUTOINST. +Takes SIGS list, adds MESSAGE to front and inserts each at INDENT-PT." + (when sigs + (insert "\n") + (indent-to indent-pt) + (insert message) + (insert "\n") + (let ((space "")) + (indent-to indent-pt) + (while sigs + (cond ((> (+ 2 (current-column) (length (verilog-sig-name (car sigs)))) fill-column) + (insert "\n") + (indent-to indent-pt)) + (t (insert space))) + (insert (verilog-sig-name (car sigs)) ",") + (setq sigs (cdr sigs) + space " "))))) + +(defun verilog-auto-arg () + "Expand AUTOARG statements. +Replace the argument declarations at the beginning of the +module with ones automatically derived from input and output +statements. This can be dangerous if the module is instantiated +using position-based connections, so use only name-based when +instantiating the resulting module. Long lines are split based +on the `fill-column', see \\[set-fill-column]. + +Limitations: + Concatenation and outputting partial busses is not supported. + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + +For example: + + module ex_arg (/*AUTOARG*/); + input i; + output o; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_arg (/*AUTOARG*/ + // Outputs + o, + // Inputs + i + ); + input i; + output o; + endmodule + +Any ports declared between the ( and /*AUTOARG*/ are presumed to be +predeclared and are not redeclared by AUTOARG. AUTOARG will make a +conservative guess on adding a comma for the first signal, if you have any +ifdefs or complicated expressions before the AUTOARG you will need to +choose the comma yourself. + +Avoid declaring ports manually, as it makes code harder to maintain." + (save-excursion + (let ((modi (verilog-modi-current)) + (skip-pins (aref (verilog-read-arg-pins) 0))) + (verilog-repair-open-comma) + (verilog-auto-arg-ports (verilog-signals-not-in + (verilog-modi-get-outputs modi) + skip-pins) + "// Outputs" + verilog-indent-level-declaration) + (verilog-auto-arg-ports (verilog-signals-not-in + (verilog-modi-get-inouts modi) + skip-pins) + "// Inouts" + verilog-indent-level-declaration) + (verilog-auto-arg-ports (verilog-signals-not-in + (verilog-modi-get-inputs modi) + skip-pins) + "// Inputs" + verilog-indent-level-declaration) + (verilog-repair-close-comma) + (unless (eq (char-before) ?/ ) + (insert "\n")) + (indent-to verilog-indent-level-declaration) + ))) + +(defun verilog-auto-inst-port-map (port-st) + nil) + +(defvar vector-skip-list nil) ; Prevent compile warning +(defvar vl-cell-type nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-cell-name nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-name nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-width nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-dir nil "See `verilog-auto-inst'.") ; Prevent compile warning + +(defun verilog-auto-inst-port (port-st indent-pt tpl-list tpl-num for-star) + "Print out a instantiation connection for this PORT-ST. +Insert to INDENT-PT, use template TPL-LIST. +@ are instantiation numbers, replaced with TPL-NUM. +@\"(expression @)\" are evaluated, with @ as a variable." + (let* ((port (verilog-sig-name port-st)) + (tpl-ass (or (assoc port (car tpl-list)) + (verilog-auto-inst-port-map port-st))) + ;; vl-* are documented for user use + (vl-name (verilog-sig-name port-st)) + (vl-width (verilog-sig-width port-st)) + (vl-bits (if (or verilog-auto-inst-vector + (not (assoc port vector-skip-list)) + (not (equal (verilog-sig-bits port-st) + (verilog-sig-bits (assoc port vector-skip-list))))) + (or (verilog-sig-bits port-st) "") + "")) + ;; Default if not found + (tpl-net (if (verilog-sig-multidim port-st) + (concat port "/*" (verilog-sig-multidim-string port-st) + vl-bits "*/") + (concat port vl-bits)))) + ;; Find template + (cond (tpl-ass ; Template of exact port name + (setq tpl-net (nth 1 tpl-ass))) + ((nth 1 tpl-list) ; Wildcards in template, search them + (let ((wildcards (nth 1 tpl-list))) + (while wildcards + (when (string-match (nth 0 (car wildcards)) port) + (setq tpl-ass (car wildcards) ; so allow @ parsing + tpl-net (replace-match (nth 1 (car wildcards)) + t nil port))) + (setq wildcards (cdr wildcards)))))) + ;; Parse Templated variable + (when tpl-ass + ;; Evaluate @"(lispcode)" + (when (string-match "@\".*[^\\]\"" tpl-net) + (while (string-match "@\"\\(\\([^\\\"]*\\(\\\\.\\)*\\)*\\)\"" tpl-net) + (setq tpl-net + (concat + (substring tpl-net 0 (match-beginning 0)) + (save-match-data + (let* ((expr (match-string 1 tpl-net)) + (value + (progn + (setq expr (verilog-string-replace-matches "\\\\\"" "\"" nil nil expr)) + (setq expr (verilog-string-replace-matches "@" tpl-num nil nil expr)) + (prin1 (eval (car (read-from-string expr))) + (lambda (ch) ()))))) + (if (numberp value) (setq value (number-to-string value))) + value + )) + (substring tpl-net (match-end 0)))))) + ;; Replace @ and [] magic variables in final output + (setq tpl-net (verilog-string-replace-matches "@" tpl-num nil nil tpl-net)) + (setq tpl-net (verilog-string-replace-matches "\\[\\]" vl-bits nil nil tpl-net)) + ) + (indent-to indent-pt) + (insert "." port) + (indent-to verilog-auto-inst-column) + (insert "(" tpl-net "),") + (cond (tpl-ass + (indent-to (+ (if (< verilog-auto-inst-column 48) 24 16) + verilog-auto-inst-column)) + (insert " // Templated") + (when verilog-auto-inst-template-numbers + (insert " T" (int-to-string (nth 2 tpl-ass)) + " L" (int-to-string (nth 3 tpl-ass))))) + (for-star + (indent-to (+ (if (< verilog-auto-inst-column 48) 24 16) + verilog-auto-inst-column)) + (insert " // Implicit .\*"))) ;For some reason the . or * must be escaped... + (insert "\n"))) +;;(verilog-auto-inst-port (list "foo" "[5:0]") 10 (list (list "foo" "a@\"(% (+ @ 1) 4)\"a")) "3") +;;(x "incom[@\"(+ (* 8 @) 7)\":@\"(* 8 @)\"]") +;;(x ".out (outgo[@\"(concat (+ (* 8 @) 7) \\\":\\\" ( * 8 @))\"]));") + +(defun verilog-auto-inst-first () + "Insert , etc before first ever port in this instant, as part of \\[verilog-auto-inst]." + ;; Do we need a trailing comma? + ;; There maybe a ifdef or something similar before us. What a mess. Thus + ;; to avoid trouble we only insert on preceeding ) or *. + ;; Insert first port on new line + (insert "\n") ;; Must insert before search, so point will move forward if insert comma + (save-excursion + (verilog-re-search-backward "[^ \t\n\f]" nil nil) + (when (looking-at ")\\|\\*") ;; Generally don't insert, unless we are fairly sure + (forward-char 1) + (insert ",")))) + +(defun verilog-auto-star () + "Expand SystemVerilog .* pins, as part of \\[verilog-auto]. + +If `verilog-auto-star-expand' is set, .* pins are treated if they were +AUTOINST statements, otherwise they are ignored. For safety, Verilog-Mode +will also ignore any .* that are not last in your pin list (this prevents +it from deleting pins following the .* when it expands the AUTOINST.) + +On writing your file, unless `verilog-auto-star-save' is set, any +non-templated expanded pins will be removed. You may do this at any time +with \\[verilog-delete-auto-star-implicit]. + +If you are converting a module to use .* for the first time, you may wish +to use \\[verilog-inject-auto] and then replace the created AUTOINST with .*. + +See `verilog-auto-inst' for examples, templates, and more information." + (when (verilog-auto-star-safe) + (verilog-auto-inst))) + +(defun verilog-auto-inst () + "Expand AUTOINST statements, as part of \\[verilog-auto]. +Replace the pin connections to an instantiation with ones +automatically derived from the module header of the instantiated netlist. + +If `verilog-auto-star-expand' is set, also expand SystemVerilog .* ports, +and delete them before saving unless `verilog-auto-star-save' is set. +See `verilog-auto-star' for more information. + +Limitations: + Module names must be resolvable to filenames by adding a + `verilog-library-extensions', and being found in the same directory, or + by changing the variable `verilog-library-flags' or + `verilog-library-directories'. Macros `modname are translated through the + vh-{name} Emacs variable, if that is not found, it just ignores the `. + + In templates you must have one signal per line, ending in a ), or ));, + and have proper () nesting, including a final ); to end the template. + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + SystemVerilog multidimmensional input/output has only experimental support. + +For example, first take the submodule inst.v: + + module inst (o,i) + output [31:0] o; + input i; + wire [31:0] o = {32{i}}; + endmodule + +This is then used in a upper level module: + + module ex_inst (o,i) + output o; + input i; + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_inst (o,i) + output o; + input i; + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule + +Where the list of inputs and outputs came from the inst module. + +Exceptions: + + Unless you are instantiating a module multiple times, or the module is + something trivial like a adder, DO NOT CHANGE SIGNAL NAMES ACROSS HIERARCHY. + It just makes for unmaintainable code. To sanitize signal names, try + vrename from http://www.veripool.com + + When you need to violate this suggestion there are two ways to list + exceptions, placing them before the AUTOINST, or using templates. + + Any ports defined before the /*AUTOINST*/ are not included in the list of + automatics. This is similar to making a template as described below, but + is restricted to simple connections just like you normally make. Also note + that any signals before the AUTOINST will only be picked up by AUTOWIRE if + you have the appropriate // Input or // Output comment, and exactly the + same line formatting as AUTOINST itself uses. + + inst inst (// Inputs + .i (my_i_dont_mess_with_it), + /*AUTOINST*/ + // Outputs + .ov (ov[31:0])); + + +Templates: + + For multiple instantiations based upon a single template, create a + commented out template: + + /* instantiating_module_name AUTO_TEMPLATE ( + .sig3 (sigz[]), + ); + */ + + Templates go ABOVE the instantiation(s). When a instantiation is + expanded `verilog-mode' simply searches up for the closest template. + Thus you can have multiple templates for the same module, just alternate + between the template for a instantiation and the instantiation itself. + + The module name must be the same as the name of the module in the + instantiation name, and the code \"AUTO_TEMPLATE\" must be in these exact + words and capitalized. Only signals that must be different for each + instantiation need to be listed. + + Inside a template, a [] in a connection name (with nothing else inside + the brackets) will be replaced by the same bus subscript as it is being + connected to, or the [] will be removed if it is a single bit signal. + Generally it is a good idea to do this for all connections in a template, + as then they will work for any width signal, and with AUTOWIRE. See + PTL_BUS becoming PTL_BUSNEW below. + + If you have a complicated template, set `verilog-auto-inst-template-numbers' + to see which regexps are matching. Don't leave that mode set after + debugging is completed though, it will result in lots of extra differences + and merge conflicts. + + For example: + + /* psm_mas AUTO_TEMPLATE ( + .ptl_bus (ptl_busnew[]), + ); + */ + psm_mas ms2m (/*AUTOINST*/); + + Typing \\[verilog-auto] will make this into: + + psm_mas ms2m (/*AUTOINST*/ + // Outputs + .NotInTemplate (NotInTemplate), + .ptl_bus (ptl_busnew[3:0]), // Templated + .... + +@ Templates: + + It is common to instantiate a cell multiple times, so templates make it + trivial to substitute part of the cell name into the connection name. + + /* cell_type AUTO_TEMPLATE <optional \"REGEXP\"> ( + .sig1 (sigx[@]), + .sig2 (sigy[@\"(% (+ 1 @) 4)\"]), + ); + */ + + If no regular expression is provided immediately after the AUTO_TEMPLATE + keyword, then the @ character in any connection names will be replaced + with the instantiation number; the first digits found in the cell's + instantiation name. + + If a regular expression is provided, the @ character will be replaced + with the first \(\) grouping that matches against the cell name. Using a + regexp of \"\\([0-9]+\\)\" provides identical values for @ as when no + regexp is provided. If you use multiple layers of parenthesis, + \"test\\([^0-9]+\\)_\\([0-9]+\\)\" would replace @ with non-number + characters after test and before _, whereas + \"\\(test\\([a-z]+\\)_\\([0-9]+\\)\\)\" would replace @ with the entire + match. + + For example: + + /* psm_mas AUTO_TEMPLATE ( + .ptl_mapvalidx (ptl_mapvalid[@]), + .ptl_mapvalidp1x (ptl_mapvalid[@\"(% (+ 1 @) 4)\"]), + ); + */ + psm_mas ms2m (/*AUTOINST*/); + + Typing \\[verilog-auto] will make this into: + + psm_mas ms2m (/*AUTOINST*/ + // Outputs + .ptl_mapvalidx (ptl_mapvalid[2]), + .ptl_mapvalidp1x (ptl_mapvalid[3])); + + Note the @ character was replaced with the 2 from \"ms2m\". + + Alternatively, using a regular expression for @: + + /* psm_mas AUTO_TEMPLATE \"_\\([a-z]+\\)\" ( + .ptl_mapvalidx (@_ptl_mapvalid), + .ptl_mapvalidp1x (ptl_mapvalid_@), + ); + */ + psm_mas ms2_FOO (/*AUTOINST*/); + psm_mas ms2_BAR (/*AUTOINST*/); + + Typing \\[verilog-auto] will make this into: + + psm_mas ms2_FOO (/*AUTOINST*/ + // Outputs + .ptl_mapvalidx (FOO_ptl_mapvalid), + .ptl_mapvalidp1x (ptl_mapvalid_FOO)); + psm_mas ms2_BAR (/*AUTOINST*/ + // Outputs + .ptl_mapvalidx (BAR_ptl_mapvalid), + .ptl_mapvalidp1x (ptl_mapvalid_BAR)); + + +Regexp Templates: + + A template entry of the form + + .pci_req\\([0-9]+\\)_l (pci_req_jtag_[\\1]), + + will apply a Emacs style regular expression search for any port beginning + in pci_req followed by numbers and ending in _l and connecting that to + the pci_req_jtag_[] net, with the bus subscript coming from what matches + inside the first set of \\( \\). Thus pci_req2_l becomes pci_req_jtag_[2]. + + Since \\([0-9]+\\) is so common and ugly to read, a @ in the port name + does the same thing. (Note a @ in the connection/replacement text is + completely different -- still use \\1 there!) Thus this is the same as + the above template: + + .pci_req@_l (pci_req_jtag_[\\1]), + + Here's another example to remove the _l, useful when naming conventions + specify _ alone to mean active low. Note the use of [] to keep the bus + subscript: + + .\\(.*\\)_l (\\1_[]), + +Lisp Templates: + + First any regular expression template is expanded. + + If the syntax @\"( ... )\" is found in a connection, the expression in + quotes will be evaluated as a Lisp expression, with @ replaced by the + instantiation number. The MAPVALIDP1X example above would put @+1 modulo + 4 into the brackets. Quote all double-quotes inside the expression with + a leading backslash (\\\"). There are special variables defined that are + useful in these Lisp functions: + + vl-name Name portion of the input/output port + vl-bits Bus bits portion of the input/output port ('[2:0]') + vl-width Width of the input/output port ('3' for [2:0]) + May be a (...) expression if bits isn't a constant. + vl-dir Direction of the pin input/output/inout. + vl-cell-type Module name/type of the cell ('psm_mas') + vl-cell-name Instance name of the cell ('ms2m') + + Normal Lisp variables may be used in expressions. See + `verilog-read-defines' which can set vh-{definename} variables for use + here. Also, any comments of the form: + + /*AUTO_LISP(setq foo 1)*/ + + will evaluate any Lisp expression inside the parenthesis between the + beginning of the buffer and the point of the AUTOINST. This allows + functions to be defined or variables to be changed between instantiations. + + Note that when using lisp expressions errors may occur when @ is not a + number, you may need to use the standard Emacs Lisp functions + `number-to-string' and `string-to-number'. + + After the evaluation is completed, @ substitution and [] substitution + occur." + (save-excursion + ;; Find beginning + (let* ((pt (point)) + (for-star (save-excursion (backward-char 2) (looking-at "\\.\\*"))) + (indent-pt (save-excursion (verilog-backward-open-paren) + (1+ (current-column)))) + (verilog-auto-inst-column (max verilog-auto-inst-column + (+ 16 (* 8 (/ (+ indent-pt 7) 8))))) + (modi (verilog-modi-current)) + (vector-skip-list (unless verilog-auto-inst-vector + (verilog-modi-get-signals modi))) + submod submodi inst skip-pins tpl-list tpl-num did-first) + ;; Find module name that is instantiated + (setq submod (verilog-read-inst-module) + inst (verilog-read-inst-name) + vl-cell-type submod + vl-cell-name inst + skip-pins (aref (verilog-read-inst-pins) 0)) + + ;; Parse any AUTO_LISP() before here + (verilog-read-auto-lisp (point-min) pt) + + ;; Lookup position, etc of submodule + ;; Note this may raise an error + (when (setq submodi (verilog-modi-lookup submod t)) + ;; If there's a number in the instantiation, it may be a argument to the + ;; automatic variable instantiation program. + (let* ((tpl-info (verilog-read-auto-template submod)) + (tpl-regexp (aref tpl-info 0))) + (setq tpl-num (if (string-match tpl-regexp inst) + (match-string 1 inst) + "") + tpl-list (aref tpl-info 1))) + ;; Find submodule's signals and dump + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-outputs submodi) + skip-pins)) + (vl-dir "output")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Outputs\n") ;; Note these are searched for in verilog-read-sub-decls + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num for-star))) + sig-list))) + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-inouts submodi) + skip-pins)) + (vl-dir "inout")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Inouts\n") + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num for-star))) + sig-list))) + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-inputs submodi) + skip-pins)) + (vl-dir "input")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Inputs\n") + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num for-star))) + sig-list))) + ;; Kill extra semi + (save-excursion + (cond (did-first + (re-search-backward "," pt t) + (delete-char 1) + (insert ");") + (search-forward "\n") ;; Added by inst-port + (delete-backward-char 1) + (if (search-forward ")" nil t) ;; From user, moved up a line + (delete-backward-char 1)) + (if (search-forward ";" nil t) ;; Don't error if user had syntax error and forgot it + (delete-backward-char 1)) + ))) + )))) + +(defun verilog-auto-inst-param () + "Expand AUTOINSTPARAM statements, as part of \\[verilog-auto]. +Replace the parameter connections to an instantiation with ones +automatically derived from the module header of the instantiated netlist. + +See \\[verilog-auto-inst] for limitations, and templates to customize the +output. + +For example, first take the submodule inst.v: + + module inst (o,i) + parameter PAR; + endmodule + +This is then used in a upper level module: + + module ex_inst (o,i) + parameter PAR; + inst #(/*AUTOINSTPARAM*/) + inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_inst (o,i) + output o; + input i; + inst (/*AUTOINSTPARAM*/ + // Parameters + .PAR (PAR)); + inst (/*AUTOINST*/); + endmodule + +Where the list of parameter connections come from the inst module. + +Templates: + + You can customize the parameter connections using AUTO_TEMPLATEs, + just as you would with \\[verilog-auto-inst]." + (save-excursion + ;; Find beginning + (let* ((pt (point)) + (indent-pt (save-excursion (verilog-backward-open-paren) + (1+ (current-column)))) + (verilog-auto-inst-column (max verilog-auto-inst-column + (+ 16 (* 8 (/ (+ indent-pt 7) 8))))) + (modi (verilog-modi-current)) + (vector-skip-list (unless verilog-auto-inst-vector + (verilog-modi-get-signals modi))) + submod submodi inst skip-pins tpl-list tpl-num did-first) + ;; Find module name that is instantiated + (setq submod (save-excursion + ;; Get to the point where AUTOINST normally is to read the module + (verilog-re-search-forward-quick "[(;]" nil nil) + (verilog-read-inst-module)) + inst (save-excursion + ;; Get to the point where AUTOINST normally is to read the module + (verilog-re-search-forward-quick "[(;]" nil nil) + (verilog-read-inst-name)) + vl-cell-type submod + vl-cell-name inst + skip-pins (aref (verilog-read-inst-pins) 0)) + + ;; Parse any AUTO_LISP() before here + (verilog-read-auto-lisp (point-min) pt) + + ;; Lookup position, etc of submodule + ;; Note this may raise an error + (when (setq submodi (verilog-modi-lookup submod t)) + ;; If there's a number in the instantiation, it may be a argument to the + ;; automatic variable instantiation program. + (let* ((tpl-info (verilog-read-auto-template submod)) + (tpl-regexp (aref tpl-info 0))) + (setq tpl-num (if (string-match tpl-regexp inst) + (match-string 1 inst) + "") + tpl-list (aref tpl-info 1))) + ;; Find submodule's signals and dump + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-gparams submodi) + skip-pins)) + (vl-dir "parameter")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Parameters\n") ;; Note these are searched for in verilog-read-sub-decls + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num nil))) + sig-list))) + ;; Kill extra semi + (save-excursion + (cond (did-first + (re-search-backward "," pt t) + (delete-char 1) + (insert ")") + (search-forward "\n") ;; Added by inst-port + (delete-backward-char 1) + (if (search-forward ")" nil t) ;; From user, moved up a line + (delete-backward-char 1)) + ))) + )))) + +(defun verilog-auto-reg () + "Expand AUTOREG statements, as part of \\[verilog-auto]. +Make reg statements for any output that isn't already declared, +and isn't a wire output from a block. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + This does NOT work on memories, declare those yourself. + +An example: + + module ex_reg (o,i) + output o; + input i; + /*AUTOREG*/ + always o = i; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_reg (o,i) + output o; + input i; + /*AUTOREG*/ + // Beginning of automatic regs (for this module's undeclared outputs) + reg o; + // End of automatics + always o = i; + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-outputs modi) + (append (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-assigns modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (forward-line 1) + (when sig-list + (verilog-insert-indent "// Beginning of automatic regs (for this module's undeclared outputs)\n") + (verilog-insert-definition sig-list "reg" indent-pt nil) + (verilog-modi-cache-add-regs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + ))) + +(defun verilog-auto-reg-input () + "Expand AUTOREGINPUT statements, as part of \\[verilog-auto]. +Make reg statements instantiation inputs that aren't already declared. +This is useful for making a top level shell for testing the module that is +to be instantiated. + +Limitations: + This ONLY detects inputs of AUTOINSTants (see `verilog-read-sub-decls'). + + This does NOT work on memories, declare those yourself. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_reg_input (o,i) + output o; + input i; + /*AUTOREGINPUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_reg_input (o,i) + output o; + input i; + /*AUTOREGINPUT*/ + // Beginning of automatic reg inputs (for undeclared ... + reg [31:0] iv; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .o (o[31:0]), + // Inputs + .iv (iv)); + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-combine-bus + (verilog-signals-not-in + (append (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-inouts modi)) + (verilog-modi-get-signals modi) + )))) + (forward-line 1) + (when sig-list + (verilog-insert-indent "// Beginning of automatic reg inputs (for undeclared instantiated-module inputs)\n") + (verilog-insert-definition sig-list "reg" indent-pt nil) + (verilog-modi-cache-add-regs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + ))) + +(defun verilog-auto-wire () + "Expand AUTOWIRE statements, as part of \\[verilog-auto]. +Make wire statements for instantiations outputs that aren't +already declared. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'), + and all busses must have widths, such as those from AUTOINST, or using [] + in AUTO_TEMPLATEs. + + This does NOT work on memories or SystemVerilog .name connections, + declare those yourself. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_wire (o,i) + output o; + input i; + /*AUTOWIRE*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_wire (o,i) + output o; + input i; + /*AUTOWIRE*/ + // Beginning of automatic wires + wire [31:0] ov; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + wire o = | ov; + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-combine-bus + (verilog-signals-not-in + (append (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi)) + (verilog-modi-get-signals modi) + )))) + (forward-line 1) + (when sig-list + (verilog-insert-indent "// Beginning of automatic wires (for undeclared instantiated-module outputs)\n") + (verilog-insert-definition sig-list "wire" indent-pt nil) + (verilog-modi-cache-add-wires modi sig-list) + (verilog-insert-indent "// End of automatics\n") + (when nil ;; Too slow on huge modules, plus makes everyone's module change + (beginning-of-line) + (setq pnt (point)) + (verilog-pretty-declarations) + (goto-char pnt) + (verilog-pretty-expr "//"))) + ))) + +(defun verilog-auto-output () + "Expand AUTOOUTPUT statements, as part of \\[verilog-auto]. +Make output statements for any output signal from an /*AUTOINST*/ that +isn't a input to another AUTOINST. This is useful for modules which +only instantiate other modules. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + If any concatenation, or bit-subscripts are missing in the AUTOINSTant's + instantiation, all bets are off. (For example due to a AUTO_TEMPLATE). + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + Signals matching `verilog-auto-output-ignore-regexp' are not included. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_output (ov,i) + input i; + /*AUTOOUTPUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_output (ov,i) + input i; + /*AUTOOUTPUT*/ + // Beginning of automatic outputs (from unused autoinst outputs) + output [31:0] ov; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-sub-outputs modi) + (append (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-output-ignore-regexp)) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic outputs (from unused autoinst outputs)\n") + (verilog-insert-definition sig-list "output" indent-pt v2k) + (verilog-modi-cache-add-outputs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-output-every () + "Expand AUTOOUTPUTEVERY statements, as part of \\[verilog-auto]. +Make output statements for any signals that aren't primary inputs or +outputs already. This makes every signal in the design a output. This is +useful to get Synopsys to preserve every signal in the design, since it +won't optimize away the outputs. + +An example: + + module ex_output_every (o,i,tempa,tempb) + output o; + input i; + /*AUTOOUTPUTEVERY*/ + wire tempa = i; + wire tempb = tempa; + wire o = tempb; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_output_every (o,i,tempa,tempb) + output o; + input i; + /*AUTOOUTPUTEVERY*/ + // Beginning of automatic outputs (every signal) + output tempb; + output tempa; + // End of automatics + wire tempa = i; + wire tempb = tempa; + wire o = tempb; + endmodule" + (save-excursion + ;;Point must be at insertion point + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-combine-bus + (verilog-signals-not-in + (verilog-modi-get-signals modi) + (verilog-modi-get-ports modi) + )))) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic outputs (every signal)\n") + (verilog-insert-definition sig-list "output" indent-pt v2k) + (verilog-modi-cache-add-outputs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-input () + "Expand AUTOINPUT statements, as part of \\[verilog-auto]. +Make input statements for any input signal into an /*AUTOINST*/ that +isn't declared elsewhere inside the module. This is useful for modules which +only instantiate other modules. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + If any concatenation, or bit-subscripts are missing in the AUTOINSTant's + instantiation, all bets are off. (For example due to a AUTO_TEMPLATE). + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + Signals matching `verilog-auto-input-ignore-regexp' are not included. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_input (ov,i) + output [31:0] ov; + /*AUTOINPUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_input (ov,i) + output [31:0] ov; + /*AUTOINPUT*/ + // Beginning of automatic inputs (from unused autoinst inputs) + input i; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule" + (save-excursion + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-sub-inputs modi) + (append (verilog-modi-get-inputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-input-ignore-regexp)) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic inputs (from unused autoinst inputs)\n") + (verilog-insert-definition sig-list "input" indent-pt v2k) + (verilog-modi-cache-add-inputs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-inout () + "Expand AUTOINOUT statements, as part of \\[verilog-auto]. +Make inout statements for any inout signal in an /*AUTOINST*/ that +isn't declared elsewhere inside the module. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + If any concatenation, or bit-subscripts are missing in the AUTOINSTant's + instantiation, all bets are off. (For example due to a AUTO_TEMPLATE). + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + Signals matching `verilog-auto-inout-ignore-regexp' are not included. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_inout (ov,i) + input i; + /*AUTOINOUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_inout (ov,i) + input i; + /*AUTOINOUT*/ + // Beginning of automatic inouts (from unused autoinst inouts) + inout [31:0] ov; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Inouts + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-sub-inouts modi) + (append (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi) + (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-outputs modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-inout-ignore-regexp)) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic inouts (from unused autoinst inouts)\n") + (verilog-insert-definition sig-list "inout" indent-pt v2k) + (verilog-modi-cache-add-inouts modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-inout-module () + "Expand AUTOINOUTMODULE statements, as part of \\[verilog-auto]. +Take input/output/inout statements from the specified module and insert +into the current module. This is useful for making null templates and +shell modules which need to have identical I/O with another module. Any +I/O which are already defined in this module will not be redefined. + +Limitations: + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + Concatenation and outputting partial busses is not supported. + + Module names must be resolvable to filenames. See `verilog-auto-inst'. + + Signals are not inserted in the same order as in the original module, + though they will appear to be in the same order to a AUTOINST + instantiating either module. + +An example: + + module ex_shell (/*AUTOARG*/) + /*AUTOINOUTMODULE(\"ex_main\")*/ + endmodule + + module ex_main (i,o,io) + input i; + output o; + inout io; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_shell (/*AUTOARG*/i,o,io) + /*AUTOINOUTMODULE(\"ex_main\")*/ + // Beginning of automatic in/out/inouts (from specific module) + input i; + output o; + inout io; + // End of automatics + endmodule" + (save-excursion + (let* ((submod (car (verilog-read-auto-params 1))) submodi) + ;; Lookup position, etc of co-module + ;; Note this may raise an error + (when (setq submodi (verilog-modi-lookup submod t)) + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list-i (verilog-signals-not-in + (verilog-modi-get-inputs submodi) + (append (verilog-modi-get-inputs modi)))) + (sig-list-o (verilog-signals-not-in + (verilog-modi-get-outputs submodi) + (append (verilog-modi-get-outputs modi)))) + (sig-list-io (verilog-signals-not-in + (verilog-modi-get-inouts submodi) + (append (verilog-modi-get-inouts modi))))) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when (or sig-list-i sig-list-o sig-list-io) + (verilog-insert-indent "// Beginning of automatic in/out/inouts (from specific module)\n") + ;; Don't sort them so a upper AUTOINST will match the main module + (verilog-insert-definition sig-list-o "output" indent-pt v2k t) + (verilog-insert-definition sig-list-io "inout" indent-pt v2k t) + (verilog-insert-definition sig-list-i "input" indent-pt v2k t) + (verilog-modi-cache-add-inputs modi sig-list-i) + (verilog-modi-cache-add-outputs modi sig-list-o) + (verilog-modi-cache-add-inouts modi sig-list-io) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))))) + +(defun verilog-auto-sense-sigs (modi presense-sigs) + "Return list of signals for current AUTOSENSE block." + (let* ((sigss (verilog-read-always-signals)) + (sig-list (verilog-signals-not-params + (verilog-signals-not-in (verilog-alw-get-inputs sigss) + (append (and (not verilog-auto-sense-include-inputs) + (verilog-alw-get-outputs sigss)) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + presense-sigs))))) + sig-list)) + +(defun verilog-auto-sense () + "Expand AUTOSENSE statements, as part of \\[verilog-auto]. +Replace the always (/*AUTOSENSE*/) sensitivity list (/*AS*/ for short) +with one automatically derived from all inputs declared in the always +statement. Signals that are generated within the same always block are NOT +placed into the sensitivity list (see `verilog-auto-sense-include-inputs'). +Long lines are split based on the `fill-column', see \\[set-fill-column]. + +Limitations: + Verilog does not allow memories (multidimensional arrays) in sensitivity + lists. AUTOSENSE will thus exclude them, and add a /*memory or*/ comment. + +Constant signals: + AUTOSENSE cannot always determine if a `define is a constant or a signal + (it could be in a include file for example). If a `define or other signal + is put into the AUTOSENSE list and is not desired, use the AUTO_CONSTANT + declaration anywhere in the module (parenthesis are required): + + /* AUTO_CONSTANT ( `this_is_really_constant_dont_autosense_it ) */ + + Better yet, use a parameter, which will be understood to be constant + automatically. + +OOps! + If AUTOSENSE makes a mistake, please report it. (First try putting + a begin/end after your always!) As a workaround, if a signal that + shouldn't be in the sensitivity list was, use the AUTO_CONSTANT above. + If a signal should be in the sensitivity list wasn't, placing it before + the /*AUTOSENSE*/ comment will prevent it from being deleted when the + autos are updated (or added if it occurs there already). + +An example: + + always @ (/*AUTOSENSE*/) begin + /* AUTO_CONSTANT (`constant) */ + outin = ina | inb | `constant; + out = outin; + end + +Typing \\[verilog-auto] will make this into: + + always @ (/*AUTOSENSE*/ina or inb) begin + /* AUTO_CONSTANT (`constant) */ + outin = ina | inb | `constant; + out = outin; + end" + (save-excursion + ;; Find beginning + (let* ((start-pt (save-excursion + (verilog-re-search-backward "(" nil t) + (point))) + (indent-pt (save-excursion + (or (and (goto-char start-pt) (1+ (current-column))) + (current-indentation)))) + (modi (verilog-modi-current)) + (sig-memories (verilog-signals-memory + (append + (verilog-modi-get-regs modi) + (verilog-modi-get-wires modi)))) + sig-list not-first presense-sigs) + ;; Read signals in always, eliminate outputs from sense list + (setq presense-sigs (verilog-signals-from-signame + (save-excursion + (verilog-read-signals start-pt (point))))) + (setq sig-list (verilog-auto-sense-sigs modi presense-sigs)) + (when sig-memories + (let ((tlen (length sig-list))) + (setq sig-list (verilog-signals-not-in sig-list sig-memories)) + (if (not (eq tlen (length sig-list))) (insert " /*memory or*/ ")))) + (if (and presense-sigs ;; Add a "or" if not "(.... or /*AUTOSENSE*/" + (save-excursion (goto-char (point)) + (verilog-re-search-backward "[a-zA-Z0-9$_.%`]+" start-pt t) + (verilog-re-search-backward "\\s-" start-pt t) + (while (looking-at "\\s-`endif") + (verilog-re-search-backward "[a-zA-Z0-9$_.%`]+" start-pt t) + (verilog-re-search-backward "\\s-" start-pt t)) + (not (looking-at "\\s-or\\b")))) + (setq not-first t)) + (setq sig-list (sort sig-list `verilog-signals-sort-compare)) + (while sig-list + (cond ((> (+ 4 (current-column) (length (verilog-sig-name (car sig-list)))) fill-column) ;+4 for width of or + (insert "\n") + (indent-to indent-pt) + (if not-first (insert "or "))) + (not-first (insert " or "))) + (insert (verilog-sig-name (car sig-list))) + (setq sig-list (cdr sig-list) + not-first t)) + ))) + +(defun verilog-auto-reset () + "Expand AUTORESET statements, as part of \\[verilog-auto]. +Replace the /*AUTORESET*/ comment with code to initialize all +registers set elsewhere in the always block. + +Limitations: + AUTORESET will not clear memories. + + AUTORESET uses <= if there are any <= in the block, else it uses =. + +/*AUTORESET*/ presumes that any signals mentioned between the previous +begin/case/if statement and the AUTORESET comment are being reset manually +and should not be automatically reset. This includes omitting any signals +used on the right hand side of assignments. + +By default, AUTORESET will include the width of the signal in the autos, +this is a recent change. To control this behavior, see +`verilog-auto-reset-widths'. + +AUTORESET ties signals to deasserted, which is presumed to be zero. +Signals that match `verilog-active-low-regexp' will be deasserted by tieing +them to a one. + +An example: + + always @(posedge clk or negedge reset_l) begin + if (!reset_l) begin + c <= 1; + /*AUTORESET*/ + end + else begin + a <= in_a; + b <= in_b; + c <= in_c; + end + end + +Typing \\[verilog-auto] will make this into: + + always @(posedge core_clk or negedge reset_l) begin + if (!reset_l) begin + c <= 1; + /*AUTORESET*/ + // Beginning of autoreset for uninitialized flops + a <= 0; + b <= 0; + // End of automatics + end + else begin + a <= in_a; + b <= in_b; + c <= in_c; + end + end" + + (interactive) + (save-excursion + ;; Find beginning + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (all-list (verilog-modi-get-signals modi)) + sigss sig-list prereset-sigs assignment-str) + ;; Read signals in always, eliminate outputs from reset list + (setq prereset-sigs (verilog-signals-from-signame + (save-excursion + (verilog-read-signals + (save-excursion + (verilog-re-search-backward "\\(@\\|\\<begin\\>\\|\\<if\\>\\|\\<case\\>\\)" nil t) + (point)) + (point))))) + (save-excursion + (verilog-re-search-backward "@" nil t) + (setq sigss (verilog-read-always-signals))) + (setq assignment-str (if (verilog-alw-get-uses-delayed sigss) + (concat " <= " verilog-assignment-delay) + " = ")) + (setq sig-list (verilog-signals-not-in (verilog-alw-get-outputs sigss) + prereset-sigs)) + (setq sig-list (sort sig-list `verilog-signals-sort-compare)) + (when sig-list + (insert "\n"); + (indent-to indent-pt) + (insert "// Beginning of autoreset for uninitialized flops\n"); + (indent-to indent-pt) + (while sig-list + (let ((sig (or (assoc (verilog-sig-name (car sig-list)) all-list) ;; As sig-list has no widths + (car sig-list)))) + (insert (verilog-sig-name sig) + assignment-str + (verilog-sig-tieoff sig (not verilog-auto-reset-widths)) + ";\n") + (indent-to indent-pt) + (setq sig-list (cdr sig-list)))) + (insert "// End of automatics")) + ))) + +(defun verilog-auto-tieoff () + "Expand AUTOTIEOFF statements, as part of \\[verilog-auto]. +Replace the /*AUTOTIEOFF*/ comment with code to wire-tie all unused output +signals to deasserted. + +/*AUTOTIEOFF*/ is used to make stub modules; modules that have the same +input/output list as another module, but no internals. Specifically, it +finds all outputs in the module, and if that input is not otherwise declared +as a register or wire, creates a tieoff. + +AUTORESET ties signals to deasserted, which is presumed to be zero. +Signals that match `verilog-active-low-regexp' will be deasserted by tieing +them to a one. + +An example of making a stub for another module: + + module FooStub (/*AUTOINST*/); + /*AUTOINOUTMODULE(\"Foo\")*/ + /*AUTOTIEOFF*/ + // verilator lint_off UNUSED + wire _unused_ok = &{1'b0, + /*AUTOUNUSED*/ + 1'b0}; + // verilator lint_on UNUSED + endmodule + +Typing \\[verilog-auto] will make this into: + + module FooStub (/*AUTOINST*/...); + /*AUTOINOUTMODULE(\"Foo\")*/ + // Beginning of autotieoff + output [2:0] foo; + // End of automatics + + /*AUTOTIEOFF*/ + // Beginning of autotieoff + wire [2:0] foo = 3'b0; + // End of automatics + ... + endmodule" + (interactive) + (save-excursion + ;; Find beginning + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-outputs modi) + (append (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-assigns modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (when sig-list + (forward-line 1) + (verilog-insert-indent "// Beginning of automatic tieoffs (for this module's unterminated outputs)\n") + (setq sig-list (sort (copy-alist sig-list) `verilog-signals-sort-compare)) + (verilog-modi-cache-add-wires modi sig-list) ; Before we trash list + (while sig-list + (let ((sig (car sig-list))) + (verilog-insert-one-definition sig "wire" indent-pt) + (indent-to (max 48 (+ indent-pt 40))) + (insert "= " (verilog-sig-tieoff sig) + ";\n") + (setq sig-list (cdr sig-list)))) + (verilog-insert-indent "// End of automatics\n") + )))) + +(defun verilog-auto-unused () + "Expand AUTOUNUSED statements, as part of \\[verilog-auto]. +Replace the /*AUTOUNUSED*/ comment with a comma separated list of all unused +input and inout signals. + +/*AUTOUNUSED*/ is used to make stub modules; modules that have the same +input/output list as another module, but no internals. Specifically, it +finds all inputs and inouts in the module, and if that input is not otherwise +used, adds it to a comma separated list. + +The comma separated list is intended to be used to create a _unused_ok +signal. Using the exact name \"_unused_ok\" for name of the temporary +signal is recommended as it will insure maximum forward compatibility, it +also makes lint warnings easy to understand; ignore any unused warnings +with \"unused\" in the signal name. + +To reduce simulation time, the _unused_ok signal should be forced to a +constant to prevent wiggling. The easiest thing to do is use a +reduction-and with 1'b0 as shown. + +This way all unused signals are in one place, making it convenient to add +your tool's specific pragmas around the assignment to disable any unused +warnings. + +You can add signals you do not want included in AUTOUNUSED with +`verilog-auto-unused-ignore-regexp'. + +An example of making a stub for another module: + + module FooStub (/*AUTOINST*/); + /*AUTOINOUTMODULE(\"Foo\")*/ + /*AUTOTIEOFF*/ + // verilator lint_off UNUSED + wire _unused_ok = &{1'b0, + /*AUTOUNUSED*/ + 1'b0}; + // verilator lint_on UNUSED + endmodule + +Typing \\[verilog-auto] will make this into: + + ... + // verilator lint_off UNUSED + wire _unused_ok = &{1'b0, + /*AUTOUNUSED*/ + // Beginning of automatics + unused_input_a, + unused_input_b, + unused_input_c, + // End of automatics + 1'b0}; + // verilator lint_on UNUSED + endmodule" + (interactive) + (save-excursion + ;; Find beginning + (let* ((indent-pt (progn (search-backward "/*") (current-column))) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (append (verilog-modi-get-inputs modi) + (verilog-modi-get-inouts modi)) + (append (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-unused-ignore-regexp)) + (when sig-list + (forward-line 1) + (verilog-insert-indent "// Beginning of automatic unused inputs\n") + (setq sig-list (sort (copy-alist sig-list) `verilog-signals-sort-compare)) + (while sig-list + (let ((sig (car sig-list))) + (indent-to indent-pt) + (insert (verilog-sig-name sig) ",\n") + (setq sig-list (cdr sig-list)))) + (verilog-insert-indent "// End of automatics\n") + )))) + +(defun verilog-enum-ascii (signm elim-regexp) + "Convert a enum name SIGNM to a ascii string for insertion. +Remove user provided prefix ELIM-REGEXP." + (or elim-regexp (setq elim-regexp "_ DONT MATCH IT_")) + (let ((case-fold-search t)) + ;; All upper becomes all lower for readability + (downcase (verilog-string-replace-matches elim-regexp "" nil nil signm)))) + +(defun verilog-auto-ascii-enum () + "Expand AUTOASCIIENUM statements, as part of \\[verilog-auto]. +Create a register to contain the ASCII decode of a enumerated signal type. +This will allow trace viewers to show the ASCII name of states. + +First, parameters are built into a enumeration using the synopsys enum +comment. The comment must be between the keyword and the symbol. +(Annoying, but that's what Synopsys's dc_shell FSM reader requires.) + +Next, registers which that enum applies to are also tagged with the same +enum. Synopsys also suggests labeling state vectors, but `verilog-mode' +doesn't care. + +Finally, a AUTOASCIIENUM command is used. + + The first parameter is the name of the signal to be decoded. + + The second parameter is the name to store the ASCII code into. For the + signal foo, I suggest the name _foo__ascii, where the leading _ indicates + a signal that is just for simulation, and the magic characters _ascii + tell viewers like Dinotrace to display in ASCII format. + + The final optional parameter is a string which will be removed from the + state names. + +An example: + + //== State enumeration + parameter [2:0] // synopsys enum state_info + SM_IDLE = 3'b000, + SM_SEND = 3'b001, + SM_WAIT1 = 3'b010; + //== State variables + reg [2:0] /* synopsys enum state_info */ + state_r; /* synopsys state_vector state_r */ + reg [2:0] /* synopsys enum state_info */ + state_e1; + + //== ASCII state decoding + + /*AUTOASCIIENUM(\"state_r\", \"state_ascii_r\", \"SM_\")*/ + +Typing \\[verilog-auto] will make this into: + + ... same front matter ... + + /*AUTOASCIIENUM(\"state_r\", \"state_ascii_r\", \"SM_\")*/ + // Beginning of automatic ASCII enum decoding + reg [39:0] state_ascii_r; // Decode of state_r + always @(state_r) begin + case ({state_r}) + SM_IDLE: state_ascii_r = \"idle \"; + SM_SEND: state_ascii_r = \"send \"; + SM_WAIT1: state_ascii_r = \"wait1\"; + default: state_ascii_r = \"%Erro\"; + endcase + end + // End of automatics" + (save-excursion + (let* ((params (verilog-read-auto-params 2 3)) + (undecode-name (nth 0 params)) + (ascii-name (nth 1 params)) + (elim-regexp (nth 2 params)) + ;; + (indent-pt (current-indentation)) + (modi (verilog-modi-current)) + ;; + (sig-list-consts (append (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi))) + (sig-list-all (append (verilog-modi-get-regs modi) + (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi) + (verilog-modi-get-wires modi))) + ;; + (undecode-sig (or (assoc undecode-name sig-list-all) + (error "%s: Signal %s not found in design" (verilog-point-text) undecode-name))) + (undecode-enum (or (verilog-sig-enum undecode-sig) + (error "%s: Signal %s does not have a enum tag" (verilog-point-text) undecode-name))) + ;; + (enum-sigs (or (verilog-signals-matching-enum sig-list-consts undecode-enum) + (error "%s: No state definitions for %s" (verilog-point-text) undecode-enum))) + ;; + (enum-chars 0) + (ascii-chars 0)) + ;; + ;; Find number of ascii chars needed + (let ((tmp-sigs enum-sigs)) + (while tmp-sigs + (setq enum-chars (max enum-chars (length (verilog-sig-name (car tmp-sigs)))) + ascii-chars (max ascii-chars (length (verilog-enum-ascii + (verilog-sig-name (car tmp-sigs)) + elim-regexp))) + tmp-sigs (cdr tmp-sigs)))) + ;; + (forward-line 1) + (verilog-insert-indent "// Beginning of automatic ASCII enum decoding\n") + (let ((decode-sig-list (list (list ascii-name (format "[%d:0]" (- (* ascii-chars 8) 1)) + (concat "Decode of " undecode-name) nil nil)))) + (verilog-insert-definition decode-sig-list "reg" indent-pt nil) + (verilog-modi-cache-add-regs modi decode-sig-list)) + ;; + (verilog-insert-indent "always @(" undecode-name ") begin\n") + (setq indent-pt (+ indent-pt verilog-indent-level)) + (indent-to indent-pt) + (insert "case ({" undecode-name "})\n") + (setq indent-pt (+ indent-pt verilog-case-indent)) + ;; + (let ((tmp-sigs enum-sigs) + (chrfmt (format "%%-%ds %s = \"%%-%ds\";\n" (1+ (max 8 enum-chars)) + ascii-name ascii-chars)) + (errname (substring "%Error" 0 (min 6 ascii-chars)))) + (while tmp-sigs + (verilog-insert-indent + (format chrfmt (concat (verilog-sig-name (car tmp-sigs)) ":") + (verilog-enum-ascii (verilog-sig-name (car tmp-sigs)) + elim-regexp))) + (setq tmp-sigs (cdr tmp-sigs))) + (verilog-insert-indent (format chrfmt "default:" errname))) + ;; + (setq indent-pt (- indent-pt verilog-case-indent)) + (verilog-insert-indent "endcase\n") + (setq indent-pt (- indent-pt verilog-indent-level)) + (verilog-insert-indent "end\n" + "// End of automatics\n") + ))) + +(defun verilog-auto-templated-rel () + "Replace Templated relative line numbers with absolute line numbers. +Internal use only. This hacks around the line numbers in AUTOINST Templates +being different from the final output's line numbering." + (let ((templateno 0) (template-line (list 0))) + ;; Find line number each template is on + (goto-char (point-min)) + (while (search-forward "AUTO_TEMPLATE" nil t) + (setq templateno (1+ templateno)) + (setq template-line (cons (count-lines (point-min) (point)) template-line))) + (setq template-line (nreverse template-line)) + ;; Replace T# L# with absolute line number + (goto-char (point-min)) + (while (re-search-forward " Templated T\\([0-9]+\\) L\\([0-9]+\\)" nil t) + (replace-match (concat " Templated " + (int-to-string (+ (nth (string-to-int (match-string 1)) + template-line) + (string-to-int (match-string 2))))) + t t)))) + + +;; +;; Auto top level +;; + +(defun verilog-auto (&optional inject) ; Use verilog-inject-auto instead of passing a arg + "Expand AUTO statements. +Look for any /*AUTO...*/ commands in the code, as used in +instantiations or argument headers. Update the list of signals +following the /*AUTO...*/ command. + +Use \\[verilog-delete-auto] to remove the AUTOs. + +Use \\[verilog-inject-auto] to insert AUTOs for the first time. + +Use \\[verilog-faq] for a pointer to frequently asked questions. + +The hooks `verilog-before-auto-hook' and `verilog-auto-hook' are +called before and after this function, respectively. + +For example: + module (/*AUTOARG*/) + /*AUTOINPUT*/ + /*AUTOOUTPUT*/ + /*AUTOWIRE*/ + /*AUTOREG*/ + somesub sub #(/*AUTOINSTPARAM*/) (/*AUTOINST*/); + +You can also update the AUTOs from the shell using: + emacs --batch <filenames.v> -f verilog-batch-auto +Or fix indentation with: + emacs --batch <filenames.v> -f verilog-batch-indent +Likewise, you can delete or inject AUTOs with: + emacs --batch <filenames.v> -f verilog-batch-delete-auto + emacs --batch <filenames.v> -f verilog-batch-inject-auto + +Using \\[describe-function], see also: + `verilog-auto-arg' for AUTOARG module instantiations + `verilog-auto-ascii-enum' for AUTOASCIIENUM enumeration decoding + `verilog-auto-inout-module' for AUTOINOUTMODULE copying i/o from elsewhere + `verilog-auto-inout' for AUTOINOUT making hierarchy inouts + `verilog-auto-input' for AUTOINPUT making hierarchy inputs + `verilog-auto-inst' for AUTOINST instantiation pins + `verilog-auto-star' for AUTOINST .* SystemVerilog pins + `verilog-auto-inst-param' for AUTOINSTPARAM instantiation params + `verilog-auto-output' for AUTOOUTPUT making hierarchy outputs + `verilog-auto-output-every' for AUTOOUTPUTEVERY making all outputs + `verilog-auto-reg' for AUTOREG registers + `verilog-auto-reg-input' for AUTOREGINPUT instantiation registers + `verilog-auto-reset' for AUTORESET flop resets + `verilog-auto-sense' for AUTOSENSE always sensitivity lists + `verilog-auto-tieoff' for AUTOTIEOFF output tieoffs + `verilog-auto-unused' for AUTOUNUSED unused inputs/inouts + `verilog-auto-wire' for AUTOWIRE instantiation wires + + `verilog-read-defines' for reading `define values + `verilog-read-includes' for reading `includes + +If you have bugs with these autos, try contacting the AUTOAUTHOR +Wilson Snyder (wsnyder@wsnyder.org), and/or see http://www.veripool.com." + (interactive) + (unless noninteractive (message "Updating AUTOs...")) + (if (featurep 'dinotrace) + (dinotrace-unannotate-all)) + (let ((oldbuf (if (not (buffer-modified-p)) + (buffer-string))) + ;; Before version 20, match-string with font-lock returns a + ;; vector that is not equal to the string. IE if on "input" + ;; nil==(equal "input" (progn (looking-at "input") (match-string 0))) + (fontlocked (when (and ;(memq 'v19 verilog-emacs-features) + (boundp 'font-lock-mode) + font-lock-mode) + (font-lock-mode nil) + t))) + (unwind-protect + (save-excursion + ;; If we're not in verilog-mode, change syntax table so parsing works right + (unless (eq major-mode `verilog-mode) (verilog-mode)) + ;; Allow user to customize + (run-hooks 'verilog-before-auto-hook) + ;; Try to save the user from needing to revert-file to reread file local-variables + (verilog-auto-reeval-locals) + (verilog-read-auto-lisp (point-min) (point-max)) + (verilog-getopt-flags) + ;; These two may seem obvious to do always, but on large includes it can be way too slow + (when verilog-auto-read-includes + (verilog-read-includes) + (verilog-read-defines nil nil t)) + ;; This particular ordering is important + ;; INST: Lower modules correct, no internal dependencies, FIRST + (verilog-preserve-cache + ;; Clear existing autos else we'll be screwed by existing ones + (verilog-delete-auto) + ;; Injection if appropriate + (when inject + (verilog-inject-inst) + (verilog-inject-sense) + (verilog-inject-arg)) + ;; + (verilog-auto-search-do "/*AUTOINSTPARAM*/" 'verilog-auto-inst-param) + (verilog-auto-search-do "/*AUTOINST*/" 'verilog-auto-inst) + (verilog-auto-search-do ".*" 'verilog-auto-star) + ;; Doesn't matter when done, but combine it with a common changer + (verilog-auto-re-search-do "/\\*\\(AUTOSENSE\\|AS\\)\\*/" 'verilog-auto-sense) + (verilog-auto-re-search-do "/\\*AUTORESET\\*/" 'verilog-auto-reset) + ;; Must be done before autoin/out as creates a reg + (verilog-auto-re-search-do "/\\*AUTOASCIIENUM([^)]*)\\*/" 'verilog-auto-ascii-enum) + ;; + ;; first in/outs from other files + (verilog-auto-re-search-do "/\\*AUTOINOUTMODULE([^)]*)\\*/" 'verilog-auto-inout-module) + ;; next in/outs which need previous sucked inputs first + (verilog-auto-search-do "/*AUTOOUTPUT*/" 'verilog-auto-output) + (verilog-auto-search-do "/*AUTOINPUT*/" 'verilog-auto-input) + (verilog-auto-search-do "/*AUTOINOUT*/" 'verilog-auto-inout) + ;; Then tie off those in/outs + (verilog-auto-search-do "/*AUTOTIEOFF*/" 'verilog-auto-tieoff) + ;; Wires/regs must be after inputs/outputs + (verilog-auto-search-do "/*AUTOWIRE*/" 'verilog-auto-wire) + (verilog-auto-search-do "/*AUTOREG*/" 'verilog-auto-reg) + (verilog-auto-search-do "/*AUTOREGINPUT*/" 'verilog-auto-reg-input) + ;; outputevery needs AUTOOUTPUTs done first + (verilog-auto-search-do "/*AUTOOUTPUTEVERY*/" 'verilog-auto-output-every) + ;; After we've created all new variables + (verilog-auto-search-do "/*AUTOUNUSED*/" 'verilog-auto-unused) + ;; Must be after all inputs outputs are generated + (verilog-auto-search-do "/*AUTOARG*/" 'verilog-auto-arg) + ;; Fix line numbers (comments only) + (verilog-auto-templated-rel) + ) + ;; + (run-hooks 'verilog-auto-hook) + ;; + (set (make-local-variable 'verilog-auto-update-tick) (buffer-modified-tick)) + ;; + ;; If end result is same as when started, clear modified flag + (cond ((and oldbuf (equal oldbuf (buffer-string))) + (set-buffer-modified-p nil) + (unless noninteractive (message "Updating AUTOs...done (no changes)"))) + (t (unless noninteractive (message "Updating AUTOs...done"))))) + ;; Unwind forms + (progn + ;; Restore font-lock + (when fontlocked (font-lock-mode t))) + ))) + + +;; +;; Skeleton based code insertion +;; +(defvar verilog-template-map nil + "Keymap used in Verilog mode for smart template operations.") + +(let ((verilog-mp (make-sparse-keymap))) + (define-key verilog-mp "a" 'verilog-sk-always) + (define-key verilog-mp "b" 'verilog-sk-begin) + (define-key verilog-mp "c" 'verilog-sk-case) + (define-key verilog-mp "f" 'verilog-sk-for) + (define-key verilog-mp "g" 'verilog-sk-generate) + (define-key verilog-mp "h" 'verilog-sk-header) + (define-key verilog-mp "i" 'verilog-sk-initial) + (define-key verilog-mp "j" 'verilog-sk-fork) + (define-key verilog-mp "m" 'verilog-sk-module) + (define-key verilog-mp "p" 'verilog-sk-primitive) + (define-key verilog-mp "r" 'verilog-sk-repeat) + (define-key verilog-mp "s" 'verilog-sk-specify) + (define-key verilog-mp "t" 'verilog-sk-task) + (define-key verilog-mp "w" 'verilog-sk-while) + (define-key verilog-mp "x" 'verilog-sk-casex) + (define-key verilog-mp "z" 'verilog-sk-casez) + (define-key verilog-mp "?" 'verilog-sk-if) + (define-key verilog-mp ":" 'verilog-sk-else-if) + (define-key verilog-mp "/" 'verilog-sk-comment) + (define-key verilog-mp "A" 'verilog-sk-assign) + (define-key verilog-mp "F" 'verilog-sk-function) + (define-key verilog-mp "I" 'verilog-sk-input) + (define-key verilog-mp "O" 'verilog-sk-output) + (define-key verilog-mp "S" 'verilog-sk-state-machine) + (define-key verilog-mp "=" 'verilog-sk-inout) + (define-key verilog-mp "W" 'verilog-sk-wire) + (define-key verilog-mp "R" 'verilog-sk-reg) + (define-key verilog-mp "D" 'verilog-sk-define-signal) + (setq verilog-template-map verilog-mp)) + +;; +;; Place the templates into Verilog Mode. They may be inserted under any key. +;; C-c C-t will be the default. If you use templates a lot, you +;; may want to consider moving the binding to another key in your .emacs +;; file. +;; +;(define-key verilog-mode-map "\C-ct" verilog-template-map) +(define-key verilog-mode-map "\C-c\C-t" verilog-template-map) + +;;; ---- statement skeletons ------------------------------------------ + +(define-skeleton verilog-sk-prompt-condition + "Prompt for the loop condition." + "[condition]: " str ) + +(define-skeleton verilog-sk-prompt-init + "Prompt for the loop init statement." + "[initial statement]: " str ) + +(define-skeleton verilog-sk-prompt-inc + "Prompt for the loop increment statement." + "[increment statement]: " str ) + +(define-skeleton verilog-sk-prompt-name + "Prompt for the name of something." + "[name]: " str) + +(define-skeleton verilog-sk-prompt-clock + "Prompt for the name of something." + "name and edge of clock(s): " str) + +(defvar verilog-sk-reset nil) +(defun verilog-sk-prompt-reset () + "Prompt for the name of a state machine reset." + (setq verilog-sk-reset (read-input "name of reset: " "rst"))) + + +(define-skeleton verilog-sk-prompt-state-selector + "Prompt for the name of a state machine selector." + "name of selector (eg {a,b,c,d}): " str ) + +(define-skeleton verilog-sk-prompt-output + "Prompt for the name of something." + "output: " str) + +(define-skeleton verilog-sk-prompt-msb + "Prompt for least significant bit specification." + "msb:" str & ?: & (verilog-sk-prompt-lsb) | -1 ) + +(define-skeleton verilog-sk-prompt-lsb + "Prompt for least significant bit specification." + "lsb:" str ) + +(defvar verilog-sk-p nil) +(define-skeleton verilog-sk-prompt-width + "Prompt for a width specification." + () + (progn + (setq verilog-sk-p (point)) + (verilog-sk-prompt-msb) + (if (> (point) verilog-sk-p) "] " " "))) + +(defun verilog-sk-header () + "Insert a descriptive header at the top of the file." + (interactive "*") + (save-excursion + (goto-char (point-min)) + (verilog-sk-header-tmpl))) + +(define-skeleton verilog-sk-header-tmpl + "Insert a comment block containing the module title, author, etc." + "[Description]: " + "// -*- Mode: Verilog -*-" + "\n// Filename : " (buffer-name) + "\n// Description : " str + "\n// Author : " (user-full-name) + "\n// Created On : " (current-time-string) + "\n// Last Modified By: ." + "\n// Last Modified On: ." + "\n// Update Count : 0" + "\n// Status : Unknown, Use with caution!" + "\n") + +(define-skeleton verilog-sk-module + "Insert a module definition." + () + > "module " (verilog-sk-prompt-name) " (/*AUTOARG*/ ) ;" \n + > _ \n + > (- verilog-indent-level-behavioral) "endmodule" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-primitive + "Insert a task definition." + () + > "primitive " (verilog-sk-prompt-name) " ( " (verilog-sk-prompt-output) ("input:" ", " str ) " );"\n + > _ \n + > (- verilog-indent-level-behavioral) "endprimitive" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-task + "Insert a task definition." + () + > "task " (verilog-sk-prompt-name) & ?; \n + > _ \n + > "begin" \n + > \n + > (- verilog-indent-level-behavioral) "end" \n + > (- verilog-indent-level-behavioral) "endtask" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-function + "Insert a function definition." + () + > "function [" (verilog-sk-prompt-width) | -1 (verilog-sk-prompt-name) ?; \n + > _ \n + > "begin" \n + > \n + > (- verilog-indent-level-behavioral) "end" \n + > (- verilog-indent-level-behavioral) "endfunction" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-always + "Insert always block. Uses the minibuffer to prompt +for sensitivity list." + () + > "always @ ( /*AUTOSENSE*/ ) begin\n" + > _ \n + > (- verilog-indent-level-behavioral) "end" \n > + ) + +(define-skeleton verilog-sk-initial + "Insert an initial block." + () + > "initial begin\n" + > _ \n + > (- verilog-indent-level-behavioral) "end" \n > ) + +(define-skeleton verilog-sk-specify + "Insert specify block. " + () + > "specify\n" + > _ \n + > (- verilog-indent-level-behavioral) "endspecify" \n > ) + +(define-skeleton verilog-sk-generate + "Insert generate block. " + () + > "generate\n" + > _ \n + > (- verilog-indent-level-behavioral) "endgenerate" \n > ) + +(define-skeleton verilog-sk-begin + "Insert begin end block. Uses the minibuffer to prompt for name" + () + > "begin" (verilog-sk-prompt-name) \n + > _ \n + > (- verilog-indent-level-behavioral) "end" +) + +(define-skeleton verilog-sk-fork + "Insert an fork join block." + () + > "fork\n" + > "begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end" \n + > "begin" \n + > \n + > (- verilog-indent-level-behavioral) "end" \n + > (- verilog-indent-level-behavioral) "join" \n + > ) + + +(define-skeleton verilog-sk-case + "Build skeleton case statement, prompting for the selector expression, +and the case items." + "[selector expression]: " + > "case (" str ") " \n + > ("case selector: " str ": begin" \n > _ \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-casex + "Build skeleton casex statement, prompting for the selector expression, +and the case items." + "[selector expression]: " + > "casex (" str ") " \n + > ("case selector: " str ": begin" \n > _ \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-casez + "Build skeleton casez statement, prompting for the selector expression, +and the case items." + "[selector expression]: " + > "casez (" str ") " \n + > ("case selector: " str ": begin" \n > _ \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-if + "Insert a skeleton if statement." + > "if (" (verilog-sk-prompt-condition) & ")" " begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " \n ) + +(define-skeleton verilog-sk-else-if + "Insert a skeleton else if statement." + > (verilog-indent-line) "else if (" + (progn (setq verilog-sk-p (point)) nil) (verilog-sk-prompt-condition) (if (> (point) verilog-sk-p) ") " -1 ) & " begin" \n + > _ \n + > "end" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-datadef + "Common routine to get data definition" + () + (verilog-sk-prompt-width) | -1 ("name (RET to end):" str ", ") -2 ";" \n) + +(define-skeleton verilog-sk-input + "Insert an input definition." + () + > "input [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-output + "Insert an output definition." + () + > "output [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-inout + "Insert an inout definition." + () + > "inout [" (verilog-sk-datadef)) + +(defvar verilog-sk-signal nil) +(define-skeleton verilog-sk-def-reg + "Insert a reg definition." + () + > "reg [" (verilog-sk-prompt-width) | -1 verilog-sk-signal ";" \n (verilog-pretty-declarations) ) + +(defun verilog-sk-define-signal () + "Insert a definition of signal under point at top of module." + (interactive "*") + (let* ( + (sig-re "[a-zA-Z0-9_]*") + (v1 (buffer-substring + (save-excursion + (skip-chars-backward sig-re) + (point)) + (save-excursion + (skip-chars-forward sig-re) + (point)))) + ) + (if (not (member v1 verilog-keywords)) + (save-excursion + (setq verilog-sk-signal v1) + (verilog-beg-of-defun) + (verilog-end-of-statement) + (verilog-forward-syntactic-ws) + (verilog-sk-def-reg) + (message "signal at point is %s" v1)) + (message "object at point (%s) is a keyword" v1)) + ) + ) + + +(define-skeleton verilog-sk-wire + "Insert a wire definition." + () + > "wire [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-reg + "Insert a reg definition." + () + > "reg [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-assign + "Insert a skeleton assign statement." + () + > "assign " (verilog-sk-prompt-name) " = " _ ";" \n) + +(define-skeleton verilog-sk-while + "Insert a skeleton while loop statement." + () + > "while (" (verilog-sk-prompt-condition) ") begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-repeat + "Insert a skeleton repeat loop statement." + () + > "repeat (" (verilog-sk-prompt-condition) ") begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-for + "Insert a skeleton while loop statement." + () + > "for (" + (verilog-sk-prompt-init) "; " + (verilog-sk-prompt-condition) "; " + (verilog-sk-prompt-inc) + ") begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-comment + "Inserts three comment lines, making a display comment." + () + > "/*\n" + > "* " _ \n + > "*/") + +(define-skeleton verilog-sk-state-machine + "Insert a state machine definition." + "Name of state variable: " + '(setq input "state") + > "// State registers for " str | -23 \n + '(setq verilog-sk-state str) + > "reg [" (verilog-sk-prompt-width) | -1 verilog-sk-state ", next_" verilog-sk-state ?; \n + '(setq input nil) + > \n + > "// State FF for " verilog-sk-state \n + > "always @ ( " (read-string "clock:" "posedge clk") " or " (verilog-sk-prompt-reset) " ) begin" \n + > "if ( " verilog-sk-reset " ) " verilog-sk-state " = 0; else" \n + > verilog-sk-state " = next_" verilog-sk-state ?; \n + > (- verilog-indent-level-behavioral) "end" (progn (electric-verilog-terminate-line) nil) + > \n + > "// Next State Logic for " verilog-sk-state \n + > "always @ ( /*AUTOSENSE*/ ) begin\n" + > "case (" (verilog-sk-prompt-state-selector) ") " \n + > ("case selector: " str ": begin" \n > "next_" verilog-sk-state " = " _ ";" \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil) + > (- verilog-indent-level-behavioral) "end" (progn (electric-verilog-terminate-line) nil)) + +;; Eliminate compile warning +(eval-when-compile + (if (not (boundp 'mode-popup-menu)) + (defvar mode-popup-menu nil "Compatibility with XEmacs."))) + +;; ---- add menu 'Statements' in Verilog mode (MH) +(defun verilog-add-statement-menu () + "Add the menu 'Statements' to the menu bar in Verilog mode." + (if verilog-running-on-xemacs + (progn + (easy-menu-add verilog-stmt-menu) + (easy-menu-add verilog-menu) + (setq mode-popup-menu (cons "Verilog Mode" verilog-stmt-menu))))) + +(add-hook 'verilog-mode-hook 'verilog-add-statement-menu) + + + +;; +;; Include file loading with mouse/return event +;; +;; idea & first impl.: M. Rouat (eldo-mode.el) +;; second (emacs/xemacs) impl.: G. Van der Plas (spice-mode.el) + +(if verilog-running-on-xemacs + (require 'overlay) + (require 'lucid)) ;; what else can we do ?? + +(defconst verilog-include-file-regexp + "^`include\\s-+\"\\([^\n\"]*\\)\"" + "Regexp that matches the include file.") + +(defvar verilog-mode-mouse-map nil + "Map containing mouse bindings for `verilog-mode'.") + +(if verilog-mode-mouse-map + () + (let ((map (make-sparse-keymap))) ; as described in info pages, make a map + (set-keymap-parent map verilog-mode-map) + ;; mouse button bindings + (define-key map "\r" 'verilog-load-file-at-point) + (if verilog-running-on-xemacs + (define-key map 'button2 'verilog-load-file-at-mouse);ffap-at-mouse ? + (define-key map [mouse-2] 'verilog-load-file-at-mouse)) + (if verilog-running-on-xemacs + (define-key map 'Sh-button2 'mouse-yank) ; you wanna paste don't you ? + (define-key map [S-mouse-2] 'mouse-yank-at-click)) + (setq verilog-mode-mouse-map map))) ;; copy complete map now + +;; create set-extent-keymap procedure when it does not exist +(eval-and-compile + (unless (fboundp 'set-extent-keymap) + (defun set-extent-keymap (extent keymap) + "fallback version of set-extent-keymap (for emacs 2[01])" + (set-extent-property extent 'local-map keymap)))) + +(defun verilog-colorize-include-files (beg end old-len) + "This function colorizes included files when the mouse passes over them. +Clicking on the middle-mouse button loads them in a buffer (as in dired)." + (save-excursion + (save-match-data + (let (end-point) + (goto-char end) + (setq end-point (verilog-get-end-of-line)) + (goto-char beg) + (beginning-of-line) ; scan entire line ! + ;; delete overlays existing on this line + (let ((overlays (overlays-in (point) end-point))) + (while overlays + (if (and + (overlay-get (car overlays) 'detachable) + (overlay-get (car overlays) 'verilog-include-file)) + (delete-overlay (car overlays))) + (setq overlays (cdr overlays)))) ; let + ;; make new ones, could reuse deleted one ? + (while (search-forward-regexp verilog-include-file-regexp end-point t) + (let (extent) + (goto-char (match-beginning 1)) + (or (extent-at (point) (buffer-name) 'mouse-face) ;; not yet extended + (progn + (setq extent (make-extent (match-beginning 1) (match-end 1))) + (set-extent-property extent 'start-closed 't) + (set-extent-property extent 'end-closed 't) + (set-extent-property extent 'detachable 't) + (set-extent-property extent 'verilog-include-file 't) + (set-extent-property extent 'mouse-face 'highlight) + (set-extent-keymap extent verilog-mode-mouse-map))))))))) + + +(defun verilog-colorize-include-files-buffer () + "Colorize a include file." + (interactive) + ;; delete overlays + (let ((overlays (overlays-in (point-min) (point-max)))) + (while overlays + (if (and + (overlay-get (car overlays) 'detachable) + (overlay-get (car overlays) 'verilog-include-file)) + (delete-overlay (car overlays))) + (setq overlays (cdr overlays)))) ; let + ;; remake overlays + (verilog-colorize-include-files (point-min) (point-max) nil)) + +;; ffap-at-mouse isn't useful for verilog mode. It uses library paths. +;; so define this function to do more or less the same as ffap-at-mouse +;; but first resolve filename... +(defun verilog-load-file-at-mouse (event) + "Load file under button 2 click's EVENT. +Files are checked based on `verilog-library-directories'." + (interactive "@e") + (save-excursion ;; implement a verilog specific ffap-at-mouse + (mouse-set-point event) + (beginning-of-line) + (if (looking-at verilog-include-file-regexp) + (if (and (car (verilog-library-filenames + (match-string 1) (buffer-file-name))) + (file-readable-p (car (verilog-library-filenames + (match-string 1) (buffer-file-name))))) + (find-file (car (verilog-library-filenames + (match-string 1) (buffer-file-name)))) + (progn + (message + "File '%s' isn't readable, use shift-mouse2 to paste in this field" + (match-string 1)))) + ))) + +;; ffap isn't useable for verilog mode. It uses library paths. +;; so define this function to do more or less the same as ffap +;; but first resolve filename... +(defun verilog-load-file-at-point () + "Load file under point. +Files are checked based on `verilog-library-directories'." + (interactive) + (save-excursion ;; implement a verilog specific ffap + (beginning-of-line) + (if (looking-at verilog-include-file-regexp) + (if (and + (car (verilog-library-filenames + (match-string 1) (buffer-file-name))) + (file-readable-p (car (verilog-library-filenames + (match-string 1) (buffer-file-name))))) + (find-file (car (verilog-library-filenames + (match-string 1) (buffer-file-name)))))) + )) + + +;; +;; Bug reporting +;; + +(defun verilog-faq () + "Tell the user their current version, and where to get the FAQ etc." + (interactive) + (with-output-to-temp-buffer "*verilog-mode help*" + (princ (format "You are using verilog-mode %s\n" verilog-mode-version)) + (princ "\n") + (princ "For new releases, see http://www.verilog.com\n") + (princ "\n") + (princ "For frequently asked questions, see http://www.veripool.com/verilog-mode-faq.html\n") + (princ "\n") + (princ "To submit a bug, use M-x verilog-submit-bug-report\n") + (princ "\n"))) + +(defun verilog-submit-bug-report () + "Submit via mail a bug report on verilog-mode.el." + (interactive) + (let ((reporter-prompt-for-summary-p t)) + (reporter-submit-bug-report + "mac@verilog.com" + (concat "verilog-mode v" verilog-mode-version) + '( + verilog-align-ifelse + verilog-auto-endcomments + verilog-auto-hook + verilog-auto-indent-on-newline + verilog-auto-inst-vector + verilog-auto-inst-template-numbers + verilog-auto-lineup + verilog-auto-newline + verilog-auto-save-policy + verilog-auto-sense-defines-constant + verilog-auto-sense-include-inputs + verilog-before-auto-hook + verilog-case-indent + verilog-cexp-indent + verilog-compiler + verilog-coverage + verilog-highlight-translate-off + verilog-indent-begin-after-if + verilog-indent-declaration-macros + verilog-indent-level + verilog-indent-level-behavioral + verilog-indent-level-declaration + verilog-indent-level-directive + verilog-indent-level-module + verilog-indent-lists + verilog-library-flags + verilog-library-directories + verilog-library-extensions + verilog-library-files + verilog-linter + verilog-minimum-comment-distance + verilog-mode-hook + verilog-simulator + verilog-tab-always-indent + verilog-tab-to-comment + ) + nil nil + (concat "Hi Mac, + +I want to report a bug. I've read the `Bugs' section of `Info' on +Emacs, so I know how to make a clear and unambiguous report. To get +to that Info section, I typed + +M-x info RET m " invocation-name " RET m bugs RET + +Before I go further, I want to say that Verilog mode has changed my life. +I save so much time, my files are colored nicely, my co workers respect +my coding ability... until now. I'd really appreciate anything you +could do to help me out with this minor deficiency in the product. + +If you have bugs with the AUTO functions, please CC the AUTOAUTHOR Wilson +Snyder (wsnyder@wsnyder.org) and/or see http://www.veripool.com. +You may also want to look at the Verilog-Mode FAQ, see +http://www.veripool.com/verilog-mode-faq.html. + +To reproduce the bug, start a fresh Emacs via " invocation-name " +-no-init-file -no-site-file'. In a new buffer, in verilog mode, type +the code included below. + +Given those lines, I expected [[Fill in here]] to happen; +but instead, [[Fill in here]] happens!. + +== The code: ==")))) + +;; Local Variables: +;; checkdoc-permit-comma-termination-flag:t +;; checkdoc-force-docstrings-flag:nil +;; End: + +;;; verilog-mode.el ends here diff --git a/emacs/xcscope.el b/emacs/xcscope.el new file mode 100644 index 0000000..ce382a4 --- /dev/null +++ b/emacs/xcscope.el @@ -0,0 +1,2463 @@ +; -*-Emacs-Lisp-*- +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; File: xcscope.el +; RCS: $RCSfile: xcscope.el,v $ $Revision: 1.14 $ $Date: 2002/04/10 16:59:00 $ $Author: darrylo $ +; Description: cscope interface for (X)Emacs +; Author: Darryl Okahata +; Created: Wed Apr 19 17:03:38 2000 +; Modified: Thu Apr 4 17:22:22 2002 (Darryl Okahata) darrylo@soco.agilent.com +; Language: Emacs-Lisp +; Package: N/A +; Status: Experimental +; +; (C) Copyright 2000, 2001, 2002, Darryl Okahata <darrylo@sonic.net>, +; all rights reserved. +; GNU Emacs enhancements (C) Copyright 2001, +; Triet H. Lai <thlai@mail.usyd.edu.au> +; Fuzzy matching and navigation code (C) Copyright 2001, +; Steven Elliott <selliott4@austin.rr.com> +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ALPHA VERSION 0.96 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This is a cscope interface for (X)Emacs. +;; It currently runs under Unix only. +;; +;; Using cscope, you can easily search for where symbols are used and defined. +;; Cscope is designed to answer questions like: +;; +;; Where is this variable used? +;; What is the value of this preprocessor symbol? +;; Where is this function in the source files? +;; What functions call this function? +;; What functions are called by this function? +;; Where does the message "out of space" come from? +;; Where is this source file in the directory structure? +;; What files include this header file? +;; +;; Send comments to one of: darrylo@soco.agilent.com +;; darryl_okahata@agilent.com +;; darrylo@sonic.net +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ***** INSTALLATION ***** +;; +;; * NOTE: this interface currently runs under Unix only. +;; +;; This module needs a shell script called "cscope-indexer", which +;; should have been supplied along with this emacs-lisp file. The +;; purpose of "cscope-indexer" is to create and optionally maintain +;; the cscope databases. If all of your source files are in one +;; directory, you don't need this script; it's very nice to have, +;; though, as it handles recursive subdirectory indexing, and can be +;; used in a nightly or weekly cron job to index very large source +;; repositories. See the beginning of the file, "cscope-indexer", for +;; usage information. +;; +;; Installation steps: +;; +;; 0. (It is, of course, assumed that cscope is already properly +;; installed on the current system.) +;; +;; 1. Install the "cscope-indexer" script into some convenient +;; directory in $PATH. The only real constraint is that (X)Emacs +;; must be able to find and execute it. You may also have to edit +;; the value of PATH in the script, although this is unlikely; the +;; majority of people should be able to use the script, "as-is". +;; +;; 2. Make sure that the "cscope-indexer" script is executable. In +;; particular, if you had to ftp this file, it is probably no +;; longer executable. +;; +;; 3. Put this emacs-lisp file somewhere where (X)Emacs can find it. It +;; basically has to be in some directory listed in "load-path". +;; +;; 4. Edit your ~/.emacs file to add the line: +;; +;; (require 'xcscope) +;; +;; 5. If you intend to use xcscope.el often you can optionally edit your +;; ~/.emacs file to add keybindings that reduce the number of keystrokes +;; required. For example, the following will add "C-f#" keybindings, which +;; are easier to type than the usual "C-c s" prefixed keybindings. Note +;; that specifying "global-map" instead of "cscope:map" makes the +;; keybindings available in all buffers: +;; +;; (define-key global-map [(control f3)] 'cscope-set-initial-directory) +;; (define-key global-map [(control f4)] 'cscope-unset-initial-directory) +;; (define-key global-map [(control f5)] 'cscope-find-this-symbol) +;; (define-key global-map [(control f6)] 'cscope-find-global-definition) +;; (define-key global-map [(control f7)] +;; 'cscope-find-global-definition-no-prompting) +;; (define-key global-map [(control f8)] 'cscope-pop-mark) +;; (define-key global-map [(control f9)] 'cscope-next-symbol) +;; (define-key global-map [(control f10)] 'cscope-next-file) +;; (define-key global-map [(control f11)] 'cscope-prev-symbol) +;; (define-key global-map [(control f12)] 'cscope-prev-file) +;; (define-key global-map [(meta f9)] 'cscope-display-buffer) +;; (defin-ekey global-map [(meta f10)] 'cscope-display-buffer-toggle) +;; +;; 6. Restart (X)Emacs. That's it. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ***** USING THIS MODULE ***** +;; +;; * Basic usage: +;; +;; If all of your C/C++/lex/yacc source files are in the same +;; directory, you can just start using this module. If your files are +;; spread out over multiple directories, see "Advanced usage", below. +;; +;; Just edit a source file, and use the pull-down or pop-up (button 3) +;; menus to select one of: +;; +;; Find symbol +;; Find global definition +;; Find called functions +;; Find functions calling a function +;; Find text string +;; Find egrep pattern +;; Find a file +;; Find files #including a file +;; +;; The cscope database will be automatically created in the same +;; directory as the source files (assuming that you've never used +;; cscope before), and a buffer will pop-up displaying the results. +;; You can then use button 2 (the middle button) on the mouse to edit +;; the selected file, or you can move the text cursor over a selection +;; and press [Enter]. +;; +;; Hopefully, the interface should be fairly intuitive. +;; +;; +;; * Locating the cscope databases: +;; +;; This module will first use the variable, `cscope-database-regexps', +;; to search for a suitable database directory. If a database location +;; cannot be found using this variable then a search is begun at the +;; variable, `cscope-initial-directory', if set, or the current +;; directory otherwise. If the directory is not a cscope database +;; directory then the directory's parent, parent's parent, etc. is +;; searched until a cscope database directory is found, or the root +;; directory is reached. If the root directory is reached, the current +;; directory will be used. +;; +;; A cscope database directory is one in which EITHER a cscope database +;; file (e.g., "cscope.out") OR a cscope file list (e.g., +;; "cscope.files") exists. If only "cscope.files" exists, the +;; corresponding "cscope.out" will be automatically created by cscope +;; when a search is done. By default, the cscope database file is called +;; "cscope.out", but this can be changed (on a global basis) via the +;; variable, `cscope-database-file'. There is limited support for cscope +;; databases that are named differently than that given by +;; `cscope-database-file', using the variable, `cscope-database-regexps'. +;; +;; Note that the variable, `cscope-database-regexps', is generally not +;; needed, as the normal hierarchical database search is sufficient +;; for placing and/or locating the cscope databases. However, there +;; may be cases where it makes sense to place the cscope databases +;; away from where the source files are kept; in this case, this +;; variable is used to determine the mapping. One use for this +;; variable is when you want to share the database file with other +;; users; in this case, the database may be located in a directory +;; separate from the source files. +;; +;; Setting the variable, `cscope-initial-directory', is useful when a +;; search is to be expanded by specifying a cscope database directory +;; that is a parent of the directory that this module would otherwise +;; use. For example, consider a project that contains the following +;; cscope database directories: +;; +;; /users/jdoe/sources +;; /users/jdoe/sources/proj1 +;; /users/jdoe/sources/proj2 +;; +;; If a search is initiated from a .c file in /users/jdoe/sources/proj1 +;; then (assuming the variable, `cscope-database-regexps', is not set) +;; /users/jdoe/sources/proj1 will be used as the cscope data base directory. +;; Only matches in files in /users/jdoe/sources/proj1 will be found. This +;; can be remedied by typing "C-c s a" and then "M-del" to remove single +;; path element in order to use a cscope database directory of +;; /users/jdoe/sources. Normal searching can be restored by typing "C-c s A". +;; +;; +;; * Keybindings: +;; +;; All keybindings use the "C-c s" prefix, but are usable only while +;; editing a source file, or in the cscope results buffer: +;; +;; C-c s s Find symbol. +;; C-c s d Find global definition. +;; C-c s g Find global definition (alternate binding). +;; C-c s G Find global definition without prompting. +;; C-c s c Find functions calling a function. +;; C-c s C Find called functions (list functions called +;; from a function). +;; C-c s t Find text string. +;; C-c s e Find egrep pattern. +;; C-c s f Find a file. +;; C-c s i Find files #including a file. +;; +;; These pertain to navigation through the search results: +;; +;; C-c s b Display *cscope* buffer. +;; C-c s B Auto display *cscope* buffer toggle. +;; C-c s n Next symbol. +;; C-c s N Next file. +;; C-c s p Previous symbol. +;; C-c s P Previous file. +;; C-c s u Pop mark. +;; +;; These pertain to setting and unsetting the variable, +;; `cscope-initial-directory', (location searched for the cscope database +;; directory): +;; +;; C-c s a Set initial directory. +;; C-c s A Unset initial directory. +;; +;; These pertain to cscope database maintenance: +;; +;; C-c s L Create list of files to index. +;; C-c s I Create list and index. +;; C-c s E Edit list of files to index. +;; C-c s W Locate this buffer's cscope directory +;; ("W" --> "where"). +;; C-c s S Locate this buffer's cscope directory. +;; (alternate binding: "S" --> "show"). +;; C-c s T Locate this buffer's cscope directory. +;; (alternate binding: "T" --> "tell"). +;; C-c s D Dired this buffer's directory. +;; +;; +;; * Advanced usage: +;; +;; If the source files are spread out over multiple directories, +;; you've got a few choices: +;; +;; [ NOTE: you will need to have the script, "cscope-indexer", +;; properly installed in order for the following to work. ] +;; +;; 1. If all of the directories exist below a common directory +;; (without any extraneous, unrelated subdirectories), you can tell +;; this module to place the cscope database into the top-level, +;; common directory. This assumes that you do not have any cscope +;; databases in any of the subdirectories. If you do, you should +;; delete them; otherwise, they will take precedence over the +;; top-level database. +;; +;; If you do have cscope databases in any subdirectory, the +;; following instructions may not work right. +;; +;; It's pretty easy to tell this module to use a top-level, common +;; directory: +;; +;; a. Make sure that the menu pick, "Cscope/Index recursively", is +;; checked (the default value). +;; +;; b. Select the menu pick, "Cscope/Create list and index", and +;; specify the top-level directory. This will run the script, +;; "cscope-indexer", in the background, so you can do other +;; things if indexing takes a long time. A list of files to +;; index will be created in "cscope.files", and the cscope +;; database will be created in "cscope.out". +;; +;; Once this has been done, you can then use the menu picks +;; (described in "Basic usage", above) to search for symbols. +;; +;; Note, however, that, if you add or delete source files, you'll +;; have to either rebuild the database using the above procedure, +;; or edit the file, "cscope.files" to add/delete the names of the +;; source files. To edit this file, you can use the menu pick, +;; "Cscope/Edit list of files to index". +;; +;; +;; 2. If most of the files exist below a common directory, but a few +;; are outside, you can use the menu pick, "Cscope/Create list of +;; files to index", and specify the top-level directory. Make sure +;; that "Cscope/Index recursively", is checked before you do so, +;; though. You can then edit the list of files to index using the +;; menu pick, "Cscope/Edit list of files to index". Just edit the +;; list to include any additional source files not already listed. +;; +;; Once you've created, edited, and saved the list, you can then +;; use the menu picks described under "Basic usage", above, to +;; search for symbols. The first time you search, you will have to +;; wait a while for cscope to fully index the source files, though. +;; If you have a lot of source files, you may want to manually run +;; cscope to build the database: +;; +;; cd top-level-directory # or wherever +;; rm -f cscope.out # not always necessary +;; cscope -b +;; +;; +;; 3. If the source files are scattered in many different, unrelated +;; places, you'll have to manually create cscope.files and put a +;; list of all pathnames into it. Then build the database using: +;; +;; cd some-directory # wherever cscope.files exists +;; rm -f cscope.out # not always necessary +;; cscope -b +;; +;; Next, read the documentation for the variable, +;; "cscope-database-regexps", and set it appropriately, such that +;; the above-created cscope database will be referenced when you +;; edit a related source file. +;; +;; Once this has been done, you can then use the menu picks +;; described under "Basic usage", above, to search for symbols. +;; +;; +;; * Interesting configuration variables: +;; +;; "cscope-truncate-lines" +;; This is the value of `truncate-lines' to use in cscope +;; buffers; the default is the current setting of +;; `truncate-lines'. This variable exists because it can be +;; easier to read cscope buffers with truncated lines, while +;; other buffers do not have truncated lines. +;; +;; "cscope-use-relative-paths" +;; If non-nil, use relative paths when creating the list of files +;; to index. The path is relative to the directory in which the +;; cscope database will be created. If nil, absolute paths will +;; be used. Absolute paths are good if you plan on moving the +;; database to some other directory (if you do so, you'll +;; probably also have to modify `cscope-database-regexps'). +;; Absolute paths may also be good if you share the database file +;; with other users (you'll probably want to specify some +;; automounted network path for this). +;; +;; "cscope-index-recursively" +;; If non-nil, index files in the current directory and all +;; subdirectories. If nil, only files in the current directory +;; are indexed. This variable is only used when creating the +;; list of files to index, or when creating the list of files and +;; the corresponding cscope database. +;; +;; "cscope-name-line-width" +;; The width of the combined "function name:line number" field in +;; the cscope results buffer. If negative, the field is +;; left-justified. +;; +;; "cscope-do-not-update-database" +;; If non-nil, never check and/or update the cscope database when +;; searching. Beware of setting this to non-nil, as this will +;; disable automatic database creation, updating, and +;; maintenance. +;; +;; "cscope-display-cscope-buffer" +;; If non-nil, display the *cscope* buffer after each search +;; (default). This variable can be set in order to reduce the +;; number of keystrokes required to navigate through the matches. +;; +;; "cscope-database-regexps" +;; List to force directory-to-cscope-database mappings. +;; This is a list of `(REGEXP DBLIST [ DBLIST ... ])', where: +;; +;; REGEXP is a regular expression matched against the current buffer's +;; current directory. The current buffer is typically some source file, +;; and you're probably searching for some symbol in or related to this +;; file. Basically, this regexp is used to relate the current directory +;; to a cscope database. You need to start REGEXP with "^" if you want +;; to match from the beginning of the current directory. +;; +;; DBLIST is a list that contains one or more of: +;; +;; ( DBDIR ) +;; ( DBDIR ( OPTIONS ) ) +;; ( t ) +;; t +;; +;; Here, DBDIR is a directory (or a file) that contains a cscope +;; database. If DBDIR is a directory, then it is expected that the +;; cscope database, if present, has the filename given by the variable, +;; `cscope-database-file'; if DBDIR is a file, then DBDIR is the path +;; name to a cscope database file (which does not have to be the same as +;; that given by `cscope-database-file'). If only DBDIR is specified, +;; then that cscope database will be searched without any additional +;; cscope command-line options. If OPTIONS is given, then OPTIONS is a +;; list of strings, where each string is a separate cscope command-line +;; option. +;; +;; In the case of "( t )", this specifies that the search is to use the +;; normal hierarchical database search. This option is used to +;; explicitly search using the hierarchical database search either before +;; or after other cscope database directories. +;; +;; If "t" is specified (not inside a list), this tells the searching +;; mechanism to stop searching if a match has been found (at the point +;; where "t" is encountered). This is useful for those projects that +;; consist of many subprojects. You can specify the most-used +;; subprojects first, followed by a "t", and then followed by a master +;; cscope database directory that covers all subprojects. This will +;; cause the most-used subprojects to be searched first (hopefully +;; quickly), and the search will then stop if a match was found. If not, +;; the search will continue using the master cscope database directory. +;; +;; Here, `cscope-database-regexps' is generally not used, as the normal +;; hierarchical database search is sufficient for placing and/or locating +;; the cscope databases. However, there may be cases where it makes +;; sense to place the cscope databases away from where the source files +;; are kept; in this case, this variable is used to determine the +;; mapping. +;; +;; This module searches for the cscope databases by first using this +;; variable; if a database location cannot be found using this variable, +;; then the current directory is searched, then the parent, then the +;; parent's parent, until a cscope database directory is found, or the +;; root directory is reached. If the root directory is reached, the +;; current directory will be used. +;; +;; A cscope database directory is one in which EITHER a cscope database +;; file (e.g., "cscope.out") OR a cscope file list (e.g., +;; "cscope.files") exists. If only "cscope.files" exists, the +;; corresponding "cscope.out" will be automatically created by cscope +;; when a search is done. By default, the cscope database file is called +;; "cscope.out", but this can be changed (on a global basis) via the +;; variable, `cscope-database-file'. There is limited support for cscope +;; databases that are named differently than that given by +;; `cscope-database-file', using the variable, `cscope-database-regexps'. +;; +;; Here is an example of `cscope-database-regexps': +;; +;; (setq cscope-database-regexps +;; '( +;; ( "^/users/jdoe/sources/proj1" +;; ( t ) +;; ( "/users/jdoe/sources/proj2") +;; ( "/users/jdoe/sources/proj3/mycscope.out") +;; ( "/users/jdoe/sources/proj4") +;; t +;; ( "/some/master/directory" ("-d" "-I/usr/local/include") ) +;; ) +;; ( "^/users/jdoe/sources/gnome/" +;; ( "/master/gnome/database" ("-d") ) +;; ) +;; )) +;; +;; If the current buffer's directory matches the regexp, +;; "^/users/jdoe/sources/proj1", then the following search will be +;; done: +;; +;; 1. First, the normal hierarchical database search will be used to +;; locate a cscope database. +;; +;; 2. Next, searches will be done using the cscope database +;; directories, "/users/jdoe/sources/proj2", +;; "/users/jdoe/sources/proj3/mycscope.out", and +;; "/users/jdoe/sources/proj4". Note that, instead of the file, +;; "cscope.out", the file, "mycscope.out", will be used in the +;; directory "/users/jdoe/sources/proj3". +;; +;; 3. If a match was found, searching will stop. +;; +;; 4. If a match was not found, searching will be done using +;; "/some/master/directory", and the command-line options "-d" +;; and "-I/usr/local/include" will be passed to cscope. +;; +;; If the current buffer's directory matches the regexp, +;; "^/users/jdoe/sources/gnome", then the following search will be +;; done: +;; +;; The search will be done only using the directory, +;; "/master/gnome/database". The "-d" option will be passed to +;; cscope. +;; +;; If the current buffer's directory does not match any of the above +;; regexps, then only the normal hierarchical database search will be +;; done. +;; +;; +;; * Other notes: +;; +;; 1. The script, "cscope-indexer", uses a sed command to determine +;; what is and is not a C/C++/lex/yacc source file. It's idea of a +;; source file may not correspond to yours. +;; +;; 2. This module is called, "xcscope", because someone else has +;; already written a "cscope.el" (although it's quite old). +;; +;; +;; * KNOWN BUGS: +;; +;; 1. Cannot handle whitespace in directory or file names. +;; +;; 2. By default, colored faces are used to display results. If you happen +;; to use a black background, part of the results may be invisible +;; (because the foreground color may be black, too). There are at least +;; two solutions for this: +;; +;; 2a. Turn off colored faces, by setting `cscope-use-face' to `nil', +;; e.g.: +;; +;; (setq cscope-use-face nil) +;; +;; 2b. Explicitly set colors for the faces used by cscope. The faces +;; are: +;; +;; cscope-file-face +;; cscope-function-face +;; cscope-line-number-face +;; cscope-line-face +;; cscope-mouse-face +;; +;; The face most likely to cause problems (e.g., black-on-black +;; color) is `cscope-line-face'. +;; +;; 3. The support for cscope databases different from that specified by +;; `cscope-database-file' is quirky. If the file does not exist, it +;; will not be auto-created (unlike files names by +;; `cscope-database-file'). You can manually force the file to be +;; created by using touch(1) to create a zero-length file; the +;; database will be created the next time a search is done. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'easymenu) + + +(defgroup cscope nil + "Cscope interface for (X)Emacs. +Using cscope, you can easily search for where symbols are used and defined. +It is designed to answer questions like: + + Where is this variable used? + What is the value of this preprocessor symbol? + Where is this function in the source files? + What functions call this function? + What functions are called by this function? + Where does the message \"out of space\" come from? + Where is this source file in the directory structure? + What files include this header file? +" + :prefix "cscope-" + :group 'tools) + + +(defcustom cscope-do-not-update-database nil + "*If non-nil, never check and/or update the cscope database when searching. +Beware of setting this to non-nil, as this will disable automatic database +creation, updating, and maintenance." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-database-regexps nil + "*List to force directory-to-cscope-database mappings. +This is a list of `(REGEXP DBLIST [ DBLIST ... ])', where: + +REGEXP is a regular expression matched against the current buffer's +current directory. The current buffer is typically some source file, +and you're probably searching for some symbol in or related to this +file. Basically, this regexp is used to relate the current directory +to a cscope database. You need to start REGEXP with \"^\" if you want +to match from the beginning of the current directory. + +DBLIST is a list that contains one or more of: + + ( DBDIR ) + ( DBDIR ( OPTIONS ) ) + ( t ) + t + +Here, DBDIR is a directory (or a file) that contains a cscope database. +If DBDIR is a directory, then it is expected that the cscope database, +if present, has the filename given by the variable, +`cscope-database-file'; if DBDIR is a file, then DBDIR is the path name +to a cscope database file (which does not have to be the same as that +given by `cscope-database-file'). If only DBDIR is specified, then that +cscope database will be searched without any additional cscope +command-line options. If OPTIONS is given, then OPTIONS is a list of +strings, where each string is a separate cscope command-line option. + +In the case of \"( t )\", this specifies that the search is to use the +normal hierarchical database search. This option is used to +explicitly search using the hierarchical database search either before +or after other cscope database directories. + +If \"t\" is specified (not inside a list), this tells the searching +mechanism to stop searching if a match has been found (at the point +where \"t\" is encountered). This is useful for those projects that +consist of many subprojects. You can specify the most-used +subprojects first, followed by a \"t\", and then followed by a master +cscope database directory that covers all subprojects. This will +cause the most-used subprojects to be searched first (hopefully +quickly), and the search will then stop if a match was found. If not, +the search will continue using the master cscope database directory. + +Here, `cscope-database-regexps' is generally not used, as the normal +hierarchical database search is sufficient for placing and/or locating +the cscope databases. However, there may be cases where it makes +sense to place the cscope databases away from where the source files +are kept; in this case, this variable is used to determine the +mapping. + +This module searches for the cscope databases by first using this +variable; if a database location cannot be found using this variable, +then the current directory is searched, then the parent, then the +parent's parent, until a cscope database directory is found, or the +root directory is reached. If the root directory is reached, the +current directory will be used. + +A cscope database directory is one in which EITHER a cscope database +file (e.g., \"cscope.out\") OR a cscope file list (e.g., +\"cscope.files\") exists. If only \"cscope.files\" exists, the +corresponding \"cscope.out\" will be automatically created by cscope +when a search is done. By default, the cscope database file is called +\"cscope.out\", but this can be changed (on a global basis) via the +variable, `cscope-database-file'. There is limited support for cscope +databases that are named differently than that given by +`cscope-database-file', using the variable, `cscope-database-regexps'. + +Here is an example of `cscope-database-regexps': + + (setq cscope-database-regexps + '( + ( \"^/users/jdoe/sources/proj1\" + ( t ) + ( \"/users/jdoe/sources/proj2\") + ( \"/users/jdoe/sources/proj3/mycscope.out\") + ( \"/users/jdoe/sources/proj4\") + t + ( \"/some/master/directory\" (\"-d\" \"-I/usr/local/include\") ) + ) + ( \"^/users/jdoe/sources/gnome/\" + ( \"/master/gnome/database\" (\"-d\") ) + ) + )) + +If the current buffer's directory matches the regexp, +\"^/users/jdoe/sources/proj1\", then the following search will be +done: + + 1. First, the normal hierarchical database search will be used to + locate a cscope database. + + 2. Next, searches will be done using the cscope database + directories, \"/users/jdoe/sources/proj2\", + \"/users/jdoe/sources/proj3/mycscope.out\", and + \"/users/jdoe/sources/proj4\". Note that, instead of the file, + \"cscope.out\", the file, \"mycscope.out\", will be used in the + directory \"/users/jdoe/sources/proj3\". + + 3. If a match was found, searching will stop. + + 4. If a match was not found, searching will be done using + \"/some/master/directory\", and the command-line options \"-d\" + and \"-I/usr/local/include\" will be passed to cscope. + +If the current buffer's directory matches the regexp, +\"^/users/jdoe/sources/gnome\", then the following search will be +done: + + The search will be done only using the directory, + \"/master/gnome/database\". The \"-d\" option will be passed to + cscope. + +If the current buffer's directory does not match any of the above +regexps, then only the normal hierarchical database search will be +done. + +" + :type '(repeat (list :format "%v" + (choice :value "" + (regexp :tag "Buffer regexp") + string) + (choice :value "" + (directory :tag "Cscope database directory") + string) + (string :value "" + :tag "Optional cscope command-line arguments") + )) + :group 'cscope) +(defcustom cscope-name-line-width -30 + "*The width of the combined \"function name:line number\" field in the +cscope results buffer. If negative, the field is left-justified." + :type 'integer + :group 'cscope) + + +(defcustom cscope-truncate-lines truncate-lines + "*The value of `truncate-lines' to use in cscope buffers. +This variable exists because it can be easier to read cscope buffers +with truncated lines, while other buffers do not have truncated lines." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-display-times t + "*If non-nil, display how long each search took. +The elasped times are in seconds. Floating-point support is required +for this to work." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-program "cscope" + "*The pathname of the cscope executable to use." + :type 'string + :group 'cscope) + + +(defcustom cscope-index-file "cscope.files" + "*The name of the cscope file list file." + :type 'string + :group 'cscope) + + +(defcustom cscope-database-file "cscope.out" + "*The name of the cscope database file." + :type 'string + :group 'cscope) + + +(defcustom cscope-edit-single-match t + "*If non-nil and only one match is output, edit the matched location." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-display-cscope-buffer t + "*If non-nil automatically display the *cscope* buffer after each search." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-stop-at-first-match-dir nil + "*If non-nil, stop searching through multiple databases if a match is found. +This option is useful only if multiple cscope database directories are being +used. When multiple databases are searched, setting this variable to non-nil +will cause searches to stop when a search outputs anything; no databases after +this one will be searched." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-use-relative-paths t + "*If non-nil, use relative paths when creating the list of files to index. +The path is relative to the directory in which the cscope database +will be created. If nil, absolute paths will be used. Absolute paths +are good if you plan on moving the database to some other directory +(if you do so, you'll probably also have to modify +\`cscope-database-regexps\'). Absolute paths may also be good if you +share the database file with other users (you\'ll probably want to +specify some automounted network path for this)." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-index-recursively t + "*If non-nil, index files in the current directory and all subdirectories. +If nil, only files in the current directory are indexed. This +variable is only used when creating the list of files to index, or +when creating the list of files and the corresponding cscope database." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-no-mouse-prompts nil + "*If non-nil, use the symbol under the cursor instead of prompting. +Do not prompt for a value, except for when seaching for a egrep pattern +or a file." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-suppress-empty-matches t + "*If non-nil, delete empty matches.") + + +(defcustom cscope-indexing-script "cscope-indexer" + "*The shell script used to create cscope indices." + :type 'string + :group 'cscope) + + +(defcustom cscope-symbol-chars "A-Za-z0-9_" + "*A string containing legal characters in a symbol. +The current syntax table should really be used for this." + :type 'string + :group 'cscope) + + +(defcustom cscope-filename-chars "-.,/A-Za-z0-9_~!@#$%&+=\\\\" + "*A string containing legal characters in a symbol. +The current syntax table should really be used for this." + :type 'string + :group 'cscope) + + +(defcustom cscope-allow-arrow-overlays t + "*If non-nil, use an arrow overlay to show target lines. +Arrow overlays are only used when the following functions are used: + + cscope-show-entry-other-window + cscope-show-next-entry-other-window + cscope-show-prev-entry-other-window + +The arrow overlay is removed when other cscope functions are used. +Note that the arrow overlay is not an actual part of the text, and can +be removed by quitting the cscope buffer." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-overlay-arrow-string "=>" + "*The overlay string to use when displaying arrow overlays." + :type 'string + :group 'cscope) + + +(defvar cscope-minor-mode-hooks nil + "List of hooks to call when entering cscope-minor-mode.") + + +(defconst cscope-separator-line + "-------------------------------------------------------------------------------\n" + "Line of text to use as a visual separator. +Must end with a newline.") + + +;;;; +;;;; Faces for fontification +;;;; + +(defcustom cscope-use-face t + "*Whether to use text highlighting (à la font-lock) or not." + :group 'cscope + :type '(boolean)) + + +(defface cscope-file-face + '((((class color) (background dark)) + (:foreground "yellow")) + (((class color) (background light)) + (:foreground "blue")) + (t (:bold t))) + "Face used to highlight file name in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-function-face + '((((class color) (background dark)) + (:foreground "cyan")) + (((class color) (background light)) + (:foreground "magenta")) + (t (:bold t))) + "Face used to highlight function name in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-line-number-face + '((((class color) (background dark)) + (:foreground "red")) + (((class color) (background light)) + (:foreground "red")) + (t (:bold t))) + "Face used to highlight line number in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-line-face + '((((class color) (background dark)) + (:foreground "green")) + (((class color) (background light)) + (:foreground "black")) + (t (:bold nil))) + "Face used to highlight the rest of line in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-mouse-face + '((((class color) (background dark)) + (:foreground "white" :background "blue")) + (((class color) (background light)) + (:foreground "white" :background "blue")) + (t (:bold nil))) + "Face used when mouse pointer is within the region of an entry." + :group 'cscope) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Probably, nothing user-customizable past this point. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defconst cscope-running-in-xemacs (string-match "XEmacs\\|Lucid" emacs-version)) + +(defvar cscope-list-entry-keymap nil + "The keymap used in the *cscope* buffer which lists search results.") +(if cscope-list-entry-keymap + nil + (setq cscope-list-entry-keymap (make-keymap)) + (suppress-keymap cscope-list-entry-keymap) + ;; The following section does not appear in the "Cscope" menu. + (if cscope-running-in-xemacs + (define-key cscope-list-entry-keymap [button2] 'cscope-mouse-select-entry-other-window) + (define-key cscope-list-entry-keymap [mouse-2] 'cscope-mouse-select-entry-other-window)) + (define-key cscope-list-entry-keymap [return] 'cscope-select-entry-other-window) + (define-key cscope-list-entry-keymap " " 'cscope-show-entry-other-window) + (define-key cscope-list-entry-keymap "o" 'cscope-select-entry-one-window) + (define-key cscope-list-entry-keymap "q" 'cscope-bury-buffer) + (define-key cscope-list-entry-keymap "Q" 'cscope-quit) + (define-key cscope-list-entry-keymap "h" 'cscope-help) + (define-key cscope-list-entry-keymap "?" 'cscope-help) + ;; The following line corresponds to be beginning of the "Cscope" menu. + (define-key cscope-list-entry-keymap "s" 'cscope-find-this-symbol) + (define-key cscope-list-entry-keymap "d" 'cscope-find-this-symbol) + (define-key cscope-list-entry-keymap "g" 'cscope-find-global-definition) + (define-key cscope-list-entry-keymap "G" + 'cscope-find-global-definition-no-prompting) + (define-key cscope-list-entry-keymap "c" 'cscope-find-functions-calling-this-function) + (define-key cscope-list-entry-keymap "C" 'cscope-find-called-functions) + (define-key cscope-list-entry-keymap "t" 'cscope-find-this-text-string) + (define-key cscope-list-entry-keymap "e" 'cscope-find-egrep-pattern) + (define-key cscope-list-entry-keymap "f" 'cscope-find-this-file) + (define-key cscope-list-entry-keymap "i" 'cscope-find-files-including-file) + ;; --- (The '---' indicates that this line corresponds to a menu separator.) + (define-key cscope-list-entry-keymap "n" 'cscope-next-symbol) + (define-key cscope-list-entry-keymap "N" 'cscope-next-file) + (define-key cscope-list-entry-keymap "p" 'cscope-prev-symbol) + (define-key cscope-list-entry-keymap "P" 'cscope-prev-file) + (define-key cscope-list-entry-keymap "u" 'cscope-pop-mark) + ;; --- + (define-key cscope-list-entry-keymap "a" 'cscope-set-initial-directory) + (define-key cscope-list-entry-keymap "A" 'cscope-unset-initial-directory) + ;; --- + (define-key cscope-list-entry-keymap "L" 'cscope-create-list-of-files-to-index) + (define-key cscope-list-entry-keymap "I" 'cscope-index-files) + (define-key cscope-list-entry-keymap "E" 'cscope-edit-list-of-files-to-index) + (define-key cscope-list-entry-keymap "W" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "S" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "T" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "D" 'cscope-dired-directory) + ;; The previous line corresponds to be end of the "Cscope" menu. + ) + + +(defvar cscope-list-entry-hook nil + "*Hook run after cscope-list-entry-mode entered.") + + +(defun cscope-list-entry-mode () + "Major mode for jumping/showing entry from the list in the *cscope* buffer. + +\\{cscope-list-entry-keymap}" + (use-local-map cscope-list-entry-keymap) + (setq buffer-read-only t + mode-name "cscope" + major-mode 'cscope-list-entry-mode + overlay-arrow-string cscope-overlay-arrow-string) + (or overlay-arrow-position + (setq overlay-arrow-position (make-marker))) + (run-hooks 'cscope-list-entry-hook)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-output-buffer-name "*cscope*" + "The name of the cscope output buffer.") + + +(defvar cscope-info-buffer-name "*cscope-info*" + "The name of the cscope information buffer.") + + +(defvar cscope-process nil + "The current cscope process.") +(make-variable-buffer-local 'cscope-process) + + +(defvar cscope-process-output nil + "A buffer for holding partial cscope process output.") +(make-variable-buffer-local 'cscope-process-output) + + +(defvar cscope-command-args nil + "Internal variable for holding major command args to pass to cscope.") +(make-variable-buffer-local 'cscope-command-args) + + +(defvar cscope-start-directory nil + "Internal variable used to save the initial start directory. +The results buffer gets reset to this directory when a search has +completely finished.") +(make-variable-buffer-local 'cscope-start-directory) + + +(defvar cscope-search-list nil + "A list of (DIR . FLAGS) entries. +This is a list of database directories to search. Each entry in the list +is a (DIR . FLAGS) cell. DIR is the directory to search, and FLAGS are the +flags to pass to cscope when using this database directory. FLAGS can be +nil (meaning, \"no flags\").") +(make-variable-buffer-local 'cscope-search-list) + + +(defvar cscope-searched-dirs nil + "The list of database directories already searched.") +(make-variable-buffer-local 'cscope-searched-dirs) + + +(defvar cscope-filter-func nil + "Internal variable for holding the filter function to use (if any) when +searching.") +(make-variable-buffer-local 'cscope-filter-func) + + +(defvar cscope-sentinel-func nil + "Internal variable for holding the sentinel function to use (if any) when +searching.") +(make-variable-buffer-local 'cscope-filter-func) + + +(defvar cscope-last-file nil + "The file referenced by the last line of cscope process output.") +(make-variable-buffer-local 'cscope-last-file) + + +(defvar cscope-start-time nil + "The search start time, in seconds.") +(make-variable-buffer-local 'cscope-start-time) + + +(defvar cscope-first-match nil + "The first match result output by cscope.") +(make-variable-buffer-local 'cscope-first-match) + + +(defvar cscope-first-match-point nil + "Buffer location of the first match.") +(make-variable-buffer-local 'cscope-first-match-point) + + +(defvar cscope-item-start nil + "The point location of the start of a search's output, before header info.") +(make-variable-buffer-local 'cscope-output-start) + + +(defvar cscope-output-start nil + "The point location of the start of a search's output.") +(make-variable-buffer-local 'cscope-output-start) + + +(defvar cscope-matched-multiple nil + "Non-nil if cscope output multiple matches.") +(make-variable-buffer-local 'cscope-matched-multiple) + + +(defvar cscope-stop-at-first-match-dir-meta nil + "") +(make-variable-buffer-local 'cscope-stop-at-first-match-dir-meta) + + +(defvar cscope-symbol nil + "The last symbol searched for.") + + +(defvar cscope-adjust t + "True if the symbol searched for (cscope-symbol) should be on +the line specified by the cscope database. In such cases the point will be +adjusted if need be (fuzzy matching).") + + +(defvar cscope-adjust-range 1000 + "How far the point should be adjusted if the symbol is not on the line +specified by the cscope database.") + + +(defvar cscope-marker nil + "The location from which cscope was invoked.") + + +(defvar cscope-marker-window nil + "The window which should contain cscope-marker. This is the window from +which cscope-marker is set when searches are launched from the *cscope* +buffer.") + + +(defvar cscope-marker-ring-length 16 + "Length of the cscope marker ring.") + + +(defvar cscope-marker-ring (make-ring cscope-marker-ring-length) + "Ring of markers which are locations from which cscope was invoked.") + + +(defvar cscope-initial-directory nil + "When set the directory in which searches for the cscope database +directory should begin.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope:map nil + "The cscope keymap.") +(if cscope:map + nil + (setq cscope:map (make-sparse-keymap)) + ;; The following line corresponds to be beginning of the "Cscope" menu. + (define-key cscope:map "\C-css" 'cscope-find-this-symbol) + (define-key cscope:map "\C-csd" 'cscope-find-global-definition) + (define-key cscope:map "\C-csg" 'cscope-find-global-definition) + (define-key cscope:map "\C-csG" 'cscope-find-global-definition-no-prompting) + (define-key cscope:map "\C-csc" 'cscope-find-functions-calling-this-function) + (define-key cscope:map "\C-csC" 'cscope-find-called-functions) + (define-key cscope:map "\C-cst" 'cscope-find-this-text-string) + (define-key cscope:map "\C-cse" 'cscope-find-egrep-pattern) + (define-key cscope:map "\C-csf" 'cscope-find-this-file) + (define-key cscope:map "\C-csi" 'cscope-find-files-including-file) + ;; --- (The '---' indicates that this line corresponds to a menu separator.) + (define-key cscope:map "\C-csb" 'cscope-display-buffer) + (define-key cscope:map "\C-csB" 'cscope-display-buffer-toggle) + (define-key cscope:map "\C-csn" 'cscope-next-symbol) + (define-key cscope:map "\C-csN" 'cscope-next-file) + (define-key cscope:map "\C-csp" 'cscope-prev-symbol) + (define-key cscope:map "\C-csP" 'cscope-prev-file) + (define-key cscope:map "\C-csu" 'cscope-pop-mark) + ;; --- + (define-key cscope:map "\C-csa" 'cscope-set-initial-directory) + (define-key cscope:map "\C-csA" 'cscope-unset-initial-directory) + ;; --- + (define-key cscope:map "\C-csL" 'cscope-create-list-of-files-to-index) + (define-key cscope:map "\C-csI" 'cscope-index-files) + (define-key cscope:map "\C-csE" 'cscope-edit-list-of-files-to-index) + (define-key cscope:map "\C-csW" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csS" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csT" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csD" 'cscope-dired-directory)) + ;; The previous line corresponds to be end of the "Cscope" menu. + +(easy-menu-define cscope:menu + (list cscope:map cscope-list-entry-keymap) + "cscope menu" + '("Cscope" + [ "Find symbol" cscope-find-this-symbol t ] + [ "Find global definition" cscope-find-global-definition t ] + [ "Find global definition no prompting" + cscope-find-global-definition-no-prompting t ] + [ "Find functions calling a function" + cscope-find-functions-calling-this-function t ] + [ "Find called functions" cscope-find-called-functions t ] + [ "Find text string" cscope-find-this-text-string t ] + [ "Find egrep pattern" cscope-find-egrep-pattern t ] + [ "Find a file" cscope-find-this-file t ] + [ "Find files #including a file" + cscope-find-files-including-file t ] + "-----------" + [ "Display *cscope* buffer" cscope-display-buffer t ] + [ "Auto display *cscope* buffer toggle" + cscope-display-buffer-toggle t ] + [ "Next symbol" cscope-next-symbol t ] + [ "Next file" cscope-next-file t ] + [ "Previous symbol" cscope-prev-symbol t ] + [ "Previous file" cscope-prev-file t ] + [ "Pop mark" cscope-pop-mark t ] + "-----------" + ( "Cscope Database" + [ "Set initial directory" + cscope-set-initial-directory t ] + [ "Unset initial directory" + cscope-unset-initial-directory t ] + "-----------" + [ "Create list of files to index" + cscope-create-list-of-files-to-index t ] + [ "Create list and index" + cscope-index-files t ] + [ "Edit list of files to index" + cscope-edit-list-of-files-to-index t ] + [ "Locate this buffer's cscope directory" + cscope-tell-user-about-directory t ] + [ "Dired this buffer's cscope directory" + cscope-dired-directory t ] + ) + "-----------" + ( "Options" + [ "Auto edit single match" + (setq cscope-edit-single-match + (not cscope-edit-single-match)) + :style toggle :selected cscope-edit-single-match ] + [ "Auto display *cscope* buffer" + (setq cscope-display-cscope-buffer + (not cscope-display-cscope-buffer)) + :style toggle :selected cscope-display-cscope-buffer ] + [ "Stop at first matching database" + (setq cscope-stop-at-first-match-dir + (not cscope-stop-at-first-match-dir)) + :style toggle + :selected cscope-stop-at-first-match-dir ] + [ "Never update cscope database" + (setq cscope-do-not-update-database + (not cscope-do-not-update-database)) + :style toggle :selected cscope-do-not-update-database ] + [ "Index recursively" + (setq cscope-index-recursively + (not cscope-index-recursively)) + :style toggle :selected cscope-index-recursively ] + [ "Suppress empty matches" + (setq cscope-suppress-empty-matches + (not cscope-suppress-empty-matches)) + :style toggle :selected cscope-suppress-empty-matches ] + [ "Use relative paths" + (setq cscope-use-relative-paths + (not cscope-use-relative-paths)) + :style toggle :selected cscope-use-relative-paths ] + [ "No mouse prompts" (setq cscope-no-mouse-prompts + (not cscope-no-mouse-prompts)) + :style toggle :selected cscope-no-mouse-prompts ] + ) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Internal functions and variables +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-common-text-plist + (let (plist) + (setq plist (plist-put plist 'mouse-face 'cscope-mouse-face)) + plist) + "List of common text properties to be added to the entry line.") + + +(defun cscope-insert-with-text-properties (text filename &optional line-number) + "Insert an entry with given TEXT, add entry attributes as text properties. +The text properties to be added: +- common property: mouse-face, +- properties are used to open target file and its location: cscope-file, + cscope-line-number" + (let ((plist cscope-common-text-plist) + beg end) + (setq beg (point)) + (insert text) + (setq end (point) + plist (plist-put plist 'cscope-file filename)) + (if line-number + (progn + (if (stringp line-number) + (setq line-number (string-to-number line-number))) + (setq plist (plist-put plist 'cscope-line-number line-number)) + )) + (add-text-properties beg end plist) + )) + + +(if cscope-running-in-xemacs + (progn + (defalias 'cscope-event-window 'event-window) + (defalias 'cscope-event-point 'event-point) + (defalias 'cscope-recenter 'recenter) + ) + (defun cscope-event-window (event) + "Return the window at which the mouse EVENT occurred." + (posn-window (event-start event))) + (defun cscope-event-point (event) + "Return the point at which the mouse EVENT occurred." + (posn-point (event-start event))) + (defun cscope-recenter (&optional n window) + "Center point in WINDOW and redisplay frame. With N, put point on line N." + (save-selected-window + (if (windowp window) + (select-window window)) + (recenter n))) + ) + + +(defun cscope-show-entry-internal (file line-number + &optional save-mark-p window arrow-p) + "Display the buffer corresponding to FILE and LINE-NUMBER +in some window. If optional argument WINDOW is given, +display the buffer in that WINDOW instead. The window is +not selected. Save point on mark ring before goto +LINE-NUMBER if optional argument SAVE-MARK-P is non-nil. +Put `overlay-arrow-string' if arrow-p is non-nil. +Returns the window displaying BUFFER." + (let (buffer old-pos old-point new-point forward-point backward-point + line-end line-length) + (if (and (stringp file) + (integerp line-number)) + (progn + (unless (file-readable-p file) + (error "%s is not readable or exists" file)) + (setq buffer (find-file-noselect file)) + (if (windowp window) + (set-window-buffer window buffer) + (setq window (display-buffer buffer))) + (set-buffer buffer) + (if (> line-number 0) + (progn + (setq old-pos (point)) + (goto-line line-number) + (setq old-point (point)) + (if (and cscope-adjust cscope-adjust-range) + (progn + ;; Calculate the length of the line specified by cscope. + (end-of-line) + (setq line-end (point)) + (goto-char old-point) + (setq line-length (- line-end old-point)) + + ;; Search forward and backward for the pattern. + (setq forward-point (search-forward + cscope-symbol + (+ old-point + cscope-adjust-range) t)) + (goto-char old-point) + (setq backward-point (search-backward + cscope-symbol + (- old-point + cscope-adjust-range) t)) + (if forward-point + (progn + (if backward-point + (setq new-point + ;; Use whichever of forward-point or + ;; backward-point is closest to old-point. + ;; Give forward-point a line-length advantage + ;; so that if the symbol is on the current + ;; line the current line is chosen. + (if (<= (- (- forward-point line-length) + old-point) + (- old-point backward-point)) + forward-point + backward-point)) + (setq new-point forward-point))) + (if backward-point + (setq new-point backward-point) + (setq new-point old-point))) + (goto-char new-point) + (beginning-of-line) + (setq new-point (point))) + (setq new-point old-point)) + (set-window-point window new-point) + (if (and cscope-allow-arrow-overlays arrow-p) + (set-marker overlay-arrow-position (point)) + (set-marker overlay-arrow-position nil)) + (or (not save-mark-p) + (= old-pos (point)) + (push-mark old-pos)) + )) + + (if cscope-marker + (progn ;; The search was successful. Save the marker so it + ;; can be returned to by cscope-pop-mark. + (ring-insert cscope-marker-ring cscope-marker) + ;; Unset cscope-marker so that moving between matches + ;; (cscope-next-symbol, etc.) does not fill + ;; cscope-marker-ring. + (setq cscope-marker nil))) + (setq cscope-marker-window window) + ) + (message "No entry found at point.")) + ) + window) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; functions in *cscope* buffer which lists the search results +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-select-entry-other-window () + "Display the entry at point in other window, select the window. +Push current point on mark ring and select the entry window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number)) + window) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (select-window window)) + )) + + +(defun cscope-select-entry-one-window () + "Display the entry at point in one window, select the window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number)) + window) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (progn + (select-window window) + (sit-for 0) ;; Redisplay hack to allow delete-other-windows + ;; to continue displaying the correct location. + (delete-other-windows window) + )) + )) + + +(defun cscope-select-entry-specified-window (window) + "Display the entry at point in a specified window, select the window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number))) + (setq window (cscope-show-entry-internal file line-number t window)) + (if (windowp window) + (select-window window)) + )) + + +(defun cscope-mouse-select-entry-other-window (event) + "Display the entry over which the mouse event occurred, select the window." + (interactive "e") + (let ((ep (cscope-event-point event)) + (win (cscope-event-window event)) + buffer file line-number window) + (if ep + (progn + (setq buffer (window-buffer win) + file (get-text-property ep 'cscope-file buffer) + line-number (get-text-property ep 'cscope-line-number buffer)) + (select-window win) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (select-window window)) + ) + (message "No entry found at point.") + ) + )) + + +(defun cscope-show-entry-other-window () + "Display the entry at point in other window. +Point is not saved on mark ring." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number))) + (cscope-show-entry-internal file line-number nil nil t) + )) + + +(defun cscope-buffer-search (do-symbol do-next) + "The body of the following four functions." + (let* (line-number old-point point + (search-file (not do-symbol)) + (search-prev (not do-next)) + (direction (if do-next 1 -1)) + (old-buffer (current-buffer)) + (old-buffer-window (get-buffer-window old-buffer)) + (buffer (get-buffer cscope-output-buffer-name)) + (buffer-window (get-buffer-window (or buffer (error "The *cscope* buffer does not exist yet")))) + ) + (set-buffer buffer) + (setq old-point (point)) + (forward-line direction) + (setq point (point)) + (setq line-number (get-text-property point 'cscope-line-number)) + (while (or (not line-number) + (or (and do-symbol (= line-number -1)) + (and search-file (/= line-number -1)))) + (forward-line direction) + (setq point (point)) + (if (or (and do-next (>= point (point-max))) + (and search-prev (<= point (point-min)))) + (progn + (goto-char old-point) + (error "The %s of the *cscope* buffer has been reached" + (if do-next "end" "beginning")))) + (setq line-number (get-text-property point 'cscope-line-number))) + (if (eq old-buffer buffer) ;; In the *cscope* buffer. + (cscope-show-entry-other-window) + (cscope-select-entry-specified-window old-buffer-window) ;; else + (if (windowp buffer-window) + (set-window-point buffer-window point))) + (set-buffer old-buffer) + )) + + +(defun cscope-display-buffer () + "Display the *cscope* buffer." + (interactive) + (let ((buffer (get-buffer cscope-output-buffer-name))) + (if buffer + (pop-to-buffer buffer) + (error "The *cscope* buffer does not exist yet")))) + + +(defun cscope-display-buffer-toggle () + "Toggle cscope-display-cscope-buffer, which corresponds to +\"Auto display *cscope* buffer\"." + (interactive) + (setq cscope-display-cscope-buffer (not cscope-display-cscope-buffer)) + (message "The cscope-display-cscope-buffer variable is now %s." + (if cscope-display-cscope-buffer "set" "unset"))) + + +(defun cscope-next-symbol () + "Move to the next symbol in the *cscope* buffer." + (interactive) + (cscope-buffer-search t t)) + + +(defun cscope-next-file () + "Move to the next file in the *cscope* buffer." + (interactive) + (cscope-buffer-search nil t)) + + +(defun cscope-prev-symbol () + "Move to the previous symbol in the *cscope* buffer." + (interactive) + (cscope-buffer-search t nil)) + + +(defun cscope-prev-file () + "Move to the previous file in the *cscope* buffer." + (interactive) + (cscope-buffer-search nil nil)) + + +(defun cscope-pop-mark () + "Pop back to where cscope was last invoked." + (interactive) + + ;; This function is based on pop-tag-mark, which can be found in + ;; lisp/progmodes/etags.el. + + (if (ring-empty-p cscope-marker-ring) + (error "There are no marked buffers in the cscope-marker-ring yet")) + (let* ( (marker (ring-remove cscope-marker-ring 0)) + (old-buffer (current-buffer)) + (marker-buffer (marker-buffer marker)) + marker-window + (marker-point (marker-position marker)) + (cscope-buffer (get-buffer cscope-output-buffer-name)) ) + + ;; After the following both cscope-marker-ring and cscope-marker will be + ;; in the state they were immediately after the last search. This way if + ;; the user now makes a selection in the previously generated *cscope* + ;; buffer things will behave the same way as if that selection had been + ;; made immediately after the last search. + (setq cscope-marker marker) + + (if marker-buffer + (if (eq old-buffer cscope-buffer) + (progn ;; In the *cscope* buffer. + (set-buffer marker-buffer) + (setq marker-window (display-buffer marker-buffer)) + (set-window-point marker-window marker-point) + (select-window marker-window)) + (switch-to-buffer marker-buffer)) + (error "The marked buffer has been deleted")) + (goto-char marker-point) + (set-buffer old-buffer))) + + +(defun cscope-set-initial-directory (cs-id) + "Set the cscope-initial-directory variable. The +cscope-initial-directory variable, when set, specifies the directory +where searches for the cscope database directory should begin. This +overrides the current directory, which would otherwise be used." + (interactive "DCscope Initial Directory: ") + (setq cscope-initial-directory cs-id)) + + +(defun cscope-unset-initial-directory () + "Unset the cscope-initial-directory variable." + (interactive) + (setq cscope-initial-directory nil) + (message "The cscope-initial-directory variable is now unset.")) + + +(defun cscope-help () + (interactive) + (message + (format "RET=%s, SPC=%s, o=%s, n=%s, p=%s, q=%s, h=%s" + "Select" + "Show" + "SelectOneWin" + "ShowNext" + "ShowPrev" + "Quit" + "Help"))) + + +(defun cscope-bury-buffer () + "Clean up cscope, if necessary, and bury the buffer." + (interactive) + (let () + (if overlay-arrow-position + (set-marker overlay-arrow-position nil)) + (setq overlay-arrow-position nil + overlay-arrow-string nil) + (bury-buffer (get-buffer cscope-output-buffer-name)) + )) + + +(defun cscope-quit () + (interactive) + (cscope-bury-buffer) + (kill-buffer cscope-output-buffer-name) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-canonicalize-directory (dir) + (or dir + (setq dir default-directory)) + (setq dir (file-name-as-directory + (expand-file-name (substitute-in-file-name dir)))) + dir + ) + + +(defun cscope-search-directory-hierarchy (directory) + "Look for a cscope database in the directory hierarchy. +Starting from DIRECTORY, look upwards for a cscope database." + (let (this-directory database-dir) + (catch 'done + (if (file-regular-p directory) + (throw 'done directory)) + (setq directory (cscope-canonicalize-directory directory) + this-directory directory) + (while this-directory + (if (or (file-exists-p (concat this-directory cscope-database-file)) + (file-exists-p (concat this-directory cscope-index-file))) + (progn + (setq database-dir this-directory) + (throw 'done database-dir) + )) + (if (string-match "^\\(/\\|[A-Za-z]:[\\/]\\)$" this-directory) + (throw 'done directory)) + (setq this-directory (file-name-as-directory + (file-name-directory + (directory-file-name this-directory)))) + )) + )) + + +(defun cscope-find-info (top-directory) + "Locate a suitable cscope database directory. +First, `cscope-database-regexps' is used to search for a suitable +database directory. If a database location cannot be found using this +variable, then the current directory is searched, then the parent, +then the parent's parent, until a cscope database directory is found, +or the root directory is reached. If the root directory is reached, +the current directory will be used." + (let (info regexps dir-regexp this-directory) + (setq top-directory (cscope-canonicalize-directory + (or top-directory cscope-initial-directory))) + (catch 'done + ;; Try searching using `cscope-database-regexps' ... + (setq regexps cscope-database-regexps) + (while regexps + (setq dir-regexp (car (car regexps))) + (cond + ( (stringp dir-regexp) + (if (string-match dir-regexp top-directory) + (progn + (setq info (cdr (car regexps))) + (throw 'done t) + )) ) + ( (and (symbolp dir-regexp) dir-regexp) + (progn + (setq info (cdr (car regexps))) + (throw 'done t) + ) )) + (setq regexps (cdr regexps)) + ) + + ;; Try looking in the directory hierarchy ... + (if (setq this-directory + (cscope-search-directory-hierarchy top-directory)) + (progn + (setq info (list (list this-directory))) + (throw 'done t) + )) + + ;; Should we add any more places to look? + + ) ;; end catch + (if (not info) + (setq info (list (list top-directory)))) + info + )) + + +(defun cscope-make-entry-line (func-name line-number line) + ;; The format of entry line: + ;; func-name[line-number]______line + ;; <- cscope-name-line-width -> + ;; `format' of Emacs doesn't have "*s" spec. + (let* ((fmt (format "%%%ds %%s" cscope-name-line-width)) + (str (format fmt (format "%s[%s]" func-name line-number) line)) + beg end) + (if cscope-use-face + (progn + (setq end (length func-name)) + (put-text-property 0 end 'face 'cscope-function-face str) + (setq beg (1+ end) + end (+ beg (length line-number))) + (put-text-property beg end 'face 'cscope-line-number-face str) + (setq end (length str) + beg (- end (length line))) + (put-text-property beg end 'face 'cscope-line-face str) + )) + str)) + + +(defun cscope-process-filter (process output) + "Accept cscope process output and reformat it for human readability. +Magic text properties are added to allow the user to select lines +using the mouse." + (let ( (old-buffer (current-buffer)) ) + (unwind-protect + (progn + (set-buffer (process-buffer process)) + ;; Make buffer-read-only nil + (let (buffer-read-only line file function-name line-number moving) + (setq moving (= (point) (process-mark process))) + (save-excursion + (goto-char (process-mark process)) + ;; Get the output thus far ... + (if cscope-process-output + (setq cscope-process-output (concat cscope-process-output + output)) + (setq cscope-process-output output)) + ;; Slice and dice it into lines. + ;; While there are whole lines left ... + (while (and cscope-process-output + (string-match "\\([^\n]+\n\\)\\(\\(.\\|\n\\)*\\)" + cscope-process-output)) + (setq file nil + glimpse-stripped-directory nil + ) + ;; Get a line + (setq line (substring cscope-process-output + (match-beginning 1) (match-end 1))) + (setq cscope-process-output (substring cscope-process-output + (match-beginning 2) + (match-end 2))) + (if (= (length cscope-process-output) 0) + (setq cscope-process-output nil)) + + ;; This should always match. + (if (string-match + "^\\([^ \t]+\\)[ \t]+\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\(.*\\)\n" + line) + (progn + (let (str) + (setq file (substring line (match-beginning 1) + (match-end 1)) + function-name (substring line (match-beginning 2) + (match-end 2)) + line-number (substring line (match-beginning 3) + (match-end 3)) + line (substring line (match-beginning 4) + (match-end 4)) + ) + ;; If the current file is not the same as the previous + ;; one ... + (if (not (and cscope-last-file + (string= file cscope-last-file))) + (progn + ;; The current file is different. + + ;; Insert a separating blank line if + ;; necessary. + (if cscope-last-file (insert "\n")) + ;; Insert the file name + (setq str (concat "*** " file ":")) + (if cscope-use-face + (put-text-property 0 (length str) + 'face 'cscope-file-face + str)) + (cscope-insert-with-text-properties + str + (expand-file-name file) + ;; Yes, -1 is intentional + -1) + (insert "\n") + )) + (if (not cscope-first-match) + (setq cscope-first-match-point (point))) + ;; ... and insert the line, with the + ;; appropriate indentation. + (cscope-insert-with-text-properties + (cscope-make-entry-line function-name + line-number + line) + (expand-file-name file) + line-number) + (insert "\n") + (setq cscope-last-file file) + (if cscope-first-match + (setq cscope-matched-multiple t) + (setq cscope-first-match + (cons (expand-file-name file) + (string-to-number line-number)))) + )) + (insert line "\n") + )) + (set-marker (process-mark process) (point)) + ) + (if moving + (goto-char (process-mark process))) + (set-buffer-modified-p nil) + )) + (set-buffer old-buffer)) + )) + + +(defun cscope-process-sentinel (process event) + "Sentinel for when the cscope process dies." + (let* ( (buffer (process-buffer process)) window update-window + (done t) (old-buffer (current-buffer)) + (old-buffer-window (get-buffer-window old-buffer)) ) + (set-buffer buffer) + (save-window-excursion + (save-excursion + (if (or (and (setq window (get-buffer-window buffer)) + (= (window-point window) (point-max))) + (= (point) (point-max))) + (progn + (setq update-window t) + )) + (delete-process process) + (let (buffer-read-only continue) + (goto-char (point-max)) + (if (and cscope-suppress-empty-matches + (= cscope-output-start (point))) + (delete-region cscope-item-start (point-max)) + (progn + (if (not cscope-start-directory) + (setq cscope-start-directory default-directory)) + (insert cscope-separator-line) + )) + (setq continue + (and cscope-search-list + (not (and cscope-first-match + cscope-stop-at-first-match-dir + (not cscope-stop-at-first-match-dir-meta))))) + (if continue + (setq continue (cscope-search-one-database))) + (if continue + (progn + (setq done nil) + ) + (progn + (insert "\nSearch complete.") + (if cscope-display-times + (let ( (times (current-time)) cscope-stop elapsed-time ) + (setq cscope-stop (+ (* (car times) 65536.0) + (car (cdr times)) + (* (car (cdr (cdr times))) 1.0E-6))) + (setq elapsed-time (- cscope-stop cscope-start-time)) + (insert (format " Search time = %.2f seconds." + elapsed-time)) + )) + (setq cscope-process nil) + (if cscope-running-in-xemacs + (setq modeline-process ": Search complete")) + (if cscope-start-directory + (setq default-directory cscope-start-directory)) + (if (not cscope-first-match) + (message "No matches were found.")) + ) + )) + (set-buffer-modified-p nil) + )) + (if (and done cscope-first-match-point update-window) + (if window + (set-window-point window cscope-first-match-point) + (goto-char cscope-first-match-point)) + ) + (cond + ( (not done) ;; we're not done -- do nothing for now + (if update-window + (if window + (set-window-point window (point-max)) + (goto-char (point-max)))) + ) + ( cscope-first-match + (if cscope-display-cscope-buffer + (if (and cscope-edit-single-match (not cscope-matched-multiple)) + (cscope-show-entry-internal(car cscope-first-match) + (cdr cscope-first-match) t)) + (cscope-select-entry-specified-window old-buffer-window)) + ) + ) + (if (and done (eq old-buffer buffer) cscope-first-match) + (cscope-help)) + (set-buffer old-buffer) + )) + + +(defun cscope-search-one-database () + "Pop a database entry from cscope-search-list and do a search there." + (let ( next-item options cscope-directory database-file outbuf done + base-database-file-name) + (setq outbuf (get-buffer-create cscope-output-buffer-name)) + (save-excursion + (catch 'finished + (set-buffer outbuf) + (setq options '("-L")) + (while (and (not done) cscope-search-list) + (setq next-item (car cscope-search-list) + cscope-search-list (cdr cscope-search-list) + base-database-file-name cscope-database-file + ) + (if (listp next-item) + (progn + (setq cscope-directory (car next-item)) + (if (not (stringp cscope-directory)) + (setq cscope-directory + (cscope-search-directory-hierarchy + default-directory))) + (if (file-regular-p cscope-directory) + (progn + ;; Handle the case where `cscope-directory' is really + ;; a full path name to a cscope database. + (setq base-database-file-name + (file-name-nondirectory cscope-directory) + cscope-directory + (file-name-directory cscope-directory)) + )) + (setq cscope-directory + (file-name-as-directory cscope-directory)) + (if (not (member cscope-directory cscope-searched-dirs)) + (progn + (setq cscope-searched-dirs (cons cscope-directory + cscope-searched-dirs) + done t) + )) + ) + (progn + (if (and cscope-first-match + cscope-stop-at-first-match-dir + cscope-stop-at-first-match-dir-meta) + (throw 'finished nil)) + )) + ) + (if (not done) + (throw 'finished nil)) + (if (car (cdr next-item)) + (let (newopts) + (setq newopts (car (cdr next-item))) + (if (not (listp newopts)) + (error (format "Cscope options must be a list: %s" newopts))) + (setq options (append options newopts)) + )) + (if cscope-command-args + (setq options (append options cscope-command-args))) + (setq database-file (concat cscope-directory base-database-file-name) + cscope-searched-dirs (cons cscope-directory + cscope-searched-dirs) + ) + + ;; The database file and the directory containing the database file + ;; must both be writable. + (if (or (not (file-writable-p database-file)) + (not (file-writable-p (file-name-directory database-file))) + cscope-do-not-update-database) + (setq options (cons "-d" options))) + + (goto-char (point-max)) + (setq cscope-item-start (point)) + (if (string= base-database-file-name cscope-database-file) + (insert "\nDatabase directory: " cscope-directory "\n" + cscope-separator-line) + (insert "\nDatabase directory/file: " + cscope-directory base-database-file-name "\n" + cscope-separator-line)) + ;; Add the correct database file to search + (setq options (cons base-database-file-name options)) + (setq options (cons "-f" options)) + (setq cscope-output-start (point)) + (setq default-directory cscope-directory) + (if cscope-filter-func + (progn + (setq cscope-process-output nil + cscope-last-file nil + ) + (setq cscope-process + (apply 'start-process "cscope" outbuf + cscope-program options)) + (set-process-filter cscope-process cscope-filter-func) + (set-process-sentinel cscope-process cscope-sentinel-func) + (set-marker (process-mark cscope-process) (point)) + (process-kill-without-query cscope-process) + (if cscope-running-in-xemacs + (setq modeline-process ": Searching ...")) + (setq buffer-read-only t) + ) + (apply 'call-process cscope-program nil outbuf t options) + ) + t + )) + )) + + +(defun cscope-call (msg args &optional directory filter-func sentinel-func) + "Generic function to call to process cscope requests. +ARGS is a list of command-line arguments to pass to the cscope +process. DIRECTORY is the current working directory to use (generally, +the directory in which the cscope database is located, but not +necessarily), if different that the current one. FILTER-FUNC and +SENTINEL-FUNC are optional process filter and sentinel, respectively." + (let ( (outbuf (get-buffer-create cscope-output-buffer-name)) + (old-buffer (current-buffer)) ) + (if cscope-process + (error "A cscope search is still in progress -- only one at a time is allowed")) + (setq directory (cscope-canonicalize-directory + (or cscope-initial-directory directory))) + (if (eq outbuf old-buffer) ;; In the *cscope* buffer. + (if cscope-marker-window + (progn + ;; Assume that cscope-marker-window is the window, from the + ;; users perspective, from which the search was launched and the + ;; window that should be returned to upon cscope-pop-mark. + (set-buffer (window-buffer cscope-marker-window)) + (setq cscope-marker (point-marker)) + (set-buffer old-buffer))) + (progn ;; Not in the *cscope buffer. + ;; Set the cscope-marker-window to whichever window this search + ;; was launched from. + (setq cscope-marker-window (get-buffer-window old-buffer)) + (setq cscope-marker (point-marker)))) + (save-excursion + (set-buffer outbuf) + (if cscope-display-times + (let ( (times (current-time)) ) + (setq cscope-start-time (+ (* (car times) 65536.0) (car (cdr times)) + (* (car (cdr (cdr times))) 1.0E-6))))) + (setq default-directory directory + cscope-start-directory nil + cscope-search-list (cscope-find-info directory) + cscope-searched-dirs nil + cscope-command-args args + cscope-filter-func filter-func + cscope-sentinel-func sentinel-func + cscope-first-match nil + cscope-first-match-point nil + cscope-stop-at-first-match-dir-meta (memq t cscope-search-list) + cscope-matched-multiple nil + buffer-read-only nil) + (buffer-disable-undo) + (erase-buffer) + (setq truncate-lines cscope-truncate-lines) + (if msg + (insert msg "\n")) + (cscope-search-one-database) + ) + (if cscope-display-cscope-buffer + (progn + (pop-to-buffer outbuf) + (cscope-help)) + (set-buffer outbuf)) + (goto-char (point-max)) + (cscope-list-entry-mode) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-unix-index-process-buffer-name "*cscope-indexing-buffer*" + "The name of the buffer to use for displaying indexing status/progress.") + + +(defvar cscope-unix-index-process-buffer nil + "The buffer to use for displaying indexing status/progress.") + + +(defvar cscope-unix-index-process nil + "The current indexing process.") + + +(defun cscope-unix-index-files-sentinel (process event) + "Simple sentinel to print a message saying that indexing is finished." + (let (buffer) + (save-window-excursion + (save-excursion + (setq buffer (process-buffer process)) + (set-buffer buffer) + (goto-char (point-max)) + (insert cscope-separator-line "\nIndexing finished\n") + (delete-process process) + (setq cscope-unix-index-process nil) + (set-buffer-modified-p nil) + )) + )) + + +(defun cscope-unix-index-files-internal (top-directory header-text args) + "Core function to call the indexing script." + (let () + (save-excursion + (setq top-directory (cscope-canonicalize-directory top-directory)) + (setq cscope-unix-index-process-buffer + (get-buffer-create cscope-unix-index-process-buffer-name)) + (display-buffer cscope-unix-index-process-buffer) + (set-buffer cscope-unix-index-process-buffer) + (setq buffer-read-only nil) + (setq default-directory top-directory) + (buffer-disable-undo) + (erase-buffer) + (if header-text + (insert header-text)) + (setq args (append args + (list "-v" + "-i" cscope-index-file + "-f" cscope-database-file + (if cscope-use-relative-paths + "." top-directory)))) + (if cscope-index-recursively + (setq args (cons "-r" args))) + (setq cscope-unix-index-process + (apply 'start-process "cscope-indexer" + cscope-unix-index-process-buffer + cscope-indexing-script args)) + (set-process-sentinel cscope-unix-index-process + 'cscope-unix-index-files-sentinel) + (process-kill-without-query cscope-unix-index-process) + ) + )) + + +(defun cscope-index-files (top-directory) + "Index files in a directory. +This function creates a list of files to index, and then indexes +the listed files. +The variable, \"cscope-index-recursively\", controls whether or not +subdirectories are indexed." + (interactive "DIndex files in directory: ") + (let () + (cscope-unix-index-files-internal + top-directory + (format "Creating cscope index `%s' in:\n\t%s\n\n%s" + cscope-database-file top-directory cscope-separator-line) + nil) + )) + + +(defun cscope-create-list-of-files-to-index (top-directory) + "Create a list of files to index. +The variable, \"cscope-index-recursively\", controls whether or not +subdirectories are indexed." + (interactive "DCreate file list in directory: ") + (let () + (cscope-unix-index-files-internal + top-directory + (format "Creating cscope file list `%s' in:\n\t%s\n\n" + cscope-index-file top-directory) + '("-l")) + )) + + +(defun cscope-edit-list-of-files-to-index () + "Search for and edit the list of files to index. +If this functions causes a new file to be edited, that means that a +cscope.out file was found without a corresponding cscope.files file." + (interactive) + (let (info directory file) + (setq info (cscope-find-info nil)) + (if (/= (length info) 1) + (error "There is no unique cscope database directory!")) + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy default-directory))) + (setq file (concat (file-name-as-directory directory) cscope-index-file)) + (find-file file) + (message (concat "File: " file)) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-tell-user-about-directory () + "Display the name of the directory containing the cscope database." + (interactive) + (let (info directory) + (setq info (cscope-find-info nil)) + (if (= (length info) 1) + (progn + (setq directory (car (car info))) + (message (concat "Cscope directory: " directory)) + ) + (let ( (outbuf (get-buffer-create cscope-info-buffer-name)) ) + (display-buffer outbuf) + (save-excursion + (set-buffer outbuf) + (buffer-disable-undo) + (erase-buffer) + (insert "Cscope search directories:\n") + (while info + (if (listp (car info)) + (progn + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy + default-directory))) + (insert "\t" directory "\n") + )) + (setq info (cdr info)) + ) + ) + )) + )) + + +(defun cscope-dired-directory () + "Run dired upon the cscope database directory. +If possible, the cursor is moved to the name of the cscope database +file." + (interactive) + (let (info directory buffer p1 p2 pos) + (setq info (cscope-find-info nil)) + (if (/= (length info) 1) + (error "There is no unique cscope database directory!")) + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy default-directory))) + (setq buffer (dired-noselect directory nil)) + (switch-to-buffer buffer) + (set-buffer buffer) + (save-excursion + (goto-char (point-min)) + (setq p1 (search-forward cscope-index-file nil t)) + (if p1 + (setq p1 (- p1 (length cscope-index-file)))) + ) + (save-excursion + (goto-char (point-min)) + (setq p2 (search-forward cscope-database-file nil t)) + (if p2 + (setq p2 (- p2 (length cscope-database-file)))) + ) + (cond + ( (and p1 p2) + (if (< p1 p2) + (setq pos p1) + (setq pos p2)) + ) + ( p1 + (setq pos p1) + ) + ( p2 + (setq pos p2) + ) + ) + (if pos + (set-window-point (get-buffer-window buffer) pos)) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-extract-symbol-at-cursor (extract-filename) + (let* ( (symbol-chars (if extract-filename + cscope-filename-chars + cscope-symbol-chars)) + (symbol-char-regexp (concat "[" symbol-chars "]")) + ) + (save-excursion + (buffer-substring-no-properties + (progn + (if (not (looking-at symbol-char-regexp)) + (re-search-backward "\\w" nil t)) + (skip-chars-backward symbol-chars) + (point)) + (progn + (skip-chars-forward symbol-chars) + (point) + ))) + )) + + +(defun cscope-prompt-for-symbol (prompt extract-filename) + "Prompt the user for a cscope symbol." + (let (sym) + (setq sym (cscope-extract-symbol-at-cursor extract-filename)) + (if (or (not sym) + (string= sym "") + (not (and cscope-running-in-xemacs + cscope-no-mouse-prompts current-mouse-event + (or (mouse-event-p current-mouse-event) + (misc-user-event-p current-mouse-event)))) + ;; Always prompt for symbol in dired mode. + (eq major-mode 'dired-mode) + ) + (setq sym (read-from-minibuffer prompt sym)) + sym) + )) + + +(defun cscope-find-this-symbol (symbol) + "Locate a symbol in source code." + (interactive (list + (cscope-prompt-for-symbol "Find this symbol: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding symbol: %s" symbol) + (list "-0" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-global-definition (symbol) + "Find a symbol's global definition." + (interactive (list + (cscope-prompt-for-symbol "Find this global definition: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding global definition: %s" symbol) + (list "-1" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-global-definition-no-prompting () + "Find a symbol's global definition without prompting." + (interactive) + (let ( (symbol (cscope-extract-symbol-at-cursor nil)) + (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding global definition: %s" symbol) + (list "-1" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-called-functions (symbol) + "Display functions called by a function." + (interactive (list + (cscope-prompt-for-symbol + "Find functions called by this function: " nil) + )) + (let ( (cscope-adjust nil) ) ;; Disable fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding functions called by: %s" symbol) + (list "-2" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-functions-calling-this-function (symbol) + "Display functions calling a function." + (interactive (list + (cscope-prompt-for-symbol + "Find functions calling this function: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding functions calling: %s" symbol) + (list "-3" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-this-text-string (symbol) + "Locate where a text string occurs." + (interactive (list + (cscope-prompt-for-symbol "Find this text string: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding text string: %s" symbol) + (list "-4" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-egrep-pattern (symbol) + "Run egrep over the cscope database." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol "Find this egrep pattern: " nil)) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding egrep pattern: %s" symbol) + (list "-6" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-this-file (symbol) + "Locate a file." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol "Find this file: " t)) + )) + (let ( (cscope-adjust nil) ) ;; Disable fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding file: %s" symbol) + (list "-7" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-files-including-file (symbol) + "Locate all files #including a file." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol + "Find files #including this file: " t)) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding files #including file: %s" symbol) + (list "-8" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-minor-mode nil + "") +(make-variable-buffer-local 'cscope-minor-mode) +(put 'cscope-minor-mode 'permanent-local t) + + +(defun cscope-minor-mode (&optional arg) + "" + (progn + (setq cscope-minor-mode (if (null arg) t (car arg))) + (if cscope-minor-mode + (progn + (easy-menu-add cscope:menu cscope:map) + (run-hooks 'cscope-minor-mode-hooks) + )) + cscope-minor-mode + )) + + +(defun cscope:hook () + "" + (progn + (cscope-minor-mode) + )) + + +(or (assq 'cscope-minor-mode minor-mode-map-alist) + (setq minor-mode-map-alist (cons (cons 'cscope-minor-mode cscope:map) + minor-mode-map-alist))) + +(add-hook 'c-mode-hook (function cscope:hook)) +(add-hook 'c++-mode-hook (function cscope:hook)) +(add-hook 'dired-mode-hook (function cscope:hook)) + +(provide 'xcscope) diff --git a/emacs/xml-rpc.el b/emacs/xml-rpc.el new file mode 100644 index 0000000..a807bf4 --- /dev/null +++ b/emacs/xml-rpc.el @@ -0,0 +1,865 @@ +;;; xml-rpc.el --- An elisp implementation of clientside XML-RPC + +;; Copyright (C) 2002-2010 Mark A. Hershberger +;; Copyright (C) 2001 CodeFactory AB. +;; Copyright (C) 2001 Daniel Lundin. +;; Copyright (C) 2006 Shun-ichi Goto +;; Modified for non-ASCII character handling. + +;; Author: Mark A. Hershberger <mah@everybody.org> +;; Original Author: Daniel Lundin <daniel@codefactory.se> +;; Version: 1.6.8 +;; Created: May 13 2001 +;; Keywords: xml rpc network +;; URL: http://launchpad.net/xml-rpc-el +;; Last Modified: <2010-02-27 07:02:36 mah> + +(defconst xml-rpc-version "1.6.8" + "Current version of xml-rpc.el") + +;; This file is NOT (yet) part of 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 3 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, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This is an XML-RPC client implementation in elisp, capable of both +;; synchronous and asynchronous method calls (using the url package's async +;; retrieval functionality). +;; XML-RPC is remote procedure calls over HTTP using XML to describe the +;; function call and return values. + +;; xml-rpc.el represents XML-RPC datatypes as lisp values, automatically +;; converting to and from the XML datastructures as needed, both for method +;; parameters and return values, making using XML-RPC methods fairly +;; transparent to the lisp code. + +;;; Installation: + +;; If you use ELPA (http://tromey.com/elpa), you can install via the +;; M-x package-list-packages interface. This is preferrable as you +;; will have access to updates automatically. + +;; Otherwise, just make sure this file in your load-path (usually +;; ~/.emacs.d is included) and put (require 'xml-rpc) in your +;; ~/.emacs or ~/.emacs.d/init.el file. + +;;; Requirements + +;; xml-rpc.el uses the url package for http handling and xml.el for +;; XML parsing. url is a part of the W3 browser package. The url +;; package that is part of Emacs 22+ works great. +;; +;; xml.el is a part of GNU Emacs 21, but can also be downloaded from +;; here: <URL:ftp://ftp.codefactory.se/pub/people/daniel/elisp/xml.el> + +;;; Bug reports + +;; Please use M-x xml-rpc-submit-bug-report to report bugs. + +;;; XML-RPC datatypes are represented as follows + +;; int: 42 +;; float/double: 42.0 +;; string: "foo" +;; array: '(1 2 3 4) '(1 2 3 (4.1 4.2)) +;; struct: '(("name" . "daniel") ("height" . 6.1)) +;; dateTime: (:datetime (1234 124)) + + +;;; Examples + +;; Here follows some examples demonstrating the use of xml-rpc.el + +;; Normal synchronous operation +;; ---------------------------- + +;; (xml-rpc-method-call "http://localhost:80/RPC" 'foo-method foo bar zoo) + +;; Asynchronous example (cb-foo will be called when the methods returns) +;; --------------------------------------------------------------------- + +;; (defun cb-foo (foo) +;; (print (format "%s" foo))) + +;; (xml-rpc-method-call-async 'cb-foo "http://localhost:80/RPC" +;; 'foo-method foo bar zoo) + + +;; Some real world working examples for fun and play +;; ------------------------------------------------- + +;; Check the temperature (celsius) outside jonas@codefactory.se's apartment + +;; (xml-rpc-method-call +;; "http://flint.bengburken.net:80/xmlrpc/onewire_temp.php" +;; 'onewire.getTemp) + + +;; Fetch the latest NetBSD news the past 5 days from O'reillynet + +;; (xml-rpc-method-call "http://www.oreillynet.com/meerkat/xml-rpc/server.php" +;; 'meerkat.getItems +;; '(("channel" . 1024) +;; ("search" . "/NetBSD/") +;; ("time_period" . "5DAY") +;; ("ids" . 0) +;; ("descriptions" . 200) +;; ("categories" . 0) +;; ("channels" . 0) +;; ("dates" . 0) +;; ("num_items" . 5))) + + +;;; History: + +;; 1.6.8 - Add a report-xml-rpc-bug function + +;; 1.6.7 - Skipped version + +;; 1.6.6 - Use the correct dateTime elements. Fix bug in parsing null int. + +;; 1.6.5.1 - Fix compile time warnings. + +;; 1.6.5 - Made handling of dateTime elements more robust. + +;; 1.6.4.1 - Updated to work with both Emacs22 and Emacs23. + +;; 1.6.2.2 - Modified to allow non-ASCII string again. +;; It can handle non-ASCII page name and comment +;; on Emacs 21 also. + +;; 1.6.2.1 - Modified to allow non-ASCII string. +;; If xml-rpc-allow-unicode-string is non-nil, +;; make 'value' object instead of 'base64' object. +;; This is good for WikiRPC. + +;; 1.6.2 - Fix whitespace issues to work better with new xml.el +;; Fix bug in string handling. +;; Add support for gzip-encoding when needed. + +;; 1.6.1 - base64 support added. +;; url-insert-entities-in-string done on string types now. + +;; 1.6 - Fixed dependencies (remove w3, add cl). +;; Move string-to-boolean and boolean-to-string into xml-rpc +;; namespace. +;; Fix bug in xml-rpc-xml-to-response where non-existent var was. +;; More tweaking of "Connection: close" header. +;; Fix bug in xml-rpc-request-process-buffer so that this works with +;; different mixes of the url.el code. + +;; 1.5.1 - Added Andrew J Cosgriff's patch to make the +;; xml-rpc-clean-string function work in XEmacs. + +;; 1.5 - Added headers to the outgoing url-retreive-synchronously +;; so that it would close connections immediately on completion. + +;; 1.4 - Added conditional debugging code. Added version tag. + +;; 1.2 - Better error handling. The documentation didn't match +;; the code. That was changed so that an error was +;; signaled. Also, better handling of various and +;; different combinations of xml.el and url.el. + +;; 1.1 - Added support for boolean types. If the type of a +;; returned value is not specified, string is assumed + +;; 1.0 - First version + + +;;; Code: + +(require 'xml) +(require 'url-http) +(require 'timezone) +(eval-when-compile + (require 'cl)) + +(defconst xml-rpc-maintainer-address "mah@everybody.org" + "The address where bug reports should be sent.") + +(defcustom xml-rpc-load-hook nil + "*Hook run after loading xml-rpc." + :type 'hook :group 'xml-rpc) + +(defcustom xml-rpc-use-coding-system + (if (coding-system-p 'utf-8) 'utf-8 'iso-8859-1) + "The coding system to use." + :type 'symbol :group 'xml-rpc) + +(defcustom xml-rpc-allow-unicode-string (coding-system-p 'utf-8) + "If non-nil, non-ASCII data is composed as 'value' instead of 'base64'. +And this option overrides `xml-rpc-base64-encode-unicode' and +`xml-rpc-base64-decode-unicode' if set as non-nil." + :type 'boolean :group 'xml-rpc) + +(defcustom xml-rpc-base64-encode-unicode (coding-system-p 'utf-8) + "If non-nil, then strings with non-ascii characters will be turned +into Base64." + :type 'boolean :group 'xml-rpc) + +(defcustom xml-rpc-base64-decode-unicode (coding-system-p 'utf-8) + "If non-nil, then base64 strings will be decoded using the +utf-8 coding system." + :type 'boolean :group 'xml-rpc) + +(defcustom xml-rpc-debug 0 + "Set this to 1 or greater to avoid killing temporary buffers. +Set it higher to get some info in the *Messages* buffer" + :type 'integerp :group 'xml-rpc) + +(defvar xml-rpc-fault-string nil + "Contains the fault string if a fault is returned") + +(defvar xml-rpc-fault-code nil + "Contains the fault code if a fault is returned") + +;; +;; Value type handling functions +;; + +(defsubst xml-rpc-value-intp (value) + "Return t if VALUE is an integer." + (integerp value)) + +(defsubst xml-rpc-value-doublep (value) + "Return t if VALUE is a double precision number." + (floatp value)) + +(defsubst xml-rpc-value-stringp (value) + "Return t if VALUE is a string." + (stringp value)) + +;; An XML-RPC struct is a list where every car is cons or a list of +;; length 1 or 2 and has a string for car. +(defsubst xml-rpc-value-structp (value) + "Return t if VALUE is an XML-RPC struct." + (and (listp value) + (let ((vals value) + (result t) + curval) + (while (and vals result) + (setq result (and + (setq curval (car-safe vals)) + (consp curval) + (stringp (car-safe curval)))) + (setq vals (cdr-safe vals))) + result))) + +;; A somewhat lazy predicate for arrays +(defsubst xml-rpc-value-arrayp (value) + "Return t if VALUE is an XML-RPC struct." + (and (listp value) + (not (xml-rpc-value-datetimep value)) + (not (xml-rpc-value-structp value)))) + +(defun xml-rpc-submit-bug-report () + "Submit a bug report on xml-rpc." + (interactive) + (require 'reporter) + (let ((xml-rpc-tz-pd-defined-in + (if (fboundp 'find-lisp-object-file-name) + (find-lisp-object-file-name + 'timezone-parse-date (symbol-function 'timezone-parse-date)) + (symbol-file 'timezone-parse-date))) + (date-parses-as (timezone-parse-date "20091130T00:52:53"))) + (reporter-submit-bug-report + xml-rpc-maintainer-address + (concat "xml-rpc.el " xml-rpc-version) + (list 'xml-rpc-tz-pd-defined-in + 'date-parses-as + 'xml-rpc-load-hook + 'xml-rpc-use-coding-system + 'xml-rpc-allow-unicode-string + 'xml-rpc-base64-encode-unicode + 'xml-rpc-base64-decode-unicode)))) + +(defun xml-rpc-value-booleanp (value) + "Return t if VALUE is a boolean." + (or (eq value nil) + (eq value t))) + +(defun xml-rpc-value-datetimep (value) + "Return t if VALUE is a datetime. For Emacs XML-RPC +implementation, you must put time keyword :datetime before the +time, or it will be confused for a list." + (and (listp value) + (eq (car value) :datetime))) + +(defun xml-rpc-string-to-boolean (value) + "Return t if VALUE is a boolean" + (or (string-equal value "true") (string-equal value "1"))) + +(defun xml-rpc-caddar-safe (list) + (car-safe (cdr-safe (cdr-safe (car-safe list))))) + +(defun xml-rpc-xml-list-to-value (xml-list) + "Convert an XML-RPC structure in an xml.el style XML-LIST to an elisp list, \ +interpreting and simplifying it while retaining its structure." + (let (valtype valvalue) + (cond + ((and (xml-rpc-caddar-safe xml-list) + (listp (car-safe (cdr-safe (cdr-safe (car-safe xml-list)))))) + + (setq valtype (car (caddar xml-list)) + valvalue (caddr (caddar xml-list))) + (cond + ;; Base64 + ((eq valtype 'base64) + (if xml-rpc-base64-decode-unicode + (decode-coding-string (base64-decode-string valvalue) 'utf-8) + (base64-decode-string valvalue))) + ;; Boolean + ((eq valtype 'boolean) + (xml-rpc-string-to-boolean valvalue)) + ;; String + ((eq valtype 'string) + valvalue) + ;; Integer + ((or (eq valtype 'int) (eq valtype 'i4)) + (string-to-number (or valvalue "0"))) + ;; Double/float + ((eq valtype 'double) + (string-to-number valvalue)) + ;; Struct + ((eq valtype 'struct) + (mapcar (lambda (member) + (let ((membername (cadr (cdaddr member))) + (membervalue (xml-rpc-xml-list-to-value + (cdddr member)))) + (cons membername membervalue))) + (cddr (caddar xml-list)))) + ;; Fault + ((eq valtype 'fault) + (let* ((struct (xml-rpc-xml-list-to-value (list valvalue))) + (fault-string (cdr (assoc "faultString" struct))) + (fault-code (cdr (assoc "faultCode" struct)))) + (list 'fault fault-code fault-string))) + ;; DateTime + ((or (eq valtype 'dateTime.iso8601) + (eq valtype 'dateTime)) + (list :datetime (date-to-time valvalue))) + ;; Array + ((eq valtype 'array) + (mapcar (lambda (arrval) + (xml-rpc-xml-list-to-value (list arrval))) + (cddr valvalue))))) + ((xml-rpc-caddar-safe xml-list))))) + +(defun xml-rpc-boolean-to-string (value) + "Convert a boolean value to a string" + (if value + "1" + "0")) + +(defun xml-rpc-datetime-to-string (value) + "Convert a date time to a valid XML-RPC date" + (format-time-string "%Y%m%dT%H:%M:%S" (cadr value))) + +(defun xml-rpc-value-to-xml-list (value) + "Return XML representation of VALUE properly formatted for use with the \ +functions in xml.el." + (cond + ;; ((not value) + ;; nil) + ((xml-rpc-value-booleanp value) + `((value nil (boolean nil ,(xml-rpc-boolean-to-string value))))) + ;; Date + ((xml-rpc-value-datetimep value) + `((value nil (dateTime.iso8601 nil ,(xml-rpc-datetime-to-string value))))) + ;; list + ((xml-rpc-value-arrayp value) + (let ((result nil) + (xmlval nil)) + (while (setq xmlval (xml-rpc-value-to-xml-list (car value)) + result (if result (append result xmlval) + xmlval) + value (cdr value))) + `((value nil (array nil ,(append '(data nil) result)))))) + ;; struct + ((xml-rpc-value-structp value) + (let ((result nil) + (xmlval nil)) + (while (setq xmlval `((member nil (name nil ,(caar value)) + ,(car (xml-rpc-value-to-xml-list + (cdar value))))) + result (append result xmlval) + value (cdr value))) + `((value nil ,(append '(struct nil) result))))) + ;; Value is a scalar + ((xml-rpc-value-intp value) + `((value nil (int nil ,(int-to-string value))))) + ((xml-rpc-value-stringp value) + (let ((charset-list (find-charset-string value))) + (if (or xml-rpc-allow-unicode-string + (and (eq 1 (length charset-list)) + (eq 'ascii (car charset-list))) + (not xml-rpc-base64-encode-unicode)) + `((value nil (string nil ,value))) + `((value nil (base64 nil ,(if xml-rpc-base64-encode-unicode + (base64-encode-string + (encode-coding-string + value xml-rpc-use-coding-system)) + (base64-encode-string value)))))))) + ((xml-rpc-value-doublep value) + `((value nil (double nil ,(number-to-string value))))) + (t + `((value nil (base64 nil ,(base64-encode-string value))))))) + +(defun xml-rpc-xml-to-string (xml) + "Return a string representation of the XML tree as valid XML markup." + (let ((tree (xml-node-children xml)) + (result (concat "<" (symbol-name (xml-node-name xml)) ">"))) + (while tree + (cond + ((listp (car tree)) + (setq result (concat result (xml-rpc-xml-to-string (car tree))))) + ((stringp (car tree)) + (setq result (concat result (car tree)))) + (t + (error "Invalid XML tree"))) + (setq tree (cdr tree))) + (setq result (concat result "</" (symbol-name (xml-node-name xml)) ">")) + result)) + +;; +;; Response handling +;; + +(defsubst xml-rpc-response-errorp (response) + "An 'xml-rpc-method-call' result value is always a list, where the first \ +element in RESPONSE is either nil or if an error occured, a cons pair \ +according to (errnum . \"Error string\")," + (eq 'fault (car-safe (caddar response)))) + +(defsubst xml-rpc-response-error-code (response) + "Return the error code from RESPONSE." + (and (xml-rpc-response-errorp response) + (nth 1 (xml-rpc-xml-list-to-value response)))) + +(defsubst xml-rpc-response-error-string (response) + "Return the error code from RESPONSE." + (and (xml-rpc-response-errorp response) + (nth 2 (xml-rpc-xml-list-to-value response)))) + +(defun xml-rpc-xml-to-response (xml) + "Convert an XML list to a method response list. An error is +signaled if there is a fault or if the response does not appear +to be an XML-RPC response (i.e. no methodResponse). Otherwise, +the parsed XML response is returned." + ;; Check if we have a methodResponse + (cond + ((not (eq (car-safe (car-safe xml)) 'methodResponse)) + (error "No methodResponse found")) + + ;; Did we get a fault response + ((xml-rpc-response-errorp xml) + (let ((resp (xml-rpc-xml-list-to-value xml))) + (setq xml-rpc-fault-string (nth 2 resp)) + (setq xml-rpc-fault-code (nth 1 resp)) + (error "XML-RPC fault `%s'" xml-rpc-fault-string))) + + ;; Interpret the XML list and produce a more useful data structure + (t + (let ((valpart (cdr (cdaddr (caddar xml))))) + (xml-rpc-xml-list-to-value valpart))))) + +;; +;; Method handling +;; + +(defun xml-rpc-request (server-url xml &optional async-callback-function) + "Perform http post request to SERVER-URL using XML. + +If ASYNC-CALLBACK-FUNCTION is non-nil, the request will be performed +asynchronously and ASYNC-CALLBACK-FUNCTION should be a callback function to +be called when the reuest is finished. ASYNC-CALLBACK-FUNCTION is called with +a single argument being an xml.el style XML list. + +It returns an XML list containing the method response from the XML-RPC server, +or nil if called with ASYNC-CALLBACK-FUNCTION." + (declare (special url-current-callback-data + url-current-callback-func + url-http-response-status)) + (unwind-protect + (save-excursion + (let ((url-request-method "POST") + (url-package-name "xml-rpc.el") + (url-package-version xml-rpc-version) + (url-request-data (concat "<?xml version=\"1.0\"" + " encoding=\"UTF-8\"?>\n" + (with-temp-buffer + (xml-print xml) + (when xml-rpc-allow-unicode-string + (encode-coding-region + (point-min) (point-max) 'utf-8)) + (buffer-string)) + "\n")) + (url-mime-charset-string "utf-8;q=1, iso-8859-1;q=0.5") + (url-request-coding-system xml-rpc-use-coding-system) + (url-http-attempt-keepalives t) + (url-request-extra-headers (list + (cons "Connection" "keep-alive") + (cons "Content-Type" + "text/xml; charset=utf-8")))) + (when (> xml-rpc-debug 1) + (print url-request-data (create-file-buffer "request-data"))) + + (cond ((boundp 'url-be-asynchronous) ; Sniff for w3 lib capability + (if async-callback-function + (setq url-be-asynchronous t + url-current-callback-data (list + async-callback-function + (current-buffer)) + url-current-callback-func + 'xml-rpc-request-callback-handler) + (setq url-be-asynchronous nil)) + (url-retrieve server-url t) + + (when (not url-be-asynchronous) + (let ((result (xml-rpc-request-process-buffer + (current-buffer)))) + (when (> xml-rpc-debug 1) + (with-current-buffer (create-file-buffer "result-data") + (insert result))) + result))) + (t ; Post emacs20 w3-el + (if async-callback-function + (url-retrieve server-url async-callback-function) + (let ((buffer (url-retrieve-synchronously server-url)) + result) + (with-current-buffer buffer + (when (not (numberp url-http-response-status)) + ;; this error may occur when keep-alive bug + ;; of url-http.el is not cleared. + (error "Why? url-http-response-status is %s" + url-http-response-status)) + (when (> url-http-response-status 299) + (error "Error during request: %s" + url-http-response-status))) + (xml-rpc-request-process-buffer buffer))))))))) + + +(defun xml-rpc-clean-string (s) + (if (string-match "\\`[ \t\n\r]*\\'" s) + ;;"^[ \t\n]*$" s) + nil + s)) + +(defun xml-rpc-clean (l) + (cond + ((listp l) + (let ((remain l) + elem + (result nil)) + (while l + ;; iterate + (setq elem (car l) + l (cdr l)) + ;; test the head + (cond + ;; a string, so clean it. + ((stringp elem) + (let ((tmp (xml-rpc-clean-string elem))) + (when (and tmp xml-rpc-allow-unicode-string) + (setq tmp (decode-coding-string tmp xml-rpc-use-coding-system))) + (if tmp + (setq result (append result (list tmp))) + result))) + ;; a list, so recurse. + ((listp elem) + (setq result (append result (list (xml-rpc-clean elem))))) + + ;; everthing else, as is. + (t + (setq result (append result (list elem)))))) + result)) + + ((stringp l) ; will returning nil be acceptable ? + nil) + + (t l))) + +(defun xml-rpc-request-process-buffer (xml-buffer) + "Process buffer XML-BUFFER." + (unwind-protect + (with-current-buffer xml-buffer + (when (fboundp 'url-uncompress) + (let ((url-working-buffer xml-buffer)) + (url-uncompress))) + (goto-char (point-min)) + (search-forward-regexp "<\\?xml" nil t) + (move-to-column 0) + ;; Gather the results + (let* ((status (if (boundp 'url-http-response-status) + ;; Old URL lib doesn't save the result. + url-http-response-status 200)) + (result (cond + ;; A probable XML response + ((looking-at "<\\?xml ") + (xml-rpc-clean (xml-parse-region (point-min) + (point-max)))) + + ;; No HTTP status returned + ((not status) + (let ((errstart + (search-forward "\n---- Error was: ----\n"))) + (and errstart + (buffer-substring errstart (point-max))))) + + ;; Maybe they just gave us an the XML w/o PI? + ((search-forward "<methodResponse>" nil t) + (xml-rpc-clean (xml-parse-region (match-beginning 0) + (point-max)))) + + ;; Valid HTTP status + (t + (int-to-string status))))) + (when (< xml-rpc-debug 3) + (kill-buffer (current-buffer))) + result)))) + + +(defun xml-rpc-request-callback-handler (callback-fun xml-buffer) + "Marshall a callback function request to CALLBACK-FUN with the results \ +handled from XML-BUFFER." + (let ((xml-response (xml-rpc-request-process-buffer xml-buffer))) + (when (< xml-rpc-debug 1) + (kill-buffer xml-buffer)) + (funcall callback-fun (xml-rpc-xml-to-response xml-response)))) + + +(defun xml-rpc-method-call-async (async-callback-func server-url method + &rest params) + "Call an XML-RPC method asynchronously at SERVER-URL named METHOD with \ +PARAMS as parameters. When the method returns, ASYNC-CALLBACK-FUNC will be \ +called with the result as parameter." + (let* ((m-name (if (stringp method) + method + (symbol-name method))) + (m-params (mapcar '(lambda (p) + `(param nil ,(car (xml-rpc-value-to-xml-list + p)))) + (if async-callback-func + params + (car-safe params)))) + (m-func-call `((methodCall nil (methodName nil ,m-name) + ,(append '(params nil) m-params))))) + (when (> xml-rpc-debug 1) + (print m-func-call (create-file-buffer "func-call"))) + (xml-rpc-request server-url m-func-call async-callback-func))) + +(defun xml-rpc-method-call (server-url method &rest params) + "Call an XML-RPC method at SERVER-URL named METHOD with PARAMS as \ +parameters." + (let ((response + (xml-rpc-method-call-async nil server-url method params))) + (cond ((stringp response) + (list (cons nil (concat "URL/HTTP Error: " response)))) + (t + (xml-rpc-xml-to-response response))))) + +(unless (fboundp 'xml-escape-string) + (defun xml-debug-print (xml &optional indent-string) + "Outputs the XML in the current buffer. +XML can be a tree or a list of nodes. +The first line is indented with the optional INDENT-STRING." + (setq indent-string (or indent-string "")) + (dolist (node xml) + (xml-debug-print-internal node indent-string))) + + (defalias 'xml-print 'xml-debug-print) + + (when (not (boundp 'xml-entity-alist)) + (defvar xml-entity-alist + '(("lt" . "<") + ("gt" . ">") + ("apos" . "'") + ("quot" . "\"") + ("amp" . "&")))) + + (defun xml-escape-string (string) + "Return the string with entity substitutions made from +xml-entity-alist." + (mapconcat (lambda (byte) + (let ((char (char-to-string byte))) + (if (rassoc char xml-entity-alist) + (concat "&" (car (rassoc char xml-entity-alist)) ";") + char))) + ;; This differs from the non-unicode branch. Just + ;; grabbing the string works here. + string "")) + + (defun xml-debug-print-internal (xml indent-string) + "Outputs the XML tree in the current buffer. +The first line is indented with INDENT-STRING." + (let ((tree xml) + attlist) + (insert indent-string ?< (symbol-name (xml-node-name tree))) + + ;; output the attribute list + (setq attlist (xml-node-attributes tree)) + (while attlist + (insert ?\ (symbol-name (caar attlist)) "=\"" + (xml-escape-string (cdar attlist)) ?\") + (setq attlist (cdr attlist))) + + (setq tree (xml-node-children tree)) + + (if (null tree) + (insert ?/ ?>) + (insert ?>) + + ;; output the children + (dolist (node tree) + (cond + ((listp node) + (insert ?\n) + (xml-debug-print-internal node (concat indent-string " "))) + ((stringp node) + (insert (xml-escape-string node))) + (t + (error "Invalid XML tree")))) + + (when (not (and (null (cdr tree)) + (stringp (car tree)))) + (insert ?\n indent-string)) + (insert ?< ?/ (symbol-name (xml-node-name xml)) ?>))))) + +(let ((tdate (timezone-parse-date "20090101T010101Z"))) + (when (not (string-equal (aref tdate 0) "2009")) + (defun timezone-parse-date (date) + "Parse DATE and return a vector [YEAR MONTH DAY TIME TIMEZONE]. +Two-digit dates are `windowed'. Those <69 have 2000 added; otherwise 1900 +is added. Three-digit dates have 1900 added. +TIMEZONE is nil for DATEs without a zone field. + +Understands the following styles: + (1) 14 Apr 89 03:20[:12] [GMT] + (2) Fri, 17 Mar 89 4:01[:33] [GMT] + (3) Mon Jan 16 16:12[:37] [GMT] 1989 + (4) 6 May 1992 1641-JST (Wednesday) + (5) 22-AUG-1993 10:59:12.82 + (6) Thu, 11 Apr 16:17:12 91 [MET] + (7) Mon, 6 Jul 16:47:20 T 1992 [MET] + (8) 1996-06-24 21:13:12 [GMT] + (9) 1996-06-24 21:13-ZONE + (10) 19960624T211312" + ;; Get rid of any text properties. + (and (stringp date) + (or (text-properties-at 0 date) + (next-property-change 0 date)) + (setq date (copy-sequence date)) + (set-text-properties 0 (length date) nil date)) + (let ((date (or date "")) + (year nil) + (month nil) + (day nil) + (time nil) + (zone nil)) ;This may be nil. + (cond ((string-match + "\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([-+a-zA-Z0-9]+\\)" date) + ;; Styles: (1) and (2) with timezone and buggy timezone + ;; This is most common in mail and news, + ;; so it is worth trying first. + (setq year 3 month 2 day 1 time 4 zone 5)) + ((string-match + "\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]*\\'" date) + ;; Styles: (1) and (2) without timezone + (setq year 3 month 2 day 1 time 4 zone nil)) + ((string-match + "\\([^ \t,]+\\),[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\(T[ \t]+\\|\\)\\([0-9]+\\)[ \t]*\\'" date) + ;; Styles: (6) and (7) without timezone + (setq year 6 month 3 day 2 time 4 zone nil)) + ((string-match + "\\([^ \t,]+\\),[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\(T[ \t]+\\|\\)\\([0-9]+\\)[ \t]*\\([-+a-zA-Z0-9]+\\)" date) + ;; Styles: (6) and (7) with timezone and buggy timezone + (setq year 6 month 3 day 2 time 4 zone 7)) + ((string-match + "\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([0-9]+\\)" date) + ;; Styles: (3) without timezone + (setq year 4 month 1 day 2 time 3 zone nil)) + ((string-match + "\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([-+a-zA-Z0-9]+\\)[ \t]+\\([0-9]+\\)" date) + ;; Styles: (3) with timezone + (setq year 5 month 1 day 2 time 3 zone 4)) + ((string-match + "\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)[ \t]*\\([-+a-zA-Z0-9]+\\)" date) + ;; Styles: (4) with timezone + (setq year 3 month 2 day 1 time 4 zone 5)) + ((string-match + "\\([0-9]+\\)-\\([A-Za-z]+\\)-\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9]+:[0-9]+\\)\\(\\.[0-9]+\\)?[ \t]+\\([-+a-zA-Z0-9]+\\)" date) + ;; Styles: (5) with timezone. + (setq year 3 month 2 day 1 time 4 zone 6)) + ((string-match + "\\([0-9]+\\)-\\([A-Za-z]+\\)-\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9]+:[0-9]+\\)\\(\\.[0-9]+\\)?" date) + ;; Styles: (5) without timezone. + (setq year 3 month 2 day 1 time 4 zone nil)) + ((string-match + "\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9]+:[0-9]+\\)[ \t]+\\([-+a-zA-Z0-9]+\\)" date) + ;; Styles: (8) with timezone. + (setq year 1 month 2 day 3 time 4 zone 5)) + ((string-match + "\\([0-9]\\{4\\}\\)-?\\([0-9]\\{0,2\\}\\)-?\\([0-9]\\{0,2\\}\\)[T \t]+\\([0-9]\\{0,2\\}:?[0-9]\\{0,2\\}:?[0-9]\\{0,2\\}\\)[ \t]*\\([-+a-zA-Z]+[0-9:]*\\)" date) + ;; Styles: (8) with timezone with a colon in it. + (setq year 1 month 2 day 3 time 4 zone 5)) + ((string-match + "\\([0-9]\\{4\\}\\)-?\\([0-9]\\{0,2\\}\\)-?\\([0-9]\\{0,2\\}\\)[T \t]+\\([0-9]+:?[0-9]+:?[0-9]+\\)" date) + ;; Styles: (8) without timezone. + (setq year 1 month 2 day 3 time 4 zone nil))) + + (when year + (setq year (match-string year date)) + ;; Guess ambiguous years. Assume years < 69 don't predate the + ;; Unix Epoch, so are 2000+. Three-digit years are assumed to + ;; be relative to 1900. + (when (< (length year) 4) + (let ((y (string-to-number year))) + (when (< y 69) + (setq y (+ y 100))) + (setq year (int-to-string (+ 1900 y))))) + (setq month + (if (or (= (aref date (+ (match-beginning month) 2)) ?-) + (let ((n (string-to-number + (char-to-string + (aref date (+ (match-beginning month) 2)))))) + (= (aref (number-to-string n) 0) + (aref date (+ (match-beginning month) 2))))) + ;; Handle numeric months, spanning exactly two digits. + (substring date + (match-beginning month) + (+ (match-beginning month) 2)) + (let* ((string (substring date + (match-beginning month) + (+ (match-beginning month) 3))) + (monthnum + (cdr (assoc (upcase string) timezone-months-assoc)))) + (when monthnum + (int-to-string monthnum))))) + (setq day (match-string day date)) + (setq time (match-string time date))) + (when zone (setq zone (match-string zone date))) + ;; Return a vector. + (if (and year month) + (vector year month day time zone) + (vector "0" "0" "0" "0" nil)))))) + +(provide 'xml-rpc) + +;; Local Variables: +;; time-stamp-pattern: "20/^;; Last Modified: <%%>$" +;; End: + +;;; xml-rpc.el ends here diff --git a/init.el b/init.el index 3c620b7..f27270d 100644 --- a/init.el +++ b/init.el @@ -15,6 +15,8 @@ (load "my-slime.el") (load "my-twitter.el") (load "my-python.el") +(load "my-haskell.el") +(load "my-swank-js.el") ;; setup font (if (>= emacs-major-version 23) @@ -245,36 +247,10 @@ ;;; displays "\" at the end of lines that wrap (setq longlines-show-hard-newlines t) -;;; haskell mode -(setq auto-mode-alist - (append auto-mode-alist - '(("\\.[hg]s$" . haskell-mode) - ("\\.hic?$" . haskell-mode) - ("\\.hsc$" . haskell-mode) - ("\\.chs$" . haskell-mode) - ("\\.l[hg]s$" . literate-haskell-mode)))) -(autoload 'haskell-mode "haskell-mode" - "Major mode for editing Haskell scripts." t) -(autoload 'literate-haskell-mode "haskell-mode" - "Major mode for editing literate Haskell scripts." t) - -;adding the following lines according to which modules you want to use: -(require 'inf-haskell) - -(add-hook 'haskell-mode-hook 'turn-on-font-lock) -(add-hook 'haskell-mode-hook 'turn-on-haskell-ghci) -(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode) -(add-hook 'haskell-mode-hook 'turn-on-haskell-indent) -(set-variable 'haskell-program-name "ghci") - ;; javascript mode (autoload 'js2-mode "js2-mode" nil t) (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)) -;; swank-js -(add-to-list 'load-path "~/src/swank-js/") -(require 'slime-js) - ;; geiser for Scheme programming ;(load-file "~/src/geiser/elisp/geiser.el") @@ -312,8 +288,6 @@ (autoload 'sml-mode "sml-mode" "Major mode for editing SML." t) (autoload 'run-sml "sml-proc" "Run an inferior SML process." t) -;; notmuch for email/searching -(require 'notmuch) (require 'gnus-art) ;; sending email @@ -327,6 +301,7 @@ (setq message-kill-buffer-on-exit t) ; kill buffer after sending mail) -(setq notmuch-fcc-dirs "Gmail/Sent") ; stores sent mail to the specified directory -(setq message-directory "Gmail/Drafts") ; stores postponed messages to the specified directory +;; cursor +(setq-default cursor-type '(bar . 2)) +(set-cursor-color "#ff0000") diff --git a/themes/solarized b/themes/solarized new file mode 160000 index 0000000..3863263 --- /dev/null +++ b/themes/solarized @@ -0,0 +1 @@ +Subproject commit 3863263b04bd57092d2b15e0b0fe8b3057d5ffc9 diff --git a/themes/solarized-dark-theme.el b/themes/solarized-dark-theme.el new file mode 100644 index 0000000..548b48e --- /dev/null +++ b/themes/solarized-dark-theme.el @@ -0,0 +1,7 @@ +(require 'solarized) + +(deftheme solarized-dark "The dark variant of the Solarized colour theme") + +(create-solarized-theme 'dark 'solarized-dark) + +(provide-theme 'solarized-dark) diff --git a/themes/solarized-light-theme.el b/themes/solarized-light-theme.el new file mode 100644 index 0000000..15802c9 --- /dev/null +++ b/themes/solarized-light-theme.el @@ -0,0 +1,7 @@ +(require 'solarized) + +(deftheme solarized-light "The light variant of the Solarized colour theme") + +(create-solarized-theme 'light 'solarized-light) + +(provide-theme 'solarized-light) diff --git a/themes/zenburn b/themes/zenburn new file mode 160000 index 0000000..27cee3d --- /dev/null +++ b/themes/zenburn @@ -0,0 +1 @@ +Subproject commit 27cee3d6ccc586b4bc30fb322927a6d275e54c34 diff --git a/themes/zenburn-theme.el b/themes/zenburn-theme.el new file mode 100644 index 0000000..76b5eaa --- /dev/null +++ b/themes/zenburn-theme.el @@ -0,0 +1,811 @@ +;;; zenburn-theme.el --- A low contrast color theme for Emacs. + +;; Copyright (C) 2011-2013 Bozhidar Batsov + +;; Author: Bozhidar Batsov <bozhidar@batsov.com> +;; URL: http://github.com/bbatsov/zenburn-emacs +;; Version: 2.0 + +;; 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 3 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, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; A port of the popular Vim theme Zenburn for Emacs 24, built on top +;; of the new built-in theme support in Emacs 24. +;; +;;; Credits: +;; +;; Jani Nurminen created the original theme for vim on such this port +;; is based. + +;;; Code: +(deftheme zenburn "The Zenburn color theme") + +(let ((class '((class color) (min-colors 89))) + ;; Zenburn palette + ;; colors with +x are lighter, colors with -x are darker + (zenburn-fg "#dcdccc") + (zenburn-fg-1 "#656555") + (zenburn-bg-1 "#2b2b2b") + (zenburn-bg-05 "#383838") + (zenburn-bg "#3f3f3f") + (zenburn-bg+1 "#4f4f4f") + (zenburn-bg+2 "#5f5f5f") + (zenburn-bg+3 "#6f6f6f") + (zenburn-red+1 "#dca3a3") + (zenburn-red "#cc9393") + (zenburn-red-1 "#bc8383") + (zenburn-red-2 "#ac7373") + (zenburn-red-3 "#9c6363") + (zenburn-red-4 "#8c5353") + (zenburn-orange "#dfaf8f") + (zenburn-yellow "#f0dfaf") + (zenburn-yellow-1 "#e0cf9f") + (zenburn-yellow-2 "#d0bf8f") + (zenburn-green-1 "#5f7f5f") + (zenburn-green "#7f9f7f") + (zenburn-green+1 "#8fb28f") + (zenburn-green+2 "#9fc59f") + (zenburn-green+3 "#afd8af") + (zenburn-green+4 "#bfebbf") + (zenburn-cyan "#93e0e3") + (zenburn-blue+1 "#94bff3") + (zenburn-blue "#8cd0d3") + (zenburn-blue-1 "#7cb8bb") + (zenburn-blue-2 "#6ca0a3") + (zenburn-blue-3 "#5c888b") + (zenburn-blue-4 "#4c7073") + (zenburn-blue-5 "#366060") + (zenburn-magenta "#dc8cc3")) + (custom-theme-set-faces + 'zenburn + '(button ((t (:underline t)))) + `(link ((t (:foreground ,zenburn-yellow :underline t :weight bold)))) + `(link-visited ((t (:foreground ,zenburn-yellow-2 :underline t :weight normal)))) + + ;;; basic coloring + `(default ((t (:foreground ,zenburn-fg :background ,zenburn-bg)))) + `(cursor ((t (:foreground ,zenburn-fg :background "white")))) + `(escape-glyph ((t (:foreground ,zenburn-yellow :bold t)))) + `(fringe ((t (:foreground ,zenburn-fg :background ,zenburn-bg+1)))) + `(header-line ((t (:foreground ,zenburn-yellow + :background ,zenburn-bg-1 + :box (:line-width -1 :style released-button))))) + `(highlight ((t (:background ,zenburn-bg-05)))) + `(success ((t (:foreground ,zenburn-green :weight bold)))) + `(warning ((t (:foreground ,zenburn-orange :weight bold)))) + + ;;; compilation + `(compilation-column-face ((t (:foreground ,zenburn-yellow)))) + `(compilation-enter-directory-face ((t (:foreground ,zenburn-green)))) + `(compilation-error-face ((t (:foreground ,zenburn-red-1 :weight bold :underline t)))) + `(compilation-face ((t (:foreground ,zenburn-fg)))) + `(compilation-info-face ((t (:foreground ,zenburn-blue)))) + `(compilation-info ((t (:foreground ,zenburn-green+4 :underline t)))) + `(compilation-leave-directory-face ((t (:foreground ,zenburn-green)))) + `(compilation-line-face ((t (:foreground ,zenburn-yellow)))) + `(compilation-line-number ((t (:foreground ,zenburn-yellow)))) + `(compilation-message-face ((t (:foreground ,zenburn-blue)))) + `(compilation-warning-face ((t (:foreground ,zenburn-orange :weight bold :underline t)))) + `(compilation-mode-line-exit ((t (:foreground ,zenburn-green+2 :weight bold)))) + `(compilation-mode-line-fail ((t (:foreground ,zenburn-red :weight bold)))) + `(compilation-mode-line-run ((t (:foreground ,zenburn-yellow :weight bold)))) + + ;;; grep + `(grep-context-face ((t (:foreground ,zenburn-fg)))) + `(grep-error-face ((t (:foreground ,zenburn-red-1 :weight bold :underline t)))) + `(grep-hit-face ((t (:foreground ,zenburn-blue)))) + `(grep-match-face ((t (:foreground ,zenburn-orange :weight bold)))) + `(match ((t (:background ,zenburn-bg-1 :foreground ,zenburn-orange :weight bold)))) + + ;; faces used by isearch + `(isearch ((t (:foreground ,zenburn-yellow-2 :weight bold :background ,zenburn-bg-1)))) + `(isearch-fail ((t (:foreground ,zenburn-fg :background ,zenburn-red-4)))) + `(lazy-highlight ((t (:foreground ,zenburn-yellow-2 :weight bold :background ,zenburn-bg-05)))) + + `(menu ((t (:foreground ,zenburn-fg :background ,zenburn-bg)))) + `(minibuffer-prompt ((t (:foreground ,zenburn-yellow)))) + `(mode-line + ((,class (:foreground ,zenburn-green+1 + :background ,zenburn-bg-1 + :box (:line-width -1 :style released-button))) + (t :inverse-video t))) + `(mode-line-buffer-id ((t (:foreground ,zenburn-yellow :weight bold)))) + `(mode-line-inactive + ((t (:foreground ,zenburn-green-1 + :background ,zenburn-bg-05 + :box (:line-width -1 :style released-button))))) + `(region ((,class (:background ,zenburn-bg-1)) + (t :inverse-video t))) + `(secondary-selection ((t (:background ,zenburn-bg+2)))) + `(trailing-whitespace ((t (:background ,zenburn-red)))) + `(vertical-border ((t (:foreground ,zenburn-fg)))) + + ;;; font lock + `(font-lock-builtin-face ((t (:foreground ,zenburn-cyan)))) + `(font-lock-comment-face ((t (:foreground ,zenburn-green)))) + `(font-lock-comment-delimiter-face ((t (:foreground ,zenburn-green)))) + `(font-lock-constant-face ((t (:foreground ,zenburn-green+4)))) + `(font-lock-doc-face ((t (:foreground ,zenburn-green+1)))) + `(font-lock-doc-string-face ((t (:foreground ,zenburn-blue-2)))) + `(font-lock-function-name-face ((t (:foreground ,zenburn-blue)))) + `(font-lock-keyword-face ((t (:foreground ,zenburn-yellow :weight bold)))) + `(font-lock-negation-char-face ((t (:foreground ,zenburn-fg)))) + `(font-lock-preprocessor-face ((t (:foreground ,zenburn-blue+1)))) + `(font-lock-string-face ((t (:foreground ,zenburn-red)))) + `(font-lock-type-face ((t (:foreground ,zenburn-blue-1)))) + `(font-lock-variable-name-face ((t (:foreground ,zenburn-orange)))) + `(font-lock-warning-face ((t (:foreground ,zenburn-yellow-2 :weight bold)))) + + `(c-annotation-face ((t (:inherit font-lock-constant-face)))) + + ;;; newsticker + `(newsticker-date-face ((t (:foreground ,zenburn-fg)))) + `(newsticker-default-face ((t (:foreground ,zenburn-fg)))) + `(newsticker-enclosure-face ((t (:foreground ,zenburn-green+3)))) + `(newsticker-extra-face ((t (:foreground ,zenburn-bg+2 :height 0.8)))) + `(newsticker-feed-face ((t (:foreground ,zenburn-fg)))) + `(newsticker-immortal-item-face ((t (:foreground ,zenburn-green)))) + `(newsticker-new-item-face ((t (:foreground ,zenburn-blue)))) + `(newsticker-obsolete-item-face ((t (:foreground ,zenburn-red)))) + `(newsticker-old-item-face ((t (:foreground ,zenburn-bg+3)))) + `(newsticker-statistics-face ((t (:foreground ,zenburn-fg)))) + `(newsticker-treeview-face ((t (:foreground ,zenburn-fg)))) + `(newsticker-treeview-immortal-face ((t (:foreground ,zenburn-green)))) + `(newsticker-treeview-listwindow-face ((t (:foreground ,zenburn-fg)))) + `(newsticker-treeview-new-face ((t (:foreground ,zenburn-blue :weight bold)))) + `(newsticker-treeview-obsolete-face ((t (:foreground ,zenburn-red)))) + `(newsticker-treeview-old-face ((t (:foreground ,zenburn-bg+3)))) + `(newsticker-treeview-selection-face ((t (:foreground ,zenburn-yellow)))) + + ;;; external + `(ace-jump-face-background + ((t (:foreground ,zenburn-fg-1 :background ,zenburn-bg :inverse-video nil)))) + `(ace-jump-face-foreground + ((t (:foreground ,zenburn-green+2 :background ,zenburn-bg :inverse-video nil)))) + + ;; full-ack + `(ack-separator ((t (:foreground ,zenburn-fg)))) + `(ack-file ((t (:foreground ,zenburn-blue)))) + `(ack-line ((t (:foreground ,zenburn-yellow)))) + `(ack-match ((t (:foreground ,zenburn-orange :background ,zenburn-bg-1 :weight bold)))) + + ;; auctex + `(font-latex-bold ((t (:inherit bold)))) + `(font-latex-warning ((t (:inherit font-lock-warning)))) + `(font-latex-sedate ((t (:foreground ,zenburn-yellow :weight bold )))) + `(font-latex-title-4 ((t (:inherit variable-pitch :weight bold)))) + + ;; auto-complete + `(ac-candidate-face ((t (:background ,zenburn-bg+3 :foreground "black")))) + `(ac-selection-face ((t (:background ,zenburn-blue-4 :foreground ,zenburn-fg)))) + `(popup-tip-face ((t (:background ,zenburn-yellow-2 :foreground "black")))) + `(popup-scroll-bar-foreground-face ((t (:background ,zenburn-blue-5)))) + `(popup-scroll-bar-background-face ((t (:background ,zenburn-bg-1)))) + `(popup-isearch-match ((t (:background ,zenburn-bg :foreground ,zenburn-fg)))) + + ;; android mode + `(android-mode-debug-face ((t (:foreground ,zenburn-green+1)))) + `(android-mode-error-face ((t (:foreground ,zenburn-orange :weight bold)))) + `(android-mode-info-face ((t (:foreground ,zenburn-fg)))) + `(android-mode-verbose-face ((t (:foreground ,zenburn-green)))) + `(android-mode-warning-face ((t (:foreground ,zenburn-yellow)))) + + ;; bm + `(bm-face ((t (:background ,zenburn-yellow-1 :foreground ,zenburn-bg)))) + `(bm-fringe-face ((t (:background ,zenburn-yellow-1 :foreground ,zenburn-bg)))) + `(bm-fringe-persistent-face ((t (:background ,zenburn-green-1 :foreground ,zenburn-bg)))) + `(bm-persistent-face ((t (:background ,zenburn-green-1 :foreground ,zenburn-bg)))) + + ;; clojure-test-mode + `(clojure-test-failure-face ((t (:foreground ,zenburn-orange :weight bold :underline t)))) + `(clojure-test-error-face ((t (:foreground ,zenburn-red :weight bold :underline t)))) + `(clojure-test-success-face ((t (:foreground ,zenburn-green+1 :weight bold :underline t)))) + + ;; ctable + `(ctbl:face-cell-select ((t (:background ,zenburn-blue :foreground ,zenburn-bg)))) + `(ctbl:face-continue-bar ((t (:background ,zenburn-bg-05 :foreground ,zenburn-bg)))) + `(ctbl:face-row-select ((t (:background ,zenburn-cyan :foreground ,zenburn-bg)))) + + ;; diff + `(diff-added ((,class (:foreground ,zenburn-green+4 :background nil)) + (t (:foreground ,zenburn-green-1 :background nil)))) + `(diff-changed ((t (:foreground ,zenburn-yellow)))) + `(diff-removed ((,class (:foreground ,zenburn-red :background nil)) + (t (:foreground ,zenburn-red-3 :background nil)))) + `(diff-refine-added ((t :inherit diff-added :weight bold))) + `(diff-refine-change ((t :inherit diff-changed :weight bold))) + `(diff-refine-removed ((t :inherit diff-removed :weight bold))) + `(diff-header ((,class (:background ,zenburn-bg+2)) + (t (:background ,zenburn-fg :foreground ,zenburn-bg)))) + `(diff-file-header + ((,class (:background ,zenburn-bg+2 :foreground ,zenburn-fg :bold t)) + (t (:background ,zenburn-fg :foreground ,zenburn-bg :bold t)))) + + ;; dired+ + `(diredp-display-msg ((t (:foreground ,zenburn-blue)))) + `(diredp-compressed-file-suffix ((t (:foreground ,zenburn-orange)))) + `(diredp-date-time ((t (:foreground ,zenburn-magenta)))) + `(diredp-deletion ((t (:foreground ,zenburn-yellow)))) + `(diredp-deletion-file-name ((t (:foreground ,zenburn-red)))) + `(diredp-dir-heading ((t (:foreground ,zenburn-blue :background ,zenburn-bg-1)))) + `(diredp-dir-priv ((t (:foreground ,zenburn-cyan)))) + `(diredp-exec-priv ((t (:foreground ,zenburn-red)))) + `(diredp-executable-tag ((t (:foreground ,zenburn-green+1)))) + `(diredp-file-name ((t (:foreground ,zenburn-blue)))) + `(diredp-file-suffix ((t (:foreground ,zenburn-green)))) + `(diredp-flag-mark ((t (:foreground ,zenburn-yellow)))) + `(diredp-flag-mark-line ((t (:foreground ,zenburn-orange)))) + `(diredp-ignored-file-name ((t (:foreground ,zenburn-red)))) + `(diredp-link-priv ((t (:foreground ,zenburn-yellow)))) + `(diredp-mode-line-flagged ((t (:foreground ,zenburn-yellow)))) + `(diredp-mode-line-marked ((t (:foreground ,zenburn-orange)))) + `(diredp-no-priv ((t (:foreground ,zenburn-fg)))) + `(diredp-number ((t (:foreground ,zenburn-green+1)))) + `(diredp-other-priv ((t (:foreground ,zenburn-yellow-1)))) + `(diredp-rare-priv ((t (:foreground ,zenburn-red-1)))) + `(diredp-read-priv ((t (:foreground ,zenburn-green-1)))) + `(diredp-symlink ((t (:foreground ,zenburn-yellow)))) + `(diredp-write-priv ((t (:foreground ,zenburn-magenta)))) + + ;; ert + `(ert-test-result-expected ((t (:foreground ,zenburn-green+4 :background ,zenburn-bg)))) + `(ert-test-result-unexpected ((t (:foreground ,zenburn-red :background ,zenburn-bg)))) + + ;; eshell + `(eshell-prompt ((t (:foreground ,zenburn-yellow :weight bold)))) + `(eshell-ls-archive ((t (:foreground ,zenburn-red-1 :weight bold)))) + `(eshell-ls-backup ((t (:inherit font-lock-comment)))) + `(eshell-ls-clutter ((t (:inherit font-lock-comment)))) + `(eshell-ls-directory ((t (:foreground ,zenburn-blue+1 :weight bold)))) + `(eshell-ls-executable ((t (:foreground ,zenburn-red+1 :weight bold)))) + `(eshell-ls-unreadable ((t (:foreground ,zenburn-fg)))) + `(eshell-ls-missing ((t (:inherit font-lock-warning)))) + `(eshell-ls-product ((t (:inherit font-lock-doc)))) + `(eshell-ls-special ((t (:foreground ,zenburn-yellow :weight bold)))) + `(eshell-ls-symlink ((t (:foreground ,zenburn-cyan :weight bold)))) + + ;; flycheck + `(flycheck-error-face ((t (:foreground ,zenburn-red-1 :weight bold :underline t)))) + `(flycheck-warning-face ((t (:foreground ,zenburn-orange :weight bold :underline t)))) + + ;; flymake + `(flymake-errline ((t (:foreground ,zenburn-red-1 :weight bold :underline t)))) + `(flymake-warnline ((t (:foreground ,zenburn-orange :weight bold :underline t)))) + + ;; flyspell + `(flyspell-duplicate ((t (:foreground ,zenburn-orange :weight bold :underline t)))) + `(flyspell-incorrect ((t (:foreground ,zenburn-red-1 :weight bold :underline t)))) + + ;; erc + `(erc-action-face ((t (:inherit erc-default-face)))) + `(erc-bold-face ((t (:weight bold)))) + `(erc-current-nick-face ((t (:foreground ,zenburn-blue :weight bold)))) + `(erc-dangerous-host-face ((t (:inherit font-lock-warning)))) + `(erc-default-face ((t (:foreground ,zenburn-fg)))) + `(erc-direct-msg-face ((t (:inherit erc-default)))) + `(erc-error-face ((t (:inherit font-lock-warning)))) + `(erc-fool-face ((t (:inherit erc-default)))) + `(erc-highlight-face ((t (:inherit hover-highlight)))) + `(erc-input-face ((t (:foreground ,zenburn-yellow)))) + `(erc-keyword-face ((t (:foreground ,zenburn-blue :weight bold)))) + `(erc-nick-default-face ((t (:foreground ,zenburn-yellow :weight bold)))) + `(erc-my-nick-face ((t (:foreground ,zenburn-red :weight bold)))) + `(erc-nick-msg-face ((t (:inherit erc-default)))) + `(erc-notice-face ((t (:foreground ,zenburn-green)))) + `(erc-pal-face ((t (:foreground ,zenburn-orange :weight bold)))) + `(erc-prompt-face ((t (:foreground ,zenburn-orange :background ,zenburn-bg :weight bold)))) + `(erc-timestamp-face ((t (:foreground ,zenburn-green+1)))) + `(erc-underline-face ((t (:underline t)))) + + ;; git-gutter + `(git-gutter:added ((t (:foreground ,zenburn-green :weight bold :inverse-video t)))) + `(git-gutter:deleted ((t (:foreground ,zenburn-red :weight bold :inverse-video t)))) + `(git-gutter:modified ((t (:foreground ,zenburn-magenta :weight bold :inverse-video t)))) + `(git-gutter:unchanged ((t (:foreground ,zenburn-fg :weight bold :inverse-video t)))) + + ;; git-gutter-fr + `(git-gutter-fr:added ((t (:foreground ,zenburn-green :weight bold)))) + `(git-gutter-fr:deleted ((t (:foreground ,zenburn-red :weight bold)))) + `(git-gutter-fr:modified ((t (:foreground ,zenburn-magenta :weight bold)))) + + ;; gnus + `(gnus-group-mail-1 ((t (:bold t :inherit gnus-group-mail-1-empty)))) + `(gnus-group-mail-1-empty ((t (:inherit gnus-group-news-1-empty)))) + `(gnus-group-mail-2 ((t (:bold t :inherit gnus-group-mail-2-empty)))) + `(gnus-group-mail-2-empty ((t (:inherit gnus-group-news-2-empty)))) + `(gnus-group-mail-3 ((t (:bold t :inherit gnus-group-mail-3-empty)))) + `(gnus-group-mail-3-empty ((t (:inherit gnus-group-news-3-empty)))) + `(gnus-group-mail-4 ((t (:bold t :inherit gnus-group-mail-4-empty)))) + `(gnus-group-mail-4-empty ((t (:inherit gnus-group-news-4-empty)))) + `(gnus-group-mail-5 ((t (:bold t :inherit gnus-group-mail-5-empty)))) + `(gnus-group-mail-5-empty ((t (:inherit gnus-group-news-5-empty)))) + `(gnus-group-mail-6 ((t (:bold t :inherit gnus-group-mail-6-empty)))) + `(gnus-group-mail-6-empty ((t (:inherit gnus-group-news-6-empty)))) + `(gnus-group-mail-low ((t (:bold t :inherit gnus-group-mail-low-empty)))) + `(gnus-group-mail-low-empty ((t (:inherit gnus-group-news-low-empty)))) + `(gnus-group-news-1 ((t (:bold t :inherit gnus-group-news-1-empty)))) + `(gnus-group-news-2 ((t (:bold t :inherit gnus-group-news-2-empty)))) + `(gnus-group-news-3 ((t (:bold t :inherit gnus-group-news-3-empty)))) + `(gnus-group-news-4 ((t (:bold t :inherit gnus-group-news-4-empty)))) + `(gnus-group-news-5 ((t (:bold t :inherit gnus-group-news-5-empty)))) + `(gnus-group-news-6 ((t (:bold t :inherit gnus-group-news-6-empty)))) + `(gnus-group-news-low ((t (:bold t :inherit gnus-group-news-low-empty)))) + `(gnus-header-content ((t (:inherit message-header-other)))) + `(gnus-header-from ((t (:inherit message-header-from)))) + `(gnus-header-name ((t (:inherit message-header-name)))) + `(gnus-header-newsgroups ((t (:inherit message-header-other)))) + `(gnus-header-subject ((t (:inherit message-header-subject)))) + `(gnus-summary-cancelled ((t (:foreground ,zenburn-orange)))) + `(gnus-summary-high-ancient ((t (:foreground ,zenburn-blue)))) + `(gnus-summary-high-read ((t (:foreground ,zenburn-green :weight bold)))) + `(gnus-summary-high-ticked ((t (:foreground ,zenburn-orange :weight bold)))) + `(gnus-summary-high-unread ((t (:foreground ,zenburn-fg :weight bold)))) + `(gnus-summary-low-ancient ((t (:foreground ,zenburn-blue)))) + `(gnus-summary-low-read ((t (:foreground ,zenburn-green)))) + `(gnus-summary-low-ticked ((t (:foreground ,zenburn-orange :weight bold)))) + `(gnus-summary-low-unread ((t (:foreground ,zenburn-fg)))) + `(gnus-summary-normal-ancient ((t (:foreground ,zenburn-blue)))) + `(gnus-summary-normal-read ((t (:foreground ,zenburn-green)))) + `(gnus-summary-normal-ticked ((t (:foreground ,zenburn-orange :weight bold)))) + `(gnus-summary-normal-unread ((t (:foreground ,zenburn-fg)))) + `(gnus-summary-selected ((t (:foreground ,zenburn-yellow :weight bold)))) + `(gnus-cite-1 ((t (:foreground ,zenburn-blue)))) + `(gnus-cite-10 ((t (:foreground ,zenburn-yellow-1)))) + `(gnus-cite-11 ((t (:foreground ,zenburn-yellow)))) + `(gnus-cite-2 ((t (:foreground ,zenburn-blue-1)))) + `(gnus-cite-3 ((t (:foreground ,zenburn-blue-2)))) + `(gnus-cite-4 ((t (:foreground ,zenburn-green+2)))) + `(gnus-cite-5 ((t (:foreground ,zenburn-green+1)))) + `(gnus-cite-6 ((t (:foreground ,zenburn-green)))) + `(gnus-cite-7 ((t (:foreground ,zenburn-red)))) + `(gnus-cite-8 ((t (:foreground ,zenburn-red-1)))) + `(gnus-cite-9 ((t (:foreground ,zenburn-red-2)))) + `(gnus-group-news-1-empty ((t (:foreground ,zenburn-yellow)))) + `(gnus-group-news-2-empty ((t (:foreground ,zenburn-green+3)))) + `(gnus-group-news-3-empty ((t (:foreground ,zenburn-green+1)))) + `(gnus-group-news-4-empty ((t (:foreground ,zenburn-blue-2)))) + `(gnus-group-news-5-empty ((t (:foreground ,zenburn-blue-3)))) + `(gnus-group-news-6-empty ((t (:foreground ,zenburn-bg+2)))) + `(gnus-group-news-low-empty ((t (:foreground ,zenburn-bg+2)))) + `(gnus-signature ((t (:foreground ,zenburn-yellow)))) + `(gnus-x ((t (:background ,zenburn-fg :foreground ,zenburn-bg)))) + + ;; guide-key + `(guide-key/highlight-command-face ((t (:foreground ,zenburn-blue)))) + `(guide-key/key-face ((t (:foreground ,zenburn-green)))) + `(guide-key/prefix-command-face ((t (:foreground ,zenburn-green+1)))) + + ;; helm + `(helm-header + ((t (:foreground ,zenburn-green + :background ,zenburn-bg + :underline nil + :box nil)))) + `(helm-source-header + ((t (:foreground ,zenburn-yellow + :background ,zenburn-bg-1 + :underline nil + :weight bold + :box (:line-width -1 :style released-button))))) + `(helm-selection ((t (:background ,zenburn-bg+1 :underline nil)))) + `(helm-selection-line ((t (:background ,zenburn-bg+1)))) + `(helm-visible-mark ((t (:foreground ,zenburn-bg :background ,zenburn-yellow-2)))) + `(helm-candidate-number ((t (:foreground ,zenburn-green+4 :background ,zenburn-bg-1)))) + `(helm-ff-directory ((t (:foreground ,zenburn-magenta)))) + + ;; hl-line-mode + `(hl-line-face ((,class (:background ,zenburn-bg-05)) + (t :weight bold))) + `(hl-line ((,class (:background ,zenburn-bg-05)) ; old emacsen + (t :weight bold))) + + ;; hl-sexp + `(hl-sexp-face ((,class (:background ,zenburn-bg+1)) + (t :weight bold))) + + ;; ido-mode + `(ido-first-match ((t (:foreground ,zenburn-yellow :weight bold)))) + `(ido-only-match ((t (:foreground ,zenburn-orange :weight bold)))) + `(ido-subdir ((t (:foreground ,zenburn-yellow)))) + + ;; js2-mode + `(js2-warning-face ((t (:underline ,zenburn-orange)))) + `(js2-error-face ((t (:foreground ,zenburn-red :weight bold)))) + `(js2-jsdoc-tag-face ((t (:foreground ,zenburn-green-1)))) + `(js2-jsdoc-type-face ((t (:foreground ,zenburn-green+2)))) + `(js2-jsdoc-value-face ((t (:foreground ,zenburn-green+3)))) + `(js2-function-param-face ((t (:foreground, zenburn-green+3)))) + `(js2-external-variable-face ((t (:foreground ,zenburn-orange)))) + + ;; jabber-mode + `(jabber-roster-user-away ((t (:foreground ,zenburn-green+2)))) + `(jabber-roster-user-online ((t (:foreground ,zenburn-blue-1)))) + `(jabber-roster-user-dnd ((t (:foreground ,zenburn-red+1)))) + `(jabber-rare-time-face ((t (:foreground ,zenburn-green+1)))) + `(jabber-chat-prompt-local ((t (:foreground ,zenburn-blue-1)))) + `(jabber-chat-prompt-foreign ((t (:foreground ,zenburn-red+1)))) + `(jabber-activity-face((t (:foreground ,zenburn-red+1)))) + `(jabber-activity-personal-face ((t (:foreground ,zenburn-blue+1)))) + `(jabber-title-small ((t (:height 1.1 :weight bold)))) + `(jabber-title-medium ((t (:height 1.2 :weight bold)))) + `(jabber-title-large ((t (:height 1.3 :weight bold)))) + + ;; linum-mode + `(linum ((t (:foreground ,zenburn-green+2 :background ,zenburn-bg)))) + + ;; macrostep + `(macrostep-gensym-1 + ((t (:foreground ,zenburn-green+2 :background ,zenburn-bg-1)))) + `(macrostep-gensym-2 + ((t (:foreground ,zenburn-red+1 :background ,zenburn-bg-1)))) + `(macrostep-gensym-3 + ((t (:foreground ,zenburn-blue+1 :background ,zenburn-bg-1)))) + `(macrostep-gensym-4 + ((t (:foreground ,zenburn-magenta :background ,zenburn-bg-1)))) + `(macrostep-gensym-5 + ((t (:foreground ,zenburn-yellow :background ,zenburn-bg-1)))) + `(macrostep-expansion-highlight-face + ((t (:inherit highlight)))) + `(macrostep-macro-face + ((t (:underline t)))) + + ;; magit + `(magit-section-title ((t (:foreground ,zenburn-yellow :weight bold)))) + `(magit-branch ((t (:foreground ,zenburn-orange :weight bold)))) + `(magit-item-highlight ((t (:background ,zenburn-bg+1)))) + + ;; egg + `(egg-text-base ((t (:foreground ,zenburn-fg)))) + `(egg-help-header-1 ((t (:foreground ,zenburn-yellow)))) + `(egg-help-header-2 ((t (:foreground ,zenburn-green+3)))) + `(egg-branch ((t (:foreground ,zenburn-yellow)))) + `(egg-branch-mono ((t (:foreground ,zenburn-yellow)))) + `(egg-term ((t (:foreground ,zenburn-yellow)))) + `(egg-diff-add ((t (:foreground ,zenburn-green+4)))) + `(egg-diff-del ((t (:foreground ,zenburn-red+1)))) + `(egg-diff-file-header ((t (:foreground ,zenburn-yellow-2)))) + `(egg-section-title ((t (:foreground ,zenburn-yellow)))) + `(egg-stash-mono ((t (:foreground ,zenburn-green+4)))) + + ;; message-mode + `(message-cited-text ((t (:inherit font-lock-comment)))) + `(message-header-name ((t (:foreground ,zenburn-green+1)))) + `(message-header-other ((t (:foreground ,zenburn-green)))) + `(message-header-to ((t (:foreground ,zenburn-yellow :weight bold)))) + `(message-header-from ((t (:foreground ,zenburn-yellow :weight bold)))) + `(message-header-cc ((t (:foreground ,zenburn-yellow :weight bold)))) + `(message-header-newsgroups ((t (:foreground ,zenburn-yellow :weight bold)))) + `(message-header-subject ((t (:foreground ,zenburn-orange :weight bold)))) + `(message-header-xheader ((t (:foreground ,zenburn-green)))) + `(message-mml ((t (:foreground ,zenburn-yellow :weight bold)))) + `(message-separator ((t (:inherit font-lock-comment)))) + + ;; mew + `(mew-face-header-subject ((t (:foreground ,zenburn-orange)))) + `(mew-face-header-from ((t (:foreground ,zenburn-yellow)))) + `(mew-face-header-date ((t (:foreground ,zenburn-green)))) + `(mew-face-header-to ((t (:foreground ,zenburn-red)))) + `(mew-face-header-key ((t (:foreground ,zenburn-green)))) + `(mew-face-header-private ((t (:foreground ,zenburn-green)))) + `(mew-face-header-important ((t (:foreground ,zenburn-blue)))) + `(mew-face-header-marginal ((t (:foreground ,zenburn-fg :weight bold)))) + `(mew-face-header-warning ((t (:foreground ,zenburn-red)))) + `(mew-face-header-xmew ((t (:foreground ,zenburn-green)))) + `(mew-face-header-xmew-bad ((t (:foreground ,zenburn-red)))) + `(mew-face-body-url ((t (:foreground ,zenburn-orange)))) + `(mew-face-body-comment ((t (:foreground ,zenburn-fg :slant italic)))) + `(mew-face-body-cite1 ((t (:foreground ,zenburn-green)))) + `(mew-face-body-cite2 ((t (:foreground ,zenburn-blue)))) + `(mew-face-body-cite3 ((t (:foreground ,zenburn-orange)))) + `(mew-face-body-cite4 ((t (:foreground ,zenburn-yellow)))) + `(mew-face-body-cite5 ((t (:foreground ,zenburn-red)))) + `(mew-face-mark-review ((t (:foreground ,zenburn-blue)))) + `(mew-face-mark-escape ((t (:foreground ,zenburn-green)))) + `(mew-face-mark-delete ((t (:foreground ,zenburn-red)))) + `(mew-face-mark-unlink ((t (:foreground ,zenburn-yellow)))) + `(mew-face-mark-refile ((t (:foreground ,zenburn-green)))) + `(mew-face-mark-unread ((t (:foreground ,zenburn-red-2)))) + `(mew-face-eof-message ((t (:foreground ,zenburn-green)))) + `(mew-face-eof-part ((t (:foreground ,zenburn-yellow)))) + + ;; mic-paren + `(paren-face-match ((t (:foreground ,zenburn-cyan :background ,zenburn-bg :weight bold)))) + `(paren-face-mismatch ((t (:foreground ,zenburn-bg :background ,zenburn-magenta :weight bold)))) + `(paren-face-no-match ((t (:foreground ,zenburn-bg :background ,zenburn-red :weight bold)))) + + ;; mingus + `(mingus-directory-face ((t (:foreground ,zenburn-blue)))) + `(mingus-pausing-face ((t (:foreground ,zenburn-magenta)))) + `(mingus-playing-face ((t (:foreground ,zenburn-cyan)))) + `(mingus-playlist-face ((t (:foreground ,zenburn-cyan )))) + `(mingus-song-file-face ((t (:foreground ,zenburn-yellow)))) + `(mingus-stopped-face ((t (:foreground ,zenburn-red)))) + + ;; nav + `(nav-face-heading ((t (:foreground ,zenburn-yellow)))) + `(nav-face-button-num ((t (:foreground ,zenburn-cyan)))) + `(nav-face-dir ((t (:foreground ,zenburn-green)))) + `(nav-face-hdir ((t (:foreground ,zenburn-red)))) + `(nav-face-file ((t (:foreground ,zenburn-fg)))) + `(nav-face-hfile ((t (:foreground ,zenburn-red-4)))) + + ;; mu4e + `(mu4e-cited-1-face ((t (:foreground ,zenburn-blue :slant italic)))) + `(mu4e-cited-2-face ((t (:foreground ,zenburn-green+2 :slant italic)))) + `(mu4e-cited-3-face ((t (:foreground ,zenburn-blue-2 :slant italic)))) + `(mu4e-cited-4-face ((t (:foreground ,zenburn-green :slant italic)))) + `(mu4e-cited-5-face ((t (:foreground ,zenburn-blue-4 :slant italic)))) + `(mu4e-cited-6-face ((t (:foreground ,zenburn-green-1 :slant italic)))) + `(mu4e-cited-7-face ((t (:foreground ,zenburn-blue :slant italic)))) + `(mu4e-replied-face ((t (:foreground ,zenburn-bg+3)))) + `(mu4e-trashed-face ((t (:foreground ,zenburn-bg+3 :strike-through t)))) + + ;; mumamo + `(mumamo-background-chunk-major ((t (:background nil)))) + `(mumamo-background-chunk-submode1 ((t (:background ,zenburn-bg-1)))) + `(mumamo-background-chunk-submode2 ((t (:background ,zenburn-bg+2)))) + `(mumamo-background-chunk-submode3 ((t (:background ,zenburn-bg+3)))) + `(mumamo-background-chunk-submode4 ((t (:background ,zenburn-bg+1)))) + + ;; org-mode + `(org-agenda-date-today + ((t (:foreground "white" :slant italic :weight bold))) t) + `(org-agenda-structure + ((t (:inherit font-lock-comment-face)))) + `(org-archived ((t (:foreground ,zenburn-fg :weight bold)))) + `(org-checkbox ((t (:background ,zenburn-bg+2 :foreground "white" + :box (:line-width 1 :style released-button))))) + `(org-date ((t (:foreground ,zenburn-blue :underline t)))) + `(org-deadline-announce ((t (:foreground ,zenburn-red-1)))) + `(org-done ((t (:bold t :weight bold :foreground ,zenburn-green+3)))) + `(org-formula ((t (:foreground ,zenburn-yellow-2)))) + `(org-headline-done ((t (:foreground ,zenburn-green+3)))) + `(org-hide ((t (:foreground ,zenburn-bg-1)))) + `(org-level-1 ((t (:foreground ,zenburn-orange)))) + `(org-level-2 ((t (:foreground ,zenburn-green+4)))) + `(org-level-3 ((t (:foreground ,zenburn-blue-1)))) + `(org-level-4 ((t (:foreground ,zenburn-yellow-2)))) + `(org-level-5 ((t (:foreground ,zenburn-cyan)))) + `(org-level-6 ((t (:foreground ,zenburn-green+2)))) + `(org-level-7 ((t (:foreground ,zenburn-red-4)))) + `(org-level-8 ((t (:foreground ,zenburn-blue-4)))) + `(org-link ((t (:foreground ,zenburn-yellow-2 :underline t)))) + `(org-scheduled ((t (:foreground ,zenburn-green+4)))) + `(org-scheduled-previously ((t (:foreground ,zenburn-red-4)))) + `(org-scheduled-today ((t (:foreground ,zenburn-blue+1)))) + `(org-special-keyword ((t (:foreground ,zenburn-fg-1 :weight normal)))) + `(org-table ((t (:foreground ,zenburn-green+2)))) + `(org-tag ((t (:bold t :weight bold)))) + `(org-time-grid ((t (:foreground ,zenburn-orange)))) + `(org-todo ((t (:bold t :foreground ,zenburn-red :weight bold)))) + `(org-upcoming-deadline ((t (:inherit font-lock-keyword-face)))) + `(org-warning ((t (:bold t :foreground ,zenburn-red :weight bold :underline nil)))) + `(org-column ((t (:background ,zenburn-bg-1)))) + `(org-column-title ((t (:background ,zenburn-bg-1 :underline t :weight bold)))) + + ;; outline + `(outline-1 ((t (:foreground ,zenburn-orange)))) + `(outline-2 ((t (:foreground ,zenburn-green+4)))) + `(outline-3 ((t (:foreground ,zenburn-blue-1)))) + `(outline-4 ((t (:foreground ,zenburn-yellow-2)))) + `(outline-5 ((t (:foreground ,zenburn-cyan)))) + `(outline-6 ((t (:foreground ,zenburn-green+2)))) + `(outline-7 ((t (:foreground ,zenburn-red-4)))) + `(outline-8 ((t (:foreground ,zenburn-blue-4)))) + + ;; rainbow-delimiters + `(rainbow-delimiters-depth-1-face ((t (:foreground ,zenburn-fg)))) + `(rainbow-delimiters-depth-2-face ((t (:foreground ,zenburn-green+2)))) + `(rainbow-delimiters-depth-3-face ((t (:foreground ,zenburn-yellow-2)))) + `(rainbow-delimiters-depth-4-face ((t (:foreground ,zenburn-cyan)))) + `(rainbow-delimiters-depth-5-face ((t (:foreground ,zenburn-green-1)))) + `(rainbow-delimiters-depth-6-face ((t (:foreground ,zenburn-blue+1)))) + `(rainbow-delimiters-depth-7-face ((t (:foreground ,zenburn-yellow-1)))) + `(rainbow-delimiters-depth-8-face ((t (:foreground ,zenburn-green+1)))) + `(rainbow-delimiters-depth-9-face ((t (:foreground ,zenburn-blue-2)))) + `(rainbow-delimiters-depth-10-face ((t (:foreground ,zenburn-orange)))) + `(rainbow-delimiters-depth-11-face ((t (:foreground ,zenburn-green)))) + `( rainbow-delimiters-depth-12-face ((t (:foreground ,zenburn-blue-5)))) + + ;;rcirc + `(rcirc-my-nick ((t (:foreground ,zenburn-blue)))) + `(rcirc-other-nick ((t (:foreground ,zenburn-orange)))) + `(rcirc-bright-nick ((t (:foreground ,zenburn-blue+1)))) + `(rcirc-dim-nick ((t (:foreground ,zenburn-blue-2)))) + `(rcirc-server ((t (:foreground ,zenburn-green)))) + `(rcirc-server-prefix ((t (:foreground ,zenburn-green+1)))) + `(rcirc-timestamp ((t (:foreground ,zenburn-green+2)))) + `(rcirc-nick-in-message ((t (:foreground ,zenburn-yellow)))) + `(rcirc-nick-in-message-full-line ((t (:bold t)))) + `(rcirc-prompt ((t (:foreground ,zenburn-yellow :bold t)))) + `(rcirc-track-nick ((t (:inverse-video t)))) + `(rcirc-track-keyword ((t (:bold t)))) + `(rcirc-url ((t (:bold t)))) + `(rcirc-keyword ((t (:foreground ,zenburn-yellow :bold t)))) + + ;; rpm-mode + `(rpm-spec-dir-face ((t (:foreground ,zenburn-green)))) + `(rpm-spec-doc-face ((t (:foreground ,zenburn-green)))) + `(rpm-spec-ghost-face ((t (:foreground ,zenburn-red)))) + `(rpm-spec-macro-face ((t (:foreground ,zenburn-yellow)))) + `(rpm-spec-obsolete-tag-face ((t (:foreground ,zenburn-red)))) + `(rpm-spec-package-face ((t (:foreground ,zenburn-red)))) + `(rpm-spec-section-face ((t (:foreground ,zenburn-yellow)))) + `(rpm-spec-tag-face ((t (:foreground ,zenburn-blue)))) + `(rpm-spec-var-face ((t (:foreground ,zenburn-red)))) + + ;; rst-mode + `(rst-level-1-face ((t (:foreground ,zenburn-orange)))) + `(rst-level-2-face ((t (:foreground ,zenburn-green+1)))) + `(rst-level-3-face ((t (:foreground ,zenburn-blue-1)))) + `(rst-level-4-face ((t (:foreground ,zenburn-yellow-2)))) + `(rst-level-5-face ((t (:foreground ,zenburn-cyan)))) + `(rst-level-6-face ((t (:foreground ,zenburn-green-1)))) + + ;; show-paren + `(show-paren-mismatch ((t (:foreground ,zenburn-red-3 :background ,zenburn-bg :weight bold)))) + `(show-paren-match ((t (:foreground ,zenburn-blue-1 :background ,zenburn-bg :weight bold)))) + + ;; sml-mode-line + '(sml-modeline-end-face ((t :inherit default :width condensed))) + + ;; SLIME + `(slime-repl-inputed-output-face ((t (:foreground ,zenburn-red)))) + + ;; tabbar + `(tabbar-button ((t (:foreground ,zenburn-fg + :background ,zenburn-bg)))) + `(tabbar-selected ((t (:foreground ,zenburn-fg + :background ,zenburn-bg + :box (:line-width -1 :style pressed-button))))) + `(tabbar-unselected ((t (:foreground ,zenburn-fg + :background ,zenburn-bg+1 + :box (:line-width -1 :style released-button))))) + + ;; term + `(term-color-black ((t (:foreground ,zenburn-bg + :background ,zenburn-bg-1)))) + `(term-color-red ((t (:foreground ,zenburn-red-2 + :background ,zenburn-red-4)))) + `(term-color-green ((t (:foreground ,zenburn-green + :background ,zenburn-green+2)))) + `(term-color-yellow ((t (:foreground ,zenburn-orange + :background ,zenburn-yellow)))) + `(term-color-blue ((t (:foreground ,zenburn-blue-1 + :background ,zenburn-blue-4)))) + `(term-color-magenta ((t (:foreground ,zenburn-magenta + :background ,zenburn-red)))) + `(term-color-cyan ((t (:foreground ,zenburn-cyan + :background ,zenburn-blue)))) + `(term-color-white ((t (:foreground ,zenburn-fg + :background ,zenburn-fg-1)))) + '(term-default-fg-color ((t (:inherit term-color-white)))) + '(term-default-bg-color ((t (:inherit term-color-black)))) + + ;; volatile-highlights + `(vhl/default-face ((t (:background ,zenburn-bg-05)))) + + ;; emacs-w3m + `(w3m-anchor ((t (:foreground ,zenburn-yellow :underline t + :weight bold)))) + `(w3m-arrived-anchor ((t (:foreground ,zenburn-yellow-2 + :underline t :weight normal)))) + `(w3m-form ((t (:foreground ,zenburn-red-1 :underline t)))) + `(w3m-header-line-location-title ((t (:foreground ,zenburn-yellow + :underline t :weight bold)))) + '(w3m-history-current-url ((t (:inherit match)))) + `(w3m-lnum ((t (:foreground ,zenburn-green+2 :background ,zenburn-bg)))) + `(w3m-lnum-match ((t (:background ,zenburn-bg-1 + :foreground ,zenburn-orange + :weight bold)))) + `(w3m-lnum-minibuffer-prompt ((t (:foreground ,zenburn-yellow)))) + + ;; whitespace-mode + `(whitespace-space ((t (:background ,zenburn-bg+1 :foreground ,zenburn-bg+1)))) + `(whitespace-hspace ((t (:background ,zenburn-bg+1 :foreground ,zenburn-bg+1)))) + `(whitespace-tab ((t (:background ,zenburn-red-1)))) + `(whitespace-newline ((t (:foreground ,zenburn-bg+1)))) + `(whitespace-trailing ((t (:background ,zenburn-red)))) + `(whitespace-line ((t (:background ,zenburn-bg :foreground ,zenburn-magenta)))) + `(whitespace-space-before-tab ((t (:background ,zenburn-orange :foreground ,zenburn-orange)))) + `(whitespace-indentation ((t (:background ,zenburn-yellow :foreground ,zenburn-red)))) + `(whitespace-empty ((t (:background ,zenburn-yellow)))) + `(whitespace-space-after-tab ((t (:background ,zenburn-yellow :foreground ,zenburn-red)))) + + ;; wanderlust + `(wl-highlight-folder-few-face ((t (:foreground ,zenburn-red-2)))) + `(wl-highlight-folder-many-face ((t (:foreground ,zenburn-red-1)))) + `(wl-highlight-folder-path-face ((t (:foreground ,zenburn-orange)))) + `(wl-highlight-folder-unread-face ((t (:foreground ,zenburn-blue)))) + `(wl-highlight-folder-zero-face ((t (:foreground ,zenburn-fg)))) + `(wl-highlight-folder-unknown-face ((t (:foreground ,zenburn-blue)))) + `(wl-highlight-message-citation-header ((t (:foreground ,zenburn-red-1)))) + `(wl-highlight-message-cited-text-1 ((t (:foreground ,zenburn-red)))) + `(wl-highlight-message-cited-text-2 ((t (:foreground ,zenburn-green+2)))) + `(wl-highlight-message-cited-text-3 ((t (:foreground ,zenburn-blue)))) + `(wl-highlight-message-cited-text-4 ((t (:foreground ,zenburn-blue+1)))) + `(wl-highlight-message-header-contents-face ((t (:foreground ,zenburn-green)))) + `(wl-highlight-message-headers-face ((t (:foreground ,zenburn-red+1)))) + `(wl-highlight-message-important-header-contents ((t (:foreground ,zenburn-green+2)))) + `(wl-highlight-message-header-contents ((t (:foreground ,zenburn-green+1)))) + `(wl-highlight-message-important-header-contents2 ((t (:foreground ,zenburn-green+2)))) + `(wl-highlight-message-signature ((t (:foreground ,zenburn-green)))) + `(wl-highlight-message-unimportant-header-contents ((t (:foreground ,zenburn-fg)))) + `(wl-highlight-summary-answered-face ((t (:foreground ,zenburn-blue)))) + `(wl-highlight-summary-disposed-face ((t (:foreground ,zenburn-fg + :slant italic)))) + `(wl-highlight-summary-new-face ((t (:foreground ,zenburn-blue)))) + `(wl-highlight-summary-normal-face ((t (:foreground ,zenburn-fg)))) + `(wl-highlight-summary-thread-top-face ((t (:foreground ,zenburn-yellow)))) + `(wl-highlight-thread-indent-face ((t (:foreground ,zenburn-magenta)))) + `(wl-highlight-summary-refiled-face ((t (:foreground ,zenburn-fg)))) + `(wl-highlight-summary-displaying-face ((t (:underline t :weight bold)))) + + ;; which-func-mode + `(which-func ((t (:foreground ,zenburn-green+4)))) + + ;; yascroll + `(yascroll:thumb-text-area ((t (:background ,zenburn-bg-1)))) + `(yascroll:thumb-fringe ((t (:background ,zenburn-bg-1 :foreground ,zenburn-bg-1))))) + + ;;; custom theme variables + (custom-theme-set-variables + 'zenburn + `(ansi-color-names-vector [,zenburn-bg ,zenburn-red ,zenburn-green ,zenburn-yellow + ,zenburn-blue ,zenburn-magenta ,zenburn-cyan ,zenburn-fg]) + + ;; fill-column-indicator + `(fci-rule-color ,zenburn-bg-05) + + ;; vc-annotate + `(vc-annotate-color-map + '(( 20. . ,zenburn-red-1) + ( 40. . ,zenburn-red) + ( 60. . ,zenburn-orange) + ( 80. . ,zenburn-yellow-2) + (100. . ,zenburn-yellow-1) + (120. . ,zenburn-yellow) + (140. . ,zenburn-green-1) + (160. . ,zenburn-green) + (180. . ,zenburn-green+1) + (200. . ,zenburn-green+2) + (220. . ,zenburn-green+3) + (240. . ,zenburn-green+4) + (260. . ,zenburn-cyan) + (280. . ,zenburn-blue-2) + (300. . ,zenburn-blue-1) + (320. . ,zenburn-blue) + (340. . ,zenburn-blue+1) + (360. . ,zenburn-magenta))) + `(vc-annotate-very-old-color ,zenburn-magenta) + `(vc-annotate-background ,zenburn-bg-1) + )) + +;;;###autoload +(and load-file-name + (boundp 'custom-theme-load-path) + (add-to-list 'custom-theme-load-path + (file-name-as-directory + (file-name-directory load-file-name)))) + +(provide-theme 'zenburn) + +;; Local Variables: +;; no-byte-compile: t +;; indent-tabs-mode: nil +;; eval: (when (fboundp 'rainbow-mode) (rainbow-mode +1)) +;; End: + +;;; zenburn-theme.el ends here diff --git a/vendor/haskell-mode b/vendor/haskell-mode new file mode 160000 index 0000000..4f91247 --- /dev/null +++ b/vendor/haskell-mode @@ -0,0 +1 @@ +Subproject commit 4f91247ccb3d341732802b1faf819fd59e5e8c40 diff --git a/vendor/swank-js b/vendor/swank-js new file mode 160000 index 0000000..185e5e4 --- /dev/null +++ b/vendor/swank-js @@ -0,0 +1 @@ +Subproject commit 185e5e42f67f9591e6507fcc24330dad9d2e29fa -- 2.45.2