1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
|
@! fwmode.fw - FunnelWeb major mode for Emacs (Elisp).
@p typesetter = tex
\documentstyle{report}
\title{
An Emacs/Elisp Major Mode for FunnelWeb
}
\author{
A.B.Coates \\
Department of Physics \\
The University of Queensland \\
QLD\ \ 4072 \\
Australia \\
Email: {\tt coates@@physics.uq.oz.au}
}
\begin{document}
\maketitle
\tableofcontents
\chapter{Major and Minor Modes}
\section{The FunnelWeb Major Mode}
This is the definition of the function which defines the FunnelWeb
mode. A brief (and not exhaustive) description of the functions
available is given in its description string.
@$@<fw-mode Function Definitions@>+=@{
(defun fw-mode ()
"Major mode for editing FunnelWeb files. Built on top of
tex-mode. Makes @@} , @@) , and @@> display their matching
opening braces @@{ , @@( , or @@< .
Use \\[fw-buffer] to run FunnelWeb on the current buffer
*without* saving it.
Use \\[fw-file] to be prompted to save the buffer to a file
first, before running FunnelWeb on the file.
Use \\[fw-tex] to run the (La)TeX output file through TeX or
LaTeX as appropriate.
Use \\[fw-print] to print a .dvi file.
Use \\[fw-show-print-queue] to show the print queue that
\\[fw-print] put your job on.
Commands from tex-mode (or a similar selected mode) are
mapped to operate on the (La)TeX file produced by FunnelWeb.
Key sequences:
see documentation for `switch-mode' for key sequences
relating to mode switching.
Mode variables:
fw-autofill-mode
Whether autofill-mode is automatically invoked for
FunnelWeb files. Set to 0 for no, to a positive
number for yes.
fw-TeX-mode
The major (La)TeX mode on which fw-mode is based.
Typically either 'tex-mode or 'latex-mode
(or perhaps 'tex-init for Auc-TeX
or 'html-mode for hypertext ...).
fw-directory
Directory in which to create temporary files for
TeX jobs run by \\[fw-buffer] or \\[fw-file].
fw-use-TeX-quote-style
Set this to nil so the the \" key produces the
normal \" character. If set to true, the \" key
works as for (La)TeX mode, producing either
`` or ''.
fw-dvi-print-command
Command string used by \\[fw-print] to print a
.dvi file.
fw-show-queue-command
Command string used by \\[fw-show-print-queue] to
show the print queue that \\[fw-print] put your
job on.
Entering FunnelWeb-mode calls the value of fw-mode-hook."
(interactive)
(funcall fw-TeX-mode)
(hack-local-variables)
(setq mode-name "FunnelWeb")
(setq major-mode 'fw-mode)
(auto-fill-mode fw-auto-fill-mode)
(if fw-mode-map (use-local-map fw-mode-map))
(setq fw-buffer-p t)
(switch-mode fw-switch-minor-mode-init)
(run-hooks 'fw-mode-hook))
@}
\section{The Switch Minor Mode}
This is the definition of the function which defines the Switch
minor mode. A brief (and not exhaustive) description of the functions
available is given in its description string.
@$@<switch-mode Function Definitions 2@>+=@{
(defun switch-mode
( &optional set-mode-p
no-check-p
region-open-string
region-close-string
region-boundary-pattern )
"With no arguments, toggle whether the region mode
checking is activated or not. Optional first argument
SET-MODE-P can be used to definitely switch the region
mode checking on or off: a positive number for on, off
otherwise.
Optional second argument NO-CHECK-P is nil for a
check of whether the point is in a code region or not
to be taken immediately. With any other value, no check
is done.
Optional third and fourth arguments REGION-OPEN-STRING
and REGION-CLOSE-STRING define the boundaries by which a
code region is recognised.
Optional fourth argument REGION-BOUNDARY_PATTERN should
be a pattern equivalent to
\\(REGION-OPEN-STRING\\|REGION-CLOSE-STRING\\)
i.e. a pattern which recognises either an opening or closing
pattern.
Key sequences:
\\C-x\\C-a key sequences are used for the \"Switch\" minor
mode, which allows modes to be swapped while editing a file.
\\C-x \\C-a t : toggle Switch minor-mode on and off
\\C-x \\C-a c : check whether in macro region or not
\\C-x \\C-a p : toggles whether the default macro region
mode is used with or without prompting
\\C-x \\C-a s : set the current macro region mode"
(interactive)
@}
A variable, local to each buffer, is needed to note whether
switch-mode is active or not.
@$@<switch-mode Variable Definitions 1@>+=@{
(defvar switch-mode nil
"Whether the region checking minor mode is active or not.")
(make-variable-buffer-local 'switch-mode)
@}
The boolean value {\tt switch-on-p} is given the value {\tt t} if the
switch minor mode should be turned on, {\tt nil} otherwise. The value
depends on when the function call toggles the state or sets it
directly.
@$@<switch-mode Function Definitions 2@>+=@{@-
(let ((switch-on-p
(or (and (numberp set-mode-p)
(> set-mode-p 0))
(not switch-mode))))
(if switch-on-p
(let ((old-switch-mode-value
switch-mode))
(setq switch-mode t
switch-force-region-check-p t)
(if (not (or no-check-p old-switch-mode-value))
(switch-check-if-in-region)))
(setq switch-mode nil))
@}
Three variables, with local values in each buffer, are required to
hold the values of the region opening and closing strings and a
combined pattern.
@$@<switch-mode Variable Definitions 1@>+=@{
(defvar switch-open-region-string "@@{"
"String defining the beginning of a code region.")
(make-variable-buffer-local 'switch-open-region-string)
(defvar switch-close-region-string "@@}"
"String defining the end of a code region.")
(make-variable-buffer-local 'switch-close-region-string)
(defvar switch-boundary-region-pattern "@@\\({\\|}\\)"
"Regular expression defining the beginning or end of a code
region.")
(make-variable-buffer-local 'switch-boundary-region-pattern)
@}
@$@<switch-mode Function Definitions 2@>+=@{@-
(if region-open-string
(setq switch-open-region-string
region-open-string))
(if region-close-string
(setq switch-close-region-string
region-close-string))
(if region-boundary-pattern
(setq switch-boundary-region-pattern
region-boundary-pattern))
(force-mode-line-update t)))
@}
\section{Invocation of the FunnelWeb mode}
To cause FunnelWeb to be invoked for {\tt .fw} and {\tt .fwi} files,
the following lines should be added to the user's ``{\tt .emacs}''
file.
@$@<Emacs initialisation file additions@>@Z==@{
(autoload 'fw-mode "fw-mode")
(setq
auto-mode-alist
(reverse
(append
(reverse auto-mode-alist)
(list
(append
(list "\\.fw$")
'fw-mode
)
(append
(list "\\.fwi$")
'fw-mode
)
)
)
)
)
@}
\chapter{Function and Variable Definitions for the FunnelWeb Mode}
An alternative command for saving buffers converts all tabs to spaces
before saving, since FunnelWeb does not accept tab characters in .fw
files by default. Because mode-switching is expected to be used when
editing FunnelWeb files, a local variable in each buffer is set to
define whether a buffer is a FunnelWeb buffer or not. A global
variable is also provided to switch off the replacement of tabs by
spaces. The string used to replace tabs with spaces can also be
changed from the default of 8 spaces. Another global variable also
controls the removal of trailing spaces, since these are also not
accepted by FunnelWeb by default.
@$@<fw-mode Variable Definitions2@>+=@{
(defvar fw-untabify-before-saving-p t
"*Whether to convert tabs to spaces before saving FunnelWeb
buffers.")
(defvar fw-tab-string "@^D(009)"
"Tab character as string.")
(defvar fw-tab-space-replacement " "
"*String of spaces for replacing tabs.")
(make-variable-buffer-local 'fw-tab-space-replacement)
(defvar fw-remove-trailing-spaces-before-saving-p t
"*Whether to remove trailing spaces on lines before saving
FunnelWeb buffers.")
(defvar fw-space (string-to-char " ")
"Space character, used in removing trailing spaces.")
(defvar fw-trailing-space-pattern " +$"
"*Pattern used to identify trailing spaces on lines.")
(defvar fw-null-string ""
"Empty string used for replacing trailing spaces.")
@}
@$@<fw-mode Function Definitions@>+=@{
(defun fw-untabify-save-buffer ()
"Save the buffer, optionally removing tabs and trailing spaces
first if the buffer is a FunnelWeb buffer."
(interactive)
(if fw-buffer-p
(progn
(if fw-untabify-before-saving-p
(progn
(message "Removing tabs ...")
(save-excursion
(goto-char (point-min))
(while (search-forward fw-tab-string nil t)
(replace-match fw-tab-space-replacement nil t)))))
(if fw-remove-trailing-spaces-before-saving-p
(progn
(message "Removing trailing spaces ...")
(save-excursion
(goto-char (point-min))
(while (< (point) (point-max))
(end-of-line)
(while (eq (preceding-char) fw-space)
(backward-delete-char 1))
(forward-line 1)))))))
(save-buffer))
@}
Other variable definitions follows. Those for which the decription
text begins with a \verb$*$ can be changed on the command line by the
user, and all can be set in the users {\tt .emacs} file.
@$@<fw-mode Variable Definitions1@>+=@{
(defvar fw-TeX-mode 'tex-mode
"*The default TeX-based foundation for FunnelWeb mode.")
@}
@$@<fw-mode Variable Definitions2@>+=@{
(defvar fw-switch-minor-mode-init 1
"*Whether to activate the Switch minor mode automatically
on entering FunnelWeb mode. A positive integer for yes.")
(defvar fw-buffer-p nil
"Whether a buffer is a FunnelWeb buffer or not.")
(make-variable-buffer-local 'fw-buffer-p)
(switch-add-to-preservation-list 'fw-buffer-p)
(defvar fw-quote-style t
"*Whether to map \" to a single character or use (La)TeX
mapping to `` or '' as appropriate. Can be set to nil to
remove the (La)TeX mapping, or anything else to enable it.")
(defvar fw-auto-fill-mode 1
"*Whether autofill-mode is automatically invoked for
FunnelWeb files. Set to 0 for no, to a positive number
for yes.")
(defvar fw-command "fw"
"*The command to run FunnelWeb on a file.
Any pre-options (fw-command-pre-options) will be appended
to this string, separated by a space, followed by the
filename, also separated by a space, and finally any
post-options (fw-command-post-options), again separated
by a space.")
(defvar fw-command-pre-options nil
"*Options which go before the filename when
calling FunnelWeb.")
(make-variable-buffer-local 'fw-command-pre-options)
(defvar fw-command-post-options "+t +D"
"*Options which go after the filename when
calling FunnelWeb.")
(make-variable-buffer-local 'fw-command-post-options)
(defvar fw-shell-cd-command "cd"
"*Command to give to shell running FunnelWeb to
change directory. The value of fw-directory will be
appended to this, separated by a space.")
(defvar fw-mode-syntax-table nil
"Syntax table used while in FunnelWeb mode.")
(defvar fw-mode-map nil
"Keymap for FunnelWeb mode.")
(defvar fw-close-definition-block-additive t
"*Whether definitions should be closed using \"+=\" (t) or
\"==\" (nil).")
(make-variable-buffer-local
'fw-close-definition-block-additive)
(defvar fw-close-definition-block-newline-suppress t
"*Whether definitions should be closed using \"@@-\".")
(make-variable-buffer-local
'fw-close-definition-block-newline-suppress)
(defvar fw-close-definition-block-blank-line t
"Whether definitions should be closed leaving
a blank line.")
(make-variable-buffer-local
'fw-close-definition-block-blank-line)
@}
\chapter{Key Definitions for the FunnelWeb Mode}
These are the special key definitions for FunnelWeb commands.
@$@<fw-mode Key Definitions@>==@{
@!(define-key fw-mode-map "\C-c\C-f" 'fw-close-definition-block)
(global-set-key "\C-x\C-s" 'fw-untabify-save-buffer)
@}
\chapter{Function and Variable Definitions for the Switch Minor Mode}
The Switch minor mode works by adding a function, run after each emacs
command, which checks the position of point. If point is outside of
the current region, each code or text, a function is run to determine
whether point lies in a code or text region. Note that for speed, the
code does not update the boundaries of the current region after each
command, and so the checking may be fooled when and if sections are
deleted from a code or text region.
Variables are needed to hold the bounds of the current region and the
whether flag marking whether a region check is in progress or not (to
avoid an infinite recursion).
@$@<switch-mode Variable Definitions 1@>+=@{
(defvar switch-region-min nil
"Start of current macro or text region, or nil.")
(make-variable-buffer-local 'switch-region-min)
(defvar switch-region-max nil
"End of current macro or text region, or nil.")
(make-variable-buffer-local 'switch-region-max)
(defvar switch-not-in-region-check-routine-p t
"Whether a region check is not in progress.")
(make-variable-buffer-local
'switch-not-in-region-check-routine-p)
@}
@$@<switch-mode Function Definitions 2@>+=@{
(defun switch-post-command-hook-function ()
"Function to check if the user is in a code definition
region or not."
(if (and (not isearch-mode)
switch-mode
switch-not-in-region-check-routine-p
(or (not switch-region-min)
(not switch-region-max)
(let ((the-point (point)))
(or
(< the-point switch-region-min)
(> the-point switch-region-max)))))
(let ((switch-not-in-region-check-routine-p nil))
(switch-check-if-in-region))))
@}
The function for checking whether the point is in a code or text
region or not is as follows.
@$@<switch-mode Function Definitions 2@>+=@{
(defun switch-check-if-in-region ()
"Check if point is inside or outside a FunnelWeb macro
definition. If outside, switch to (Auc/La)TeX mode.
If inside, either ask the user for a mode, defaulting
to the last mode used in a macro definition, or directly
use the last mode chosen (depends on value of variable
switch-mode-prompt-p)."
(interactive)
@}
First, searches are carried out forwards and backwards from point to
determine what sort of region point is in.
@$@<switch-mode Function Definitions 2@>+=@{@-
(let ((backward-search-result
(switch-search-backward-check
switch-boundary-region-pattern
switch-open-region-string))
(forward-search-result
(switch-search-forward-check
switch-boundary-region-pattern
switch-close-region-string))
(backward-search-value)
(forward-search-value))
(setq backward-search-value
(car backward-search-result))
(setq forward-search-value
(car forward-search-result))
(setq switch-region-min
(car (cdr backward-search-result)))
(setq switch-region-max
(car (cdr forward-search-result)))
(if (not (or (< backward-search-value 0)
(< forward-search-value 0)
(and (eq backward-search-value 0)
(eq forward-search-value 0))))
@}
The following code determines what is done if point is inside a code
region. Variables are required to define the behaviour, and to store
the current code region mode, as well as to store whether point was
last in a code or text region.
@$@<switch-mode Variable Definitions 1@>+=@{
(defvar switch-force-region-check-p nil
"Whether a region check should be forced or not,
regardless of whether it seems to be required or not.")
(make-variable-buffer-local 'switch-force-region-check-p)
(defvar switch-mode-prompt-p t
"*Whether the user should be prompted for a new
major mode type each time point enters a code region.")
(make-variable-buffer-local 'switch-mode-prompt-p)
(defvar switch-current-mode nil
"The current mode for a code region.")
(make-variable-buffer-local 'switch-current-mode)
(defvar switch-currently-in-region-p nil
"Whether point is in a code region or not.")
(make-variable-buffer-local 'switch-currently-in-region-p)
(defvar switch-highlight-p nil
"Whether to highlight regions as they are entered.
(This requires the `hilit19' library to be loaded.)")
(make-variable-buffer-local 'switch-highlight-p)
@}
@$@<switch-mode Function Definitions 2@>+=@{@-
(if (or (not switch-currently-in-region-p)
switch-force-region-check-p)
(progn
(switch-select-mode (not switch-mode-prompt-p))
(if switch-current-mode
(progn
(message (concat "Changed to "
(prin1-to-string
switch-current-mode)))
(setq switch-currently-in-region-p t)))))
@}
Now the code for the case where point is {\em not} in a code region,
but in a text region.
@$@<switch-mode Function Definitions 2@>+=@{@-
(if switch-currently-in-region-p
(let ((preservation-list
(switch-get-preservation-values)))
(fw-mode)
(switch-set-preservation-values
preservation-list)
(message "Changed to fw-mode")
(setq switch-currently-in-region-p nil))))
(setq switch-force-region-check-p nil)))
@}
A function is provided to allow the user to toggle whether the mode is
prompted for each time a code region is entered or not.
@$@<switch-mode Function Definitions 2@>+=@{
(defun switch-mode-prompt-toggle ()
"Toggle whether the user is prompted for the major mode
each time a code region is entered."
(interactive)
(setq switch-mode-prompt-p (not switch-mode-prompt-p))
(if switch-mode-prompt-p
(message "Mode prompting switched on.")
(message "Mode prompting switched off.")))
@}
It is also sometimes useful to be able to force a major mode to be
asked for. This is necessary when editing changes cause the program
to mistake the boundaries of the current region.
@$@<switch-mode Function Definitions 2@>+=@{
(defun switch-mode-force-prompt ()
"Cause the user to be prompted for a mode type for
the current region, if a code region."
(interactive)
(let ((switch-force-region-check-p t))
(switch-check-if-in-region)))
@}
The mode selection function allows the user to choose from any command
which ends with string \"-mode\". It optionally beeps on activation,
to note to the user that a mode selection is necessary.
@$@<switch-mode Variable Definitions 2@>+=@{
(defvar switch-mode-list (make-switch-mode-list)
"Return a list of strings of all possible major modes
from which the user can choose.")
(defvar switch-beep-on-mode-selection-p t
"*Whether to beep when a mode selection is necessary.")
@}
@$@<switch-mode Function Definitions 2@>+=@{
(defun switch-select-mode ( &optional no-prompt-p )
"Interactively get the user to select a macro mode,
giving the last-used macro mode as a default, and allowing
the user to select from all possible major mode commands
with name completion.
Optional parameter NO-PROMPT-P, if non-nil, stops
prompting from taking place unless the current mode
(switch-current-mode) is nil."
(let ((old-switch-mode-value
(if switch-mode 1 0)))
(if (not (and no-prompt-p switch-current-mode))
(progn
(if switch-beep-on-mode-selection-p (beep))
(let ((new-mode (completing-read
"Mode: "
switch-mode-list
nil
nil
(switch-convert-to-default-string
switch-current-mode)
nil)))
(setq switch-current-mode
(car (read-from-string new-mode))))))
(let ((preservation-list
(switch-get-preservation-values))
(region-min switch-region-min)
(region-max switch-region-max))
(message "Changing to %s"
(prin1-to-string switch-current-mode))
(if switch-current-mode (funcall switch-current-mode))
(if (and switch-highlight-p region-min region-max)
(progn
(hilit-unhighlight-region region-min region-max)
(hilit-highlight-region region-min region-max)))
(switch-set-preservation-values preservation-list))
(switch-mode old-switch-mode-value t)
(force-mode-line-update)))
@}
A short function to convert an object to a string if non-nil.
@$@<switch-mode Function Definitions 1@>+=@{
(defun switch-convert-to-default-string ( object )
"Convert an object into a default string for
name completion."
(if object (prin1-to-string object)))
@}
The following function returns a list of possible modes, in the form
of an Emacs ``alist''. A second function allows the user to update
the list.
@$@<switch-mode Function Definitions 1@>+=@{
(defun make-switch-mode-list ()
"Return a list of all commands ending in \"-mode\",
in the form of an alist."
(let ((mode-list (apropos-internal "-mode$")))
(mapcar 'switch-convert-to-alist-string mode-list)))
@}
@$@<switch-mode Function Definitions 2@>+=@{
(defun update-switch-mode-list ()
"Update the mode list used for the switch minor-mode."
(interactive)
(setq switch-mode-list (make-switch-mode-list)))
@}
This simple function converts objects to a form suitable for an Elisp
``alist''.
@$@<switch-mode Function Definitions 1@>+=@{
(defun switch-convert-to-alist-string ( object )
"Convert an object to a string in its own list,
the format appropriate for an alist."
(list (prin1-to-string object)))
@}
Two functions are used to search for code region boundaries, one for
searching forwards from point, the other for searching backwards.
Each searches for the given regexp, and if found, compares it to the
given string. A list is returned containing an integer value
describing the search result and the position of the string which was
matched.
@$@<switch-mode Function Definitions 1@>+=@{
(defun switch-search-forward-check ( regexp string )
"Search forward for the given regexp, and if the matching
pattern is found and it matches the given string, return `1'
and the beginning of the pattern, else return `-1' and the
beginning of the pattern. If the pattern is not found when
the end of the buffer is reached, return `0' and the end of
the buffer."
(save-excursion
(if (search-forward-regexp regexp (point-max) t)
(if (string-equal
string
(buffer-substring
(match-beginning 0)
(match-end 0)))
(list 1 (match-beginning 0))
(list -1 (match-beginning 0)))
(list 0 (point-max)))))
(defun switch-search-backward-check ( regexp string )
"Search backward for the given regexp, and if the matching
pattern is found and it matches the given string, return `1'
and the end of the pattern, else return `-1' and the end of
the pattern. If the pattern is not found when the beginning
of the buffer is reached, return `0' and the beginning of the
buffer."
(save-excursion
(if (search-backward-regexp regexp (point-min) t)
(if (string-equal
string
(buffer-substring
(match-beginning 0)
(match-end 0)))
(list 1 (match-end 0))
(list -1 (match-end 0)))
(list 0 (point-min)))))
@}
It is useful to allow functions to maintain a list of variables which
should be preserved by switch-mode operations. This list can be
changed by the user.
@$@<switch-mode Variable Definitions 1@>+=@{
(defvar switch-preservation-list
(list 'switch-current-mode 'switch-mode-prompt-p)
"List of names of variables that need to be specially
preserved by switch-mode operations.")
@}
@$@<switch-mode Function Definitions 2@>+=@{
(defun switch-add-to-preservation-list ( var )
"Add a variable to the switch-mode preservation list."
(if (not (memq var switch-preservation-list))
(setq switch-preservation-list
(append switch-preservation-list (list var)))))
(defun switch-get-preservation-values ()
"Returns a list of current values which can be used by
switch-set-preservation-values to restore the values of
the variables in the preservation list
(switch-preservation-list)."
(if switch-preservation-list
(mapcar
'switch-preserve-form
switch-preservation-list)))
(defun switch-preserve-form ( var )
"Return a list of the variable name and its value."
(list var (eval var)))
(defun switch-set-preservation-values ( vallist )
"Reset the variables in the preservation value list
using the value list previously created by
switch-get-preservation-values."
(mapcar 'switch-apply-set vallist))
(defun switch-apply-set ( varpair )
"Given a list of the form (NAME . VALUE), assign the value
to the name."
(apply 'set varpair))
@}
\chapter{Key Definitions for the Switch Minor Mode}
These are the special key definitions for Switch minor-mode commands.
@$@<switch-mode Key Definitions@>==@{
(defvar switch-prefix nil
"Switch minor-mode region check \\C-x\\C-a keymap.")
(define-prefix-command 'switch-prefix)
(global-set-key "\C-x\C-a" 'switch-prefix)
(define-key switch-prefix "c" 'switch-check-if-in-region)
(define-key switch-prefix "t" 'switch-mode)
(define-key switch-prefix "p" 'switch-mode-prompt-toggle)
(define-key switch-prefix "s" 'switch-mode-force-prompt)
@}
\chapter{Construction of the elisp files}
The file ``{\tt switch-mode.el}'' requires the standard Emacs
distribution provides the new minor mode function `{\tt switch-mode}'.
The variable and function definitions are each divided up into two
lots, in the order
\begin{itemize}
\item variables which don't rely on functions for their default
values
\item functions which don't rely on variables in their definitions
\item variables which rely on functions for their default
values
\item functions which rely on variables in their definitions.
\end{itemize}
@$@<switch-mode Constructed Code@>+=@{@-
(provide 'switch-mode)
@<switch-mode Variable Definitions 1@>
@<switch-mode Function Definitions 1@>
@<switch-mode Variable Definitions 2@>
@<switch-mode Function Definitions 2@>
@<switch-mode Key Definitions@>
@}
The following code installs the minor mode and runs any user-provided
hook function.
@$@<switch-mode Constructed Code@>+=@{@-
(setq minor-mode-alist
(reverse
(append (reverse minor-mode-alist)
(list (list
'switch-mode
" Switch")))))
(force-mode-line-update t)
(add-hook 'post-command-hook
'switch-post-command-hook-function)
(run-hooks 'switch-mode-hook)@}
@$@<Standard Header@>@M==@{@-
; A.B.Coates
; Department of Physics
; The University of Queensland QLD 4072
; Australia
; Standard GNU copyleft provisions apply to this file.@}
@O@<switch-mode.el@>==@{
@<Standard Header@>
@<switch-mode Constructed Code@>
@}
The file ``{\tt fw-mode.el}'' requires the switch minor mode file
``{\tt switch-mode.el}'', and provides the new mode function
`{\tt fw-mode}'. Calling the selected \TeX-mode is a way of making
sure that the required definitions are loaded, since the
mode-selection function may be defined as an {\em autoload} function.
@$@<fw-mode Constructed Code@>+=@{@-
(require 'switch-mode)
(provide 'fw-mode)
@<fw-mode Variable Definitions1@>
(funcall fw-TeX-mode)
@<fw-mode Variable Definitions2@>
@}
\noindent In case the user forgets the precise name, some synonyms for
`{\tt fw-mode}' are provided.
@$@<fw-mode Constructed Code@>+=@{@-
(fset 'FW-mode 'fw-mode)
(fset 'funnelweb-mode 'fw-mode)
(fset 'FunnelWeb-mode 'fw-mode)
@<fw-mode Function Definitions@>@}
\noindent If the keymap has not already been set in the user's
``{\tt .emacs}'' file, then a TeX-mode keymap is copied and
used if possible.
@$@<fw-mode Constructed Code@>+=@{@-
(if fw-mode-map
(progn
(defvar tex-mode-map nil)
(if tex-mode-map
(setq fw-mode-map tex-mode-map)
(progn
(defvar latex-mode-map nil)
(if latex-mode-map
(setq fw-mode-map latex-mode-map)
(progn
(defvar LaTeX-mode-map nil)
(if LaTeX-mode-map
(setq fw-mode-map LaTeX-mode-map)
(progn
(defvar TeX-mode-map nil)
(if TeX-mode-map
(setq fw-mode-map TeX-mode-map))))))))))
@<fw-mode Key Definitions@>@}
@O@<fw-mode.el@>==@{
@<Standard Header@>
@<fw-mode Constructed Code@>
@}
\end{document}
% Local Variables:
% TeX-master: fwmode
% End:
@! end of fwmode.fw
|