/work/eiffel.el
http://github.com/tybor/Liberty · Emacs Lisp · 2776 lines · 2096 code · 310 blank · 370 comment · 78 complexity · f93f00beb9e185edba6515dd772b3527 MD5 · raw file
Large files are truncated click here to view the full file
- ;;; eiffel.el --- major mode for editing Eiffel files.
- ;; Copyright (C) 1989, 1990, 93, 94, 95, 96, 99, 2000, 01, 02, 03
- ;; Tower Technology Corporation,
- ;; Free Software Foundation,
- ;; Bob Weiner,
- ;; C. Adrian
- ;; Authors: 1989-1990 Stephen Omohundro, ISE and Bob Weiner
- ;; 1993-1996 Tower Technology Corporation
- ;; 1999-2003 Martin Schwenke <martin@meltin.net>
- ;; Maintainer: martin@meltin.net
- ;; Keywords: eiffel languages oop
- ;; Requires: font-lock, compile, easymenu, imenu
- ;; This file is derived from eiffel4.el from Tower Technology Corporation.
- ;;
- ;; Known bugs:
- ;;
- ;; * eif-short buffer doesn't get font locked under GNU Emacs 19.34.
- ;;
- ;; * eif-debug can hang under (at least) XEmacs 21.4.[89] in the wait
- ;; loop if there is input pending (that is, if the user hits return
- ;; an extra time). Not yet tested under XEmacs 21.5.
- ;;
- ;; This file is distributed under the same terms as GNU Emacs.
- ;; GNU Emacs is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation; either version 2, or (at your option)
- ;; any later version.
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;; You should have received a copy of the GNU General Public License
- ;; along with GNU Emacs; see the file COPYING. If not, write to the
- ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- ;; Boston, MA 02110-1301, USA
- ;;; Commentary:
- ;; NEW VERSIONS
- ;; The latest version of this mode is always available via:
- ;; http://meltin.net/hacks/emacs/
- ;; INSTALLATION
- ;; To install, simply copy this file into a directory in your
- ;; load-path and add the following two commands in your .emacs file:
- ;;
- ;; (add-to-list 'auto-mode-alist '("\\.e\\'" . eiffel-mode))
- ;; (autoload 'eiffel-mode "eiffel" "Major mode for Eiffel programs" t)
- ;;
- ;; Note: to be sure to have always a fresh eiffel.el, you can add the
- ;; "SmartEiffel/misc" directory in the emacs load-path by adding:
- ;;
- ;; (setq load-path (cons ".../SmartEiffel/misc" load-path))
- ;;; History:
- ;;
- ;; Add history stuff here!!!
- ;;; Code:
- (require 'font-lock)
- (require 'compile)
- (require 'easymenu)
- (require 'imenu)
- (defconst eiffel-version-string
- "$Id: eiffel.el,v 2.67 2003/06/14 10:41:01 martins Exp $"
- "Version string to make reporting bugs more meaningful.
- Note that if this file becomes part of GNU Emacs then the file might
- be changed by the Emacs maintainers without this version number
- changing. This means that if you are reporting a bug for a version
- that was shipped with Emacs, you should report the Emacs version!")
- (defgroup eiffel nil
- "Eiffel mode for Emacs"
- :group 'oop)
- (defgroup eiffel-indent nil
- "Indentation variables in Eiffel mode"
- :prefix "eif-"
- :group 'eiffel)
- (defgroup eiffel-compile nil
- "Compilation support variables in Eiffel mode"
- :prefix "eif-"
- :group 'eiffel)
- (defun eif-customize ()
- "Run \\[customize-group] for the `eiffel' group."
- (interactive)
- (customize-group 'eiffel))
- ;; Indentation amount variables.
- ;;
- ;; The default values correspond to style used in ``Eiffel: The
- ;; Language''.
- (defcustom eif-indent-increment 3
- "*Default indentation interval (in spaces)."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-class-level-kw-indent 0
- "*Indentation for Class level keywords.
- Specified as number of `eif-indent-increments'. See the variable
- `eif-class-level-keywords-regexp'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-class-level-kw-indent 0
- "*Number of extra spaces to add to `eif-class-level-kw-indent'.
- This results in the actual indentation of a class level keyword. Can
- be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-class-level-comment-indent 0
- "*Indentation of comments at the beginning of a class.
- Specified as number of `eif-indent-increments'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-class-level-comment-indent 0
- "*Number of spaces to add to `eif-class-level-comment-indent'.
- This results in the actual indentation of a class level comment. Can
- be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-inherit-level-kw-indent 2
- "*Indentation of keywords falling under the Inherit clause.
- Specified as number of `eif-indent-increments'. See the variable
- `eif-inherit-level-keywords'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-inherit-level-kw-indent 0
- "*Number of spaces to add to `eif-inherit-level-kw-indent'.
- This results in the actual indentation of an inherit level keyword.
- Can be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-feature-level-indent 1
- "*Indentation amount of features.
- Specified as number of `eif-indent-increments'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-feature-level-indent 0
- "*Number of spaces to add to `eif-feature-level-indent'.
- This results in the indentation of a feature. Can be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-feature-level-kw-indent 2
- "*Indentation of keywords belonging to individual features.
- Specified as number of `eif-indent-increments'. See the variable
- `eif-feature-level-keywords-regexp'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-feature-level-kw-indent 0
- "*Number of spaces to add to `eif-feature-level-kw-indent'.
- This results in the actual indentation of a feature level keyword.
- Can be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-feature-level-comment-indent 3
- "*Indentation of comments at the beginning of a feature.
- Specified as number of `eif-indent-increments'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-feature-level-comment-indent 0
- "*Number of spaces to add to `eif-feature-level-comment-indent'.
- This results in the actual indentation of a feature level comment.
- Can be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-body-comment-indent 0
- "*Indentation of comments in the body of a routine.
- Specified as number of `eif-indent-increments')"
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-body-comment-indent 0
- "*Number of spaces to add to `eif-body-comment-indent'.
- This results in the actual indentation of a routine body comment. Can
- be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-check-keyword-indent 0
- "*Extra indentation for the check clause as described in ETL.
- Specified as number of `eif-indent-increments'. Default is 0, which
- is different than in ETL's 1."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-check-keyword-indent 0
- "*Number of spaces to add to `eif-check-keyword-indent'.
- This results in the actual indentation of a check keyword. Can be
- negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-rescue-keyword-indent -1
- "*Extra indentation for the rescue clause as described in ETL.
- Specified as number of `eif-indent-increments'. Default is -1."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-rescue-keyword-indent 0
- "*Number of spaces to add to `eif-rescue-keyword-indent'.
- This results in the actual indentation of a rescue keyword. Can be
- negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-then-indent 0
- "*Indentation for a `then' appearing on a line by itself.
- This is as opposed to a `then' on the same line as an `if'. Specified
- as number of `eif-indent-increments'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-then-indent 0
- "*Number of spaces to add to `eif-then-indent'.
- This results in the actual indentation of a `then' appearing on a line
- by itself. Can be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-continuation-indent 1
- "*Extra indentation for a continued statement line.
- Specified as number of `eif-indent-increments'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-continuation-indent 0
- "*Number of spaces to add to `eif-continuation-indent'.
- This results in the actual indentation of a continued statement
- line. Can be negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-string-continuation-indent 0
- "*Extra indentation for a continued string.
- Specified as number of `eif-indent-increments'."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-extra-string-continuation-indent -1
- "*Number of spaces to add to `eif-string-continuation-indent'.
- This results in the actual indentation of a continued string. Can be
- negative."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-indent-string-continuations-relatively-flag t
- "*Non-nil means string continuations are indented relative to 1st character.
- That is, `eif-string-continuation-indent' and
- `eif-extra-string-continuation-indent' are added to position of first
- character of string. If nil, string continuations are indented
- relative to indent of previous line."
- :type 'boolean
- :group 'eiffel-indent)
- (defcustom eif-set-tab-width-flag t
- "*Non-nil means `tab-width' is set to `eif-indent-increment' in `eiffel-mode'."
- :type 'boolean
- :group 'eiffel-indent)
- (defcustom eif-preprocessor-indent 0
- "*Indentation for lines GOBO preprocessor directives.
- Specified as number of `eif-indent-increments' from left margin."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-fill-max-save 4096
- "*Maximum size of a paragraph to save before filling.
- Normally \\[eif-fill-paragraph] will mark a buffer as modified even if
- the fill operation does not make any changes. If the paragraph being
- filled is smaller than the value of this variable then the contents of
- the paragraph will be saved for comparison with the paragraph after
- the fill operation. If they are the same, the buffer modification
- state is restored. Set this to 0 to disable this feature, or a very
- big number to enable it for all paragraphs."
- :type 'integer
- :group 'eiffel-indent)
- (defcustom eif-use-gnu-eiffel t
- "*If t include support for compilation using GNU Liberty Eiffel."
- :type 'boolean
- :group 'eiffel-compile)
- (defcustom eif-se-command
- "se"
- "*Program to use for compiling Eiffel programs.
- The default is \"se\"."
- :type 'string
- :group 'eiffel-compile)
- (defcustom eif-compile-options ""
- "*Options to use for compiling Eiffel programs."
- :type 'string
- :group 'eiffel-compile)
- ;;
- ;; No user-customizable definitions below this point.
- ;;
- ;;
- ;; Indentation macros.
- ;;
- (defmacro eif-class-level-kw-indent-m ()
- "Indentation amount for Class level keywords (in number of spaces)."
- '(+ (* eif-class-level-kw-indent eif-indent-increment)
- eif-extra-class-level-kw-indent))
- (defmacro eif-class-level-comment-indent-m ()
- "Indentation amount for Class level comments (in number of spaces)."
- '(+ (* eif-class-level-comment-indent eif-indent-increment)
- eif-extra-class-level-comment-indent))
- (defmacro eif-inherit-level-kw-indent-m ()
- "Indentation amount for Inherit level keywords (in number of spaces)."
- '(+ (* eif-inherit-level-kw-indent eif-indent-increment)
- eif-extra-inherit-level-kw-indent))
- (defmacro eif-feature-level-indent-m ()
- "Indentation amount for features (in number of spaces)."
- '(+ (* eif-feature-level-indent eif-indent-increment)
- eif-extra-feature-level-indent))
- (defmacro eif-feature-level-kw-indent-m ()
- "Indentation amount for Feature level keywords (in number of spaces)."
- '(+ (* eif-feature-level-kw-indent eif-indent-increment)
- eif-extra-feature-level-kw-indent))
- (defmacro eif-body-comment-indent-m ()
- "Indentation amount for comments in routine bodies (in number of spaces)."
- '(+ (* eif-body-comment-indent eif-indent-increment)
- eif-extra-body-comment-indent))
- (defmacro eif-feature-level-comment-indent-m ()
- "Indentation amount for Feature level comments (in number of spaces)."
- '(+ (* eif-feature-level-comment-indent eif-indent-increment)
- eif-extra-feature-level-comment-indent))
- (defmacro eif-check-keyword-indent-m ()
- "Indentation amount for Check keyword (in number of spaces)."
- '(+ (* eif-check-keyword-indent eif-indent-increment)
- eif-extra-check-keyword-indent))
- (defmacro eif-rescue-keyword-indent-m ()
- "Indentation amount for Rescue keyword (in number of spaces)."
- '(+ (* eif-rescue-keyword-indent eif-indent-increment)
- eif-extra-rescue-keyword-indent))
- (defmacro eif-then-indent-m ()
- "Indentation amount for `then' appearing on a line by itself (in number of spaces)."
- '(+ (* eif-then-indent eif-indent-increment)
- eif-extra-then-indent))
- (defmacro eif-continuation-indent-m ()
- "Indentation amount for a statement continuation line (in number of spaces)."
- '(+ (* eif-continuation-indent eif-indent-increment)
- eif-extra-continuation-indent))
- (defmacro eif-string-continuation-indent-m ()
- "Indentation amount for a statement continuation line (in number of spaces)."
- '(+ (* eif-string-continuation-indent eif-indent-increment)
- eif-extra-string-continuation-indent))
- (defmacro eif-preprocessor-indent-m ()
- "Indentation amount for a preprocessor statement (in number of spaces)."
- '(* eif-preprocessor-indent eif-indent-increment))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Keyword Regular Expression Constants. ;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defconst eif-non-id-char-regexp "\\S_" ;; "[^a-z0-9_]"
- "The characters that are not part of identifiers.")
- (defun eif-post-anchor (regexp)
- "Anchor given REGEXP with end-word delimiter and `eif-non-id-char-regexp'."
- (concat "\\(" regexp "\\)\\>" eif-non-id-char-regexp))
- (defun eif-word-anchor (regexp)
- "Anchor given REGEXP with word delimiters and `eif-non-id-char-regexp'."
- (concat "\\<\\(" regexp "\\)\\>" eif-non-id-char-regexp))
- (defun eif-anchor (regexp)
- "Anchor given REGEXP front and back to match line break or non-symbol char."
- (concat "\\(^\\|\\S_\\<\\)\\(" regexp "\\)\\($\\|\\>\\S_\\)"))
- ;; Note invariant is handled as a special case since it is both a
- ;; class-level and a from-level keyword
- ;; Note obsolete is handled as a special case since it is both a
- ;; class-level and a feature-level keyword
- ;; Note create, note, and indexing are also handled as special cases
- (defconst eif-class-level-keywords
- (concat
- "\\(?:"
- (regexp-opt '("deferred" "expanded" "reference" "separate"))
- "[ \t]+\\)?class"
- "\\|"
- (regexp-opt '("inherit" "insert" "convert" "creation" "feature")))
- "Keywords introducing class-level clauses.
- Note that `invariant', `obsolete', `indexing', `note', and `create' are not included here since can
- function as more than one type of keyword.")
- (defconst eif-class-level-keywords-regexp
- (eif-word-anchor eif-class-level-keywords)
- "Regexp of keywords introducing class level clauses, with some context.
- See `eif-class-level-keywords'.")
- (defconst eif-inherit-level-keywords
- (regexp-opt '("rename" "redefine" "undefine" "select" "export"))
- "Those keywords which introduce subclauses of the inherit clause.")
- (defconst eif-feature-level-keywords
- (regexp-opt '("require" "local" "deferred" "separate" "do" "once" "ensure" "alias" "external" "attribute"))
- "Those keywords which are internal to features (in particular, routines).")
- (defconst eif-feature-level-keywords-regexp
- (eif-word-anchor eif-feature-level-keywords)
- "Regexp of keywords internal to features (usually routines).
- See `eif-feature-level-keywords'.")
- (defconst eif-end-keyword "end" "The `end' keyword.")
- (defconst eif-end-on-current-line ".*[ \t]end[ \t]*;?[ \t]*\\(--.*\\)?$"
- "Regular expression to identify lines ending with the `end' keyword.")
- (defconst eif-control-flow-keywords
- (regexp-opt '("if" "inspect" "from" "debug"))
- "Keywords which introduce control-flow constructs.")
- (defconst eif-control-flow-matching-keywords
- (concat (regexp-opt '("deferred" "do" "once")) "\\|" eif-control-flow-keywords)
- "Keywords that may cause the indentation of an `eif-control-flow-keyword'.
- If these occur prior to an `eif-control-flow-keyword' then the
- `eif-control-flow-keyword' is indented. Note that technically, `end'
- is part of this list but it is handled separately in the function
- \[eif-matching-kw\].")
- (defconst eif-control-flow-matching-keywords-regexp
- (eif-word-anchor eif-control-flow-matching-keywords)
- "Regexp of keywords maybe causing indentation of `eif-control-flow-keyword'.
- See `eif-control-flow-keywords'.")
- (defconst eif-check-keyword "check"
- "The `check' keyword.")
- (defconst eif-check-keywords-regexp
- (eif-word-anchor eif-check-keyword)
- "The `check' keyword (with trailing context).")
- ;; FIXME: Doesn't work if once keyword is followed by a string on next
- ;; line, but didn't get broken by this attempt at factoring.
- (defconst eif-check-matching-keywords-regexp
- eif-control-flow-matching-keywords-regexp
- "Keywords that may cause the indentation of an `eif-check-keyword'.
- If these occur prior to an `eif-check-keyword' then the
- `eif-check-keyword' is indented. Note that technically, `end' is part
- of this list but it is handled separately in the function
- \[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.")
- ;; FIXME: This could be fixed or removed.
- (defconst eif-end-keyword-regexp "\\<end\\>"
- "The `end' keyword with context.")
- (defconst eif-end-matching-keywords
- (concat (regexp-opt '("attribute" "check" "class" "feature" "rename" "redefine" "undefine"
- "select" "export" "separate" "external" "alias")) "\\|"
- eif-control-flow-matching-keywords)
- "Those keywords whose clause is terminated by an `end' keyword.")
- (defconst eif-end-matching-keywords-regexp
- (eif-word-anchor eif-end-matching-keywords)
- "Regexp of keywords whose clause is terminated by an `end' keyword.
- See `eif-end-matching-keywords'.")
- (defconst eif-rescue-keyword "rescue" "The `rescue' keyword.")
- (defconst eif-obsolete-keyword "obsolete" "The `obsolete' keyword.")
- (defconst eif-indexing-keyword
- (regexp-opt '("note" "indexing"))
- "The `indexing' and `note' keywords.")
- (defconst eif-indexing-keyword-regexp
- (eif-post-anchor eif-indexing-keyword)
- "Regexp matching `indexing' and `note' keywords, with trailing context.")
- (defconst eif-rescue-keywords-regexp
- (eif-word-anchor eif-rescue-keyword)
- "The `rescue' keyword (with trailing context).")
- (defconst eif-rescue-matching-keywords-regexp
- (eif-word-anchor (regexp-opt '("deferred" "do" "once")))
- "Keywords that may cause the indentation of an `eif-rescue-keyword'.
- If these occur prior to an `eif-rescue-keyword' then the
- `eif-rescue-keyword' is indented. Note that technically, `end' is
- part of this list but it is handled separately in the function
- \[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.")
- (defconst eif-from-level-keywords
- (regexp-opt '("until" "variant" "loop"))
- "Keywords occuring inside of a from clause.")
- (defconst eif-from-level-keywords-regexp
- (eif-word-anchor eif-from-level-keywords)
- "Regexp of keywords occuring inside of a from clause.
- See `eif-from-level-keywords'.")
- (defconst eif-from-keyword "from" "The keyword `from'.")
- (defconst eif-if-or-inspect-level-keywords
- (regexp-opt '("elseif" "else" "when"))
- "Keywords occuring inside of an if or inspect clause.")
- (defconst eif-if-or-inspect-level-keywords-regexp
- (eif-word-anchor eif-if-or-inspect-level-keywords)
- "Regexp of keywords occuring inside of an if or inspect clause.
- See eif-if-or-inspect-level-keywords.")
- (defconst eif-if-or-inspect-keyword-regexp
- (eif-word-anchor (regexp-opt '("if" "inspect")))
- "Regexp matching the `if' or `inspect' keywords.")
- (defconst eif-then-keyword ".*[ \t)]then[ \t]*$"
- "The keyword `then' with possible leading text.")
- (defconst eif-solitary-then-keyword "then" "The keyword `then'.")
- (defconst eif-then-matching-keywords
- (regexp-opt '("if" "elseif" "when") t)
- "Keywords that may alter the indentation of an `eif-then-keyword'.
- If one of these occur prior to an `eif-then-keyword' then this sets
- the indentation of the `eif-then-keyword'. Note that technically,
- `end' is part of this list but it is handled separately in the
- function \[eif-matching-kw\]. See also
- `eif-control-flow-matching-keywords-regexp'.")
- (defconst eif-invariant-keyword "invariant" "The `invariant' keyword.")
- (defconst eif-invariant-matching-keywords
- (regexp-opt '("from" "feature"))
- "Keywords that may cause the indentation of an `eif-invarient-keyword'.
- If one of these occurs prior to an `eif-invariant-keyword' then the
- `eif-invariant-keyword' is indented. Note that technically, `end' is
- part of this list but it is handled separately in the function
- \[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.")
- (defconst eif-obsolete-matching-keywords
- (regexp-opt '("is" "class") t)
- "Keywords that may cause the indentation of an `eif-obsolete-keyword'.
- If one of these occurs prior to an `eif-obsolete-keyword' then the
- `eif-obsolete-keyword' is indented.")
- (defconst eif-create-keyword
- "create"
- "Eiffel create keyword. Can be used at class or minor level.")
- (defconst eif-create-keyword-regexp
- (eif-post-anchor eif-create-keyword)
- "Regexp matching `create' keyword, with trailing context.")
- (defconst eif-indentation-keywords
- (concat (regexp-opt '("note" "indexing" "rescue" "inherit" "insert" "convert" "create" "creation"
- "invariant" "require" "local" "ensure" "obsolete")) "\\|"
- eif-from-level-keywords "\\|"
- eif-if-or-inspect-level-keywords "\\|"
- eif-end-matching-keywords)
- "Keywords that match any eiffel keyword triggering indentation.")
- (defconst eif-indentation-keywords-regexp
- (eif-word-anchor eif-indentation-keywords)
- "Regexp of keywords that match any eiffel keyword triggering indentation.
- See `eif-indentation-keywords'.")
- (defconst eif-once-non-indent-regexp
- "\\s-*once\\(\\s-\\|\n\\)+\""
- "Regexp of Eiffel once keyword in context not affecting indentation.")
- (defconst eif-feature-indentation-keywords-regexp
- (eif-word-anchor (regexp-opt '("convert" "creation" "feature")))
- "Keywords which denote the presence of features following them.")
- (defconst eif-is-keyword-regexp "\\(.*[ \t)]\\)?is[ \t]*\\(--.*\\)?$"
- "The `is' keyword (with some context).")
- (defconst eif-multiline-routine-is-keyword-regexp
- ".*([^)]*)\\([ \t\n]*\\|[ \t\n]*:[][ \t\nA-Za-x0-9_,]*\\)is[ \t]*\\(--.*\\)?$"
- "The `is' keyword (with some context).")
- (defconst eif-operator-keywords
- (regexp-opt '("and" "or" "implies"))
- "Eiffel operator keywords.")
- (defconst eif-operator-regexp
- (concat "[ \t]*\\([@*/+]\\|-[^-]\\|\\<\\("
- eif-operator-keywords
- "\\)[ \t(]\\)")
- "Eiffel operators - used to identify continuation lines.
- See `eif-operator-keywords'.")
- (defconst eif-operator-eol-regexp
- (concat ".*\\([@*/+-]\\|\\<\\(" eif-operator-keywords
- "\\)\\|:=\\)[ \t]*\\(--.*\\)?$")
- "Eiffel operators - used to identify continuation lines.")
- (defconst eif-all-keywords
- (concat eif-indentation-keywords "\\|"
- eif-solitary-then-keyword "\\|"
- eif-create-keyword "\\|"
- eif-end-keyword)
- "Regexp matching (nearly) any eiffel keyword in a line.
- Does not include `is'.")
- (defconst eif-all-keywords-regexp
- (concat "\\("
- (eif-word-anchor eif-all-keywords) "\\)")
- "Anchored regexp matching (nearly) any eiffel keyword in a line.
- Does not include `is'. See `eif-all-keywords'.")
- (defconst eiffel-comment-start-skip
- "--+|?[ \t]*"
- "Regexp matching the beginning of an Eiffel comment.")
- (defconst eif-non-source-line
- (concat "[ \t]*\\(\\(" "--" "\\).*\\)?$")
- "RE matching line with only whitespace and comment or preprocessor keyword.")
- (defconst eif-variable-or-const-regexp "[^()\n]*:[^=].*"
- "RE to match a variable or constant declaration.")
- ;; Factor out some important important regexps for use in
- ;; eif-{beginning,end}-of-feature.
- (defun eiffel-feature-re ()
- "Liberty Eiffel feature declarations"
- (let* ((argument-name "\\(?:[A-Za-z]*[a-z0-9_]+[A-Za-z0-9_]*\\)")
- (feature-name (concat "\\(?:\\(infix\\|prefix\\)\\s-+\".+?\"\\|" argument-name "\\(?:\\s-+alias\\s-+\".+?\"\\)?\\)"))
- (type-name "\\(?:like\\s-+\\sw+\\|[A-Z]\\sw*\\(?:\\[.+?\\]\\)?\\)"))
- (concat
- "\\(?:"
- "\\(?:\\<frozen\\s-\\)?"
- "\\s-*" feature-name "\\s-*,?"
- "\\)+"
- "\\(?:(" ; no \\s-* because it is matched above, if there is no trailing coma
- "\\(?:"
- "\\(?:\\s-*" argument-name "\\s-*,?\\)+?"
- ":" type-name "\\s-*;?"
- "\\)*?"
- ")\\)?" ; no \\s-* because it is matched above, if there is no trailing semi-colon
- "\\(?:\\s-*:\\s-*" type-name "\\)?"
- "\\(?:\\s-*assign\\s-*\\sw+\\)?"
- "\\(?:\\s-*is\\>\\)?")))
- (defconst eif-routine-begin-regexp
- ;"\\([a-z][a-zA-Z_0-9]*\\)\\s-*\\(([^)]*)\\)?\\s-*\\(:\\s-*[A-Z][A-Z0-9_]*\\(\\s-*\\[[^\\]]*\\]\\)?\\)?\\s-*\\(assign\\s-*[a-zA-Z0-9_]+\\)?\\s-*\\<is\\>\\s-*\\(--.*\\)?$"
- (eiffel-feature-re)
- "Regexp matching the beginning of an Eiffel routine declaration.")
- (message (concat "Liberty Eiffel features: " eif-routine-begin-regexp))
- (defconst eif-attribute-regexp
- (concat "[a-z_][^-:\n]*:\\s-*"
- "\\(like\\s-*[a-zA-Z][a-z_0-9]*\\|"
- "\\(\\(expanded\\|reference\\)\\s-*\\)?[A-Z][A-Z_0-9]*"
- "\\(\\s-*\\[[^-\n]*\\]\\)?\\)"
- "\\s-*\\($\\|[;)].*\\|--.*\\)")
- "Regexp matching an Eiffel attribute, parameter or local variable.")
- (defconst eif-constant-regexp
- "[a-z_][^-:\n]*:[^-\n]*\\<is\\>\\s-*[^ \t\n]"
- "Regexp matching an Eiffel constant declaration.")
- (defconst eif-probably-feature-regexp
- (concat "\\(" eif-routine-begin-regexp
- "\\|" eif-attribute-regexp
- "\\|" eif-constant-regexp "\\)")
- "Regexp probably matching an Eiffel feature.
- This will also match local variable and parameter declarations.")
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defvar eif-matching-indent -1
- "Indentation of the keyword found on the last call to \[eif-matching-kw\].
- -1 if no match was found.")
- (defvar eif-matching-kw-for-end nil)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Font-lock support.
- ;;
- ;; Rewritten from scratch by Cyril Adrian <cyril.adrian@gmail.com>
- ;; Specific to Liberty Eiffel
- ;;
- (defconst eiffel-keywords-feature
- '("agent" "all" "and" "as" "assign" "attribute" "check" "class"
- "convert" "create" "debug" "deferred" "do" "else" "elseif" "end" "ensure"
- "expanded" "export" "external" "feature" "from" "if" "implies"
- "indexing" "inherit" "insert" "inspect" "invariant" "is" "like"
- "local" "loop" "not" "note" "obsolete" "old" "once" "only" "or"
- "redefine" "rename" "require" "rescue" "retry" "select" "separate" "then"
- "undefine" "until" "variant" "when" "xor"))
- (defconst eiffel-keywords
- '("agent" "alias" "all" "and" "as" "assign" "attribute" "check" "class"
- "convert" "create" "debug" "deferred" "do" "else" "elseif" "end" "ensure"
- "expanded" "export" "external" "feature" "from" "frozen" "if" "implies"
- "indexing" "infix" "inherit" "insert" "inspect" "invariant" "is" "like"
- "local" "loop" "not" "note" "obsolete" "old" "once" "only" "or" "prefix"
- "redefine" "rename" "require" "rescue" "retry" "select" "separate" "then"
- "undefine" "until" "variant" "when" "xor"))
- (defconst eiffel-constants
- '("Current" "False" "Precursor" "Result" "True" "Void"))
- (defun eiffel-string-re ()
- "Liberty Eiffel strings"
- (concat "U?\"\\(?:"
- "\\(?:\\(?:[^%\"\n]\\|%[^\n]\\)*?\\)" ; single-line strings
- "\\|"
- "\\(?:\\(?:[^%\"\n]\\|%[^\n]\\)*?%[ \t]*\n\\(?:[ \t]*%\\(?:[^%\"\n]\\|%[^\n]\\)*?%[ \t]*\n\\)*[ \t]*%\\(?:[^%\"\n]\\|%[^\n]\\)*?\\)" ; older multiline strings
- "\\|"
- "\\(?:[[{][ \t]*\n\\(?:.*?\n\\)*?[ \t]*[]}]\"\\)" ; newer multiline strings
- "\\)\""))
- (defun eiffel-wordstart-re ()
- "start of words"
- "\\<\\(")
- (defun eiffel-wordend-re ()
- "end of words"
- (concat "\\)\\>"))
- (defun eiffel-keywords-re ()
- (concat
- (eiffel-wordstart-re)
- (regexp-opt eiffel-keywords)
- (eiffel-wordend-re)))
- (defun eiffel-constants-re ()
- (concat
- (eiffel-wordstart-re)
- (regexp-opt eiffel-constants)
- (eiffel-wordend-re)))
- (defun eiffel-preprocessor-re ()
- (concat
- (eiffel-wordstart-re)
- (regexp-opt '("c_inline_c" "c_inline_h" "not_yet_implemented" "se_breakpoint" "breakpoint" "to_pointer"
- "is_expanded_type" "is_basic_expanded_type"
- "object_size" "object_id_memory"
- "se_guru01" "se_guru02" "se_guru03"))
- (eiffel-wordend-re)))
- (defvar eiffel-font-lock-defaults
- (append
- `(
- ("--|\\(.*\\)\n" . font-lock-comment-face)
- ("--\\(.*\\)\n" . font-lock-doc-face)
- (,(eiffel-string-re) . font-lock-string-face)
- ("'\\(?:[^'%]\\|%.\\)'" . font-lock-string-face)
- ("\\<\\([A-Z][A-Z0-9_]*\\)\\>" . font-lock-type-face)
- (,(eiffel-keywords-re) 1 font-lock-keyword-face)
- (,(eiffel-constants-re) 1 font-lock-builtin-face)
- (,(eiffel-preprocessor-re) 1 font-lock-preprocessor-face)))
- "Default highlighting expressions for Liberty Eiffel mode")
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Compilation support for GNU SmartEiffel.
- ;;
- (defvar eif-compile-dir nil
- "Current directory where Eiffel compilations are taking place.
- Possibly used for error location.")
- (defvar eif-root-class nil
- "Current Eiffel root class being compiled/debugged.")
- (defvar eif-compile-target nil
- "Current Eiffel compilation target.")
- (defvar eif-debug-target nil
- "Current Eiffel debug target.")
- (defvar eif-root-proc nil
- "Current Eiffel root procedure.")
- (defvar eif-run-command nil
- "Current command to run after Eiffel compile.")
- (defvar eif-debug-command nil
- "Current debug command to run after Eiffel debug compile.")
- (defun eif-compilation-mode-hook ()
- "Hook function to set local value for `compilation-error-screen-columns'.
- This should be nil for SmartEiffel compiles, because column positions are
- returned as character positions rather than screen columns."
- ;; In Emacs > 20.7 compilation-error-screen-columns is buffer local.
- (or (assq 'compilation-error-screen-columns (buffer-local-variables))
- (make-local-variable 'compilation-error-screen-columns))
- (setq compilation-error-screen-columns nil))
- (defun eif-compile ()
- "Compile an Eiffel root class."
- (interactive)
- (eif-compile-prompt)
- (eif-compile-internal))
- (defun eif-set-compile-options ()
- "Set Eiffel compiler options."
- (interactive)
- (setq eif-compile-options
- (read-string "Eiffel compiler options: " eif-compile-options)))
- ;; Taken from Emacs 20.3 subr.el (just in case we're running under Emacs 19).
- (defun eif-split-string (string &optional separators)
- "Split STRING into substrings separated by SEPARATORS.
- Each match for SEPARATORS is a splitting point. The substrings
- between the splitting points are made into a list which is returned.
- If SEPARATORS is absent, it defaults to \"[ \\f\\t\\n\\r\\v]+\".
- If there is match for SEPARATORS at the beginning of STRING, we do not
- include a null substring for that. Likewise, if there is a match
- at the end of STRING, we do not include a null substring for that."
- (let ((rexp (or separators "[ \f\t\n\r\v]+"))
- (start 0)
- notfirst
- (list nil))
- (while (and (string-match rexp string
- (if (and notfirst
- (= start (match-beginning 0))
- (< start (length string)))
- (1+ start) start))
- (< (match-beginning 0) (length string)))
- (setq notfirst t)
- (or (eq (match-beginning 0) 0)
- (and (eq (match-beginning 0) (match-end 0))
- (eq (match-beginning 0) start))
- (setq list
- (cons (substring string start (match-beginning 0))
- list)))
- (setq start (match-end 0)))
- (or (eq start (length string))
- (setq list
- (cons (substring string start)
- list)))
- (nreverse list)))
- (defun eif-run ()
- "Run a compiled Eiffel program."
- (interactive)
- (setq eif-run-command
- (read-string "Command to run: "
- (or eif-run-command
- eif-compile-target
- (file-name-sans-extension
- (if (or (eq system-type 'windows-nt) (eq system-type 'cygwin))
- buffer-file-name
- (file-name-nondirectory (buffer-file-name)))))))
- (eif-run-internal))
- (defun eif-debug ()
- "Run the SmartEiffel debugger."
- (interactive)
- (eif-compile-prompt)
- (setq eif-debug-target
- (file-name-sans-extension
- (read-string "Debug target name: "
- (or eif-debug-target
- (concat eif-compile-target "_debug")))))
- (let* ((eif-compile-options (concat "-sedb " eif-compile-options))
- (eif-compile-target eif-debug-target)
- (buff (eif-compile-internal))
- (proc (get-buffer-process buff)))
- ;; This works under GNU Emacs, but hangs under at least some
- ;; versions of XEmacs if there is input pending.
- (while (eq (process-status proc) 'run)
- (sit-for 1))
- (if (= (process-exit-status proc) 0)
- (progn
- (setq eif-debug-command
- (read-string "Debugger command to run: "
- (or eif-debug-command
- eif-debug-target
- (file-name-sans-extension
- (if (eq system-type 'windows-nt)
- buffer-file-name
- (file-name-nondirectory
- (buffer-file-name)))))))
- (let ((eif-run-command eif-debug-command))
- (eif-run-internal))))))
- (defun eif-compile-prompt ()
- "Prompt for information required to compile an Eiffel root class."
- ;; Do the save first, since the user might still have their hand on
- ;; the mouse.
- (save-some-buffers (not compilation-ask-about-save) nil)
- (setq eif-compile-dir (file-name-directory (buffer-file-name)))
- (setq eif-root-class
- (file-name-sans-extension
- (read-string "Name of root class: "
- (or eif-compile-target
- (file-name-sans-extension
- (file-name-nondirectory (buffer-file-name)))))))
- (setq eif-compile-target eif-root-class)
- (setq eif-root-proc
- (read-string "Name of root procedure: "
- eif-root-proc)))
- (defun eif-compile-internal ()
- "Compile an Eiffel root class. Internal version.
- Returns the same thing as \\[compilation-start] - the compilation buffer."
- (let ((cmd (concat eif-se-command
- " compile -flymake_mode "
- eif-compile-options
- " -o " eif-compile-target
- (if (eq system-type 'windows-nt) ".exe")
- " " eif-root-class
- " " eif-root-proc))
- (buf-name "*Liberty Eiffel Compilation*")
- (compilation-mode-hook (cons 'eif-compilation-mode-hook
- compilation-mode-hook)))
- (if (fboundp 'compilation-start) ; Emacs 22 and above
- (compilation-start cmd nil #'(lambda (mode-name) buf-name))
- (compile-internal cmd "No more errors" buf-name))))
- (defun eif-run-internal ()
- "Run a compiled Eiffel program. Internal version."
- (let* ((tmp-buf (current-buffer))
- (words (eif-split-string eif-run-command))
- (cmd (expand-file-name (car words))))
- (apply 'make-comint cmd cmd nil (cdr words))
- (switch-to-buffer tmp-buf)
- (switch-to-buffer-other-window (concat "*" cmd "*"))))
- ;; This has been loosened up to spot parts of messages that contain
- ;; references to multiple locations. Thanks to Andreas
- ;; <nozone@sbox.tu-graz.ac.at>. Also, the column number is a character
- ;; count rather than a screen column, so we need to make sure that
- ;; compilation-error-screen-columns is nil. Note that in XEmacs this
- ;; variable doesn't exist, so we end up in the wrong column. Hey, at
- ;; least we're on the correct line!
- (add-to-list 'compilation-error-regexp-alist
- '("^Line \\([0-9]+\\) column \\([0-9]+\\) in [^ ]+ (\\([^)]+\\.[Ee]\\))" 3 1 2))
- (defun eif-find-file (&optional userclass)
- "Find and open an Eiffel file given by a class name"
- (interactive)
- (let* ((cn (or userclass (current-word))))
- (if (string-match "[A-Z][0-9A-Z_]*" cn)
- (let ((classname (substring cn (match-beginning 0) (match-end 0))))
- (message "Searching %s..." classname)
- (let* ((shellres (shell-command-to-string (concat "se find --raw " classname)))
- (filename (substring shellres 0 (string-match "\n" shellres))))
- (find-file filename)
- )))
- (message nil)))
- (defun eif-short ()
- "Display the short form of an Eiffel class."
- (interactive)
- (let* ((class (read-string
- "Class or file: "
- (if (buffer-file-name)
- (file-name-nondirectory (buffer-file-name)))))
- (buf (get-buffer-create (concat "*Eiffel - short " class "*"))))
- (shell-command (concat eif-se-command " short " class) buf)
- (with-current-buffer buf
- (let ((font-lock-defaults eiffel-font-lock-defaults))
- (font-lock-fontify-buffer))
- (read-only-mode 1))))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Utility Functions. ;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defun eif-feature-quote ()
- "Put a `' around the current feature name."
- (interactive)
- (save-excursion
- ;; Only try to go back to the beginning of the feature if we're
- ;; not already there.
- (if (/= (point)
- (save-excursion
- (forward-sexp)
- (backward-sexp)
- (point)))
- (backward-sexp))
- (insert "`")
- (forward-sexp)
- (insert "'"))
- (if (looking-at "'")
- (forward-char 1)))
- (defun eif-peeking-backwards-at (regexp)
- "Return non-nil is previous character exists and is matched by REGEXP.
- The match is actually an unbounded match starting at the previous character."
- (save-excursion
- (save-match-data
- (and (not (bobp))
- (or (backward-char) t)
- (looking-at regexp)))))
- (defsubst eif-in-comment-p ()
- "Return t if point is in a comment."
- (interactive)
- (save-excursion
- (nth 4 (parse-partial-sexp
- (save-excursion (beginning-of-line) (point))
- (point)))))
- (defun eif-in-comment-or-quoted-string-p ()
- "Return t if point is in a comment or quoted string."
- (or (eif-in-comment-p)
- (eif-in-quoted-string-p)))
- (defun eif-not-in-comment-or-quoted-string-p ()
- "Return t if point is not in a comment or quoted string."
- (not (eif-in-comment-or-quoted-string-p)))
- (defun eif-near-comment-p ()
- "Return t if point is close enough to a comment for filling purposes."
- (or (eif-in-comment-p)
- (and (or (looking-at comment-start-skip)
- (eif-peeking-backwards-at comment-start-skip))
- (not (eif-in-quoted-string-p)))
- (looking-at (concat "[ \t]*" comment-start-skip))))
- (defun eif-re-search-forward (regexp &optional limit noerror)
- "Search forward from point for REGEXP not in comment or string.
- `case-fold-search' is set to nil when searching. For details on other
- arguments see \\[re-search-forward]."
- (interactive "sRE search: ")
- (let ((start (point))
- found case-fold-search)
- (while (and (setq found (re-search-forward regexp limit noerror))
- (eif-in-comment-or-quoted-string-p)))
- (if (and found
- (eif-not-in-comment-or-quoted-string-p))
- found
- (if (eq noerror t)
- (goto-char start))
- nil)))
- (defun eif-re-search-backward (regexp &optional limit noerror)
- "Search backward from point for REGEXP not in comment or string.
- `case-fold-search' is set to nil when searching. For details on other
- arguments see \\[re-search-forward]."
- (interactive "sRE search: ")
- (let ((start (point))
- found case-fold-search)
- (while (and (setq found (re-search-backward regexp limit noerror))
- (eif-in-comment-or-quoted-string-p)))
- (if (and found
- (eif-not-in-comment-or-quoted-string-p))
- found
- (if (eq noerror t)
- (goto-char start))
- nil)))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Indentation Functions. ;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defun eif-skip-leading-whitespace ()
- "Move to the first non-whitespace character on the current line."
- (end-of-line)
- (let ((line-end (point)))
- (beginning-of-line)
- (skip-syntax-forward "-" line-end)))
- (defun eif-calc-indent ()
- "Calculate the indentation of the current line of eiffel code.
- This function handles the case where there is a keyword that affects
- indentation at the beginning of the current line. For lines that
- don't start with a relevant keyword, the calculation is handed off to
- \\[eif-calc-non-keyword-indent]."
- (let ((indent 0)
- kw-match)
- (save-excursion
- (eif-skip-leading-whitespace)
- ;; Look for a keyword on the current line.
- (if (looking-at eif-all-keywords-regexp)
- (cond ((looking-at eif-create-keyword-regexp)
- ;; Class-level or minor occurence?
- (if (save-excursion (eif-find-beginning-of-feature))
- ;; Minor.
- (setq indent (eif-calc-indent-non-keyword))
- ;; Class-level.
- (setq indent (eif-class-level-kw-indent-m))))
- ;; There's possibly a better way of coding this exception.
- ((looking-at eif-once-non-indent-regexp)
- (setq indent (eif-calc-indent-non-keyword)))
- ((looking-at eif-indexing-keyword-regexp)
- ;; Class-level or minor occurence?
- (if (string-match eif-check-keyword (eif-matching-kw eif-check-keywords-regexp))
- ;; In check.
- (setq indent (+ eif-matching-indent (eif-check-keyword-indent-m)))
- (if (save-excursion (eif-find-beginning-of-feature))
- ;; Minor. (BUG: "note" can also be at the END of the class!!!)
- (setq indent (eif-calc-indent-non-keyword))
- ;; Class-level.
- (setq indent (eif-class-level-kw-indent-m)))))
- ((looking-at eif-class-level-keywords-regexp)
- ;; File level keywords (indent defaults to 0)
- (setq indent (eif-class-level-kw-indent-m)))
- ((looking-at eif-inherit-level-keywords)
- ;; Inherit level keywords (indent defaults to
- ;; 2*eif-indent-increment)
- (setq indent (eif-inherit-level-kw-indent-m)))
- ((looking-at eif-feature-level-keywords-regexp)
- ;; Feature level keywords (indent defaults to
- ;; (eif-feature-level-indent-m) + eif-indent-increment)
- (setq indent (eif-feature-level-kw-indent-m)))
- ((looking-at eif-end-keyword)
- ;; End keyword (indent to level of matching keyword)
- (if (string-match "end"
- (eif-matching-kw
- eif-end-matching-keywords-regexp))
- ;; Then
- (if (= eif-matching-indent
- (eif-feature-level-kw-indent-m))
- ;; Then
- (setq indent (eif-class-level-kw-indent-m))
- ;; Else
- (setq indent
- (- eif-matching-indent eif-indent-increment)))
- ;; Else
- (setq indent eif-matching-indent))
- ;; FIXME: This is broken!!!
- (if (<= indent (eif-feature-level-indent-m))
- (save-excursion
- (end-of-line)
- (while (and (< (point) (point-max))
- (or (forward-char 1) t)
- (looking-at eif-non-source-line))
- (end-of-line))
- (if (not (looking-at eif-non-source-line))
- (setq indent (eif-inherit-level-kw-indent-m))
- (setq indent (eif-class-level-kw-indent-m))))))
- ((looking-at eif-control-flow-keywords)
- ;; Control flow keywords
- ;; Indent to same level as a preceding "end" or
- ;; if no preceding "end" is found, indent to the level
- ;; of the preceding "do" plus the value of
- ;; eif-indent-increment
- (setq kw-match
- (eif-matching-kw
- eif-control-flow-matching-keywords-regexp))
- (cond ((string-match "end" kw-match)
- (setq indent eif-matching-indent))
- (t
- (setq indent
- (+ eif-matching-indent eif-indent-increment)))))
- ((looking-at eif-check-keywords-regexp)
- ;; Check keyword
- ;; Indent to level of preceding "end"+eif-indent-increment or
- ;; if no preceding "end" is found, indent to the level of
- ;; the preceding eif-check-matching-keywords-regexp plus the
- ;; value (eif-indent-increment + eif-check-keyword-indent).
- (setq kw-match (eif-matching-kw
- eif-check-matching-keywords-regexp))
- (cond ((string-match "end" kw-match)
- (setq indent (+ eif-matching-indent
- (eif-check-keyword-indent-m))))
- (t
- (setq indent
- (+ eif-matching-indent
- (+ eif-indent-increment
- (eif-check-keyword-indent-m)))))))
- ((looking-at eif-rescue-keywords-regexp)
- ;; Rescue keyword
- ;; Indent to level of preceding "end"+eif-indent-increment or
- ;; if no preceding "end" is found, indent to the level of
- ;; the preceding eif-rescue-matching-keywords-regexp plus the
- ;; value (eif-indent-increment + eif-rescue-keyword-indent).
- (setq kw-match (eif-matching-kw
- eif-rescue-matching-keywords-regexp))
- (cond ((string-match "end" kw-match)
- (setq indent (+ eif-matching-indent
- (eif-rescue-keyword-indent-m))))
- (t
- (setq indent eif-matching-indent))))
- ((looking-at eif-from-level-keywords-regexp)
- ;; From level keywords (indent to level of matching "From")
- (if (string-match "end" (eif-matching-kw eif-from-keyword))
- ;; Closest matching KW is `end'.
- (setq indent (- eif-matching-indent eif-indent-increment))
- ;; Closest matching KW is one of `eif-from-keyword'.
- (setq indent eif-matching-indent)))
- ((looking-at eif-if-or-inspect-level-keywords-regexp)
- ;; If level keywords (indent to level of matching
- ;; "If" or "Inspect")
- (if (string-match "end"
- (eif-matching-kw
- eif-if-or-inspect-keyword-regexp))
- ;; Closest matching KW is `end'.
- (setq indent (- eif-matching-indent eif-indent-increment))
- ;; Closest matching KW is one of `eif-if-or-inspect-keyword-regexp'.
- (setq indent eif-matching-indent)))
- ((looking-at eif-solitary-then-keyword)
- ;; Handles case where "then" appears on a line by itself
- (if (eif-matching-kw eif-then-matching-keywords t)
- ;; (Indented to level of the matching if, elseif or when)
- (setq indent (+ eif-matching-indent (eif-then-indent-m)))
- (if (save-excursion (eif-find-beginning-of-feature))
- ;; (Feature-level "then")
- (setq indent (eif-feature-level-kw-indent-m))
- (message "Non-matching 'then'")
- (setq indent (eif-calc-indent-non-keyword)))))
- ((looking-at eif-invariant-keyword)
- ;; Invariant keyword
- ;; (Indented to level of the matching from or feature)
- (if (string-match "from"
- (eif-matching-kw eif-invariant-matchi…