| 490 | | |
|---|
| 491 | | @node Example Major Modes |
|---|
| 492 | | @subsection Major Mode Examples |
|---|
| 493 | | |
|---|
| 494 | | Text mode is perhaps the simplest mode besides Fundamental mode. |
|---|
| 495 | | Here are excerpts from @file{text-mode.el} that illustrate many of |
|---|
| 496 | | the conventions listed above: |
|---|
| 497 | | |
|---|
| 498 | | @smallexample |
|---|
| 499 | | @group |
|---|
| 500 | | ;; @r{Create the syntax table for this mode.} |
|---|
| 501 | | (defvar text-mode-syntax-table |
|---|
| 502 | | (let ((st (make-syntax-table))) |
|---|
| 503 | | (modify-syntax-entry ?\" ". " st) |
|---|
| 504 | | (modify-syntax-entry ?\\ ". " st) |
|---|
| 505 | | ;; Add `p' so M-c on `hello' leads to `Hello', not `hello'. |
|---|
| 506 | | (modify-syntax-entry ?' "w p" st) |
|---|
| 507 | | st) |
|---|
| 508 | | "Syntax table used while in `text-mode'.") |
|---|
| 509 | | @end group |
|---|
| 510 | | |
|---|
| 511 | | ;; @r{Create the keymap for this mode.} |
|---|
| 512 | | @group |
|---|
| 513 | | (defvar text-mode-map |
|---|
| 514 | | (let ((map (make-sparse-keymap))) |
|---|
| 515 | | (define-key map "\e\t" 'ispell-complete-word) |
|---|
| 516 | | (define-key map "\es" 'center-line) |
|---|
| 517 | | (define-key map "\eS" 'center-paragraph) |
|---|
| 518 | | map) |
|---|
| 519 | | "Keymap for `text-mode'. |
|---|
| 520 | | Many other modes, such as Mail mode, Outline mode |
|---|
| 521 | | and Indented Text mode, inherit all the commands |
|---|
| 522 | | defined in this map.") |
|---|
| 523 | | @end group |
|---|
| 524 | | @end smallexample |
|---|
| 525 | | |
|---|
| 526 | | Here is how the actual mode command is defined now: |
|---|
| 527 | | |
|---|
| 528 | | @smallexample |
|---|
| 529 | | @group |
|---|
| 530 | | (define-derived-mode text-mode nil "Text" |
|---|
| 531 | | "Major mode for editing text written for humans to read. |
|---|
| 532 | | In this mode, paragraphs are delimited only by blank or white lines. |
|---|
| 533 | | You can thus get the full benefit of adaptive filling |
|---|
| 534 | | (see the variable `adaptive-fill-mode'). |
|---|
| 535 | | \\@{text-mode-map@} |
|---|
| 536 | | Turning on Text mode runs the normal hook `text-mode-hook'." |
|---|
| 537 | | @end group |
|---|
| 538 | | @group |
|---|
| 539 | | (make-local-variable 'text-mode-variant) |
|---|
| 540 | | (setq text-mode-variant t) |
|---|
| 541 | | ;; @r{These two lines are a feature added recently.} |
|---|
| 542 | | (set (make-local-variable 'require-final-newline) |
|---|
| 543 | | mode-require-final-newline) |
|---|
| 544 | | (set (make-local-variable 'indent-line-function) 'indent-relative)) |
|---|
| 545 | | @end group |
|---|
| 546 | | @end smallexample |
|---|
| 547 | | |
|---|
| 548 | | But here is how it was defined formerly, before |
|---|
| 549 | | @code{define-derived-mode} existed: |
|---|
| 550 | | |
|---|
| 551 | | @smallexample |
|---|
| 552 | | @group |
|---|
| 553 | | ;; @r{This isn't needed nowadays, since @code{define-derived-mode} does it.} |
|---|
| 554 | | (defvar text-mode-abbrev-table nil |
|---|
| 555 | | "Abbrev table used while in text mode.") |
|---|
| 556 | | (define-abbrev-table 'text-mode-abbrev-table ()) |
|---|
| 557 | | @end group |
|---|
| 558 | | |
|---|
| 559 | | @group |
|---|
| 560 | | (defun text-mode () |
|---|
| 561 | | "Major mode for editing text intended for humans to read... |
|---|
| 562 | | Special commands: \\@{text-mode-map@} |
|---|
| 563 | | @end group |
|---|
| 564 | | @group |
|---|
| 565 | | Turning on text-mode runs the hook `text-mode-hook'." |
|---|
| 566 | | (interactive) |
|---|
| 567 | | (kill-all-local-variables) |
|---|
| 568 | | (use-local-map text-mode-map) |
|---|
| 569 | | @end group |
|---|
| 570 | | @group |
|---|
| 571 | | (setq local-abbrev-table text-mode-abbrev-table) |
|---|
| 572 | | (set-syntax-table text-mode-syntax-table) |
|---|
| 573 | | @end group |
|---|
| 574 | | @group |
|---|
| 575 | | ;; @r{These four lines are absent from the current version} |
|---|
| 576 | | ;; @r{not because this is done some other way, but rather} |
|---|
| 577 | | ;; @r{because nowadays Text mode uses the normal definition of paragraphs.} |
|---|
| 578 | | (make-local-variable 'paragraph-start) |
|---|
| 579 | | (setq paragraph-start (concat "[ \t]*$\\|" page-delimiter)) |
|---|
| 580 | | (make-local-variable 'paragraph-separate) |
|---|
| 581 | | (setq paragraph-separate paragraph-start) |
|---|
| 582 | | (make-local-variable 'indent-line-function) |
|---|
| 583 | | (setq indent-line-function 'indent-relative-maybe) |
|---|
| 584 | | @end group |
|---|
| 585 | | @group |
|---|
| 586 | | (setq mode-name "Text") |
|---|
| 587 | | (setq major-mode 'text-mode) |
|---|
| 588 | | (run-mode-hooks 'text-mode-hook)) ; @r{Finally, this permits the user to} |
|---|
| 589 | | ; @r{customize the mode with a hook.} |
|---|
| 590 | | @end group |
|---|
| 591 | | @end smallexample |
|---|
| 592 | | |
|---|
| 593 | | @cindex @file{lisp-mode.el} |
|---|
| 594 | | The three Lisp modes (Lisp mode, Emacs Lisp mode, and Lisp |
|---|
| 595 | | Interaction mode) have more features than Text mode and the code is |
|---|
| 596 | | correspondingly more complicated. Here are excerpts from |
|---|
| 597 | | @file{lisp-mode.el} that illustrate how these modes are written. |
|---|
| 598 | | |
|---|
| 599 | | @cindex syntax table example |
|---|
| 600 | | @smallexample |
|---|
| 601 | | @group |
|---|
| 602 | | ;; @r{Create mode-specific table variables.} |
|---|
| 603 | | (defvar lisp-mode-syntax-table nil "") |
|---|
| 604 | | (defvar lisp-mode-abbrev-table nil "") |
|---|
| 605 | | @end group |
|---|
| 606 | | |
|---|
| 607 | | @group |
|---|
| 608 | | (defvar emacs-lisp-mode-syntax-table |
|---|
| 609 | | (let ((table (make-syntax-table))) |
|---|
| 610 | | (let ((i 0)) |
|---|
| 611 | | @end group |
|---|
| 612 | | |
|---|
| 613 | | @group |
|---|
| 614 | | ;; @r{Set syntax of chars up to @samp{0} to say they are} |
|---|
| 615 | | ;; @r{part of symbol names but not words.} |
|---|
| 616 | | ;; @r{(The digit @samp{0} is @code{48} in the @acronym{ASCII} character set.)} |
|---|
| 617 | | (while (< i ?0) |
|---|
| 618 | | (modify-syntax-entry i "_ " table) |
|---|
| 619 | | (setq i (1+ i))) |
|---|
| 620 | | ;; @r{@dots{} similar code follows for other character ranges.} |
|---|
| 621 | | @end group |
|---|
| 622 | | @group |
|---|
| 623 | | ;; @r{Then set the syntax codes for characters that are special in Lisp.} |
|---|
| 624 | | (modify-syntax-entry ? " " table) |
|---|
| 625 | | (modify-syntax-entry ?\t " " table) |
|---|
| 626 | | (modify-syntax-entry ?\f " " table) |
|---|
| 627 | | (modify-syntax-entry ?\n "> " table) |
|---|
| 628 | | @end group |
|---|
| 629 | | @group |
|---|
| 630 | | ;; @r{Give CR the same syntax as newline, for selective-display.} |
|---|
| 631 | | (modify-syntax-entry ?\^m "> " table) |
|---|
| 632 | | (modify-syntax-entry ?\; "< " table) |
|---|
| 633 | | (modify-syntax-entry ?` "' " table) |
|---|
| 634 | | (modify-syntax-entry ?' "' " table) |
|---|
| 635 | | (modify-syntax-entry ?, "' " table) |
|---|
| 636 | | @end group |
|---|
| 637 | | @group |
|---|
| 638 | | ;; @r{@dots{}likewise for many other characters@dots{}} |
|---|
| 639 | | (modify-syntax-entry ?\( "() " table) |
|---|
| 640 | | (modify-syntax-entry ?\) ")( " table) |
|---|
| 641 | | (modify-syntax-entry ?\[ "(] " table) |
|---|
| 642 | | (modify-syntax-entry ?\] ")[ " table)) |
|---|
| 643 | | table)) |
|---|
| 644 | | @end group |
|---|
| 645 | | @group |
|---|
| 646 | | ;; @r{Create an abbrev table for lisp-mode.} |
|---|
| 647 | | (define-abbrev-table 'lisp-mode-abbrev-table ()) |
|---|
| 648 | | @end group |
|---|
| 649 | | @end smallexample |
|---|
| 650 | | |
|---|
| 651 | | Much code is shared among the three Lisp modes. The following |
|---|
| 652 | | function sets various variables; it is called by each of the major Lisp |
|---|
| 653 | | mode functions: |
|---|
| 654 | | |
|---|
| 655 | | @smallexample |
|---|
| 656 | | @group |
|---|
| 657 | | (defun lisp-mode-variables (lisp-syntax) |
|---|
| 658 | | (when lisp-syntax |
|---|
| 659 | | (set-syntax-table lisp-mode-syntax-table)) |
|---|
| 660 | | (setq local-abbrev-table lisp-mode-abbrev-table) |
|---|
| 661 | | @dots{} |
|---|
| 662 | | @end group |
|---|
| 663 | | @end smallexample |
|---|
| 664 | | |
|---|
| 665 | | Functions such as @code{forward-paragraph} use the value of the |
|---|
| 666 | | @code{paragraph-start} variable. Since Lisp code is different from |
|---|
| 667 | | ordinary text, the @code{paragraph-start} variable needs to be set |
|---|
| 668 | | specially to handle Lisp. Also, comments are indented in a special |
|---|
| 669 | | fashion in Lisp and the Lisp modes need their own mode-specific |
|---|
| 670 | | @code{comment-indent-function}. The code to set these variables is the |
|---|
| 671 | | rest of @code{lisp-mode-variables}. |
|---|
| 672 | | |
|---|
| 673 | | @smallexample |
|---|
| 674 | | @group |
|---|
| 675 | | (make-local-variable 'paragraph-start) |
|---|
| 676 | | (setq paragraph-start (concat page-delimiter "\\|$" )) |
|---|
| 677 | | (make-local-variable 'paragraph-separate) |
|---|
| 678 | | (setq paragraph-separate paragraph-start) |
|---|
| 679 | | @dots{} |
|---|
| 680 | | @end group |
|---|
| 681 | | @group |
|---|
| 682 | | (make-local-variable 'comment-indent-function) |
|---|
| 683 | | (setq comment-indent-function 'lisp-comment-indent)) |
|---|
| 684 | | @dots{} |
|---|
| 685 | | @end group |
|---|
| 686 | | @end smallexample |
|---|
| 687 | | |
|---|
| 688 | | Each of the different Lisp modes has a slightly different keymap. For |
|---|
| 689 | | example, Lisp mode binds @kbd{C-c C-z} to @code{run-lisp}, but the other |
|---|
| 690 | | Lisp modes do not. However, all Lisp modes have some commands in |
|---|
| 691 | | common. The following code sets up the common commands: |
|---|
| 692 | | |
|---|
| 693 | | @smallexample |
|---|
| 694 | | @group |
|---|
| 695 | | (defvar shared-lisp-mode-map () |
|---|
| 696 | | "Keymap for commands shared by all sorts of Lisp modes.") |
|---|
| 697 | | |
|---|
| 698 | | ;; @r{Putting this @code{if} after the @code{defvar} is an older style.} |
|---|
| 699 | | (if shared-lisp-mode-map |
|---|
| 700 | | () |
|---|
| 701 | | (setq shared-lisp-mode-map (make-sparse-keymap)) |
|---|
| 702 | | (define-key shared-lisp-mode-map "\e\C-q" 'indent-sexp) |
|---|
| 703 | | (define-key shared-lisp-mode-map "\177" |
|---|
| 704 | | 'backward-delete-char-untabify)) |
|---|
| 705 | | @end group |
|---|
| 706 | | @end smallexample |
|---|
| 707 | | |
|---|
| 708 | | @noindent |
|---|
| 709 | | And here is the code to set up the keymap for Lisp mode: |
|---|
| 710 | | |
|---|
| 711 | | @smallexample |
|---|
| 712 | | @group |
|---|
| 713 | | (defvar lisp-mode-map () |
|---|
| 714 | | "Keymap for ordinary Lisp mode...") |
|---|
| 715 | | |
|---|
| 716 | | (if lisp-mode-map |
|---|
| 717 | | () |
|---|
| 718 | | (setq lisp-mode-map (make-sparse-keymap)) |
|---|
| 719 | | (set-keymap-parent lisp-mode-map shared-lisp-mode-map) |
|---|
| 720 | | (define-key lisp-mode-map "\e\C-x" 'lisp-eval-defun) |
|---|
| 721 | | (define-key lisp-mode-map "\C-c\C-z" 'run-lisp)) |
|---|
| 722 | | @end group |
|---|
| 723 | | @end smallexample |
|---|
| 724 | | |
|---|
| 725 | | Finally, here is the complete major mode function definition for |
|---|
| 726 | | Lisp mode. |
|---|
| 727 | | |
|---|
| 728 | | @smallexample |
|---|
| 729 | | @group |
|---|
| 730 | | (defun lisp-mode () |
|---|
| 731 | | "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp. |
|---|
| 732 | | Commands: |
|---|
| 733 | | Delete converts tabs to spaces as it moves back. |
|---|
| 734 | | Blank lines separate paragraphs. Semicolons start comments. |
|---|
| 735 | | \\@{lisp-mode-map@} |
|---|
| 736 | | Note that `run-lisp' may be used either to start an inferior Lisp job |
|---|
| 737 | | or to switch back to an existing one. |
|---|
| 738 | | @end group |
|---|
| 739 | | |
|---|
| 740 | | @group |
|---|
| 741 | | Entry to this mode calls the value of `lisp-mode-hook' |
|---|
| 742 | | if that value is non-nil." |
|---|
| 743 | | (interactive) |
|---|
| 744 | | (kill-all-local-variables) |
|---|
| 745 | | @end group |
|---|
| 746 | | @group |
|---|
| 747 | | (use-local-map lisp-mode-map) ; @r{Select the mode's keymap.} |
|---|
| 748 | | (setq major-mode 'lisp-mode) ; @r{This is how @code{describe-mode}} |
|---|
| 749 | | ; @r{finds out what to describe.} |
|---|
| 750 | | (setq mode-name "Lisp") ; @r{This goes into the mode line.} |
|---|
| 751 | | (lisp-mode-variables t) ; @r{This defines various variables.} |
|---|
| 752 | | (make-local-variable 'comment-start-skip) |
|---|
| 753 | | (setq comment-start-skip |
|---|
| 754 | | "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *") |
|---|
| 755 | | (make-local-variable 'font-lock-keywords-case-fold-search) |
|---|
| 756 | | (setq font-lock-keywords-case-fold-search t) |
|---|
| 757 | | @end group |
|---|
| 758 | | @group |
|---|
| 759 | | (setq imenu-case-fold-search t) |
|---|
| 760 | | (set-syntax-table lisp-mode-syntax-table) |
|---|
| 761 | | (run-mode-hooks 'lisp-mode-hook)) ; @r{This permits the user to use a} |
|---|
| 762 | | ; @r{hook to customize the mode.} |
|---|
| 763 | | @end group |
|---|
| 764 | | @end smallexample |
|---|
| 1117 | | The two last things a major mode function should do is run its mode |
|---|
| 1118 | | hook and finally the mode independent normal hook |
|---|
| 1119 | | @code{after-change-major-mode-hook}. If the major mode is a derived |
|---|
| 1120 | | mode, that is if it calls another major mode (the parent mode) in its |
|---|
| 1121 | | body, then the parent's mode hook is run just before the derived |
|---|
| 1122 | | mode's hook. Neither the parent's mode hook nor |
|---|
| 1123 | | @code{after-change-major-mode-hook} are run at the end of the actual |
|---|
| 1124 | | call to the parent mode. This applies recursively if the parent mode |
|---|
| 1125 | | has itself a parent. That is, the mode hooks of all major modes |
|---|
| 1126 | | called directly or indirectly by the major mode function are all run |
|---|
| 1127 | | in sequence at the end, just before |
|---|
| 1128 | | @code{after-change-major-mode-hook}. |
|---|
| 1129 | | |
|---|
| 1130 | | These conventions are new in Emacs 22, and some major modes |
|---|
| 1131 | | implemented by users do not follow them yet. So if you put a function |
|---|
| 1132 | | onto @code{after-change-major-mode-hook}, keep in mind that some modes |
|---|
| 1133 | | will fail to run it. If a user complains about that, you can respond, |
|---|
| 1134 | | ``That major mode fails to follow Emacs conventions, and that's why it |
|---|
| 1135 | | fails to work. Please fix the major mode.'' In most cases, that is |
|---|
| 1136 | | good enough, so go ahead and use @code{after-change-major-mode-hook}. |
|---|
| 1137 | | However, if a certain feature needs to be completely reliable, |
|---|
| 1138 | | it should not use @code{after-change-major-mode-hook} as of yet. |
|---|
| | 844 | Every major mode function should finish by running its mode hook and |
|---|
| | 845 | the mode-independent normal hook @code{after-change-major-mode-hook}. |
|---|
| | 846 | It does this by calling @code{run-mode-hooks}. If the major mode is a |
|---|
| | 847 | derived mode, that is if it calls another major mode (the parent mode) |
|---|
| | 848 | in its body, it should do this inside @code{delay-mode-hooks} so that |
|---|
| | 849 | the parent won't run these hooks itself. Instead, the derived mode's |
|---|
| | 850 | call to @code{run-mode-hooks} runs the parent's mode hook too. |
|---|
| | 851 | @xref{Major Mode Conventions}. |
|---|
| | 852 | |
|---|
| | 853 | Emacs versions before Emacs 22 did not have @code{delay-mode-hooks}. |
|---|
| | 854 | When user-implemented major modes have not been updated to use it, |
|---|
| | 855 | they won't entirely follow these conventions: they may run the |
|---|
| | 856 | parent's mode hook too early, or fail to run |
|---|
| | 857 | @code{after-change-major-mode-hook}. If you encounter such a major |
|---|
| | 858 | mode, please correct it to follow these conventions. |
|---|
| 1167 | | Every major mode function should run this normal hook at its very end. |
|---|
| 1168 | | It normally does not need to do so explicitly. Indeed, a major mode |
|---|
| 1169 | | function should normally run its mode hook with @code{run-mode-hooks} |
|---|
| 1170 | | as the very last thing it does, and the last thing |
|---|
| 1171 | | @code{run-mode-hooks} does is run @code{after-change-major-mode-hook}. |
|---|
| 1172 | | @end defvar |
|---|
| | 888 | This is a normal hook run by @code{run-mode-hooks}. It is run at the |
|---|
| | 889 | very end of every properly-written major mode function. |
|---|
| | 890 | @end defvar |
|---|
| | 891 | |
|---|
| | 892 | @node Example Major Modes |
|---|
| | 893 | @subsection Major Mode Examples |
|---|
| | 894 | |
|---|
| | 895 | Text mode is perhaps the simplest mode besides Fundamental mode. |
|---|
| | 896 | Here are excerpts from @file{text-mode.el} that illustrate many of |
|---|
| | 897 | the conventions listed above: |
|---|
| | 898 | |
|---|
| | 899 | @smallexample |
|---|
| | 900 | @group |
|---|
| | 901 | ;; @r{Create the syntax table for this mode.} |
|---|
| | 902 | (defvar text-mode-syntax-table |
|---|
| | 903 | (let ((st (make-syntax-table))) |
|---|
| | 904 | (modify-syntax-entry ?\" ". " st) |
|---|
| | 905 | (modify-syntax-entry ?\\ ". " st) |
|---|
| | 906 | ;; Add `p' so M-c on `hello' leads to `Hello', not `hello'. |
|---|
| | 907 | (modify-syntax-entry ?' "w p" st) |
|---|
| | 908 | st) |
|---|
| | 909 | "Syntax table used while in `text-mode'.") |
|---|
| | 910 | @end group |
|---|
| | 911 | |
|---|
| | 912 | ;; @r{Create the keymap for this mode.} |
|---|
| | 913 | @group |
|---|
| | 914 | (defvar text-mode-map |
|---|
| | 915 | (let ((map (make-sparse-keymap))) |
|---|
| | 916 | (define-key map "\e\t" 'ispell-complete-word) |
|---|
| | 917 | (define-key map "\es" 'center-line) |
|---|
| | 918 | (define-key map "\eS" 'center-paragraph) |
|---|
| | 919 | map) |
|---|
| | 920 | "Keymap for `text-mode'. |
|---|
| | 921 | Many other modes, such as Mail mode, Outline mode |
|---|
| | 922 | and Indented Text mode, inherit all the commands |
|---|
| | 923 | defined in this map.") |
|---|
| | 924 | @end group |
|---|
| | 925 | @end smallexample |
|---|
| | 926 | |
|---|
| | 927 | Here is how the actual mode command is defined now: |
|---|
| | 928 | |
|---|
| | 929 | @smallexample |
|---|
| | 930 | @group |
|---|
| | 931 | (define-derived-mode text-mode nil "Text" |
|---|
| | 932 | "Major mode for editing text written for humans to read. |
|---|
| | 933 | In this mode, paragraphs are delimited only by blank or white lines. |
|---|
| | 934 | You can thus get the full benefit of adaptive filling |
|---|
| | 935 | (see the variable `adaptive-fill-mode'). |
|---|
| | 936 | \\@{text-mode-map@} |
|---|
| | 937 | Turning on Text mode runs the normal hook `text-mode-hook'." |
|---|
| | 938 | @end group |
|---|
| | 939 | @group |
|---|
| | 940 | (make-local-variable 'text-mode-variant) |
|---|
| | 941 | (setq text-mode-variant t) |
|---|
| | 942 | ;; @r{These two lines are a feature added recently.} |
|---|
| | 943 | (set (make-local-variable 'require-final-newline) |
|---|
| | 944 | mode-require-final-newline) |
|---|
| | 945 | (set (make-local-variable 'indent-line-function) 'indent-relative)) |
|---|
| | 946 | @end group |
|---|
| | 947 | @end smallexample |
|---|
| | 948 | |
|---|
| | 949 | But here is how it was defined formerly, before |
|---|
| | 950 | @code{define-derived-mode} existed: |
|---|
| | 951 | |
|---|
| | 952 | @smallexample |
|---|
| | 953 | @group |
|---|
| | 954 | ;; @r{This isn't needed nowadays, since @code{define-derived-mode} does it.} |
|---|
| | 955 | (defvar text-mode-abbrev-table nil |
|---|
| | 956 | "Abbrev table used while in text mode.") |
|---|
| | 957 | (define-abbrev-table 'text-mode-abbrev-table ()) |
|---|
| | 958 | @end group |
|---|
| | 959 | |
|---|
| | 960 | @group |
|---|
| | 961 | (defun text-mode () |
|---|
| | 962 | "Major mode for editing text intended for humans to read... |
|---|
| | 963 | Special commands: \\@{text-mode-map@} |
|---|
| | 964 | @end group |
|---|
| | 965 | @group |
|---|
| | 966 | Turning on text-mode runs the hook `text-mode-hook'." |
|---|
| | 967 | (interactive) |
|---|
| | 968 | (kill-all-local-variables) |
|---|
| | 969 | (use-local-map text-mode-map) |
|---|
| | 970 | @end group |
|---|
| | 971 | @group |
|---|
| | 972 | (setq local-abbrev-table text-mode-abbrev-table) |
|---|
| | 973 | (set-syntax-table text-mode-syntax-table) |
|---|
| | 974 | @end group |
|---|
| | 975 | @group |
|---|
| | 976 | ;; @r{These four lines are absent from the current version} |
|---|
| | 977 | ;; @r{not because this is done some other way, but rather} |
|---|
| | 978 | ;; @r{because nowadays Text mode uses the normal definition of paragraphs.} |
|---|
| | 979 | (make-local-variable 'paragraph-start) |
|---|
| | 980 | (setq paragraph-start (concat "[ \t]*$\\|" page-delimiter)) |
|---|
| | 981 | (make-local-variable 'paragraph-separate) |
|---|
| | 982 | (setq paragraph-separate paragraph-start) |
|---|
| | 983 | (make-local-variable 'indent-line-function) |
|---|
| | 984 | (setq indent-line-function 'indent-relative-maybe) |
|---|
| | 985 | @end group |
|---|
| | 986 | @group |
|---|
| | 987 | (setq mode-name "Text") |
|---|
| | 988 | (setq major-mode 'text-mode) |
|---|
| | 989 | (run-mode-hooks 'text-mode-hook)) ; @r{Finally, this permits the user to} |
|---|
| | 990 | ; @r{customize the mode with a hook.} |
|---|
| | 991 | @end group |
|---|
| | 992 | @end smallexample |
|---|
| | 993 | |
|---|
| | 994 | @cindex @file{lisp-mode.el} |
|---|
| | 995 | The three Lisp modes (Lisp mode, Emacs Lisp mode, and Lisp |
|---|
| | 996 | Interaction mode) have more features than Text mode and the code is |
|---|
| | 997 | correspondingly more complicated. Here are excerpts from |
|---|
| | 998 | @file{lisp-mode.el} that illustrate how these modes are written. |
|---|
| | 999 | |
|---|
| | 1000 | @cindex syntax table example |
|---|
| | 1001 | @smallexample |
|---|
| | 1002 | @group |
|---|
| | 1003 | ;; @r{Create mode-specific table variables.} |
|---|
| | 1004 | (defvar lisp-mode-syntax-table nil "") |
|---|
| | 1005 | (defvar lisp-mode-abbrev-table nil "") |
|---|
| | 1006 | @end group |
|---|
| | 1007 | |
|---|
| | 1008 | @group |
|---|
| | 1009 | (defvar emacs-lisp-mode-syntax-table |
|---|
| | 1010 | (let ((table (make-syntax-table))) |
|---|
| | 1011 | (let ((i 0)) |
|---|
| | 1012 | @end group |
|---|
| | 1013 | |
|---|
| | 1014 | @group |
|---|
| | 1015 | ;; @r{Set syntax of chars up to @samp{0} to say they are} |
|---|
| | 1016 | ;; @r{part of symbol names but not words.} |
|---|
| | 1017 | ;; @r{(The digit @samp{0} is @code{48} in the @acronym{ASCII} character set.)} |
|---|
| | 1018 | (while (< i ?0) |
|---|
| | 1019 | (modify-syntax-entry i "_ " table) |
|---|
| | 1020 | (setq i (1+ i))) |
|---|
| | 1021 | ;; @r{@dots{} similar code follows for other character ranges.} |
|---|
| | 1022 | @end group |
|---|
| | 1023 | @group |
|---|
| | 1024 | ;; @r{Then set the syntax codes for characters that are special in Lisp.} |
|---|
| | 1025 | (modify-syntax-entry ? " " table) |
|---|
| | 1026 | (modify-syntax-entry ?\t " " table) |
|---|
| | 1027 | (modify-syntax-entry ?\f " " table) |
|---|
| | 1028 | (modify-syntax-entry ?\n "> " table) |
|---|
| | 1029 | @end group |
|---|
| | 1030 | @group |
|---|
| | 1031 | ;; @r{Give CR the same syntax as newline, for selective-display.} |
|---|
| | 1032 | (modify-syntax-entry ?\^m "> " table) |
|---|
| | 1033 | (modify-syntax-entry ?\; "< " table) |
|---|
| | 1034 | (modify-syntax-entry ?` "' " table) |
|---|
| | 1035 | (modify-syntax-entry ?' "' " table) |
|---|
| | 1036 | (modify-syntax-entry ?, "' " table) |
|---|
| | 1037 | @end group |
|---|
| | 1038 | @group |
|---|
| | 1039 | ;; @r{@dots{}likewise for many other characters@dots{}} |
|---|
| | 1040 | (modify-syntax-entry ?\( "() " table) |
|---|
| | 1041 | (modify-syntax-entry ?\) ")( " table) |
|---|
| | 1042 | (modify-syntax-entry ?\[ "(] " table) |
|---|
| | 1043 | (modify-syntax-entry ?\] ")[ " table)) |
|---|
| | 1044 | table)) |
|---|
| | 1045 | @end group |
|---|
| | 1046 | @group |
|---|
| | 1047 | ;; @r{Create an abbrev table for lisp-mode.} |
|---|
| | 1048 | (define-abbrev-table 'lisp-mode-abbrev-table ()) |
|---|
| | 1049 | @end group |
|---|
| | 1050 | @end smallexample |
|---|
| | 1051 | |
|---|
| | 1052 | The three modes for Lisp share much of their code. For instance, |
|---|
| | 1053 | each calls the following function to set various variables: |
|---|
| | 1054 | |
|---|
| | 1055 | @smallexample |
|---|
| | 1056 | @group |
|---|
| | 1057 | (defun lisp-mode-variables (lisp-syntax) |
|---|
| | 1058 | (when lisp-syntax |
|---|
| | 1059 | (set-syntax-table lisp-mode-syntax-table)) |
|---|
| | 1060 | (setq local-abbrev-table lisp-mode-abbrev-table) |
|---|
| | 1061 | @dots{} |
|---|
| | 1062 | @end group |
|---|
| | 1063 | @end smallexample |
|---|
| | 1064 | |
|---|
| | 1065 | In Lisp and most programming languages, we want the paragraph |
|---|
| | 1066 | commands to treat only blank lines as paragraph separators. And the |
|---|
| | 1067 | modes should undestand the Lisp conventions for comments. The rest of |
|---|
| | 1068 | @code{lisp-mode-variables} sets this up: |
|---|
| | 1069 | |
|---|
| | 1070 | @smallexample |
|---|
| | 1071 | @group |
|---|
| | 1072 | (make-local-variable 'paragraph-start) |
|---|
| | 1073 | (setq paragraph-start (concat page-delimiter "\\|$" )) |
|---|
| | 1074 | (make-local-variable 'paragraph-separate) |
|---|
| | 1075 | (setq paragraph-separate paragraph-start) |
|---|
| | 1076 | @dots{} |
|---|
| | 1077 | @end group |
|---|
| | 1078 | @group |
|---|
| | 1079 | (make-local-variable 'comment-indent-function) |
|---|
| | 1080 | (setq comment-indent-function 'lisp-comment-indent)) |
|---|
| | 1081 | @dots{} |
|---|
| | 1082 | @end group |
|---|
| | 1083 | @end smallexample |
|---|
| | 1084 | |
|---|
| | 1085 | Each of the different Lisp modes has a slightly different keymap. For |
|---|
| | 1086 | example, Lisp mode binds @kbd{C-c C-z} to @code{run-lisp}, but the other |
|---|
| | 1087 | Lisp modes do not. However, all Lisp modes have some commands in |
|---|
| | 1088 | common. The following code sets up the common commands: |
|---|
| | 1089 | |
|---|
| | 1090 | @smallexample |
|---|
| | 1091 | @group |
|---|
| | 1092 | (defvar shared-lisp-mode-map () |
|---|
| | 1093 | "Keymap for commands shared by all sorts of Lisp modes.") |
|---|
| | 1094 | |
|---|
| | 1095 | ;; @r{Putting this @code{if} after the @code{defvar} is an older style.} |
|---|
| | 1096 | (if shared-lisp-mode-map |
|---|
| | 1097 | () |
|---|
| | 1098 | (setq shared-lisp-mode-map (make-sparse-keymap)) |
|---|
| | 1099 | (define-key shared-lisp-mode-map "\e\C-q" 'indent-sexp) |
|---|
| | 1100 | (define-key shared-lisp-mode-map "\177" |
|---|
| | 1101 | 'backward-delete-char-untabify)) |
|---|
| | 1102 | @end group |
|---|
| | 1103 | @end smallexample |
|---|
| | 1104 | |
|---|
| | 1105 | @noindent |
|---|
| | 1106 | And here is the code to set up the keymap for Lisp mode: |
|---|
| | 1107 | |
|---|
| | 1108 | @smallexample |
|---|
| | 1109 | @group |
|---|
| | 1110 | (defvar lisp-mode-map () |
|---|
| | 1111 | "Keymap for ordinary Lisp mode...") |
|---|
| | 1112 | |
|---|
| | 1113 | (if lisp-mode-map |
|---|
| | 1114 | () |
|---|
| | 1115 | (setq lisp-mode-map (make-sparse-keymap)) |
|---|
| | 1116 | (set-keymap-parent lisp-mode-map shared-lisp-mode-map) |
|---|
| | 1117 | (define-key lisp-mode-map "\e\C-x" 'lisp-eval-defun) |
|---|
| | 1118 | (define-key lisp-mode-map "\C-c\C-z" 'run-lisp)) |
|---|
| | 1119 | @end group |
|---|
| | 1120 | @end smallexample |
|---|
| | 1121 | |
|---|
| | 1122 | Finally, here is the complete major mode function definition for |
|---|
| | 1123 | Lisp mode. |
|---|
| | 1124 | |
|---|
| | 1125 | @smallexample |
|---|
| | 1126 | @group |
|---|
| | 1127 | (defun lisp-mode () |
|---|
| | 1128 | "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp. |
|---|
| | 1129 | Commands: |
|---|
| | 1130 | Delete converts tabs to spaces as it moves back. |
|---|
| | 1131 | Blank lines separate paragraphs. Semicolons start comments. |
|---|
| | 1132 | \\@{lisp-mode-map@} |
|---|
| | 1133 | Note that `run-lisp' may be used either to start an inferior Lisp job |
|---|
| | 1134 | or to switch back to an existing one. |
|---|
| | 1135 | @end group |
|---|
| | 1136 | |
|---|
| | 1137 | @group |
|---|
| | 1138 | Entry to this mode calls the value of `lisp-mode-hook' |
|---|
| | 1139 | if that value is non-nil." |
|---|
| | 1140 | (interactive) |
|---|
| | 1141 | (kill-all-local-variables) |
|---|
| | 1142 | @end group |
|---|
| | 1143 | @group |
|---|
| | 1144 | (use-local-map lisp-mode-map) ; @r{Select the mode's keymap.} |
|---|
| | 1145 | (setq major-mode 'lisp-mode) ; @r{This is how @code{describe-mode}} |
|---|
| | 1146 | ; @r{finds out what to describe.} |
|---|
| | 1147 | (setq mode-name "Lisp") ; @r{This goes into the mode line.} |
|---|
| | 1148 | (lisp-mode-variables t) ; @r{This defines various variables.} |
|---|
| | 1149 | (make-local-variable 'comment-start-skip) |
|---|
| | 1150 | (setq comment-start-skip |
|---|
| | 1151 | "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *") |
|---|
| | 1152 | (make-local-variable 'font-lock-keywords-case-fold-search) |
|---|
| | 1153 | (setq font-lock-keywords-case-fold-search t) |
|---|
| | 1154 | @end group |
|---|
| | 1155 | @group |
|---|
| | 1156 | (setq imenu-case-fold-search t) |
|---|
| | 1157 | (set-syntax-table lisp-mode-syntax-table) |
|---|
| | 1158 | (run-mode-hooks 'lisp-mode-hook)) ; @r{This permits the user to use a} |
|---|
| | 1159 | ; @r{hook to customize the mode.} |
|---|
| | 1160 | @end group |
|---|
| | 1161 | @end smallexample |
|---|