weiner@novavax.UUCP (Bob Weiner) (09/19/89)
If anyone has one, could you mail or post the code. Thanks. -- Bob Weiner, Motorola, Inc., USENET: ...!gatech!uflorida!novavax!weiner (407) 738-2087
om@icsib2 (Stephen M. Omohundro) (09/26/89)
Here is something I wrote that does most things correctly (if you have keywords inside quotes, you must follow them with a "\" as in "this is\ a" to keep the indentation from getting confused; it also doesn't have anything for the features of the new release). I'd be interested in ehancements anyone might make: ;; Major mode for editing Eiffel programs. ;; Author: Stephen M. Omohundro ;; International Computer Science Institute ;; om@icsi.berkeley.edu ;; Created: May 26, 1989 ;; ;; The following two statements, placed in a .emacs file or site-init.el, ;; will cause this file to be autoloaded, and eiffel-mode invoked, when ;; visiting .e files: ;; ;; (autoload 'eiffel-mode "eiffel.el" "Eiffel mode" t nil) ;; (setq auto-mode-alist ;; (append ;; (list (cons "\\.e$" 'eiffel-mode)) ;; auto-mode-alist)) (provide 'eiffel-mode) (defvar eiffel-mode-map nil "Keymap for Eiffel mode.") (if eiffel-mode-map () (let ((map (make-sparse-keymap))) (define-key map "\C-cc" 'eiffel-class) (define-key map "\C-cr" 'eiffel-routine) (define-key map "\C-ci" 'eiffel-if) (define-key map "\C-cl" 'eiffel-loop) (define-key map "\C-cs" 'eiffel-set) (define-key map "\t" 'eiffel-indent-line) (define-key map "\r" 'eiffel-return) (define-key map "\177" 'backward-delete-char-untabify) (define-key map "\M-;" 'eiffel-comment) (setq eiffel-mode-map map))) (defvar eiffel-mode-syntax-table nil "Syntax table in use in Eiffel-mode buffers.") (if eiffel-mode-syntax-table () (let ((table (make-syntax-table))) (modify-syntax-entry ?\\ "\\" table) (modify-syntax-entry ?/ ". 14" table) (modify-syntax-entry ?* ". 23" 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) (setq eiffel-mode-syntax-table table))) (defvar eiffel-mode-abbrev-table "*Abbrev table in use in Eiffel-mode buffers.") (if eiffel-mode-abbrev-table nil (define-abbrev-table 'eiffel-mode-abbrev-table ()) (define-abbrev eiffel-mode-abbrev-table "int" "INTEGER" nil) (define-abbrev eiffel-mode-abbrev-table "boo" "BOOLEAN" nil) (define-abbrev eiffel-mode-abbrev-table "cha" "CHARACTER" nil) (define-abbrev eiffel-mode-abbrev-table "str" "STRING" nil) (define-abbrev eiffel-mode-abbrev-table "res" "Result" nil) (define-abbrev eiffel-mode-abbrev-table "cre" "Create" nil) (define-abbrev eiffel-mode-abbrev-table "cur" "Current" nil)) (defconst eiffel-indent 3 "*This variable gives the indentation in Eiffel-mode") (defconst eiffel-comment-col 32 "*This variable gives the desired comment column for comments to the right of text.") (defun eiffel-mode () "A major editing mode for the language Eiffel. Comments are begun with --. Paragraphs are separated by blank lines Delete converts tabs to spaces as it moves back. Tab anywhere on a line indents it according to Eiffel conventions. M-; inserts and indents a comment on the line, or indents an existing comment if there is one. Return indents to the expected indentation for the new line. Skeletons of the major Eiffel constructs are inserted with: C-c c class C-c i if C-c set C-c r routine C-c l loop Abbreviations: int for INTEGER boo for BOOLEAN cha for CHARACTER str for STRING res for Result cre for Create cur for Current Variables controlling style: eiffel-indent Indentation of Eiffel statements. eiffel-comment-col Goal column for inline comments Turning on Eiffel mode calls the value of the variable eiffel-mode-hook with no args, if that value is non-nil." (interactive) (kill-all-local-variables) (use-local-map eiffel-mode-map) (setq major-mode 'eiffel-mode) (setq mode-name "Eiffel") (setq local-abbrev-table eiffel-mode-abbrev-table) (set-syntax-table eiffel-mode-syntax-table) (make-local-variable 'paragraph-start) (setq paragraph-start (concat "^$\\|" page-delimiter)) (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) (make-local-variable 'paragraph-ignore-fill-prefix) (setq paragraph-ignore-fill-prefix t) (make-local-variable 'require-final-newline) (setq require-final-newline t) (run-hooks 'eiffel-mode-hook)) (defun eiffel-class () "Build a class skeleton prompting for class name." (interactive) (if (not (e-empty-line-p)) (progn (end-of-line)(newline))) (indent-to 0) (insert "-- Author: " (user-full-name) "\n") (insert "-- Created: " (current-time-string) "\n\n") (insert "class ") (let ((cname (read-string "Class: "))) (insert cname " export\n\ninherit\n\nfeature\n\ninvariant\n\nend -- class " cname)) (re-search-backward "\ninherit") (eiffel-indent-line)) (defun eiffel-routine () "Build a routine skeleton prompting for routine name." (interactive) (if (not (e-empty-line-p)) (progn (end-of-line)(newline))) (indent-to eiffel-indent) (let ((rname (read-string "Routine name: "))) (insert rname " () is\n") (indent-to (* 3 eiffel-indent)) (insert "-- \n") (indent-to (* 2 eiffel-indent)) (insert "require\n\n") (indent-to (* 2 eiffel-indent)) (insert "local\n\n") (indent-to (* 2 eiffel-indent)) (insert "do\n\n") (indent-to (* 2 eiffel-indent)) (insert "ensure\n\n") (indent-to (* 2 eiffel-indent)) (insert "end; -- " rname "\n") (re-search-backward ")"))) (defun eiffel-if () "Makes a template for an Eiffel if statement." (interactive) (insert "if then") (eiffel-indent-line) (insert "\n\nelse") (eiffel-indent-line) (insert "\n\nend; -- if") (eiffel-indent-line) (re-search-backward " then")) (defun eiffel-loop () "Makes a template for an Eiffel loop statement." (interactive) (insert "from ") (eiffel-indent-line) (insert "\n\ninvariant") (eiffel-indent-line) (insert "\n\nvariant") (eiffel-indent-line) (insert "\n\nuntil") (eiffel-indent-line) (insert "\n\nloop") (eiffel-indent-line) (insert "\n\nend; -- loop") (eiffel-indent-line) (re-search-backward "from")(forward-line)(eiffel-indent-line)) (defun eiffel-set () "Makes a function to set the value of the given variable." (interactive) (let ((aname (read-string "Attribute name: "))) (insert "set_" aname "(n" aname ":) is do " aname ":=n" aname " end;") (eiffel-indent-line) (re-search-backward ")"))) (defun eiffel-return () "Return and Eiffel indent in the new line." (interactive) (newline)(eiffel-indent-line)) (defun eiffel-indent-line () "Indent the current line as Eiffel code." (interactive) (save-excursion (beginning-of-line) (delete-horizontal-space) (indent-to (e-calc-indent))) (skip-chars-forward " \t")) ;; Let us call the keywords: class, deferred class, if, from, check, ;; is, and debug block-head keywords. They start new blocks of ;; indentation which end with end. ;; A line is either ;; blank, ;; just a comment, ;; begins with a block-cont-keyword ;; :export, inherit, feature, rescue, invariant, end ;; :require, external, local, do, once, deferred, ensure ;; :then, elsif, else, variant, until, loop ;; begins with check or debug ;; a block-head or something else (defun e-calc-indent () "Return the appropriate indentation for this line as an int." (cond ((e-empty-line-p) ;an empty line (+ eiffel-indent (e-get-block-indent))) ;go in one from block ((e-comment-line-p) ;a comment line (e-comment-indent)) ((e-block-cont-p) ;begins with cont keyword (e-get-block-indent)) ;indent same as block ((e-debug-block-p) ;check or debug (+ (* 2 eiffel-indent) (e-get-block-indent))) ;goes two in (t ;block-head or something else (+ eiffel-indent (e-get-block-indent))))) (defun eiffel-comment () "Edit a comment on the line. If one exists, reindent it and move to it, otherwise, create one. Gets rid of trailing blanks, puts one space between comment header comment text, leaves point at front of comment. If comment is alone on a line it reindents relative to surrounding text. If it is before any code, puts it at beginning of line. Uses the variable eiffel-comment-col to set goal start on lines after text." (interactive) (cond ((e-comment-line-p) ;just a comment on the line (beginning-of-line) (delete-horizontal-space) (indent-to (e-comment-indent)) (forward-char 2)(delete-horizontal-space)(insert " ")) ((e-comment-on-line-p) ;comment already at end of line (cond ((e-ends-with-end-p) ;end comments come immediately (e-goto-comment-beg)(delete-horizontal-space)(insert " ") (forward-char 2)(delete-horizontal-space)(insert " ")) (t (e-goto-comment-beg)(delete-horizontal-space) (if (< (current-column) eiffel-comment-col) (indent-to eiffel-comment-col) (insert " ")) (forward-char 2)(delete-horizontal-space)(insert " ")))) ((e-empty-line-p) ;put just a comment on line (beginning-of-line) (delete-horizontal-space) (indent-to (e-comment-indent)) (insert "-- ")) ((e-ends-with-end-p) ;end comments come immediately (end-of-line)(delete-horizontal-space)(insert " -- ")) (t ;put comment at end of line (end-of-line) (delete-horizontal-space) (if (< (current-column) eiffel-comment-col) (indent-to eiffel-comment-col) (insert " ")) (insert "-- ")))) (defun e-ends-with-end-p () "t if line ends with end or end; and a comment." (save-excursion (beginning-of-line) (looking-at "^[^\n]*end;?[ \t]*\\($\\|--\\)"))) (defun e-empty-line-p () "True if current line is empty." (save-excursion (beginning-of-line) (looking-at "^[ \\t]*$"))) (defun e-comment-line-p () "t if current line is just a comment." (save-excursion (beginning-of-line) (skip-chars-forward " \t") (looking-at "--"))) (defun e-comment-on-line-p () "t if current line contains a comment." (save-excursion (beginning-of-line) (looking-at "[^\n]*--"))) (defun e-current-indentation () "Return current indentation of front of line." (save-excursion (beginning-of-line) (skip-chars-forward " \t") (current-indentation))) (defun e-goto-comment-beg () "goes to beginning of comment on line." (beginning-of-line) (re-search-forward "--")(backward-char 2)) (defun e-block-cont-p () "t if line continues the indentation of enclosing block." (save-excursion (beginning-of-line) (skip-chars-forward " \t") (looking-at "\\(export\\|inherit\\|feature\\|rescue\\|invariant\\|\ end\\|require\\|external\\|local\\|do\\|once\\|deferred\\|ensure\\|\ then\\|elsif\\|else\\|variant\\|until\\|loop\\)\\>"))) (defun e-debug-block-p () "t if line begins with check or debug (and so gets double indent)." (save-excursion (beginning-of-line) (skip-chars-forward " \t") (looking-at "\\(check\\|debug\\)\\>"))) ;; Eiffel keywords: ;; and as check class debug deferred div do else elsif end ensure ;; export external false feature from if inherit invariant is language ;; like local loop mod name nochange not old once or redefine rename require ;; rescue retry then true until variant (defun e-is-key-end () "t if current line ends with the keyword is and comment." (save-excursion (beginning-of-line) (looking-at "^.*\\<is[ \t]*\\($\\|--\\)"))) (defun e-move-to-prev-non-comment () "moves point to previous line excluding comment lines and blank lines. Returns t if successful, nil if not." (beginning-of-line) (re-search-backward "^[ \t]*\\([^ \t---\n]\\|-[^---]\\)" nil t)) (defun e-move-to-prev-non-blank () "moves point to previous line excluding blank lines. Returns t if successful, nil if not." (beginning-of-line) (re-search-backward "^[ \t]*[^ \t\n]" nil t)) (defun e-comment-indent () "return indentation for a comment line." (save-excursion (if (not (e-move-to-prev-non-blank)) ;move to prev line if there is one 0 ;early comments start to the left (cond ((e-is-key-end) ;line ends in is, indent twice (+ eiffel-indent eiffel-indent (e-current-indentation))) ((e-comment-line-p) ;is a comment, same indentation (e-current-indentation)) (t ;otherwise indent once (+ eiffel-indent (e-current-indentation))))))) (defun e-in-comment-p () "t if point is in a comment." (cond ((e-comment-on-line-p) (let ((pt (current-column))) (save-excursion (e-goto-comment-beg) (if (<= (current-column) pt) t nil)))) (t nil))) (defun e-get-block-indent () "Return the outer indentation of the current block. Returns -20 if it can't find one." (let (indent (succeed t)) (save-excursion (setq succeed (e-goto-block-head)) (cond ((not succeed) nil) ((looking-at "is") ;heads ending in is have extra indent (setq indent (+ (current-indentation) eiffel-indent))) (t (setq indent (current-indentation))))) (if succeed indent -20))) ;will put at first col if lost (defun e-prev-char-is-underscore () "true if previous character is an underscore. (common bug with keywords)" (save-excursion (backward-char 1) (looking-at "_"))) (defun e-goto-block-head () "move point to the is, then, loop, class, debug, or check that would be paired with an end at point. Return nil if none." (let ((depth 1)) (while (and (> depth 0) (re-search-backward "\\<\\(class\\|deferred[ \t]+class\\|if\\|from\\|\ check\\|is\\|debug\\|end\\)[--- \t;\n]" nil t)) (cond ((or (e-in-comment-p) ;if keyword in comment (e-prev-char-is-underscore)) ;not really a keyword nil) ;ignore it ((looking-at "end") ;end of block (setq depth (1+ depth))) (t ;head of block (setq depth (1- depth))))) (if (> depth 0) ;check whether we hit top of file nil t))) --
bertrand@eiffel.UUCP (Bertrand Meyer) (10/07/89)
Thanks for Stephen M. Omohundro for posting his Eiffel mode for GNU Emacs. Vince Kraemer from Interactive has also developed one independently, but did not feel ready to post it, if only because it was still 2.1 only. He is planning to post a revised version, resulting from a merge with Mr. Omohundro's posting. The target date is ``right after Halloween''. (This means November 1st, and is not intended to scare anyone.) -- Bertrand Meyer bertrand@eiffel.com