home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / modes / modula3.el < prev    next >
Encoding:
Text File  |  1992-05-10  |  128.0 KB  |  3,942 lines

  1. ;;; Last modified on Mon May 11 09:35:32 PDT 1992 by detlefs                  ;
  2. ;;;      modified on Thu Apr 23 17:45:03 PDT 1992 by muller                   ;
  3. ;;;      modified on Wed Mar  4 10:47:23 PST 1992 by heydon                   ;
  4. ;;;      modified on Fri Feb  2 13:04:24 1990 by discolo                      ;
  5. ;;;      modified on Tue May  2 21:59:35 1989 by ellis                        ;
  6. ;;;      modified                             by Trevor Morris                ;
  7. ;;;      modified                             by Tom Perrine                  ;
  8. ;;;      modified                             by Michael Schmidt              ;
  9. ;;;      modified                             by Peter Robinson               ;
  10. ;;;      modified                             by mjordan                      ;
  11.  
  12. ;; LCD Archive Entry:
  13. ;; modula3|Eric Muller|muller@src.dec.com|
  14. ;; Modula-3 mode.|
  15. ;; 92-04-17||~/modes/modula3.el.Z|
  16.  
  17. (provide 'modula3)
  18.  
  19. ;
  20. ; MODE SYNTAX TABLE (Added by TEP)
  21. ;
  22.  
  23. (defvar m3-mode-syntax-table nil
  24.   "Syntax table in use in Modula 3 mode buffers.")
  25.  
  26. (if m3-mode-syntax-table
  27.     ()
  28.   (let ((table (make-syntax-table)))
  29.     (modify-syntax-entry ?_ "w" table)
  30.     (modify-syntax-entry ?\\ "\\" table)
  31.     (modify-syntax-entry ?\( ". 1" table)
  32.     (modify-syntax-entry ?\) ". 4" table)
  33.     (modify-syntax-entry ?* ". 23" table)
  34.     (modify-syntax-entry ?\( "()  " table)
  35.     (modify-syntax-entry ?\) ")(  " table)
  36.     (modify-syntax-entry ?\[ "(]  " table)
  37.     (modify-syntax-entry ?\] ")[  " table)
  38.     (modify-syntax-entry ?{ "(}  " table)
  39.     (modify-syntax-entry ?} ")}  " table)
  40.     (modify-syntax-entry ?+ "." table)
  41.     (modify-syntax-entry ?- "." table)
  42.     (modify-syntax-entry ?= "." table)
  43.     (modify-syntax-entry ?% "." table)
  44.     (modify-syntax-entry ?< "." table)
  45.     (modify-syntax-entry ?> "." table)
  46.     (modify-syntax-entry ?\' "\"" table)
  47.     (setq m3-mode-syntax-table table)))
  48.  
  49. ;
  50. ; MODE KEY MAP (Added by TEP)
  51. ;
  52.  
  53. (defvar m3-mode-map nil
  54.   "Keymap used in Modula 3 mode.")
  55.  
  56. (defun setup-m3-mode-map ()
  57.   "Sets up Modula 3 mode map; this must be called after the sequence for the
  58. keypad key \"?\\C-@\" has been setup - it uses \"function-key-sequence\" on
  59. that key in order to bind the Modula 3 specific functions"
  60.   (if m3-mode-map ()
  61.     (let ((map (make-sparse-keymap)) (other-map (make-sparse-keymap)))
  62.       (define-key map "\t" 'm3-abbrev-and-or-indent)
  63.       (define-key map "\M-\t" 'm3-ident-complete)
  64.       (define-key map "\C-ca" 'm3-array)
  65.       (define-key map "\C-cb" 'm3-block)
  66.       (define-key map "\C-cc" 'm3-case)
  67.       (define-key map "\C-cd" 'm3-declare)
  68.       (define-key map "\C-ce" 'm3-else)
  69.       (define-key map "\C-cf" 'm3-for)
  70.       (define-key map "\C-ci" 'm3-if)
  71.       (define-key map "\C-cm" 'm3-choose-module)
  72.       (define-key map "\C-cl" 'm3-loop-or-lock)
  73.       (define-key map "\C-c|" 'm3-next-case)
  74.       (define-key map "\C-co" 'm3-object)
  75.       (define-key map "\C-c\C-o" other-map)
  76.       (define-key map "\C-cp" 'm3-procedure)
  77.       (define-key map "\C-cr" 'm3-record)
  78.       (define-key map "\C-ct" 'm3-try-or-typecase)
  79.       (define-key map "\C-cu" 'm3-until)
  80.       (define-key map "\C-cw" 'm3-while-or-with)
  81.       (define-key map "\C-cy" 'm3-import)
  82.       (define-key map "\C-c{" 'm3-begin-comment)
  83.       (define-key map "\C-c}" 'm3-end-comment)
  84.       (define-key other-map "a" 'm3-toggle-abbrev)
  85.       (define-key other-map "v" 'm3-path-find-file)
  86.       (define-key other-map "b" 'm3-toggle-buffer)
  87.       (define-key other-map "c" 'm3-compile)
  88.       (define-key other-map "p" 'm3-convert-proc-header)
  89.       (setq m3-mode-map map)
  90.       )))
  91.  
  92. ;
  93. ; INDENTATION
  94. ;
  95.  
  96. (defvar m3-indent 2 "*This variable gives the indentation in Modula 3 Mode")
  97.  
  98. ;
  99. ; ROUTINE TO CHECK IF BUFFER CONTAINS DEF MODULE
  100. ;
  101.  
  102. (defun m3-is-def ()
  103.   "Does current buffer's name suggest that it contains an interface?"
  104.   (or (string-equal (m3-get-extension (buffer-name)) ".i")
  105.       (string-equal (m3-get-extension (buffer-name)) ".i3")))
  106.  
  107. ;
  108. ; THE MAIN ROUTINE - SETS UP MODULA-3 MODE
  109. ;
  110.   
  111. (defun modula-3-mode ()
  112.   "This is a mode intended to support program development in Modula 3.
  113.  
  114. There are three (!) different ways of avoiding tedious entry of
  115. constructs involving long uppercase keywords:
  116.  
  117.   1) The template mechanism.  All control constructs of Modula 3 can
  118.      be reached by typing CNTRL C followed (usually!) by the first
  119.      character of the construct.
  120.   2) The 'aggressive pseudo-abbrev' mode. Typing the first letter(s)
  121.      of a construct and then hitting TAB will cause the full construct
  122.      to be inserted.  When there is overlap between two constructs
  123.      (e.g. WITH and WHILE) type the smallest unique substring (e.g.
  124.      \"wi\" for WITH) then hit TAB. If the abbreviation is not
  125.      unique alphabetic ordering is used e.g. \"w\" gives WHILE rather than
  126.      WITH.
  127.   3) The 'polite pseudo-abbrev' mode.  This differs from the
  128.      'aggressive' mode in that it does not insert full template
  129.      constructs.  Instead, in this mode, TAB invoked at the end of a
  130.      word completes just that current word as a keyword.  This mode
  131.      analyzes the context to restrict the choices admitted by partial
  132.      prefixes to as small a set as possible.  If more than 1 choice
  133.      remain after this winnowing, they are ordered according to their
  134.      popularity (assigned in an ad hoc manner by me, dld, and easily
  135.      changed), and the first completion is performed, with a message
  136.      that other completions are possible.  If the choice is wrong,
  137.      hitting TAB immediately will cycle through the other choices.
  138.  
  139. The template mechanism is always available.  The variable
  140. m3-abbrev-enabled controls the choice of aggressive or polite abbrev
  141. mode.
  142.  
  143. There are also two independent mechanism for indenting/prettyprinting
  144. text.  The main addition that I (dld) have made is adding the style of
  145. 'electric' indentation normally associated with gnuemacs language
  146. modes.  Basically, all you need to know is that TAB, in addition to
  147. completing keywords, also indents the current line properly.  ($I will
  148. soon add mechanisms for indenting the current unit, indenting a
  149. region, etc.)
  150.  
  151. The other mechanism uses a pretty printer (m3pp) that runs as a
  152. separate process.  The command m3pp-region and m3pp-unit, and the
  153. variable m3pp-options are used to apply m3pp to a portion of the
  154. buffer.  These are not at present bound to specific keys.
  155.  
  156. Another new feature is END-matching and completion.  Various non-nil
  157. values of the variable 'm3-electric-end' cause hitting TAB on a line
  158. containing just an END to do things like fill in the name of the
  159. procedure, module, or interface, or the keyword that starts the
  160. construct that the END completes.  Another, independent, variable,
  161. 'm3-blink-end-matchers', temporarily blinks the curser at the
  162. beginning of the construct that the END matches.  ($An easy thing to
  163. add would be ESC-C-b, move-to-END-matcher)
  164.  
  165. There are a few mode specific commands which are not to do with inserting text
  166. for language structures (e.g. compile module, toggle pseudo abbrev mode). These
  167. can be used by typing CTRL-C CTRL-O, \"O\" (for \"Other\") and then the
  168. command letter. See the following list for more detailed information.
  169. \\{m3-mode-map}
  170. The variable m3-indent controls the number of spaces for each indentation."
  171.   (interactive)
  172.   (kill-all-local-variables)
  173.   (setup-m3-mode-map)
  174.   (use-local-map m3-mode-map)
  175.   (setq major-mode 'modula-3-mode)
  176.   (setq mode-name "Modula 3")
  177.   (make-local-variable 'comment-column)
  178.   (setq comment-column 41)
  179.   (make-local-variable 'end-comment-column)
  180.   (setq end-comment-column 75)
  181.   (set-syntax-table m3-mode-syntax-table)
  182.   (make-local-variable 'paragraph-start)
  183.   (setq paragraph-start (concat "^$\\|" page-delimiter))
  184.   (make-local-variable 'paragraph-separate)
  185.   (setq paragraph-separate paragraph-start)
  186.   (make-local-variable 'indent-line-function)
  187.   (setq indent-line-function 'm3-indent-line)
  188.   (make-local-variable 'require-final-newline)
  189.   (setq require-final-newline t)
  190.   (make-local-variable 'comment-start)
  191.   (setq comment-start "(* ")
  192.   (make-local-variable 'comment-end)
  193.   (setq comment-end " *)")
  194.   (make-local-variable 'comment-column)
  195.   (setq comment-column 41)
  196.   (make-local-variable 'comment-start-skip)
  197.   (setq comment-start-skip "(\\*+[ \t]*")
  198.   (make-local-variable 'comment-indent-hook)
  199.   (setq comment-indent-hook 'c-comment-indent)
  200.   (make-local-variable 'parse-sexp-ignore-comments)
  201.   (setq parse-sexp-ignore-comments t)
  202.   (run-hooks 'm3-mode-hook))
  203.  
  204. ;
  205. ;  FORMATTING
  206. ;
  207.  
  208. (defun m3-newline ()
  209.   "Insert a newline and indent following line like previous line."
  210.   (interactive)
  211.   (let ((hpos (current-indentation)))
  212.     (newline)
  213.     (indent-to hpos)))
  214.  
  215. (defun m3-tab ()
  216.   "Indent to next tab stop."
  217.   (interactive)
  218.   (indent-to (* (+ (/ (current-column) m3-indent) 1) m3-indent)))
  219.  
  220.  
  221. ;;;======================================================================
  222. ;;; The stuff in this section relate to indentation.
  223.  
  224. (defun m3-indent-line ()
  225.   "Indent the current-line."
  226.   (interactive)
  227.   (m3-indent-line-work t))
  228.  
  229. (defun m3-indent-line-work (electric)
  230.   ;; If in unterminated string, give an error.  If in comment and
  231.   ;; electric, indent like previous line.
  232. ;;;  (message "indent-line-work") (sit-for 2)
  233.   (let ((string-comment-state (m3-in-comment-or-string)))
  234.     (cond
  235.      ((eq string-comment-state 'string)
  236.       (beep)
  237.       (message "Unterminated Text literal..."))
  238.      ((eq string-comment-state 'comment)
  239.       (if electric
  240.       (let ((cur-point (point)))
  241.         (beginning-of-line)
  242.         (m3-skip-whitespace-in-line)
  243.         (cond
  244.          ;; If the current line begines with a close comment,
  245.          ;; indent it to the level of the matching start comment.
  246.          ((save-excursion
  247.         (beginning-of-line)
  248.         (m3-skip-whitespace-in-line)
  249.         (looking-at "*)"))
  250.           (m3-indent-to
  251.            cur-point
  252.            (save-excursion
  253.          (beginning-of-line)
  254.          (m3-skip-whitespace-in-line)
  255.          (forward-char 2)
  256.          (m3-skip-comment-backward (point-min) t)
  257.          (current-column))))
  258.  
  259.          ;;; If the current line begins with an open-comment, and
  260.          ;;; the opened comment is not nested, indent like a code line.
  261.          ((save-excursion
  262.         (beginning-of-line)
  263.         (m3-skip-whitespace-in-line)
  264.         (and (looking-at "(*")
  265.              (not (m3-in-comment-or-string))))
  266.           (m3-indent-to cur-point (m3-indent-for-line)))
  267.  
  268.          ;;; Otherwise, indent to same level as previous
  269.          ;;; non-whitespace line.
  270.          (t
  271.           (m3-indent-to
  272.            cur-point
  273.            (save-excursion
  274.          (forward-line -1)
  275.          (while (looking-at m3-whitespace-line-re)
  276.            (forward-line -1))
  277.          (m3-skip-whitespace-in-line)
  278.          (if (looking-at "(\\*")
  279.              (progn (forward-char 2)
  280.                 (m3-skip-whitespace-in-line)))
  281.          (current-column))))))))
  282.  
  283.      ;; We're not in a comment or a string.  Indent the current line.
  284.      (t
  285.       (m3-indent-to (point) (m3-indent-for-line))
  286.       ;; Do the appropriate thing for electric end's.
  287.       (m3-do-electric-end)))))
  288.  
  289.  
  290. (defun m3-indent-for-line ()
  291.   (save-excursion
  292.     (beginning-of-line)
  293.     (let ((cur-point (point))
  294.       (part-start (save-excursion
  295.             (m3-backward-to-last-part-begin)
  296.             (point)))
  297.       (first-code
  298.        (save-excursion
  299.          (re-search-forward "[ \t]*"
  300.                 (save-excursion (end-of-line) (point))
  301.                 t)
  302.          (goto-char (match-end 0))
  303. ;;;         (message "first-code 2") (sit-for 2)
  304.          (point)))
  305.       ;; Must do this because Modula is case-sensitive
  306.       (case-fold-search nil))
  307.  
  308.       ;; Find end of previous statement or last keyword-line-starter.
  309. ;;;      (message "m3-indent-for-line(A)") (sit-for 2)
  310.  
  311.       (m3-re-search-backward
  312.        (concat "\\(;\\|^[ \t]*\\(" m3-keyword-line-starters "\\)\\)")
  313.        part-start t)
  314.       (while (m3-in-arg-list part-start)
  315.     (m3-re-search-backward
  316.      (concat "\\(;\\|^[ \t]*\\(" m3-keyword-line-starters "\\)\\)")
  317.      part-start t))
  318.       (cond
  319.        ((and (looking-at ";")
  320.          (save-excursion
  321.            (beginning-of-line)
  322.            (re-search-forward
  323.         (concat "^[ \t]*\\(" m3-keyword-line-starters "\\)")
  324.         (save-excursion (end-of-line) (point))
  325.         t)))
  326.     (beginning-of-line)
  327.     (re-search-forward "[ \t]*"))
  328.  
  329.        (t
  330.     ;; skip to the keyword;
  331.     (re-search-forward "[ \t]*")))
  332.  
  333. ;;;      (message "m3-indent-for-line(B)") (sit-for 2)
  334.  
  335.       ;; Now figure out if there is an intervening incomplete
  336.       ;; statement between here and the original line.
  337.       (let ((prev-statement-start (point)))
  338. ;;;    (message "Checking completeness") (sit-for 2)
  339.     (cond
  340.      ;; Is it incomplete?
  341.      ((m3-prev-line-incomplete-p cur-point part-start)
  342.  
  343.       ;; ...OK, the previous line *was* incomplete.
  344.       (goto-char cur-point)
  345. ;;;      (message "m3-indent-for-line: incomplete") (sit-for 2)
  346.       (m3-incomplete-indent cur-point first-code part-start))
  347.  
  348.      (t
  349.       ;; No: the previous line completed a statement, so find it's
  350.       ;; start and indent from that.
  351. ;;;      (message "m3-indent-for-line: complete") (sit-for 2)
  352.  
  353.       (let ((skip-one
  354.          (and (save-excursion
  355.             (goto-char first-code)
  356.             (looking-at m3-keyword-ssl-enders))
  357.               (save-excursion
  358.             (goto-char first-code)
  359.             (m3-re-search-backward
  360.              (concat "\\(" m3-keyword-endable-ssl-introducers
  361.                  "\\|;\\)")
  362.              part-start t)
  363.             (not (looking-at ";"))))))
  364.  
  365. ;;;        (message "m3-IFL complete(2): skip-one = %s" skip-one) (sit-for 2)
  366.         (goto-char cur-point)
  367.         (beginning-of-line)
  368.         (m3-re-search-backward
  369.          (concat "\\(;\\|END\\|\\("
  370.              m3-keyword-endable-ssl-introducers "\\|"
  371.              m3-part-starters "\\)\\)")
  372.          part-start 'move-to-limit)
  373. ;;;        (message "m3-IFL complete(2.5-1)") (sit-for 2)
  374.         (while (m3-in-arg-list part-start)
  375. ;;;          (message "m3-IFL complete(2.5-2)") (sit-for 2)
  376.           (m3-re-search-backward
  377.            (concat "\\(;\\|END\\|\\(" m3-keyword-endable-ssl-introducers
  378.                "\\|" m3-part-starters "\\)\\)")
  379.            part-start 'move-to-limit))
  380.  
  381.         ;; Should now be at the beginning of the last
  382.         ;; ';', END, comment-start on left margin, or ssl-introducer.
  383. ;;;        (message "m3-IFL complete(3)") (sit-for 2)
  384.         (cond
  385.          (skip-one
  386. ;;;          (message "m3-IFL skip-one(1)") (sit-for 2)
  387.           (if (looking-at ";") (error "Bad logic."))
  388.           (cond
  389.            ((looking-at (concat "^" m3-com-start-re))
  390. ;;;        (message "m3-IFL skip-one left-margin-commment") (sit-for 2)
  391.         0)
  392.            (t
  393.         (re-search-forward m3-keyword-line-starters (point-max) t)
  394.         (goto-char (match-end 0))
  395. ;;;        (message "m3-IFL skip-one(2)") (sit-for 2)
  396.         (let ((eol (save-excursion (end-of-line) (point))))
  397.           (m3-forward-to-code first-code)
  398. ;;;          (message "m3-IFL skip-one(3)") (sit-for 2)
  399.           (cond
  400.            ;; Is there stuff between the keyword and the current line?
  401.            ((and (> (point) eol) (< (point) first-code))
  402. ;;;            (message "m3-IFL: skip-1 indentation x") (sit-for 2)
  403.             (m3-complete-adjust-indent (current-column) first-code
  404.                            part-start))
  405.            ;; No;
  406.            (t
  407. ;;;            (message "m3-IFL: skip-1 indentation y0") (sit-for 2)
  408.             (m3-re-search-backward
  409.              (concat "^[ \t]*\\(" m3-keyword-line-starters "\\)")
  410.              part-start t)
  411.             (re-search-forward m3-keyword-line-starters first-code t)
  412.             (goto-char (match-beginning 0))
  413.             (cond
  414.              ((save-excursion
  415.             (beginning-of-line)
  416.             (looking-at (concat "[ \t]*" m3-multi-keyword-lines)))
  417.               (beginning-of-line)
  418.               (re-search-forward "[ \t]*" first-code t)
  419.               (goto-char (match-end 0))))
  420. ;;;            (message "m3-IFL: skip-1 indentation y") (sit-for 2)
  421.             (m3-after-keyword-adjust-indent
  422.              (current-column)
  423.              first-code part-start)))))))
  424.  
  425.          (t
  426. ;;;          (message "m3-IFL skip-two") (sit-for 2)
  427.           ;; First of all, are we in a procedure argument list?
  428.           (let ((in-arg-list (m3-in-arg-list part-start)))
  429.         (cond
  430.          ;; Are we at the beginning of the file?
  431.          ;; If so, move current line to left margin.
  432.          ((eq (save-excursion
  433.             (m3-backward-to-code (point-min))
  434. ;;;            (message "m3-IFL foo: %d" (point)) (sit-for 2)
  435.             (point))
  436.               1)
  437.           0)
  438.  
  439.          ;; Are we looking at a comment on the left margin?
  440.          ((looking-at (concat "^" m3-com-start-re))
  441.           0)
  442.  
  443.          ;; Is it a keyword starting a line?
  444.          ((save-excursion
  445.             (beginning-of-line)
  446.             (looking-at
  447.              (concat "[ \t]*\\(" m3-keyword-line-starters "\\|"
  448.                  m3-part-starters "\\)")))
  449. ;;;          (message "m3-IFL: after complete keyword") (sit-for 2)
  450.           (beginning-of-line)
  451.           (re-search-forward
  452.            (concat m3-keyword-line-starters "\\|" m3-part-starters)
  453.            (point-max) t)
  454.           (goto-char (match-beginning 0))
  455. ;;;          (message "m3-IFL: after complete keyword 2") (sit-for 2)
  456.           (m3-after-keyword-adjust-indent (current-column)
  457.                           first-code part-start))
  458.  
  459.          (t
  460.           ;; No; skip backwards another then forward-to-code
  461. ;;;          (message "m3-IFL: skip-two xxx") (sit-for 2)
  462.           (if (not
  463.                (looking-at
  464.             (concat m3-keyword-endable-ssl-introducers "\\|;")))
  465.               (error "Bad logic 2."))
  466.           (let ((last-complete (looking-at ";\\|END")))
  467.             (beginning-of-line)
  468.             (m3-re-search-backward
  469.              (concat "\\(;\\|END\\|\\("
  470.                  m3-keyword-endable-ssl-introducers "\\)\\)")
  471.              part-start 'move-to-limit)
  472. ;;;            (message "m3-IFL: skip-two xxx 2") (sit-for 2)
  473.             (while (and (not in-arg-list) (m3-in-arg-list part-start))
  474. ;;;              (message "m3-IFL: skip-two xxx 2.2") (sit-for 2)
  475.               (m3-re-search-backward
  476.                (concat "\\(;\\|END\\|\\("
  477.                    m3-keyword-line-starters "\\)\\)")
  478.                part-start t))
  479. ;;;            (message "m3-IFL: skip-two xxx 2.5") (sit-for 2)
  480.             (let ((continue t) (OF-end (point)))
  481.               (while (and (looking-at "OF") continue)
  482.             (if (re-search-backward
  483.                  "SET[ \t]*\\|ARRAY[ \t]*\\[[^]]*\\][ \t]*"
  484.                  part-start t)
  485.                 (cond
  486.                  ((eq (match-end 0) OF-end)
  487.                   (m3-re-search-backward
  488.                    (concat "\\(;\\|\\("
  489.                        m3-keyword-line-starters "\\)\\)")
  490.                    part-start t))
  491.                  (t (setq continue nil)))
  492.               (setq continue nil))))
  493.               
  494. ;;;            (message "m3-IFL: skip-two xxx 3") (sit-for 2)
  495.             ;; If we're at part-start, then that is the indentation
  496.             ;; (Since part-starts are not ssl-introducers?)
  497.             (if (or (not (eq (point) part-start))
  498.                 (looking-at m3-keyword-endable-ssl-introducers))
  499.             (progn
  500.               (re-search-forward
  501.                (concat "\\(;\\|END\\|\\("
  502.                    m3-keyword-endable-ssl-introducers "\\)\\)")
  503.                (point-max) t)
  504.               (goto-char (match-end 0))
  505. ;;;              (message "m3-IFL: skip-two xxx 4") (sit-for 2)
  506.               (m3-forward-to-code cur-point)))
  507.  
  508. ;;;            (message "m3-indent-for-line: indentation") (sit-for 2)
  509.             (cond
  510.              (last-complete
  511.               (m3-complete-adjust-indent (current-column) first-code
  512.                          part-start))
  513.              (t
  514.               (m3-after-keyword-adjust-indent (current-column)
  515.                               first-code part-start)
  516.               )))))))))))))))
  517.  
  518.  
  519.  
  520.  
  521. (defun m3-in-arg-list (part-start)
  522.   "Returns non-NIL iff the point is in a procedure or method argument
  523. list."
  524. ;;;  (message "m3-in-arg-list(1)") (sit-for 2)
  525.   (save-excursion
  526.     (let ((cur-point (point)))
  527.       (m3-re-search-backward "PROCEDURE\\|METHODS" part-start t)
  528.       (cond
  529.        ((looking-at "PROCEDURE")
  530.     (forward-word 1)
  531.     (m3-re-search-forward "([^*]" (point-max) t)
  532. ;;;    (message "m3-in-arg-list(3)") (sit-for 2)
  533.     (and (< (point) cur-point)
  534.          (condition-case err
  535.          (progn
  536.            (forward-sexp 1)
  537. ;;;           (message "m3-in-arg-list(4)") (sit-for 2)
  538.            (> (point) cur-point))
  539.            (error t))))
  540.  
  541.        ((looking-at "METHODS")
  542.     (let ((continue t) (res nil))
  543.       (while (and continue (< (point) cur-point))
  544.         (m3-re-search-forward "([^*]\\|END" (point-max) t)
  545. ;;;        (message "m3-in-arg-list(101)") (sit-for 2)
  546.         (cond
  547.          ((and (looking-at "([^*]") (< (point) cur-point))
  548. ;;;          (message "m3-in-arg-list(101.5)") (sit-for 2)
  549.           (condition-case err
  550.           (progn
  551.             (forward-sexp 1)
  552. ;;;            (message "m3-in-arg-list(102)") (sit-for 2)
  553.             (if (> (point) cur-point) (setq res t)))
  554.         (error
  555.          ;; No matching right paren, so must still be in arg list.
  556. ;;;         (message "m3-in-arg-list(103)") (sit-for 2)
  557.          (setq continue nil)
  558.          (setq res t))))
  559.          (t
  560. ;;;          (message "m3-in-arg-list(104)") (sit-for 2)
  561.           (setq continue nil))))
  562.       res))
  563.  
  564.        (t nil)))))
  565.           
  566.  
  567.  
  568. (defun m3-prev-line-incomplete-p (cur-point part-start)
  569. ;;;  (message "incomplete?") (sit-for 2)
  570.   (or
  571.    ;; Does the previous non-blank line end with an operator?
  572.    (save-excursion
  573. ;;;     (message "incomplete-1") (sit-for 2)
  574.      (goto-char cur-point)
  575.      (m3-backward-to-code part-start)
  576.      (or (looking-at "[+\\-*&#<,]")
  577.      (and (looking-at ">")
  578.           (save-excursion
  579.         (beginning-of-line)
  580. ;;;        (message "incomplete-1.1") (sit-for 2)
  581.         (not (looking-at
  582.               (concat "[ \t]*"
  583.                   m3-handler-start-re
  584.                   "[ \t]*\\($\\|(\\*\\)")))))
  585.      (and (looking-at "=")
  586.           (save-excursion
  587. ;;;        (message "incomplete-1.2") (sit-for 2)
  588.         (beginning-of-line)
  589. ;;;        (message "incomplete-1.21") (sit-for 2)
  590.         (and (not (looking-at
  591.                (concat "PROCEDURE.*=[ \t]*\\($\\|(\\*\\)")))
  592.              (not (m3-in-arg-list part-start)))))
  593.              
  594.      (and (> (point) 2)
  595.           (progn
  596.         (forward-char -2)
  597.         (or (looking-at
  598.              (concat m3-not-identifier-char-re "OR"))
  599.             (and
  600.              (> (point) 1)
  601.              (progn
  602.                (forward-char -1)
  603.                (looking-at
  604.             (concat m3-not-identifier-char-re
  605.                 "\(DIV\\|MOD\\|AND\\|NOT")))))))))
  606.  
  607.    (save-excursion
  608.      (goto-char cur-point)
  609.      (m3-backward-to-code part-start)
  610.      (forward-char 1)
  611. ;;;     (message "incomplete-1B1") (sit-for 2)
  612.      (let ((last-char (point)))
  613.        (beginning-of-line 1)
  614.        (and (re-search-forward
  615.          (concat "^[ \t]*\\(" m3-statement-keywords "\\)")
  616.          cur-point t)
  617.         (= last-char (match-end 0)))))
  618.  
  619.    (save-excursion
  620. ;;;     (message "incomplete-2") (sit-for 2)
  621.      (cond
  622.       ((looking-at "END;")
  623. ;;;       (message "incomplete-2.01") (sit-for 2)
  624.        (forward-char 4))
  625.       ((looking-at
  626.     (concat "END[ \t]*" m3-identifier-re "[ \t]*\\(;\\|\\.\\)"))
  627. ;;;       (message "incomplete-2.02") (sit-for 2)
  628.        (re-search-forward
  629.     (concat "END[ \t]*" m3-identifier-re "[ \t]*\\(;\\|\\.\\)")
  630.     (point-max) t)
  631.        (goto-char (match-end 0)))
  632.       ((looking-at m3-multi-keyword-line-prefix)
  633. ;;;       (message "incomplete-2.1") (sit-for 2)
  634.        (re-search-forward m3-multi-keyword-line-prefix (point-max) t)
  635.        (goto-char (match-end 0)))
  636.  
  637.       ((looking-at "PROCEDURE")
  638. ;;;       (message "incomplete-2.15") (sit-for 2)
  639.        (forward-word 1)
  640.        (m3-re-search-forward "([^*]" (point-max) t)
  641.        (let ((new-point (point)))
  642.      (save-excursion
  643.       (condition-case err
  644.           (forward-sexp 1)
  645.         (error (goto-char (point-max))))
  646. ;;;      (message "incomplete-2.15-2") (sit-for 2)
  647.       (and (< (point) cur-point)
  648.            (m3-re-search-forward "=" (point-max) t)
  649.            (progn
  650.          (forward-char 1)
  651.          (and (< (point) cur-point)
  652. ;;;              (message "incomplete-2.15-3") (sit-for 2)
  653.               (setq new-point (point))))))
  654.      (goto-char new-point)))
  655.  
  656.       ((looking-at "WITH")
  657. ;;;       (message "incomplete-2.191") (sit-for 2)
  658.        (forward-word 1)
  659.        (let ((new-point (point)))
  660.      (m3-re-search-forward "DO" first-code t)
  661. ;;;     (message "incomplete-2.192") (sit-for 2)
  662.      (cond
  663.       ((looking-at "DO")
  664.        (forward-word 1)
  665. ;;;       (message "incomplete-2.193") (sit-for 2)
  666.        (setq new-point (point))))
  667.      (goto-char new-point)))
  668.  
  669.       ((looking-at "END")
  670.        (forward-word 1)
  671.        (cond
  672.     ((save-excursion
  673.        (m3-forward-to-code (point-max))
  674.        (looking-at ";"))
  675.      (m3-forward-to-code (point-max))
  676.      (forward-char 1))))
  677.  
  678.       ;; If looking-at keyword-line-starter or part-starter
  679.       ((looking-at (concat m3-keyword-line-starters "\\|" m3-part-starters))
  680. ;;;       (message "incomplete-2.2") (sit-for 2)
  681.        (re-search-forward
  682.     (concat m3-keyword-line-starters "\\|" m3-part-starters)
  683.     (point-max) t)
  684.        (goto-char (match-end 0)))
  685.  
  686.       ((looking-at ";")
  687.        (forward-char 1)))
  688.  
  689.      ;; Go forward to code.
  690. ;;;     (message "m3-IFL: before codepoint") (sit-for 2)
  691.      (m3-forward-to-code (point-max))
  692.      ;; Is there something between the last ';' and the current
  693.      ;; line?
  694. ;;;     (message "m3-IFL: codepoint") (sit-for 2)
  695.      (and
  696.       (< (point) cur-point)
  697.       ;; Yes -- means that the previous statement was incomplete...
  698.  
  699.       ;; ...unless the current line is an ssl-ender, in which
  700.       ;; case it is assumed complete...
  701. ;;;      (message "incomplete-3") (sit-for 2)
  702.       (or (not
  703.        (save-excursion
  704.          (goto-char first-code)
  705. ;;;         (message "incomplete-3.1") (sit-for 2)
  706.          (looking-at m3-keyword-ssl-enders)))
  707.       (save-excursion
  708. ;;;        (message "incomplete-3.2") (sit-for 2)
  709.         (goto-char first-code)
  710.         (m3-backward-to-code part-start)
  711.         (forward-char 1)
  712. ;;;        (message "incomplete-3.21") (sit-for 2)
  713.         (let ((after (point)))
  714.           (m3-re-search-backward m3-keyword-endable-ssl-introducers
  715.                      part-start t)
  716.           (re-search-forward m3-keyword-endable-ssl-introducers
  717.                  cur-point t)
  718.           (goto-char (match-end 0))
  719. ;;;          (message "incomplete-3.22") (sit-for 2)
  720.           (= (point) after))))
  721.  
  722.       ;; ... or there is a an ssl-ender between here and first-code
  723.       ;; that is not a semi in an argument list...
  724.       (not (save-excursion
  725. ;;;         (message "incomplete-3.3-0") (sit-for 2)
  726.          (and (m3-re-search-forward
  727.            (concat ";\\|" m3-keyword-ssl-enders)
  728.            first-code 't)
  729.           (let ((continue t))
  730.             (while (and continue (m3-in-arg-list part-start))
  731. ;;;              (message "incomplete-3.3-1") (sit-for 2)
  732.               (re-search-forward
  733.                (concat ";\\|" m3-keyword-ssl-enders)
  734.                first-code 't)
  735.               (goto-char (match-end 0))
  736. ;;;              (message "incomplete-3.3-2") (sit-for 2)
  737.               (setq continue
  738.                 (m3-re-search-forward
  739.                  (concat ";\\|" m3-keyword-ssl-enders)
  740.                  first-code 't)))
  741.             continue)
  742. ;;;          (message "incomplete-3.3") (sit-for 2)
  743.           (< (point) first-code))))
  744.  
  745.       ;; ... or the previous statement is a multi-keyword statement
  746.       ;; and the current line is completed by a subsequent keyword...
  747.       (not
  748.        (save-excursion
  749.      (goto-char cur-point)
  750.      (m3-backward-to-non-comment-line-start part-start)
  751. ;;;     (message "m3-indent-for-line: multi-keyword") (sit-for 2)
  752.      (looking-at m3-multi-keyword-lines)))
  753.       ))))
  754.  
  755.  
  756.  
  757. ;; Constants, especially helpful regexps.
  758.  
  759. (defconst m3-identifier-char-re "[a-zA-Z0-9_]")
  760. (defconst m3-alpha-char-re "[a-zA-Z_]")
  761. (defconst m3-not-identifier-char-re "[^a-zA-Z0-9_]")
  762.  
  763. (defconst m3-identifier-re
  764.   (concat "\\b" m3-alpha-char-re m3-identifier-char-re "*\\b"))
  765.  
  766. (defconst m3-intlit-re "[1-9][0-9]*")
  767.  
  768. (defconst m3-poss-qual-ident-re
  769.   (concat "\\(" "\\(" m3-identifier-re "\\.\\)?" m3-identifier-re "\\.\\)?"
  770.       m3-identifier-re))
  771.  
  772. (defconst m3-com-start-re "\\((\\*\\|<\\*\\)")
  773. (defconst m3-com-end-re "\\(\\*)\\|\\*>\\)")
  774. (defconst m3-com-start-or-end-re
  775.   (concat "\\\(" m3-com-start-re "\\|" m3-com-end-re "\\)"))
  776.  
  777. (defconst m3-whitespace-char-re "[ \t]")
  778. (defconst m3-poss-whitespace-re "[ \t]*")
  779. (defconst m3-poss-whitespace-nl-re "[ \t\n]*")
  780. (defconst m3-whitespace-line-re "^[ \t\n]*$")
  781.  
  782.  
  783. (defconst m3-char-lit-re "'\\([^\\]\\|\\\\..?.?\\)'")
  784.  
  785. (defconst m3-range-re
  786.   (concat m3-intlit-re m3-poss-whitespace-re "\\.\\."
  787.       m3-poss-whitespace-re m3-intlit-re))
  788.   
  789.   
  790. (defconst m3-case-label-re
  791.   (concat "\\(" m3-poss-qual-ident-re "\\|"
  792.       m3-char-lit-re "\\|"
  793.       m3-intlit-re "\\|"
  794.       m3-range-re
  795.       "\\)"))
  796.  
  797. (defconst m3-handler-start-re
  798.   (concat "\\(|[ \t]*\\)?\\("
  799.       (concat "\\b" m3-poss-qual-ident-re m3-poss-whitespace-re
  800.           "(" m3-poss-whitespace-re m3-identifier-re
  801.           m3-poss-whitespace-re ")" )
  802.       "\\|"
  803.       (concat "\\b" m3-case-label-re
  804.           (concat "\\(" m3-poss-whitespace-re ","
  805.               m3-poss-whitespace-nl-re m3-case-label-re "\\)*"))
  806.       
  807.       "\\)" m3-poss-whitespace-re "=>"))
  808.  
  809. (defconst m3-object-re
  810.   (concat "\\(" m3-identifier-re "[ \t]+\\)?\\(BRANDED[ \t]+"
  811.       "\\(\"[^\"]+\"\\)?[ \t]+\\)?OBJECT"))
  812.  
  813.  
  814. (defconst m3-part-starters
  815.   (concat
  816.    "\\bINTERFACE\\b\\|\\bMODULE\\b\\|\\bIMPORT\\b\\|\\bFROM\\b\\|"
  817.    "\\bTYPE\\b\\|\\bEXCEPTION\\b\\|\\bVAR\\b\\|"
  818.    "\\bPROCEDURE\\b\\|\\bREVEAL\\b\\|\\bCONST\\b")
  819.   "These are the patterns that can start lines and change the indentation
  820. of the following line.")
  821.  
  822.  
  823. (defconst m3-keyword-endable-ssl-introducers
  824.   (concat
  825.    "\\bTYPE\\b\\|\\bVAR\\b\\|"
  826.    "\\bRECORD\\b\\|\\bOBJECT\\b\\|\\bMETHODS\\b\\|\\bOVERRIDES\\b\\|"
  827.    "\\bBEGIN\\b\\|\\bTRY\\b\\|\\bEXCEPT\\b\\|"
  828.    m3-handler-start-re "\\|"
  829.    "\\bFINALLY\\b\\|\\bLOOP\\b\\|\\bTHEN\\b\\|\\bELSE\\b\\|\\bREPEAT\\b\\|"
  830.    "\\bDO\\b\\|\\bOF\\b\\|\\bREVEAL\\b\\|\\bCONST\\b"))
  831.  
  832. ;;; These keywords have the property that they affect the indentation if they
  833. ;;; occur at the beginning of a line.
  834. (defconst m3-keyword-line-starters
  835.   (concat
  836.    "TYPE\\|\\bEND\\b\\|RECORD\\|PROCEDURE\\|OBJECT\\|METHODS\\|OVERRIDES\\|"
  837.    "VAR\\|BEGIN\\|TRY\\|EXCEPT\\b\\|"
  838.    m3-handler-start-re "\\|"
  839.    "|\\|FINALLY\\|LOOP\\|THEN\\|ELSIF\\|IF\\|ELSE\\|WHILE\\|REPEAT\\|"
  840.    "WITH\\|FOR\\b\\|DO\\|CASE\\|\\bOF\\b\\|TYPECASE\\|LOCK\\|CONST\\|FROM\\|"
  841.    "REVEAL"))
  842.  
  843.  
  844.  
  845.  
  846. (defconst m3-multi-keyword-line-prefix
  847.   (concat
  848.    "\\("
  849.    ;; ...a PROCEDURE at the start of a line that ends
  850.    ;; with an equals
  851.    "^PROCEDURE[^\n]*=" "\\|"
  852.    ;; ... or an IF or ELSEIF that ends with a THEN
  853.    "\\(IF\\|ELSIF\\)[^\n]*THEN" "\\|"
  854.    ;; ... or a WHILE, WITH, FOR, or LOCK that ends with a DO
  855.    "\\(WHILE\\|WITH\\|FOR\\b\\|LOCK\\)[^\n]*DO" "\\|"
  856.    ;; ... or a FOR that ends with a TO or BY
  857.    "FOR[^\n]*\\(DO\\|BY\\)" "\\|"          
  858.    ;; ... or a CASE or TYPECASE that ends with a OF
  859.    "\\(CASE\\|TYPECASE\\)[^\n]*OF" "\\|"
  860.    ;; ... or at a handler-start that ends with a "=>"
  861.    "\\(|\\|\\)[ \t]*" m3-handler-start-re
  862.    "\\)"
  863.    ))
  864.  
  865. (defconst m3-multi-keyword-lines
  866.   (concat m3-multi-keyword-line-prefix 
  867.       "[ \t]*\\($\\|(\\*\\)"))
  868.  
  869.  
  870. (defconst m3-statement-starters
  871.   (concat
  872.    "BEGIN\\b\\|TRY\\b\\|LOOP\\b\\|IF\\b\\|WHILE\\b\\|REPEAT\\b\\|"
  873.    "WITH\\\b\\|FOR\\b\\|CASE\\b\\|TYPECASE\\b\\|LOCK\\b")
  874.   
  875.   "These are the patterns that can start lines and change the indentation
  876. of the following line.")
  877.  
  878.  
  879.  
  880. (defconst m3-keyword-ssl-enders
  881.   "|\\|EXCEPT\\|FINALLY\\|ELSIF\\|ELSE\\|UNTIL\\|END")
  882.  
  883. (defconst m3-left-parens
  884.   "\\((\\|\\[\\|{\\)")
  885. (defconst m3-right-parens
  886.   "\\()\\|\\]\\|}\\)")
  887.  
  888. ;;; Think of a more descriptive name for these...
  889.  
  890. (defconst m3-statement-keywords
  891.   "RETURN\\|RAISE\\|EXCEPTION\\|IMPORT\\|WITH")
  892.  
  893.  
  894. ;; Variables that control indentation behavior
  895.  
  896. (defvar m3-standard-offset 2)
  897. (defvar m3-continued-line-offset 2)
  898. (defvar m3-case-offset 0)
  899. ;;;(setq m3-case-offset 2)
  900. (defvar m3-open-paren-offset 4)
  901. ;;;(setq m3-open-paren-offset 2)
  902. (defvar m3-assign-offset 4)
  903. (defvar m3-RAISES-offset 4)
  904.  
  905. (defvar m3-follow-continued-indent t)
  906.  
  907. (defvar m3-END-undent 2)
  908. (defvar m3-METHODS-undent 2)
  909. (defvar m3-OVERRIDES-undent 2)
  910. (defvar m3-EXCEPT-undent 2)
  911. (defvar m3-VERT-undent 2)
  912. (defvar m3-handler-start-undent 0)
  913. (defvar m3-EXCEPT-undent 2)
  914. (defvar m3-UNTIL-undent 2)
  915. (defvar m3-FINALLY-undent 2)
  916. (defvar m3-ELSIF-undent 2)
  917. (defvar m3-ELSE-undent 2)
  918.  
  919. (defvar m3-DO-undent 1)
  920. (defvar m3-OF-undent 1)
  921. (defvar m3-THEN-undent 1)
  922.  
  923. (defvar m3-OBJECT-undent 1)
  924. (defvar m3-RECORD-undent 1)
  925.  
  926.  
  927.  
  928. (defun m3-after-keyword-adjust-indent (indent first-code part-start)
  929.   "Point is looking at a keyword at column INDENT; if the current line has
  930. any code it starts at FIRST-CODE.  Return the proper indentation for the
  931. current line."
  932. ;;;  (message "m3-after-keyword: indent = %d" indent) (sit-for 2)
  933.   (let ((call-adjust-indent t))
  934.     (cond
  935.      ((looking-at "END")
  936. ;;;    (message "m3-after-keyword(END): i: %d, m3-END: %d, m3-stand: %d"
  937. ;;;         indent m3-END-undent m3-standard-offset)
  938. ;;;    (sit-for 2)
  939.       (setq indent (- (+ indent m3-END-undent) m3-standard-offset)))
  940.  
  941.      ((looking-at "ELSE")
  942.       (setq indent (+ indent m3-ELSE-undent))
  943.       (if (m3-in-case part-start)
  944.       (setq indent (+ indent m3-case-offset))))
  945.     
  946.  
  947.      ((looking-at "METHODS")
  948.       (setq indent (+ indent m3-METHODS-undent)))
  949.      ((looking-at "OVERRIDES")
  950.       (setq indent (+ indent m3-OVERRIDES-undent)))
  951.      ((looking-at "EXCEPT\\b")
  952. ;;;    (message "m3-after-keyword: EXCEPT" indent) (sit-for 2)
  953.       (setq indent (+ indent m3-EXCEPT-undent)))
  954.      ((looking-at "|")
  955. ;;;    (message "m3-after-keyword: vert" indent) (sit-for 2)
  956.       (setq indent (+ indent m3-VERT-undent m3-case-offset)))
  957.      ((looking-at m3-handler-start-re)
  958. ;;;      (message "m3-after-keyword: handler-start" indent) (sit-for 2)
  959.       (setq indent (+ indent m3-handler-start-undent m3-case-offset)))
  960.      ((looking-at "FINALLY")
  961.       (setq indent (+ indent m3-FINALLY-undent)))
  962.      ((looking-at "THEN")
  963.       (setq indent (+ indent m3-THEN-undent)))
  964.      ((looking-at "ELSIF")
  965.       (setq indent (+ indent m3-ELSIF-undent)))
  966.      ((looking-at "ELSE")
  967.       (setq indent (+ indent m3-ELSE-undent)))
  968.      ((looking-at "DO")
  969.       (setq indent (+ indent m3-DO-undent)))
  970.      ((looking-at "OF")
  971.       (setq indent (+ indent m3-OF-undent)))
  972.      ((looking-at m3-object-re)
  973.       (setq indent (+ indent m3-OBJECT-undent)))
  974.      ((looking-at "RECORD")
  975.       (setq indent (+ indent m3-RECORD-undent)))
  976.  
  977.      ;; These are the keywords that can be followed by an SSL that begins on
  978.      ;; the same line -- if so, indent to the level of the first elem.
  979.      ((looking-at m3-same-line-ssl-keywords)
  980. ;;;      (message "m3-after-keyword: same-line-ssl") (sit-for 2)
  981.       (let ((eol (save-excursion (end-of-line 1) (point))))
  982.     (save-excursion
  983.       (forward-word 1)
  984.       (m3-forward-to-code (point-max))
  985. ;;;      (message "m3-after-keyword: SlSSL(2)") (sit-for 2)
  986.       (cond
  987.        ((and
  988.          m3-follow-continued-indent
  989.          (<= (point) eol)
  990.          (save-excursion
  991.            (goto-char first-code)
  992.            (not (looking-at (concat m3-part-starters "\\|BEGIN"))))
  993.          (save-excursion
  994.            (end-of-line 1)
  995.            (m3-backward-to-code part-start)
  996.            (looking-at ";")))
  997. ;;;        (message "m3-after-keyword: SLSSL (3)") (sit-for 2)
  998.         (setq indent (current-column))
  999.         (setq call-adjust-indent nil))
  1000.        (t
  1001.         (setq indent (+ indent m3-standard-offset)))))))
  1002.  
  1003.      ;; These are all the keywords that don't affect the indentation
  1004.      ;; when they start complete lines.
  1005.      ((looking-at
  1006.        (concat "INTERFACE\\|MODULE\\|IMPORT\\|FROM\\|EXCEPTION"))
  1007. ;;;    (message "m3-after-keyword: no extra") (sit-for 2)
  1008.       indent)
  1009.  
  1010.      ;; Otherwise, give the standard indentation.
  1011.      (t
  1012. ;;;    (message "m3-after-keyword: standard") (sit-for 2)
  1013.       (setq indent (+ indent m3-standard-offset))))
  1014.     
  1015.     (cond
  1016.      (call-adjust-indent
  1017.       (save-excursion
  1018.     (goto-char first-code)
  1019. ;;;    (message "m3-after-keyword: calling complete-adjust") (sit-for 2)
  1020.     (m3-complete-adjust-indent indent first-code part-start)))
  1021.      (t
  1022. ;;;      (message "m3-after-keyword: not calling complete-adjust") (sit-for 2)
  1023.       indent))))
  1024.  
  1025.  
  1026. (defun m3-in-case (part-start)
  1027. ;;;  (message "M3-in-case") (sit-for 2)
  1028.   (save-excursion
  1029.     (let ((cur-point (point)))
  1030.       (m3-backward-to-end-match part-start)
  1031. ;;;      (message "M3-in-case(2)") (sit-for 2)
  1032.       (and
  1033.        (looking-at m3-case-starters)
  1034.        (progn
  1035.      (cond
  1036.       ((looking-at "TRY")
  1037.        ;; Is it a TRY-FINALLY or a TRY-EXCEPT?
  1038.        (let (res (continue t))
  1039.          (while continue
  1040.            (setq res (m3-re-search-forward "TRY\\|EXCEPT\\|FINALLY"
  1041.                          cur-point t))
  1042.            (cond
  1043.         ((looking-at "EXCEPT")
  1044.          (setq continue nil))
  1045.         ((looking-at "TRY")
  1046.          ;; Go to matchine END and try again
  1047.          (m3-forward-to-end-matcher cur-point))
  1048.         (t;; FINALLY or not found
  1049.          (setq res nil)
  1050.          (setq continue nil))))
  1051.          res))
  1052.       (t t)))
  1053.        ;;; We are now looking at a case starter.  Make sure there is
  1054.        ;;; at least one case arm starter.
  1055.        (progn
  1056.      (cond
  1057.       ((looking-at "EXCEPT") (forward-word 1))
  1058.       ((looking-at "CASE\\|TYPECASE")
  1059.        (forward-word 1)
  1060.        (m3-re-search-forward "OF" cur-point 'move-to-limit)
  1061.        (forward-word 1)))
  1062.      (m3-forward-to-code cur-point)
  1063. ;;;     (message "M3-in-case: about to test handler") (sit-for 2)
  1064.      (and (< (point) cur-point)
  1065.           (looking-at m3-handler-start-re)))
  1066.  
  1067. ;;;       (message "M3-in-case: returning t") (sit-for 2)
  1068.        ))))
  1069.  
  1070.      
  1071. (defun m3-in-continued-record-def (part-start)
  1072.   (if (not (looking-at "END"))
  1073.       (error "m3-in-continued-record-def assumes looking-at END"))
  1074.   (save-excursion
  1075.     (m3-backward-to-end-match part-start)
  1076.     (let ((end-match (point)) (eol (save-excursion (end-of-line) (point))))
  1077.       (beginning-of-line)
  1078.       (or (save-excursion
  1079.         (re-search-forward "[ \t]*" eol t)
  1080.         (= (point) end-match))
  1081.       (save-excursion
  1082.         (and
  1083.          (re-search-forward "[ \t]*BRANDED[ \t]+" eol t)
  1084.          (= (point) end-match)
  1085.          (save-excursion
  1086.            (goto-char end-match)
  1087.            (looking-at "OBJECT"))))))))
  1088.  
  1089.      
  1090. (defun m3-correct-for-trailing-ends (indent part-start)
  1091.   ;; If the previous line ends in a (series of) END(s) that does
  1092.   ;; (do) not start the line, and are unmatched by the start of the line,
  1093.   ;; subtract the END-undent(s) from indent (the Eric Muller convention.)
  1094. ;;;  (message "correct-for-trailing-ends in: %d" indent) (sit-for 2)
  1095.   (let ((prev-line-start
  1096.      (save-excursion
  1097.        (m3-backward-to-code part-start)
  1098.        (beginning-of-line)
  1099.        (m3-forward-to-code (point-max))
  1100. ;;;       (message "correct-for-trailing-ends (0)") (sit-for 2)
  1101.        (point))))
  1102.     (save-excursion
  1103.       (if (save-excursion
  1104.         (m3-backward-to-code part-start)
  1105.         (beginning-of-line)
  1106.         (not (looking-at "[ \t]*END")))
  1107.       (save-excursion
  1108.         (let ((continue t))
  1109.           (while continue
  1110.         (m3-backward-to-code part-start)
  1111. ;;;        (message "correct-for-trailing-ends (2)") (sit-for 2)
  1112.         (cond
  1113.          ((or (and (> (point) 2)
  1114.                (progn
  1115.                  (forward-char -2) (looking-at "END")))
  1116.               (and (> (point) 1)
  1117.                (progn
  1118.                  (forward-char -1) (looking-at "END;"))))
  1119. ;;;          (message "correct-for-trailing-ends (3)") (sit-for 2)
  1120.           (if (not (looking-at "END"))
  1121.               (error "m3-complete-adjust-indent(A)"))
  1122.           (let ((em-point
  1123.              (save-excursion
  1124.                (m3-backward-to-end-match part-start)
  1125. ;;;               (message "correct-for-trailing-ends EM") (sit-for 2)
  1126.                (point))))
  1127. ;;;            (message "xxx") (sit-for 2)
  1128.             (cond
  1129.               ((< em-point prev-line-start)
  1130.                (goto-char prev-line-start)
  1131. ;;;               (message "xxx<") (sit-for 2)
  1132.                (setq indent
  1133.                  (save-excursion (goto-char em-point)
  1134.                          (current-column))))
  1135.               ((= em-point prev-line-start)
  1136. ;;;               (message "xxx=") (sit-for 2)
  1137.                (setq indent (- indent m3-END-undent))
  1138.                (setq continue nil))
  1139.               ((> em-point prev-line-start)
  1140.                (goto-char em-point)))))
  1141.          (t
  1142.           (setq continue nil))))))))
  1143. ;;;    (message "m3-trailing-end returns %d" indent) (sit-for 2)
  1144.     indent))
  1145.      
  1146.  
  1147. (defun m3-complete-adjust-indent (indent first-code part-start)
  1148.   "Previous statement is complete and starts at column INDENT;
  1149. if the current line has any code it starts at FIRST-CODE.  Returns the
  1150. proper indentation for the current line."
  1151. ;;;  (message "m3-complete-adjust(A): indent = %d, first-code = %d"
  1152. ;;;       indent first-code)
  1153. ;;;  (sit-for 2)
  1154.   (save-excursion
  1155.     (goto-char first-code)
  1156. ;;;    (message "m3-complete-adjust(B)") (sit-for 2)
  1157.  
  1158.     ;; If the previous line ends in a (series of) END(s) that does
  1159.     ;; (do) not start the line, and are unmatched before the start of the line,
  1160.     ;; the END-undent(s) (the Eric Muller convention.)
  1161.     (setq indent (m3-correct-for-trailing-ends indent part-start))
  1162.           
  1163. ;;;    (message "yyy2: indent = %d" indent) (sit-for 2)
  1164.     (cond
  1165.      ;; Some things can only start parts, and must be on the left margin.
  1166.      ((looking-at (concat "TYPE\\b\\|REVEAL\\b\\|EXCEPTION\\b\\|"
  1167.               "FROM\\b\\|IMPORT\\b"))
  1168.       0)
  1169.       
  1170.      ;; These can start parts, but can also appear in the procedures.
  1171.      ((looking-at
  1172.        (concat "\\(PROCEDURE\\b\\|CONST\\b\\|VAR\\b\\|BEGIN\\b\\)"))
  1173.       ;; Look backwards for line-beginning-keywords that increase the
  1174.       ;; indentation, start an SSL, but don't require an END (i.e.,
  1175.       ;; TYPE, VAR, or CONST); or END's.  If the former is found first,
  1176.       ;; decrease the indentation to the same as the keyword line's.
  1177.       ;; If an END is found whose matcher is not something that can
  1178.       ;; occur in a TYPE, VAR, or CONST (i.e. RECORD or OBJECT),
  1179.       ;; indent normally.
  1180. ;;;      (message "yyy7") (sit-for 2)
  1181.       (let ((new-indent indent) (continue t))
  1182.     (while continue
  1183. ;;;      (message "xxx1") (sit-for 2)
  1184.       (m3-re-search-backward
  1185.        (concat "\\(^[ \t]*\\(" m3-same-line-ssl-keywords "\\)\\|END\\|"
  1186.            m3-statement-starters "\\)")
  1187.        part-start 'move-to-limit)
  1188. ;;;      (message "xxx2") (sit-for 2)
  1189.       (cond
  1190.        ;; If we reached the part-start because of the move-to-limit,
  1191.        ;; indent to here...
  1192.        ((looking-at (concat "^" m3-part-starters))
  1193. ;;;        (message "xxx2.5") (sit-for 2)
  1194.         (goto-char first-code)
  1195.         ;; If its the start of a procedure def, indent normally.
  1196.         ;; Otherwise, indent to left margin.
  1197.         (if (not (m3-after-procedure-introducer part-start))
  1198.         (setq new-indent 0))
  1199.         (setq continue nil))
  1200.           
  1201.        ((and
  1202.          (looking-at
  1203.           (concat "^[ \t]*\\(" m3-same-line-ssl-keywords "\\)"))
  1204.          (not (m3-in-arg-list part-start)))
  1205.         (setq continue nil)
  1206.  
  1207.         ;;; To accomodate part-starters that establish new indentations,
  1208.         ;;; indent to the level of the previous part-starter, unless
  1209.         ;;; that was a BEGIN.
  1210.         (goto-char first-code)
  1211.         (m3-re-search-backward
  1212.          (concat m3-part-starters "\\|BEGIN") part-start t)
  1213.         (while (m3-in-arg-list part-start)
  1214.           (m3-re-search-backward
  1215.            (concat m3-part-starters "\\|BEGIN") part-start t))
  1216. ;;;        (message "xxx3") (sit-for 2)
  1217.         (cond
  1218.          ((looking-at "BEGIN")
  1219.           (setq new-indent (- new-indent m3-standard-offset)))
  1220.          (t
  1221.           (setq new-indent (current-column)))))
  1222.          
  1223.        ((looking-at
  1224.          (concat "END[ \t]*" m3-identifier-re "[ \t]*;"))
  1225.         (setq continue nil)
  1226.         (setq new-indent (- new-indent m3-standard-offset)))
  1227.  
  1228.  
  1229.        ((looking-at "END")
  1230.         (m3-backward-to-end-match part-start)
  1231. ;;;        (message "xxxEND-match") (sit-for 2)
  1232.         (cond
  1233.          ((looking-at "\\(RECORD\\|OBJECT\\)")
  1234.           nil)
  1235.          (t
  1236.           (setq continue nil))))
  1237.  
  1238.        (t
  1239.         (setq continue nil))))
  1240.     new-indent))
  1241.  
  1242.      ;; If the current line is an END, add the END-undent.
  1243.      ((looking-at "END")
  1244. ;;;      (message "zzz1") (sit-for 2)
  1245.       (cond
  1246.        ((m3-in-case part-start)
  1247.     (- indent m3-END-undent m3-case-offset))
  1248.        (t
  1249.     (- indent m3-END-undent))))
  1250.  
  1251.  
  1252.      ((looking-at "ELSE")
  1253.       (- indent m3-ELSE-undent
  1254.      (if (m3-in-case part-start) m3-case-offset 0)))
  1255.  
  1256.      ((looking-at "METHODS")
  1257.       (- indent m3-METHODS-undent))
  1258.      ((looking-at "OVERRIDES")
  1259.       (- indent m3-OVERRIDES-undent))
  1260.      ((looking-at "EXCEPT")
  1261.       (- indent m3-EXCEPT-undent))
  1262.      ((looking-at "UNTIL")
  1263.       (- indent m3-UNTIL-undent))
  1264.      ((looking-at "|")
  1265.       (cond
  1266.        ((save-excursion
  1267.       (m3-backward-to-code part-start)
  1268. ;;;      (message "zzz2") (sit-for 2)
  1269.       (or
  1270.        (save-excursion
  1271.          (and (> (point) 1)
  1272.           (progn (forward-char -1) (looking-at "OF"))))
  1273.        (save-excursion
  1274.          (and (> (point) 5)
  1275.           (progn (forward-char -5) (looking-at "EXCEPT"))))))
  1276.     (- indent m3-VERT-undent))
  1277.        (t
  1278.     (- indent m3-VERT-undent m3-case-offset))))
  1279.  
  1280.      ((looking-at "FINALLY")
  1281.       (- indent m3-FINALLY-undent))
  1282.      ((looking-at "THEN")
  1283.       (- indent m3-THEN-undent))
  1284.      ((looking-at "ELSIF")
  1285.       (- indent m3-ELSIF-undent))
  1286.      ((looking-at "ELSE")
  1287.       (- indent m3-ELSE-undent))
  1288.      ((looking-at "DO")
  1289.       (- indent m3-DO-undent))
  1290.      ((looking-at "OF")
  1291.       (- indent m3-OF-undent))
  1292.      ((looking-at "RECORD")
  1293. ;;;      (message "zzz-record") (sit-for 2)
  1294.       (- indent m3-RECORD-undent))
  1295.      ((looking-at m3-object-re)
  1296. ;;;      (message "zzz-object") (sit-for 2)
  1297.       (- indent m3-OBJECT-undent))
  1298.      (t
  1299. ;;;      (message "zzz-t: indent = %d" indent) (sit-for 2)
  1300.       indent))))
  1301.   
  1302.  
  1303. (defun m3-incomplete-indent (cur-point first-code part-start)
  1304.   (let* (list-indent
  1305.      (prev-line-start
  1306.       (save-excursion
  1307.         (m3-backward-to-non-comment-line-start part-start)
  1308.         (point)))
  1309.      (last-char-prev-line
  1310.       (save-excursion
  1311.         (m3-backward-to-non-comment-line-start part-start)
  1312.         (end-of-line)
  1313.         (m3-backward-to-code
  1314.          (save-excursion (beginning-of-line) (point)))
  1315.         (point)))
  1316.      (prev-line-indent
  1317.       (save-excursion
  1318.         (m3-backward-to-non-comment-line-start part-start)
  1319.         (let ((pli (current-column)))
  1320.           (cond
  1321.            ((looking-at m3-statement-keywords)
  1322.         (forward-word 1)
  1323.         (m3-forward-to-code first-code)
  1324.         (cond
  1325.          ((<= (point) last-char-prev-line)
  1326.           (current-column))
  1327.          (t pli)))
  1328.            (t pli))))))
  1329. ;;;    (message "m3-incomplete-indent(A)") (sit-for 2)
  1330.     (cond
  1331.      ;; Did the previous non-blank line end with a paren?
  1332.      ((save-excursion
  1333.     (goto-char last-char-prev-line)
  1334.     (looking-at m3-left-parens))
  1335.  
  1336. ;;;      (message "m3-incomplete-indent(PAREN)") (sit-for 2)
  1337.       ;;   Find the indentation of the previous line,
  1338.       ;;     either add open-paren-offset, or indent of paren +
  1339.       ;;     open-paren-sep
  1340.       (goto-char last-char-prev-line)
  1341.       (cond
  1342.        (m3-open-paren-offset
  1343. ;;;    (message "m3-incomplete-indent(PAREN offset)") (sit-for 2)
  1344.     (re-search-backward
  1345.      (concat m3-identifier-re m3-poss-whitespace-re)
  1346.      part-start t)
  1347.     (goto-char (match-beginning 0))
  1348.     ;; Account for qualified names.
  1349.     (cond
  1350.      ((save-excursion
  1351.         (and (> (point) 1)
  1352.          (progn
  1353.            (forward-char -1)
  1354.            (looking-at "\\."))))
  1355.       (re-search-backward
  1356.        (concat m3-identifier-re m3-poss-whitespace-re)
  1357.        part-start t)
  1358.       (goto-char (match-beginning 0))))
  1359.  
  1360. ;;;    (message "m3-incomplete-indent(PAREN offset 2)") (sit-for 2)
  1361.     (+ (current-column) m3-open-paren-offset))
  1362.        (t
  1363.     (+ (current-column) m3-open-paren-sep))))
  1364.         
  1365.      ;; Did the previous line end with a ',' or ';'?:
  1366.      ((save-excursion
  1367.     (goto-char last-char-prev-line)
  1368.     (looking-at ",\\|;"))
  1369.  
  1370. ;;;      (message "m3-incomplete-indent(COMMA)") (sit-for 2)
  1371.       ;; Skip over any matched parens; if this puts us at a line
  1372.       ;; containing an unmatched left paren, indent to that +
  1373.       ;; paren-sep.  Otherwise, indent same as beginning of that line.
  1374.       (save-excursion
  1375.     (goto-char last-char-prev-line)
  1376.     (let ((continue t) res)
  1377.       (while continue
  1378. ;;;        (message "m3-incomplete-indent(COMMA) 0") (sit-for 2)
  1379.         (m3-re-search-backward
  1380.          (concat m3-left-parens "\\|" m3-right-parens)
  1381.          (save-excursion (beginning-of-line)
  1382.                  (point)) 'move-to-limit)
  1383. ;;;        (message "m3-incomplete-indent(COMMA) 1") (sit-for 2)
  1384.         (cond
  1385.          ((looking-at m3-left-parens)
  1386. ;;;          (message "m3-incomplete-indent(COMMA) lp") (sit-for 2)
  1387.           (setq continue nil)
  1388.           (forward-char 1)
  1389.           (re-search-forward "[ \t]*") (goto-char (match-end 0))
  1390.           (setq list-indent (current-column)))
  1391.          ((looking-at m3-right-parens)
  1392. ;;;          (message "m3-incomplete-indent(COMMA) rp") (sit-for 2)
  1393.           (forward-char 1)
  1394.           (backward-sexp 1))
  1395.          (t
  1396. ;;;          (message "m3-incomplete-indent(COMMA) none") (sit-for 2)
  1397.           (beginning-of-line)
  1398.           (m3-forward-to-code last-char-prev-line)
  1399.           (setq continue nil)
  1400.           (setq list-indent (current-column)))))
  1401. ;;;      (message "m3-incomplete-indent(COMMA) end") (sit-for 2)
  1402.       (cond
  1403.        ((looking-at (concat "|[ \t]*" m3-identifier-char-re))
  1404.         (forward-word 1) (forward-word -1)
  1405.         (setq list-indent (current-column)))
  1406.        ((looking-at m3-statement-keywords)
  1407.         (forward-word 1)
  1408.         (re-search-forward "[ \t]*" last-char-prev-line t)
  1409.         (setq list-indent (current-column))))))
  1410.       list-indent)
  1411.           
  1412.      ;; Did the previous non-blank line end a procedure header?
  1413.      ((m3-after-procedure-introducer part-start)
  1414. ;;;      (message "m3-incomplete-indent(PROCEDURE)") (sit-for 2)
  1415.       (goto-char last-char-prev-line)
  1416.       (m3-re-search-backward "PROCEDURE" part-start t)
  1417.       (+ (current-column) m3-standard-offset))
  1418.  
  1419.      ;; Does the current line start a RAISES clause?
  1420.      ((looking-at "^[ \t]*RAISES")
  1421. ;;;      (message "m3-incomplete-indent(RAISES)") (sit-for 2)
  1422.       (goto-char last-char-prev-line)
  1423.       (m3-re-search-backward "PROCEDURE" part-start t)
  1424.       (+ (current-column) m3-RAISES-offset))
  1425.  
  1426.      ;; Did the previous line end with an assignment?
  1427.      ((save-excursion
  1428.     (goto-char last-char-prev-line)
  1429.     (beginning-of-line)
  1430. ;;;    (message "m3-incomplete-indent(:= 1)") (sit-for 2)
  1431.     (and (m3-re-search-forward ":=" (1+ last-char-prev-line) t)
  1432.          (re-search-forward "[^ \t]" last-char-prev-line t)))
  1433. ;;;      (message "m3-incomplete-indent(:=)") (sit-for 2)
  1434.       (goto-char last-char-prev-line)
  1435.       (beginning-of-line)
  1436.       (m3-re-search-forward ":=" last-char-prev-line t)
  1437.       (forward-char 2)
  1438.       (re-search-forward "[ \t]*[^ \t]")
  1439.       (+ (- (current-column) 1) m3-assign-offset))
  1440.  
  1441.      ;; Otherwise:
  1442.      (t
  1443. ;;;      (message "m3-incomplete-indent(OTHER)") (sit-for 2)
  1444.       ;; Find out if the previous line begins the statement.
  1445.       (goto-char prev-line-start)
  1446.       (m3-re-search-backward
  1447.        (concat ";\\|" m3-keyword-line-starters "\\|" m3-part-starters
  1448.            "\\|" m3-statement-keywords)
  1449.        part-start t)
  1450.       (while (m3-in-arg-list part-start)
  1451.     (m3-re-search-backward
  1452.      (concat ";\\|" m3-keyword-line-starters "\\|" m3-part-starters
  1453.          "\\|" m3-statement-keywords)
  1454.      part-start t))
  1455. ;;;      (message "m3-incomplete-indent(OTHER1)") (sit-for 2)
  1456.       (if (or (> (point) part-start)
  1457.           (and (= (point) part-start)
  1458.            (looking-at m3-keyword-endable-ssl-introducers)))
  1459.       (progn
  1460.         (re-search-forward
  1461.          (concat ";\\|" m3-keyword-line-starters "\\|" m3-part-starters
  1462.              "\\|" m3-statement-keywords)
  1463.          cur-point t)
  1464.         (goto-char (match-end 0))))
  1465. ;;;      (message "m3-incomplete-indent(OTHER1.5)") (sit-for 2)
  1466.       (m3-forward-to-code (point-max))
  1467. ;;;      (message "m3-incomplete-indent(OTHER2), prev-line-start = %d"
  1468. ;;;           prev-line-start)
  1469. ;;;      (sit-for 2)
  1470.       (cond
  1471.        ;; If the previous line begins the statement, add
  1472.        ;; m3-standard-offset to indentation, unless the prev-line-indent
  1473.        ;; has already skipped over a keyword.
  1474.        ((= (point) prev-line-start)
  1475. ;;;    (message "m3-incomplete-indent(START): prev-line-indent = %d"
  1476. ;;;         prev-line-indent)
  1477. ;;;    (sit-for 2)
  1478.     (m3-complete-adjust-indent
  1479.      ;; Indent further if we haven't indented already.
  1480.      (cond
  1481.       ((= prev-line-indent
  1482.           (save-excursion (goto-char prev-line-start) (current-column)))
  1483.        (+ prev-line-indent m3-continued-line-offset))
  1484.       (t prev-line-indent))
  1485.      first-code part-start))
  1486.        (t
  1487. ;;;    (message "m3-incomplete-indent(CONT)") (sit-for 2)
  1488.     ;; Otherwise, same indentation as previous, modulo adjustment
  1489.     ;; for current line
  1490.     prev-line-indent))))))
  1491.  
  1492.  
  1493. (defun m3-after-procedure-introducer (part-start)
  1494.   "Returns t iff first non-blank non-comment character before point is the '='
  1495. of a procedure definition."
  1496.   (save-excursion
  1497.     (m3-backward-to-code part-start)
  1498.     (and
  1499.      (looking-at "=")
  1500. ;;;     (message "m3-API(0)") (sit-for 2)
  1501.      (let ((eq-point (point)))
  1502.        (and
  1503.     ;; Not that this does not allow any comments in
  1504.     ;;   PROCEDURE Foo <left-paren>
  1505.     ;; and all must occur on the same line.
  1506.     (m3-re-search-backward
  1507.      (concat "PROCEDURE[ \t]*" m3-identifier-re "[ \t]*(")
  1508.      part-start t)
  1509. ;;;    (message "m3-API(1)") (sit-for 2)
  1510.     (progn
  1511.       (re-search-forward
  1512.        (concat "PROCEDURE[ \t]*" m3-identifier-re "[ \t]*(")
  1513.        eq-point t)
  1514.       (goto-char (match-end 0))
  1515. ;;;      (message "m3-API(2)") (sit-for 2)
  1516.       (forward-char -1)
  1517.       (and
  1518.        (condition-case err
  1519.            (progn (forward-sexp 1) t)
  1520.          (error nil))
  1521. ;;;       (message "m3-API(3)") (sit-for 2)
  1522.        ;; We should now be at the right paren of the arg-list.
  1523.        ;; Check for a return type.
  1524.        (progn
  1525.          (m3-forward-to-code eq-point)
  1526.          (and
  1527. ;;;          (message "m3-API(4)") (sit-for 2)
  1528.           (cond
  1529.            ((looking-at ":")
  1530.         (forward-char 1)
  1531.         (m3-forward-to-code eq-point)
  1532.         (and
  1533.          (looking-at m3-poss-qual-ident-re)
  1534.          (progn
  1535.            (re-search-forward m3-poss-qual-ident-re eq-point t)
  1536.            (goto-char (match-end 0))
  1537.            (m3-forward-to-code eq-point)
  1538.            t)))
  1539.            (t t))
  1540.           ;; Now check for RAISES clause.
  1541. ;;;          (message "m3-API(5)") (sit-for 2)
  1542.           (cond
  1543.            ((looking-at "RAISES")
  1544.         (forward-word 1)
  1545.         (m3-forward-to-code eq-point)
  1546.         (cond
  1547.          ((looking-at "ANY")
  1548.           (forward-word 1)
  1549.           (m3-forward-to-code eq-point)
  1550.           t)
  1551.          ((looking-at "{")
  1552. ;;;          (message "m3-API(5.5)") (sit-for 2)
  1553.           (and
  1554.            (condition-case err
  1555.                (progn (forward-sexp 1) t)
  1556.              (error nil))
  1557.            (progn (m3-forward-to-code eq-point) t)))
  1558.          (t t)))
  1559.            (t t))
  1560.  
  1561.           ;; Now, we better be back to the original =!
  1562.           (= (point) eq-point))))))))))
  1563.  
  1564.  
  1565. (defconst m3-end-matchers
  1566.   (concat
  1567.    "\\bRECORD\\b\\|\\bOBJECT\\b\\|\\bBEGIN\\b\\|\\bTRY\\b\\|\\bLOOP\\b\\|"
  1568.    "\\bIF\\b\\|\\bWHILE\\b\\|\\bWITH\\b\\|\\bFOR\\b\\|\\bCASE\\b\\|"
  1569.    "\\bTYPECASE\\b\\|\\bLOCK\\b\\|\\bINTERFACE\\b\\|\\bMODULE\\b\\|"
  1570.    "\\bGENERIC\\b"))
  1571.  
  1572.  
  1573. (defconst m3-same-line-ssl-keywords
  1574.   "\\bVAR\\b\\|\\bTYPE\\b\\|\\bCONST\\b\\|\\bEXCEPTION\\b\\|\\bREVEAL\\b"
  1575.   "These are the keywords that can be followed by an SSL that begins on
  1576. the same line -- if so, indent to the level of the first elem.")
  1577.  
  1578. (defconst m3-case-starters
  1579.   "TRY\\|CASE\\|TYPECASE")
  1580.  
  1581.  
  1582.  
  1583. (defun m3-backward-to-end-match (part-start &optional depth)
  1584.   (if (not depth) (setq depth 0))
  1585.   (let (res (continue t))
  1586.     (while continue
  1587. ;;;      (message "m3-backward-to-end-match(1) [%d]" depth) (sit-for 1)
  1588.       (setq res (m3-re-search-backward
  1589.          (concat "\\(" m3-end-matchers "\\|END\\)") part-start t))
  1590.       (cond
  1591.        ((and res (looking-at "END"))
  1592.     (m3-backward-to-end-match part-start (1+ depth)))
  1593.        (t
  1594.     (setq continue nil))))
  1595.     res))
  1596.  
  1597. (defun m3-forward-to-end-matcher (max-point)
  1598.   (let (res (continue t))
  1599.     (while continue
  1600.       (setq res (m3-re-search-forward
  1601.          (concat "\\(" m3-statement-starters "\\|END\\)") max-point t))
  1602.       (cond
  1603.        ((looking-at m3-statement-starters)
  1604.     (re-search-forward m3-statement-starters max-point t)
  1605.     (goto-char (match-end 0))
  1606.     (m3-forward-to-end-matcher max-point))
  1607.        (t   ;; looking at END or reached max-point
  1608.     (setq continue nil))))
  1609.     res))
  1610.  
  1611.  
  1612. (defun m3-backward-to-non-comment-line-start (part-start)
  1613.   "Sets the point at the first non-whitespace character in a line that
  1614. contains something other than comments and/or whitespace."
  1615.   (m3-backward-to-code part-start)
  1616.   (beginning-of-line)
  1617.   (m3-skip-whitespace-in-line))
  1618.  
  1619.  
  1620. (defun m3-skip-whitespace-in-line ()
  1621.   (re-search-forward "[ \t]*"))
  1622.  
  1623.  
  1624. (defun m3-indent-to (cur-point new-column)
  1625.   "Make current line indentation NEW-COLUMN.  If the point is to the
  1626. left of the first non-blank character, move it to NEW-COLUMN.
  1627. Otherwise, maintain its relative position.  Has the side effect
  1628. of converting tabs to spaces."
  1629.   (goto-char cur-point)
  1630.   (untabify (save-excursion (beginning-of-line) (point))
  1631.         (save-excursion (end-of-line) (point)))
  1632.   (let ((cur-column (current-column))
  1633.     (cur-point (point))
  1634.     (first-column
  1635.      (save-excursion
  1636.        (beginning-of-line)
  1637.        (re-search-forward " *")
  1638.        (current-column))))
  1639.     (let ((diff (- new-column first-column)))
  1640.       (cond
  1641.        ((> diff 0)
  1642.     (beginning-of-line)
  1643.     ;; Must do this to make sure the keyword completion marker moves
  1644.     ;; correctly.
  1645.     (let ((d diff))
  1646.       (while (> d 0)
  1647.         (insert-before-markers " ") (setq d (1- d))))
  1648.     )
  1649.        ((< diff 0)
  1650.     (save-excursion
  1651.       (forward-char (- first-column cur-column))
  1652.       (backward-delete-char-untabify (- diff)))))
  1653.       (cond
  1654.        ((> first-column cur-column)
  1655.     (beginning-of-line)
  1656.     (forward-char new-column))
  1657.        (t
  1658.     (goto-char (+ cur-point diff)))))))
  1659.  
  1660.  
  1661. (defun m3-in-comment-or-string ()
  1662.   "Returns 'string if point is in an unterminated string, 'comment if in
  1663. an unterminated comment, otherwise, nil."
  1664.   (save-excursion
  1665.     (beginning-of-line)
  1666.     (let ((cur-point (point))
  1667.       (state nil))
  1668.       (save-excursion
  1669.     ;; We assume the lisp-like convention that "top-level defuns,"
  1670.     ;; or "parts", are the only things that occur on the left
  1671.     ;; margin (we make an exception for end-comments.)
  1672.     (m3-backward-to-last-part-begin)
  1673.     (while (and (not state)
  1674.             (re-search-forward
  1675.              (concat "\\(" m3-com-start-re "\\|\"\\)")
  1676.              cur-point t))
  1677.       (goto-char (match-beginning 0))
  1678.       (cond
  1679.        ((looking-at m3-com-start-re)
  1680.         (setq state 'comment)
  1681.         (if (m3-skip-comment-forward cur-point t) (setq state nil)))
  1682.        ((looking-at "\"\\|'")
  1683.         (setq state 'string)
  1684.         (if (re-search-forward "[^\\\\]\\(\"\\|'\\)" cur-point t)
  1685.         (setq state nil)))))
  1686.     state))))
  1687.  
  1688. (defun m3-backward-to-last-part-begin ()
  1689.   (beginning-of-line nil)
  1690.   (if (re-search-backward
  1691.        (concat "^\\(" m3-com-start-re "\\|" m3-part-starters "\\)")
  1692.        (point-min) t)
  1693.       (progn
  1694.     (goto-char (match-beginning 0)))
  1695.     (goto-char (point-min))))
  1696.  
  1697. (defun m3-forward-to-code (max-point)
  1698.   "Sets the point at the first non-comment, non-whitespace character
  1699. following the current point, else at max-point."
  1700. ;;;  (message "m3-forward-to-code (1)") (sit-for 2)
  1701.   (let ((continue t))
  1702.     (while continue
  1703. ;;;      (message "m3-forward-to-code (1.5)") (sit-for 2)
  1704.       (setq continue
  1705.         (and (re-search-forward "[^ \t\n]" max-point 'move-to-limit)
  1706.          (progn (goto-char (match-beginning 0))
  1707. ;;;            (message "m3-forward-to-code (2)") (sit-for 2)
  1708.             (and (looking-at m3-com-start-re)
  1709.                  (m3-skip-comment-forward max-point t))))))))
  1710.  
  1711.  
  1712. (defun m3-backward-to-code (min-point)
  1713.   "Sets the point at the first non-comment, non-whitespace character
  1714. before the current point, else at end-of-file"
  1715.   (interactive "n")
  1716.   (let ((continue t))
  1717.     (while continue
  1718.       (if (re-search-backward "[^ \t\n][ \t\n]*" min-point t)
  1719.       (goto-char (match-beginning 0)))
  1720.       (setq continue (and (save-excursion
  1721.                 (and (> (point) 1)
  1722.                  (progn
  1723.                    (forward-char -1)
  1724.                    (looking-at m3-com-end-re))))
  1725.               (progn
  1726.                 (forward-char 1)
  1727.                 (m3-skip-comment-backward min-point t)))))
  1728.  
  1729.     t))
  1730.  
  1731. (defun m3-re-search-forward (re max-point fail)
  1732.   "Assumes we're not in a comment.  Puts point at the start of the
  1733. first occurence of RE that is not in a comment, if such an occurence
  1734. occurs before MAX-POINT, and returns non-nil.  Otherwise, returns nil
  1735. and leaves point unaffected.  Results are undefined if RE matches any
  1736. comment starter."
  1737.   (let ((continue t)
  1738.     (save-point (point))
  1739.     (res nil))
  1740.     (while continue
  1741.       (setq res (re-search-forward
  1742.           (concat "\\(" m3-com-start-re "\\|" re "\\)")
  1743.           max-point fail))
  1744.       (goto-char (match-beginning 0))
  1745.       (cond
  1746.        (res
  1747.     (cond
  1748.      ((looking-at m3-com-start-re)
  1749.       (m3-skip-comment-forward max-point fail))
  1750.      (t
  1751.       (setq continue nil))))
  1752.        (t
  1753.     (setq continue nil)
  1754.     (if (and (eq fail t) (not res))
  1755.         (goto-char save-point)))))
  1756.     res))
  1757.     
  1758.  
  1759. (defun m3-re-search-backward (re min-point fail)
  1760.   "Assumes we're not in a comment.  Puts point the start of the
  1761. first previous occurence of RE that is not in a comment, if such an occurence
  1762. occurs before MIN-POINT, and returns non-nil.  FAIL is interpreted as is third
  1763. argument to re-search.  Results are undefined if RE matches any comment
  1764. starter." 
  1765.   (let ((continue t)
  1766.     (save-point (point))
  1767.     (res nil))
  1768.     (while continue
  1769.       (setq res (re-search-backward
  1770.          (concat "\\(" m3-com-end-re "\\|" re "\\)") min-point fail))
  1771.       (cond
  1772.        (res
  1773.     (cond
  1774.      ((looking-at m3-com-end-re)
  1775.       (forward-char 2)
  1776.       (m3-skip-comment-backward min-point fail))
  1777.      (t
  1778.       (setq continue nil))))
  1779.        (t
  1780.     (setq continue nil)
  1781.     (if (and (eq fail t) (not res))
  1782.         (goto-char save-point)))))
  1783.     res))
  1784.  
  1785. (defun m3-skip-comment-forward (max-point fail)
  1786.   "Requires that point is at the start of a comment.  If that comment
  1787. is terminated before MAX-POINT, return t and leaves point after end of
  1788. the comment.  Otherwise, if fail is 't, returns returns nil and leaves
  1789. the point unchanged; if fail is nil raises an errer; if fail is not t or nil,
  1790. returns nil and leaves the point at max-point or (point-max), whichever is
  1791. smaller."
  1792.   (if (not (looking-at m3-com-start-re))
  1793.       (error
  1794.        "m3-skip-comment-forward should only be called when looking at
  1795. comment-starter"))
  1796.   (forward-char 2)
  1797.   (let ((save-point (point)) (continue t) res)
  1798.     (while continue
  1799. ;;;      (message "m3-comment-forward (0.5)") (sit-for 2)
  1800.       (setq res (re-search-forward m3-com-start-or-end-re max-point fail))
  1801.       (cond
  1802.        (res
  1803. ;;;    (message "m3-comment-forward (1)") (sit-for 2)
  1804.     (goto-char (match-beginning 0))
  1805. ;;;    (message "m3-comment-forward (2)") (sit-for 2)
  1806.     (cond
  1807.      ((looking-at m3-com-start-re)
  1808.       (if (not (m3-skip-comment-forward max-point fail))
  1809.           (progn (setq res nil)
  1810.              (setq continue nil))))
  1811.      ((looking-at m3-com-end-re)
  1812.       (goto-char (match-end 0))
  1813.       (setq continue nil))
  1814.      (t
  1815. ;;;      (message "m3-comment-forward (4)") (sit-for 2)
  1816.       (goto-char save-point)
  1817.       (setq res nil)
  1818.       (setq continue nil))))
  1819.        (t 
  1820. ;;;    (message "m3-comment-forward (5)") (sit-for 2)
  1821.     (goto-char save-point)
  1822.     (setq res nil)
  1823.     (setq continue nil))))
  1824.     res))
  1825.  
  1826.  
  1827. (defun m3-skip-comment-backward (min-point fail)
  1828.   "Requires that point is at the end of a comment.  If that comment
  1829. is terminated before MIN-POINT, return t and leaves point at the start
  1830. the comment.  Otherwise returns nil and leaves the point in an
  1831. unspecified position."
  1832.   (forward-char -2)
  1833.   (if (not (looking-at m3-com-end-re))
  1834.       (error
  1835.        "m3-skip-comment-backward should only be called when looking at
  1836. comment-ender"))
  1837.   (let ((save-point (point)) (continue t) res)
  1838.     (while continue
  1839.       (setq res (re-search-backward m3-com-start-or-end-re min-point fail))
  1840.       (cond
  1841.        (res
  1842.     (cond
  1843.      ((looking-at m3-com-end-re)
  1844.       (forward-char 2)
  1845.       (if (not (m3-skip-comment-backward min-point fail))
  1846.           (progn
  1847.         (setq res nil)
  1848.         (setq continue nil))))
  1849.      ((looking-at m3-com-start-re)
  1850.       (setq continue nil))
  1851.      (t
  1852.       (goto-char save-point)
  1853.       (setq res nil)
  1854.       (setq continue nil))))
  1855.        (t
  1856.     (goto-char save-point)
  1857.     (setq res nil)
  1858.     (setq continue nil))))
  1859.     res))
  1860.      
  1861. ;;;======================================================================
  1862. ;;; Electric END completion
  1863.  
  1864. (defun m3-do-electric-end ()
  1865. ;;;  (message "m3-do-electric-end") (sit-for 2)
  1866.   (let ((case-fold-search nil))
  1867.     (cond
  1868.      ((and (save-excursion
  1869.          (beginning-of-line)
  1870.          (looking-at "^[ \t]*END[ \t]*$"))
  1871.        (or m3-electric-end m3-blink-end-matchers))
  1872.       (let ((insert-point
  1873.          (save-excursion (beginning-of-line) (forward-word 1) (point)))
  1874.         (insert-string))
  1875. ;;;    (progn (message "m3-do-electric-end 2") (sit-for 2) t)
  1876.     (save-excursion
  1877.       (beginning-of-line)
  1878.       (and
  1879.        (m3-backward-to-end-match (point-min))
  1880.        (if m3-blink-end-matchers (sit-for 1) t)
  1881. ;;;       (progn (message "m3-do-electric-end 3") (sit-for 1) t)
  1882.        (progn
  1883.          (cond
  1884.           ;; Do nothing if we're not supposed to...
  1885.           ((not m3-electric-end))
  1886.           ;; If it's a begin, what is it the begin of?
  1887.           ((looking-at "BEGIN")
  1888.            (cond
  1889.         ;; If it's on the left margin, it must be a module.
  1890.         ((looking-at "^BEGIN")
  1891.          (goto-char (point-min))
  1892.          (and
  1893.           (re-search-forward "MODULE\\|INTERFACE" (point-max) t)
  1894.           (progn
  1895.             (goto-char (match-end 0))
  1896.             (forward-word 1)
  1897.             (setq insert-string
  1898.               (concat
  1899.                (buffer-substring
  1900.                 (save-excursion (forward-word -1) (point))
  1901.                 (point))
  1902.                ".")))))
  1903.         ;; Is it the body of a procedure?
  1904.         ((and
  1905. ;;;        (progn (message "m3-do-electric-end PROC 1") (sit-for 2) t)
  1906.           (m3-re-search-backward "BEGIN\\|PROCEDURE" (point-min) t)
  1907.           (looking-at "PROCEDURE"))
  1908. ;;;           (progn (message "m3-do-electric-end PROC 2") (sit-for 2) t)
  1909.          (forward-word 2)
  1910.          (setq insert-string
  1911.                (concat
  1912.             (buffer-substring
  1913.              (save-excursion (forward-word -1) (point))
  1914.              (point))
  1915.             ";")))
  1916.         ;; Otherwise, it is just a random BEGIN, so
  1917.         ;; m3-electric-end must be 'all.
  1918.         ((eq m3-electric-end 'all)
  1919.          (setq insert-string "(* BEGIN *)"))))
  1920.  
  1921.           ((looking-at "INTERFACE\\|MODULE")
  1922.            (forward-word 2)
  1923.            (setq insert-string
  1924.              (concat
  1925.               (buffer-substring
  1926.                (save-excursion (forward-word -1) (point))
  1927.                (point))
  1928.               ".")))
  1929.  
  1930.           ;; Otherwise, m3-electric-end must be 'all.
  1931.           ((eq m3-electric-end 'all)
  1932. ;;;           (progn (message "m3-do-electric-end non-BEGIN") (sit-for 2) t)
  1933.            (setq insert-string
  1934.              (concat "(* "
  1935.                  (buffer-substring
  1936.                   (point)
  1937.                   (save-excursion (forward-word 1) (point)))
  1938.                  " *)")))))))
  1939.  
  1940.     (and
  1941.      insert-string
  1942.      (progn
  1943.        (goto-char insert-point)
  1944.        ;; If we completed an END and then added something, include
  1945.        ;; the something in the completion...
  1946.        (if (and (marker-position m3-cur-keyword-completion-start)
  1947.             (= insert-point
  1948.                (+ m3-cur-keyword-completion-start
  1949.               m3-cur-keyword-completion-len)))
  1950.            (setq m3-cur-keyword-completion-len
  1951.              (+ m3-cur-keyword-completion-len 1
  1952.             (length insert-string))))
  1953.        (insert " " insert-string))))))))
  1954.  
  1955.         
  1956.  
  1957. ;
  1958. ;  COMMENTS
  1959. ;
  1960.  
  1961. (defun m3-begin-comment ()
  1962.   "Indent to start comment column and then start Modula 3 comment."
  1963.   (interactive)
  1964.   (if (not (bolp))
  1965.       (indent-to comment-column 0))
  1966.   (insert "(*  "))
  1967.  
  1968. (defun m3-end-comment ()
  1969.   "Indent to end comment column and then end Modula 3 comment."
  1970.   (interactive)
  1971.   (if (not (bolp))
  1972.       (indent-to end-comment-column))
  1973.   (insert "*)\n"))
  1974.  
  1975. (defun m3-banner ()
  1976.   "Insert a comment line suitable for marking the start of a big comment."
  1977.   (insert "(***************************************************************************)\n"))
  1978.  
  1979. ;
  1980. ; STATEMENTS, DECLARATIONS AND KEYWORDS
  1981. ;
  1982.  
  1983. (defun m3-array ()
  1984.   "Insert ARRAY, prompt for index type then finish with OF."
  1985.   (interactive)
  1986.   (insert "ARRAY ")
  1987.   (insert (read-string "Index type: "))
  1988.   (insert " OF "))
  1989.  
  1990. (defun m3-case ()
  1991.   "Build skeleton CASE statement, prompting for the expression and first label(s)."
  1992.   (interactive)
  1993.   (insert "CASE ")
  1994.   (insert (read-string "Case expression: ") " OF")
  1995.   (m3-newline)
  1996.   (insert "| ")
  1997.   (insert (read-string "First case label(s): ") " =>")
  1998.   (m3-newline)
  1999.   (m3-newline)
  2000.   (insert "END; (* case *)")
  2001.   (end-of-line 0)
  2002.   (m3-tab)
  2003.   (m3-tab))
  2004.  
  2005. (defun m3-const ()
  2006.   "Insert CONST then newline and tab."
  2007.   (interactive)
  2008.   (insert "CONST")
  2009.   (m3-newline)
  2010.   (m3-tab))
  2011.  
  2012. (defun m3-declare ()
  2013.   "Insert a Modula 3 declaration; prompt the user for declaration type."
  2014.   (interactive)
  2015.   (message "Var (default), Const, Type, Exception or Procedure")
  2016.   (let ((choice (read-char)))
  2017.     (if (char-equal ?c choice) (m3-const)
  2018.       (if (char-equal ?t choice) (m3-type)
  2019.         (if (char-equal ?e choice) (m3-exception)
  2020.           (if (char-equal ?p choice) (m3-procedure) (m3-var)))))))
  2021.  
  2022. (defun m3-except ()
  2023.   "Insert EXCEPT clause of a TRY statement."
  2024.   (interactive)
  2025.   (insert "EXCEPT")
  2026.   (m3-newline)
  2027.   (m3-newline)
  2028.   (insert "END; (* try *)")
  2029.   (end-of-line -2)
  2030.   (m3-tab))
  2031.  
  2032. (defun m3-exception ()
  2033.   "Insert EXCEPTION then newline and tab."
  2034.   (interactive)
  2035.   (insert "EXCEPTION")
  2036.   (m3-newline)
  2037.   (m3-tab))
  2038.  
  2039. (defun m3-else ()
  2040.   "Insert ELSE or ELSIF keyword and indent for next line."
  2041.   (interactive)
  2042.   (m3-newline)
  2043.   (backward-delete-char-untabify m3-indent ())
  2044.   (message "elsE (default) or elsIf")
  2045.   (if (not (char-equal ?i (read-char))) (insert "ELSE")
  2046.     (insert "ELSIF ")
  2047.     (insert (read-string "Elsif expression: "))
  2048.     (insert " THEN"))
  2049.   (m3-newline)
  2050.   (m3-tab))
  2051.  
  2052. (defun m3-finally ()
  2053.   "Insert FINALLY clause of a TRY statement."
  2054.   (interactive)
  2055.   (insert "FINALLY")
  2056.   (m3-newline)
  2057.   (m3-tab)
  2058.   (m3-newline)
  2059.   (backward-delete-char-untabify m3-indent ())
  2060.   (insert "END; (* try *)")
  2061.   (end-of-line -2)
  2062.   (m3-tab))
  2063.  
  2064. (defun m3-for ()
  2065.   "Build skeleton FOR loop statement, prompting for the loop parameters."
  2066.   (interactive)
  2067.   (insert "FOR ")
  2068.   (insert (read-string "For: ") " TO ")
  2069.   (insert (read-string "To: "))
  2070.   (let ((by (read-string "By: ")))
  2071.     (if (not (string-equal by ""))
  2072.     (insert " BY " by)))
  2073.   (insert " DO")
  2074.   (m3-newline)
  2075.   (m3-newline)
  2076.   (insert "END; (* for *)")
  2077.   (end-of-line 0)
  2078.   (m3-tab))
  2079.  
  2080. (defun m3-if ()
  2081.   "Insert skeleton IF statement, prompting for the expression."
  2082.   (interactive)
  2083.   (insert "IF ")
  2084.   (insert (read-string "If expression: ") " THEN")
  2085.   (m3-newline)
  2086.   (m3-newline)
  2087.   (insert "END; (* if *)")
  2088.   (end-of-line 0)
  2089.   (m3-tab))
  2090.  
  2091. (defun m3-loop-or-lock ()
  2092.   "Insert LOOP or LOCK statement; prompt user to decide which."
  2093.   (interactive)
  2094.   (message "looP (default) or locK")
  2095.   (if (char-equal ?k (read-char)) (m3-lock) (m3-loop)))
  2096.  
  2097. (defun m3-loop ()
  2098.   "Build skeleton LOOP (with END)."
  2099.   (interactive)
  2100.   (insert "LOOP")
  2101.   (m3-newline)
  2102.   (m3-newline)
  2103.   (insert "END; (* loop *)")
  2104.   (end-of-line 0)
  2105.   (m3-tab))
  2106.  
  2107. (defun m3-lock ()
  2108.   "Build skeleton LOCK (with END)."
  2109.   (interactive)
  2110.   (insert "LOCK ")
  2111.   (insert (read-string "Lock mutex: ") " DO")
  2112.   (m3-newline)
  2113.   (m3-newline)
  2114.   (insert "END; (* lock *)")
  2115.   (end-of-line 0)
  2116.   (m3-tab))
  2117.  
  2118. (defun m3-module-type ()
  2119.   "Returns char describing module type deduced from buffername and user input."
  2120.   (interactive)
  2121.   (if (m3-is-def) ?i ?m))
  2122.  
  2123. (defun m3-choose-module ()
  2124.   "Build skeleton MODULE, decide module type from buffername and user input."
  2125.   (interactive)
  2126.   (m3-module (m3-module-type)))
  2127.  
  2128. (defun m3-choose-module-name ()
  2129.   "Prompt user for module name; if user returns null use buffer name."
  2130.   (let ((name (read-string "Module name (default is buffer name): ")))
  2131.     (if (string-equal name "")
  2132.       (m3-strip-extension (buffer-name))
  2133.       name)))
  2134.  
  2135. (defun m3-module (type)
  2136.   "Build skeleton MODULE, prompting for module name."
  2137.   (interactive)
  2138.   (if (char-equal type ?i) (insert "INTERFACE ")
  2139.     (if (char-equal type ?m) (insert "MODULE ") ()))
  2140.   (let ((name (m3-choose-module-name)) (args ""))
  2141.     (insert name)
  2142.     (if (char-equal type ?m) 
  2143.         (setq args (read-string "Exports list (default is empty): "))
  2144.         ())
  2145.     (if (not (string-equal args ""))
  2146.     (insert " EXPORTS " args))
  2147.     (insert ";\n\n")
  2148.     (m3-banner)
  2149.     (insert "(*   Author:  " (user-full-name))
  2150.     (m3-end-comment)
  2151.     (m3-banner)
  2152.     (insert "\n(* $Rev")                ; split into two so RCS can't find it!
  2153.     (insert "ision$ *)\n")
  2154.     (insert "\n\n\n")
  2155.     (if (char-equal type ?m)
  2156.         (insert "BEGIN\n\nEND " name ".\n")
  2157.         (insert "END " name ".\n"))
  2158.     (if (char-equal type ?m)
  2159.          (previous-line 5)
  2160.          (previous-line 3))
  2161.     ))
  2162.  
  2163. (defun m3-next-case ()
  2164.   "Move on to next arm of a CASE or TYPECASE statement."
  2165.   (interactive)
  2166.   (m3-newline)
  2167.   (backward-delete-char-untabify m3-indent)
  2168.   (backward-delete-char-untabify m3-indent)
  2169.   (let* ((label (read-string "Case label(s): "))
  2170.       (not-else (not (string-equal "ELSE" label))))
  2171.     (if not-else (insert "| "))
  2172.     (insert label)
  2173.     (if not-else (insert " =>"))
  2174.     (m3-newline)
  2175.     (m3-tab)
  2176.     (if not-else (m3-tab))))
  2177.  
  2178. (defun m3-object ()
  2179.   "Insert a skeleton OBJECT."
  2180.   (interactive)
  2181.   (insert "OBJECT")
  2182.   (m3-newline)
  2183.   (m3-newline)
  2184.   (insert "METHODS")
  2185.   (m3-newline)
  2186.   (insert "END; (* object *)")
  2187.   (end-of-line -1)
  2188.   (m3-tab))
  2189.  
  2190. (defun m3-procedure ()
  2191.   "Build a skeleton PROCEDURE declaration, prompting the user as necessary."
  2192.   (interactive)
  2193.   (insert "PROCEDURE ")
  2194.   (let ((name (read-string "Procedure name: " ))
  2195.     args)
  2196.     (insert name "(")
  2197.     (insert (read-string "Procedure arguments: ") ")")
  2198.     (setq args (read-string "Procedure result type: "))
  2199.     (if (not (string-equal args ""))
  2200.     (insert ": " args))
  2201.     (setq args (read-string "Procedure raises list (or ANY): "))
  2202.     (if (not (string-equal args "ANY"))
  2203.     (insert " RAISES {" args "}"))
  2204.     (if (m3-is-def) (insert ";") (insert "="))
  2205.     (m3-newline)
  2206.     (if (m3-is-def) ()
  2207.       (m3-tab)
  2208.       (insert "BEGIN")
  2209.       (m3-newline)
  2210.       (m3-newline)
  2211.       (insert "END ")
  2212.       (insert name)
  2213.       (insert ";\n\n")
  2214.       (end-of-line -2)
  2215.       (m3-tab))))
  2216.  
  2217.  
  2218. (defun m3-block ()
  2219.   "Insert a skeleton block"
  2220.   (interactive)
  2221.   (insert "BEGIN")
  2222.   (m3-newline)
  2223.   (m3-newline)
  2224.   (insert "END;")
  2225.   (end-of-line 0)
  2226.   (m3-tab))
  2227.  
  2228. (defun m3-record ()
  2229.   "Insert a skeleton RECORD."
  2230.   (interactive)
  2231.   (insert "RECORD")
  2232.   (m3-newline)
  2233.   (m3-newline)
  2234.   (insert "END; (* record *)")
  2235.   (end-of-line 0)
  2236.   (m3-tab))
  2237.  
  2238. (defun m3-type ()
  2239.   "Insert TYPE then newline and tab."
  2240.   (interactive)
  2241.   (insert "TYPE")
  2242.   (m3-newline)
  2243.   (m3-tab))
  2244.  
  2245. (defun m3-try-or-typecase ()
  2246.   "Insert a TRY or TYPECASE statement; prompt the user to decide which."
  2247.   (interactive)
  2248.   (message  "tRy (default) or tYpecase")
  2249.   (if (char-equal ?y (read-char)) (m3-typecase) (m3-try)))
  2250.  
  2251. (defun m3-try ()
  2252.   "Build TRY statement, prompting to see if it is the EXCEPT or FINALLY form."
  2253.   (interactive)
  2254.   (insert "TRY")
  2255.   (m3-newline)
  2256.   (m3-newline)
  2257.   (message  "Except (default) or Finally")
  2258.   (if (char-equal ?f (read-char)) (m3-finally) (m3-except)))
  2259.  
  2260. (defun m3-typecase ()
  2261.   "Build skeleton TYPECASE statement, prompting for the expression and first labels."
  2262.   (interactive)
  2263.   (insert "TYPECASE ")
  2264.   (insert (read-string "Typecase expression: ") " OF")
  2265.   (m3-newline)
  2266.   (insert "| " (read-string "First typecase label(s): ") " =>")
  2267.   (m3-newline)
  2268.   (m3-newline)
  2269.   (insert "END; (* typecase *)")
  2270.   (end-of-line 0)
  2271.   (m3-tab)
  2272.   (m3-tab))
  2273.  
  2274. (defun m3-until ()
  2275.   "Insert a skeleton REPEAT loop, prompting the user for the final expression."
  2276.   (interactive)
  2277.   (insert "REPEAT")
  2278.   (m3-newline)
  2279.   (m3-newline)
  2280.   (insert "UNTIL ")
  2281.   (insert (read-string "Until expression: ") ";")
  2282.   (end-of-line 0)
  2283.   (m3-tab))
  2284.  
  2285. (defun m3-var ()
  2286.   "Insert VAR then newline and tab."
  2287.   (insert "VAR")
  2288.   (m3-newline)
  2289.   (m3-tab))
  2290.  
  2291. (defun m3-while-or-with ()
  2292.   "Insert WHILE or WITH statement; prompt user to decide which."
  2293.   (interactive)
  2294.   (message  "wHile (default) or wIth")
  2295.   (if (char-equal ?i (read-char)) (m3-with) (m3-while)))
  2296.  
  2297. (defun m3-while ()
  2298.   "Insert skeleton WHILE statement; prompt user for while expression."
  2299.   (interactive)
  2300.   (insert "WHILE ")
  2301.   (insert (read-string "While expression: "))
  2302.   (insert " DO")
  2303.   (m3-newline)
  2304.   (m3-newline)
  2305.   (insert "END; (* while *)")
  2306.   (end-of-line 0)
  2307.   (m3-tab))
  2308.  
  2309. (defun m3-with ()
  2310.   "Insert skeleton WITH statement; prompt user for WITH bindings."
  2311.   (interactive)
  2312.   (insert "WITH ")
  2313.   (insert (read-string "With bindings: "))
  2314.   (insert " DO")
  2315.   (m3-newline)
  2316.   (m3-newline)
  2317.   (insert "END; (* with *)")
  2318.   (end-of-line 0)
  2319.   (m3-tab))
  2320.  
  2321. (defun m3-import ()
  2322.   "Insert FROM ... IMPORT statement, prompting user for module."
  2323.   (interactive)
  2324.   (insert "FROM ")
  2325.   (insert (read-string "Import from module: "))
  2326.   (insert " IMPORT "))
  2327.  
  2328. ;
  2329. ;  COMMANDS
  2330. ;
  2331.  
  2332. (defun m3-compile ()
  2333.   "call m3c, argument is modulename derived from current buffer name."
  2334.   (interactive)
  2335.   (if (m3-is-oli)
  2336.     (compile (concat "m3c -g " 
  2337.                    (if (m3-is-def) "-i " "-m ") 
  2338.                    (m3-strip-extension (buffer-name))))
  2339. ; else
  2340.     (compile (concat "m3 -c -g " (m3-strip-bufnum (buffer-name)))))
  2341. )
  2342.  
  2343. (defun m3-is-oli ()
  2344.   (or (string-equal (m3-get-extension (buffer-name)) ".i")
  2345.       (string-equal (m3-get-extension (buffer-name)) ".m"))) 
  2346.  
  2347. (defun m3-position-of-end-of-line ()
  2348.   "Returns position of end of line"
  2349.   (save-excursion
  2350.     (end-of-line)
  2351.     (point)))
  2352.  
  2353. (defun m3-match-regexp-here (regexp)
  2354.   "Tries to match regexp at current position and before end of line"
  2355.   (let ((save-point (point)))
  2356.     (if (and (re-search-forward regexp (m3-position-of-end-of-line) t)
  2357.         (= (match-beginning 0) save-point))
  2358.       t
  2359.       (goto-char save-point)
  2360.       nil)))
  2361.  
  2362. (defun m3-multi-to-single-line-proc-header ()
  2363.   "Convert multi line proc header to single line; do not call this directly"
  2364.   (backward-char)
  2365.   (let ((start-of-signature (point)))
  2366.     (forward-list)
  2367.     (re-search-forward "[=;]")
  2368.     (save-restriction
  2369.       (narrow-to-region start-of-signature (point))
  2370.       (goto-char (point-min))
  2371.       (save-excursion
  2372.         (replace-regexp "[ \t\n]+" " "))
  2373.       (save-excursion
  2374.         (replace-string "( " "("))
  2375.       (save-excursion
  2376.         (replace-string ") :" "):")))))
  2377.  
  2378. (defun m3-single-to-multi-line-proc-header ()
  2379.   "Convert multi line proc header to single line; do not call this directly"
  2380.   (backward-char)
  2381.   (let ((start-of-signature (point)))
  2382.     (forward-list)
  2383.     (re-search-forward "[=;]")
  2384.     (save-restriction
  2385.       (narrow-to-region start-of-signature (point))
  2386.       (goto-char (point-min))
  2387.       (save-excursion
  2388.         (replace-string " RAISES" "\n    RAISES"))
  2389.       (save-excursion
  2390.         (replace-regexp "\\([^*]\\)) ?:" "\\1)\n    :"))
  2391.       (save-excursion
  2392.         (replace-string "; " ";\n    "))
  2393.       (forward-char)
  2394.       (insert "\n    "))))
  2395.  
  2396. (defun m3-convert-proc-header ()
  2397.   "Convert single line <-> multi line proc header"
  2398.   (interactive)
  2399.   (beginning-of-line)
  2400.   (let ((old-cfs case-fold-search))
  2401.     (setq case-fold-search nil)
  2402.     (save-excursion
  2403.       (if (not (m3-match-regexp-here "\\(INLINE \\|\\) *PROCEDURE *[A-Za-z0-9_]+ *("))
  2404.         (message "Must be on first line of procedure header")
  2405.         (while (or (= (following-char) ? ) (= (following-char) ?\t))
  2406.           (delete-char 1))
  2407.         (if (or (= (following-char) ?\n) (= (following-char) ?\r))
  2408.           (m3-multi-to-single-line-proc-header)
  2409.           (m3-single-to-multi-line-proc-header))))
  2410.     (setq case-fold-search old-cfs)))
  2411.  
  2412. (defun m3-search-path-line (name)
  2413. "Appends given name to current line and sees if result is a file name.
  2414. Returns either nil or the file name."
  2415.   (let ((old-point (point)))
  2416.     (if (not (search-forward "\n" nil t))
  2417.       nil
  2418.     ; else
  2419.       (let* ((dir-name 
  2420.               (m3-filename-expand (buffer-substring old-point (- (point) 1))))
  2421.              (try (if (string= dir-name "") name (concat dir-name "/" name))))
  2422.         (if (file-exists-p try) try (m3-search-path-line name))))))
  2423.  
  2424. (defun m3-filename-expand (name)
  2425.  (let ((pos 0)
  2426.        (spos 0)
  2427.        (epos 0)
  2428.        (res nil)
  2429.        )
  2430.    (while (string-match "\\$(" name pos)
  2431.      (setq spos (match-beginning 0))
  2432.      (setq res (concat res (substring name pos spos)))
  2433.      (setq epos (string-match ")" name spos))
  2434.      (setq res (concat res (getenv (substring name (+ 2 spos) epos))))
  2435.      (setq pos (1+ epos))
  2436.    )
  2437.    (setq res (concat res (substring name pos)))
  2438.  )
  2439. )
  2440.  
  2441. (defun m3-strip-extension (name)
  2442. "Strips .ext from the given string (where ext is any extension)"
  2443.   (let ((dot-pos (string-match "\\." name)))
  2444.     (if dot-pos (substring name 0 dot-pos) name)))
  2445.  
  2446. (defun m3-strip-bufnum (name)
  2447. "Strips any <n> from the given string"
  2448.   (let ((dot-pos (string-match "<" name)))
  2449.     (if dot-pos (substring name dot-pos nil) name)))
  2450.  
  2451. (defun m3-get-extension (name)
  2452. "Gets .ext from the given string (where ext is any extension)"
  2453.   (let ((dot-pos (string-match "\\." name)))
  2454.     (if dot-pos 
  2455.       (let ((ext (substring name dot-pos nil)) ext_pos)
  2456.            (setq ext-pos (string-match "<" ext))
  2457.        (if ext-pos (substring ext 0 ext-pos) ext))
  2458.     ; else nil
  2459.     )
  2460.   )
  2461. )
  2462.  
  2463. (defun m3-search-path (name path-file extension)
  2464. "Uses path file to return full file name for given name and extension.
  2465. Arguments are NAME - the file name to search for. PATHFILE - a string which is
  2466. the name of a file containing newline separated directory names. The third
  2467. argument is EXTENSION - a string. Takes NAME, extends it by EXTENSION then
  2468. appends it to each directory given in PATHFILE until the name of an existing
  2469. file is obtained. Then returns the full file name."
  2470.   (save-excursion
  2471.       (set-buffer (generate-new-buffer (concat "*" path-file "*")))
  2472.       (delete-region (point-min) (point-max))
  2473.       (let ((old-point-max (point-max))
  2474.             (full-name (concat (m3-strip-extension name) "." extension)))
  2475.         (goto-char old-point-max)
  2476.         (if (file-readable-p path-file)
  2477.           (call-process "cat" path-file t))
  2478.         (if (= (point-max) old-point-max)
  2479.            (if (file-exists-p name) full-name nil)
  2480.         ; else
  2481.            (goto-char old-point-max)
  2482.            (m3-search-path-line full-name)))))
  2483.  
  2484. (defun m3-path-find-named-file (name path-file extension)
  2485. "Uses path file to search and open file with given name and extension.
  2486. Arguments are NAME - the file name to search for. PATHFILE - a string which is
  2487. the name of a file containing newline separated directory names. The third
  2488. argument is EXTENSION - a string. Takes NAME, extends it by EXTENSION then
  2489. appends it to each directory given in PATHFILE until the name of an existing
  2490. file is obtained.  Then opens the file in the other window."
  2491.   (let ((file-name (m3-search-path name path-file extension)))
  2492.     (if file-name (find-file-other-window file-name))))
  2493.  
  2494. (defun m3-whole-prev-word ()
  2495. "Return word under or previous to point as a string"
  2496.   (buffer-substring
  2497.     (save-excursion (backward-word 1) (point))
  2498.     (save-excursion (backward-word 1) (forward-word 1) (point))))
  2499.  
  2500. (defun m3-find-file-on-path (path-file extension)
  2501. "Uses path file to search and open file named by current word and extension.
  2502. Arguments are PATHFILE - a string which is the name of a file containing
  2503. newline separated directory names. The second argument is EXTENSION - a string.
  2504. Takes the word under point, extends it by EXTENSION then appends it to each
  2505. directory given in PATHFILE until the name of an existing file is obtained.
  2506. Then opens the file in the other window."
  2507.   (m3-path-find-named-file (m3-whole-prev-word) path-file extension))
  2508.  
  2509. (defun m3-path-find-file ()
  2510. "Visit interface corresponding to name currently under point. Looks down 
  2511. the m3path so it doesn't work unless all sources are on the m3path."
  2512.   (interactive)
  2513.   (if (m3-is-oli)
  2514.          (m3-find-file-on-path "m3path" "i")
  2515. ; else
  2516.          (m3-find-file-on-path "m3path" "i3")))
  2517.  
  2518. ;(defun execute-monitor-command (command)
  2519. ;  (let* ((shell shell-file-name)
  2520. ;     (csh (equal (file-name-nondirectory shell) "csh")))
  2521. ;    (call-process shell nil t t "-cf" (concat "exec " command))))
  2522.  
  2523. (defun m3-toggle-buffer ()
  2524.   "Toggle between .i/.i3 and .m/.m3 files for the module."
  2525.   (interactive)
  2526.   (cond ((string-equal (m3-get-extension (buffer-name)) ".i")
  2527.      (find-file-other-window
  2528.        (concat (m3-strip-extension (buffer-name)) ".m")))
  2529.     ((string-equal (m3-get-extension (buffer-name)) ".i3")
  2530.      (find-file-other-window
  2531.        (concat (m3-strip-extension (buffer-name)) ".m3")))
  2532.     ((string-equal (m3-get-extension (buffer-name)) ".m")
  2533.      (find-file-other-window
  2534.        (concat (m3-strip-extension (buffer-name))  ".i")))
  2535.         ((string-equal (m3-get-extension (buffer-name)) ".m3")
  2536.      (find-file-other-window
  2537.        (concat (m3-strip-extension (buffer-name))  ".i3")))))
  2538.  
  2539. ;
  2540. ; PSEUDO ABBREV MODE
  2541. ;
  2542.  
  2543. (defvar m3-abbrev-enabled 'aggressive
  2544.   "*Values are nil, 'aggressive, and 'polite, indicating no abbrev
  2545. completion, aggressive and polite abbrev mode, respectively.")
  2546.  
  2547. ;;;(setq m3-abbrev-enabled 'polite)
  2548.  
  2549.  
  2550. (defvar m3-electric-end nil
  2551.   "*Values are nil -- do nothing; 'proc-mod -- match name of procedure or
  2552. module; 'all -- proc-mod + add comment for others.")
  2553.  
  2554. (defvar m3-blink-end-matchers nil)
  2555.  
  2556. ;;;(setq m3-electric-end 'all)
  2557. ;;;(setq m3-blink-end-matchers 't)
  2558.  
  2559.  
  2560. (defun m3-toggle-abbrev ()
  2561.   "Toggle the flag enabling/disabling Modula 3 pseudo abbrev mode."
  2562.   (interactive)
  2563.   (cond
  2564.    ((eq m3-abbrev-enabled 'aggressive)
  2565.     (setq m3-abbrev-enabled nil))
  2566.    ((eq m3-abbrev-enabled 'polite)
  2567.     (setq m3-abbrev-enabled 'aggressive))
  2568.    ((eq m3-abbrev-enabled nil)
  2569.     (setq m3-abbrev-enabled 'polite)))
  2570.   (message "Set m3-abbrev style to %s." m3-abbrev-enabled))
  2571.  
  2572. (defun m3-prev-word ()
  2573.   "returns last word in buffer."
  2574.   (buffer-substring (point) (save-excursion (backward-word 1) (point))))
  2575.  
  2576. (defun m3-is-abbrev (keyword word)
  2577.   "Returns non-nil if WORD is abbreviation of given KEYWORD."
  2578.   (if (> (length word) (length keyword)) ()
  2579.     (string-equal (substring keyword 0 (length word)) (upcase word))))
  2580.  
  2581.  
  2582. (defun m3-is-prefix (word prefix &optional no-upper)
  2583.   "returns non-nil if PREFIX is a (non-proper) prefix of WORD."
  2584.   (let ((uword (if no-upper word (upcase word)))
  2585.     (uprefix (if no-upper prefix (upcase prefix))))
  2586.     (if (> (length prefix) (length word)) nil
  2587.       (string-equal (substring uword 0 (length prefix)) uprefix))))
  2588.  
  2589.  
  2590. (defun m3-if-abbrev-kill-prev (keyword word)
  2591.   "checks if word is abbreviation of keyword; if so deletes last word
  2592. in buffer." 
  2593.   (if (not (m3-is-abbrev keyword word)) ()
  2594.     (forward-word -1)
  2595.     (delete-region (point) (save-excursion (forward-word 1) (point)))
  2596.     t))
  2597.          
  2598.  
  2599. (defun m3-abbrev ()
  2600.   "call appropriate m3-function depending on value of last word in buffer."
  2601.   (let ((pw (m3-prev-word)))
  2602.     ;; Must split this in two because it's so big (or else elisp
  2603.     ;; can't handle it.)
  2604.     (cond 
  2605.      ((eq m3-abbrev-enabled 'aggressive)
  2606.       (or (m3-aggressive-abbrev-1 pw)
  2607.       (m3-aggressive-abbrev-2 pw)))
  2608.      (t ;; "polite"
  2609.       (m3-polite-abbrev pw)))))
  2610.       
  2611.  
  2612. (defun m3-aggressive-abbrev-1 (pw)
  2613.   (cond
  2614.    ((m3-if-abbrev-kill-prev "ABS" pw) (insert "ABS") t)
  2615.    ((m3-if-abbrev-kill-prev "ADDRESS" pw) (insert "ADDRESS") t)
  2616.    ((m3-if-abbrev-kill-prev "ADR" pw) (insert "ADR") t)
  2617.    ((m3-if-abbrev-kill-prev "ADRSIZE" pw) (insert "ADRSIZE") t)
  2618.    ((m3-if-abbrev-kill-prev "AND" pw) (insert "AND ") t)
  2619.    ((m3-if-abbrev-kill-prev "BEGIN" pw) (insert "BEGIN") t)
  2620.    ((m3-if-abbrev-kill-prev "BITS" pw) (insert "BITS ") t)
  2621.    ((m3-if-abbrev-kill-prev "BITSIZE" pw) (insert "BITSIZE") t)
  2622.    ((m3-if-abbrev-kill-prev "BOOLEAN" pw) (insert "BOOLEAN") t)
  2623.    ((m3-if-abbrev-kill-prev "BRANDED" pw) (insert "BRANDED") t)
  2624.    ((m3-if-abbrev-kill-prev "BY" pw) (insert "BY") t)
  2625.    ((m3-if-abbrev-kill-prev "BYTESIZE" pw) (insert "BYTESIZE") t)
  2626.    ((m3-if-abbrev-kill-prev "CARDINAL" pw) (insert "CARDINAL") t)
  2627.    ((m3-if-abbrev-kill-prev "CEILING" pw) (insert "CEILING") t)
  2628.    ((m3-if-abbrev-kill-prev "CHAR" pw) (insert "CHAR") t)
  2629.    ((m3-if-abbrev-kill-prev "DEC" pw) (insert "DEC") t)
  2630.    ((m3-if-abbrev-kill-prev "DISPOSE" pw) (insert "DISPOSE") t)
  2631.    ((m3-if-abbrev-kill-prev "DIV" pw) (insert "DIV ") t)
  2632.    ((m3-if-abbrev-kill-prev "DO" pw) (insert "DO ") t)
  2633.    ((m3-if-abbrev-kill-prev "ELSIF" pw) (insert "ELSIF") t)
  2634.    ((m3-if-abbrev-kill-prev "END" pw) (insert "END") t)
  2635.    ((m3-if-abbrev-kill-prev "EVAL" pw) (insert "EVAL") t)
  2636.    ((m3-if-abbrev-kill-prev "EXCEPT" pw) (insert "EXCEPT") t)
  2637.    ((m3-if-abbrev-kill-prev "EXIT" pw) (insert "EXIT") t)
  2638.    ((m3-if-abbrev-kill-prev "EXPORTS" pw) (insert "EXPORTS ") t)
  2639.    ((m3-if-abbrev-kill-prev "FALSE" pw) (insert "FALSE") t)
  2640.    ((m3-if-abbrev-kill-prev "FINALLY" pw) (insert "FINALLY") t)
  2641.    ((m3-if-abbrev-kill-prev "FIRST" pw) (insert "FIRST") t)
  2642.    ((m3-if-abbrev-kill-prev "FLOAT" pw) (insert "FLOAT") t)
  2643.    ((m3-if-abbrev-kill-prev "FLOOR" pw) (insert "FLOOR") t)
  2644.    ((m3-if-abbrev-kill-prev "IMPORT" pw) (insert "IMPORT ") t)
  2645.    ((m3-if-abbrev-kill-prev "IN" pw) (insert "IN") t)
  2646.    ((m3-if-abbrev-kill-prev "INC" pw) (insert "INC") t)
  2647.    ((m3-if-abbrev-kill-prev "INLINE" pw) (insert "INLINE") t)
  2648.    ((m3-if-abbrev-kill-prev "INTEGER" pw) (insert "INTEGER") t)
  2649.    ((m3-if-abbrev-kill-prev "LAST" pw) (insert "LAST") t)
  2650.    ((m3-if-abbrev-kill-prev "LONGFLOAT" pw) (insert "LONGFLOAT") t)
  2651.    ((m3-if-abbrev-kill-prev "LONGREAL" pw) (insert "LONGREAL") t)
  2652.    ((m3-if-abbrev-kill-prev "LOOPHOLE" pw) (insert "LOOPHOLE") t)
  2653.    ((m3-if-abbrev-kill-prev "MAX" pw) (insert "MAX") t)
  2654.    ((m3-if-abbrev-kill-prev "METHODS" pw) (insert "METHODS") t)
  2655.    ((m3-if-abbrev-kill-prev "MIN" pw) (insert "MIN") t)
  2656.    ((m3-if-abbrev-kill-prev "MOD" pw) (insert "MOD") t)
  2657.  
  2658.    ;; These may be either "aggressive" or "polite".
  2659.    ((m3-if-abbrev-kill-prev "ARRAY" pw) (m3-array) t)
  2660.    ((m3-if-abbrev-kill-prev "CASE" pw) (m3-case) t)
  2661.    ((m3-if-abbrev-kill-prev "CONST" pw) (m3-const) t)
  2662.    ((m3-if-abbrev-kill-prev "ELSE" pw) (m3-else) t)
  2663.    ((m3-if-abbrev-kill-prev "FOR" pw) (m3-for) t)
  2664.    ((m3-if-abbrev-kill-prev "FROM" pw) (m3-import) t)
  2665.    ((m3-if-abbrev-kill-prev "IF" pw) (m3-if) t)
  2666.    ((m3-if-abbrev-kill-prev "LOCK" pw) (m3-lock) t)
  2667.    ((m3-if-abbrev-kill-prev "LOOP" pw) (m3-loop) t)
  2668.    ((m3-if-abbrev-kill-prev "INTERFACE" pw) (m3-module ?i) t)
  2669.    ((m3-if-abbrev-kill-prev "MODULE" pw) (m3-module ?m) t)
  2670.    ((m3-if-abbrev-kill-prev "EXCEPTION" pw) (m3-exception) t)
  2671.    (t nil)))
  2672.  
  2673.  
  2674. (defun m3-aggressive-abbrev-2 (pw)
  2675.   (cond
  2676.    ((m3-if-abbrev-kill-prev "NARROW" pw) (insert "NARROW") t)
  2677.    ((m3-if-abbrev-kill-prev "NEW" pw) (insert "NEW") t)
  2678.    ((m3-if-abbrev-kill-prev "NIL" pw) (insert "NIL") t)
  2679.    ((m3-if-abbrev-kill-prev "NULL" pw) (insert "NULL") t)
  2680.    ((m3-if-abbrev-kill-prev "NUMBER" pw) (insert "NUMBER") t)
  2681.    ((m3-if-abbrev-kill-prev "NOT" pw) (insert "NOT ") t)
  2682.    ((m3-if-abbrev-kill-prev "OF" pw) (insert "OF") t)
  2683.    ((m3-if-abbrev-kill-prev "OR" pw) (insert "OR ") t)
  2684.    ((m3-if-abbrev-kill-prev "ORD" pw) (insert "ORD") t)
  2685.    ((m3-if-abbrev-kill-prev "OVERRIDES" pw) (insert "OVERRIDES") t)
  2686.    ((m3-if-abbrev-kill-prev "RAISE" pw) (insert "RAISE") t)
  2687.    ((m3-if-abbrev-kill-prev "RAISES" pw) (insert "RAISES") t)
  2688.    ((m3-if-abbrev-kill-prev "READONLY" pw) (insert "READONLY") t)
  2689.    ((m3-if-abbrev-kill-prev "REAL" pw) (insert "REAL") t)
  2690.    ((m3-if-abbrev-kill-prev "REF" pw) (insert "REF ") t)
  2691.    ((m3-if-abbrev-kill-prev "REFANY" pw) (insert "REFANY") t)
  2692.    ((m3-if-abbrev-kill-prev "RETURN" pw) (insert "RETURN") t)
  2693.    ((m3-if-abbrev-kill-prev "REVEAL" pw) (insert "REVEAL") t)
  2694.    ((m3-if-abbrev-kill-prev "ROUND" pw) (insert "ROUND") t)
  2695.    ((m3-if-abbrev-kill-prev "SET" pw) (insert "SET OF ") t)
  2696.    ((m3-if-abbrev-kill-prev "SUBARRAY" pw) (insert "SUBARRAY") t)
  2697.    ((m3-if-abbrev-kill-prev "THEN" pw) (insert "THEN") t)
  2698.    ((m3-if-abbrev-kill-prev "TO" pw) (insert "TO") t)
  2699.    ((m3-if-abbrev-kill-prev "TRUE" pw) (insert "TRUE") t)
  2700.    ((m3-if-abbrev-kill-prev "TRUNC" pw) (insert "TRUNC") t)
  2701.    ((m3-if-abbrev-kill-prev "TYPECODE" pw) (insert "TYPECODE") t)
  2702.    ((m3-if-abbrev-kill-prev "UNSAFE" pw) (insert "UNSAFE") t)
  2703.    ((m3-if-abbrev-kill-prev "UNTIL" pw) (insert "UNTIL") t)
  2704.    ((m3-if-abbrev-kill-prev "UNTRACED" pw) (insert "UNTRACED") t)
  2705.    ((m3-if-abbrev-kill-prev "VAL" pw) (insert "VAL") t)
  2706.    ((m3-if-abbrev-kill-prev "VALUE" pw) (insert "VALUE") t)
  2707.    ((m3-if-abbrev-kill-prev "REPEAT" pw) (m3-until) t)
  2708.    ((m3-if-abbrev-kill-prev "OBJECT" pw) (m3-object) t)
  2709.    ((m3-if-abbrev-kill-prev "PROCEDURE" pw) (m3-procedure) t)
  2710.    ((m3-if-abbrev-kill-prev "RECORD" pw) (m3-record) t)
  2711.    ((m3-if-abbrev-kill-prev "TRY" pw) (m3-try) t)
  2712.    ((m3-if-abbrev-kill-prev "TYPE" pw) (m3-type) t)
  2713.    ((m3-if-abbrev-kill-prev "TYPECASE" pw) (m3-typecase) t)
  2714.    ((m3-if-abbrev-kill-prev "VAR" pw) (m3-var) t)
  2715.    ((m3-if-abbrev-kill-prev "WHILE" pw) (m3-while) t)
  2716.    ((m3-if-abbrev-kill-prev "WITH" pw) (m3-with) t)
  2717.    (t nil)))
  2718.  
  2719.  
  2720. ;;; Here are the data structure we'll use for the "intelligent" keyword
  2721. ;;; completion:
  2722. ;;;
  2723. ;;; We associate each keyword with a weight.  When we complete a keyword,
  2724. ;;; 
  2725.  
  2726. (defvar m3-cur-keyword-completion-start (make-marker)
  2727.   "A marker indicating the start of the last word that was keyword-completed.")
  2728.  
  2729. (defvar m3-cur-keyword-completion-len nil
  2730.   "The length of the completed keyword at the time of completion, to allow
  2731. us to determine if the user has entered more text.")
  2732.  
  2733. (defvar m3-cur-keyword-completions nil
  2734.   "A list of the strings that matched the originally input keyword text.")
  2735.  
  2736. ;;; This alist associates with each keyword:
  2737. ;;; (<score> <left-margin> <pred>)
  2738. ;;;
  2739. ;;; <score> is a score for breaking ties.  Smaller numbers are
  2740. ;;;    preferred to higher.
  2741. ;;; <props> is a list of properties of the keyword.
  2742. ;;;    Properties include:
  2743. ;;;      left-margin status:  It is assumed that a keyword cannot
  2744. ;;;        appear at the left-margin unless it has one of the
  2745. ;;;        properties 'lm-ok or 'lm-only, which indicate that it can
  2746. ;;;        or must appear at the left margin, respectively.
  2747. ;;;      line-starter status:  It is assumed that a keyword cannot
  2748. ;;;        appear after an ssl-introducer unless it has one of the
  2749. ;;;        properties 'ls-ok or 'ls-only, which indicate that it can
  2750. ;;;        or must appear after an ssl-introducer, respectively.
  2751. ;;; <pred>, if non-nil, is a function that must return non-nil for the
  2752. ;;;    completion to be legal
  2753.  
  2754. (defconst m3-keyword-completions
  2755.   '(("ABS" . (3 ()))
  2756.     ("ADDRESS" . (5 ()))
  2757.     ("ADR" . (6 ()))
  2758.     ("ADRSIZE" . (7 ()))
  2759.     ("AND" . (2 ()))
  2760.     ("ANY" . (1 () (lambda (on-lm starts-ssl)
  2761.              (m3-keyword-before-ssl-introducer-p "RAISES"))))
  2762.     ("ARRAY" . (4 (ls-ok) (lambda (on-lm starts-ssl)
  2763.                 (or (not starts-ssl)
  2764.                 (save-excursion
  2765.                   (forward-word -2)
  2766.                   (looking-at "OF"))))))
  2767.  
  2768.     ("BEGIN" . (1 (lm-ok ls-ok) (lambda (on-lm starts-ssl)
  2769.                     (save-excursion
  2770.                       (forward-word -1)
  2771.                       (if (not starts-ssl)
  2772.                       (m3-after-procedure-introducer
  2773.                        (point-min))
  2774.                     t)))))
  2775.     ("BITS" . (6 ()))
  2776.     ("BITSIZE" . (7 ()))
  2777.     ("BOOLEAN" . (3 ()))
  2778.     ("BRANDED" . (4 ()))
  2779.     ("BY" . (2 () (lambda (on-lm starts-ssl)
  2780.             (m3-keyword-before-ssl-introducer-p "FOR"))))
  2781.     ("BYTESIZE" . (5 ()))
  2782.  
  2783.     ("CARDINAL" . (4 ()))
  2784.     ("CASE" . (3 (ls-only)))
  2785.     ("CEILING" . (5 ()))
  2786.     ("CHAR" . (2 ()))
  2787.     ("CONST" . (1 (lm-ok ls-ok)))
  2788.  
  2789.     ("DEC" . (2 (ls-only)))
  2790.     ("DISPOSE" . (4 (ls-only)))
  2791.     ("DIV" . (3 ()))
  2792.     ("DO" . (1 () (lambda (on-lm starts-ssl)
  2793.             (save-excursion
  2794.               (forward-word -1)
  2795.               (or
  2796.                (m3-keyword-before-ssl-introducer-p "WHILE")
  2797.                (m3-keyword-before-ssl-introducer-p "WITH")
  2798.                (m3-keyword-before-ssl-introducer-p "FOR")
  2799.                (m3-keyword-before-ssl-introducer-p "LOCK"))))))
  2800.  
  2801.     ("ELSE" . (2 (ls-ok) (lambda (on-lm starts-ssl)
  2802.                (or (m3-end-matcher-is-p "IF")
  2803.                    (m3-end-matcher-is-p "TRY")
  2804.                    (m3-end-matcher-is-p "\\bCASE")
  2805.                    (m3-end-matcher-is-p "\\bTYPECASE")))))
  2806.     ("ELSIF" . (3 (ls-ok) (lambda (on-lm starts-ssl)
  2807.                 (m3-end-matcher-is-p "IF"))))
  2808.     ("END" . (1 (lm-ok ls-ok)))
  2809.     ("EVAL" . (7 (ls-only)))
  2810.     ("EXCEPT" . (6 (ls-ok) (lambda (on-lm starts-ssl)
  2811.                  (m3-end-matcher-is-p "TRY"))))
  2812.     ("EXCEPTION" . (5 (lm-only ls-ok)))
  2813.     ("EXIT" . (8 (ls-only)))
  2814.     ("EXPORTS"  . (4 () (lambda (on-lm starts-ssl)
  2815.               (save-excursion
  2816.                 ;; One for prefix of EXPORTS one for module name,
  2817.                 ;; one for MODULE.
  2818.                 (forward-word -3)
  2819.                 (looking-at "MODULE")))))
  2820.  
  2821.     ("FALSE" . (4 ()))
  2822.     ("FINALLY" . (3 (ls-ok) (lambda (on-lm starts-ssl)
  2823.                   (m3-end-matcher-is-p "TRY"))))
  2824.     ("FIRST" . (5 ()))
  2825.     ("FLOAT" . (6 ()))
  2826.     ("FLOOR" . (7 ()))
  2827.     ("FOR" . (2 (ls-only)))
  2828.     ("FROM" . (1 (lm-only ls-ok)))
  2829.  
  2830.     ("GENERIC" . (1 (lm-only)))
  2831.  
  2832.     ("IMPORT"  . (2 (lm-ok ls-ok)
  2833.             (lambda (on-lm starts-ssl)
  2834.               (or on-lm
  2835.               (save-excursion
  2836.                 (forward-word -3)
  2837.                 (looking-at "FROM"))))))
  2838.     ("IF" . (3 (ls-only)
  2839.            (lambda (on-lm starts-ssl)
  2840.          (or (not starts-ssl)
  2841.              (save-excursion
  2842.                (forward-word -3)
  2843.                (not (looking-at "\\(\\bARRAY\\|\bSET\\)[ \t]+OF")))))))
  2844.     ("IN" . (7 ()))
  2845.     ("INC" . (4 (ls-only)
  2846.         (lambda (on-lm starts-ssl)
  2847.           (or (not starts-ssl)
  2848.               (save-excursion
  2849.             (forward-word -3)
  2850.             (not (looking-at
  2851.                   "\\(\\bARRAY\\|\bSET\\)[ \t]+OF")))))))
  2852.     ("INTEGER" . (5 (ls-ok)
  2853.             (lambda (on-lm starts-ssl)
  2854.               (or (not starts-ssl)
  2855.               (save-excursion
  2856.                 (forward-word -2)
  2857.                 (looking-at "OF"))))))
  2858.     ("INTERFACE" . (1 (lm-ok) (lambda (on-lm starts-ssl)
  2859.                 (save-excursion
  2860.                   (or on-lm
  2861.                       (progn
  2862.                     (forward-word -2)
  2863.                     (and
  2864.                      (m3-at-left-margin-p)
  2865.                      (looking-at "GENERIC\\|UNSAFE"))))))))
  2866.     ("ISTYPE" . (7 ()))
  2867.  
  2868.     ("LAST" . (3 ()))
  2869.     ("LOCK" . (1 (ls-only)))
  2870.     ("LOOP" . (2 (ls-only)))
  2871.     ("LONGFLOAT" . (4 ()))
  2872.     ("LONGREAL" . (5 ()))
  2873.     ("LOOPHOLE" . (6 ()))
  2874.  
  2875.     ("MAX" . (5 ()))
  2876.     ("METHODS" . (2 (ls-only)))
  2877.     ("MIN" . (4 ()))
  2878.     ("MOD" . (3 ()))
  2879.     ("MODULE" . (1 (lm-ok)
  2880.            (lambda (on-lm starts-ssl)
  2881.              (save-excursion
  2882.                (forward-word -1)
  2883.                (or (m3-at-left-margin-p)
  2884.                (progn
  2885.                  (forward-word -1)
  2886.                  (and (m3-at-left-margin-p)
  2887.                   (looking-at "GENERIC\\|UNSAFE"))))))))
  2888.  
  2889.     ("NARROW" . (1 ()))
  2890.     ("NEW" . (2 ()))
  2891.     ("NIL" . (3 ()))
  2892.     ("NULL" . (6 ()))
  2893.     ("NUMBER" . (5 ()))
  2894.     ("NOT" . (4 ()))
  2895.  
  2896.     ("OBJECT" . (2 ()
  2897.            (lambda (on-lm starts-ssl)
  2898.              (save-excursion
  2899.                (m3-re-search-backward m3-part-starters (point-min) t)
  2900.                (looking-at "TYPE\\|REVEAL")))))
  2901.     ("OF" . (1 () (lambda (on-lm starts-ssl)
  2902.             (or (m3-keyword-before-ssl-introducer-p
  2903.              "\\bCASE\\|\\bTYPECASE")
  2904.             (m3-keyword-before-ssl-introducer-p
  2905.              "\\bARRAY\\|SET\\b")))))
  2906.     ("OR" . (4 ()))
  2907.     ("ORD" . (5 ()))
  2908.     ("OVERRIDES" . (3 (ls-only)))
  2909.  
  2910.     ("PROCEDURE" . (1 (lm-ok ls-ok)))
  2911.  
  2912.     ("RAISE" . (5 (ls-only)))
  2913.     ("RAISES" . (3 () m3-raises-ok))
  2914.     ("READONLY" . (4 () (lambda (on-lm starts-ssl)
  2915.               (m3-in-arg-list 0))))
  2916.     ("REAL" . (9 ()))
  2917.     ("RECORD" . (6 ()))
  2918.     ("REF" . (7 ()))
  2919.     ("REFANY" . (8 ()))
  2920.     ("REPEAT" . (10 (ls-only)))
  2921.     ("RETURN" . (2 (ls-only)))
  2922.     ("REVEAL" . (1 (lm-only ls-ok)))
  2923.     ("ROOT" . (11 ()))
  2924.     ("ROUND" . (12 ()))
  2925.  
  2926.     ("SET" . (1 ()))
  2927.     ("SUBARRAY" . (2 (ls-ok)))
  2928.  
  2929.     ("THEN" . (1 () (lambda (on-lm starts-ssl)
  2930.               (or (m3-keyword-before-ssl-introducer-p "\\bIF")
  2931.               (m3-keyword-before-ssl-introducer-p "\\bELSIF")))))
  2932.     ("TO" . (2 () (lambda (on-lm starts-ssl)
  2933.             (m3-keyword-before-ssl-introducer-p "\\bFOR"))))
  2934.     ("TRUE" . (7 ()))
  2935.     ("TRUNC" . (8 ()))
  2936.     ("TRY" . (3 (ls-only)))
  2937.     ("TYPE" . (4 (lm-only ls-ok)))
  2938.     ("TYPECASE" . (5 (ls-only)))
  2939.     ("TYPECODE" . (6 ()))
  2940.  
  2941.     ("UNSAFE" . (1 (lm-only)))
  2942.     ("UNTIL" . (2 (ls-ok)))
  2943.     ("UNTRACED" . (3 ()))
  2944.  
  2945.     ("VAL" . (2 () (lambda (on-lm starts-ssl)
  2946.              (and (not (save-excursion
  2947.                  (forward-word -1)
  2948.                  (m3-after-procedure-introducer 0)))
  2949.               (not (m3-in-arg-list 0))))))
  2950.  
  2951.     ("VALUE" . (3 ()
  2952.           (lambda (on-lm starts-ssl)
  2953.             (not (save-excursion
  2954.                (forward-word -1)
  2955.                (m3-after-procedure-introducer 0))))))
  2956.  
  2957.     ("VAR" . (1 (lm-ok ls-ok)
  2958.         (lambda (on-lm starts-ssl)
  2959.           (or on-lm starts-ssl
  2960.               (save-excursion
  2961.             (forward-word -1)
  2962.             (m3-after-procedure-introducer 0))
  2963.               (m3-in-arg-list 0)))))
  2964.  
  2965.     ("WHILE" . (1 (ls-only)))
  2966.     ("WITH" . (2 (ls-only)))))
  2967.  
  2968.  
  2969.  
  2970. (defun m3-at-left-margin-p () (eq (current-column) 0))
  2971.  
  2972. (defun m3-keyword-before-ssl-introducer-p (keyword)
  2973.   "Returns non-nil if KEYWORD occurs before an ssl-introducer (other than
  2974. KEYWORD), looking backward."
  2975.   (save-excursion
  2976.     (m3-re-search-backward
  2977.      (concat "\\(;\\|END\\|" m3-keyword-endable-ssl-introducers "\\|"
  2978.          keyword "\\)")
  2979.      (point-min) 't)
  2980.     (looking-at keyword)))
  2981.       
  2982. (defun m3-end-matcher-is-p (keyword)
  2983.   "Returns non-nil if the keyword that would match an END inserted at
  2984. point is KEYWORD."
  2985.   (save-excursion
  2986.     (m3-backward-to-end-match (point-min))
  2987.     (looking-at keyword)))
  2988.  
  2989. (defun m3-raises-ok (on-lm starts-ssl)
  2990.   (save-excursion
  2991.     (forward-word -1)
  2992.     (let ((save-point (point)))
  2993.       (and
  2994.        (m3-re-search-backward "[^*])" 0 t)
  2995.        (progn
  2996.      (forward-char 1)
  2997.      (and
  2998.       (m3-in-arg-list 0)
  2999.       (progn
  3000.         (forward-char 1)
  3001.         (let ((retval-pat
  3002.            (concat "[ \t\n]*:[ \t\n]*" m3-poss-qual-ident-re)))
  3003.           (if (looking-at retval-pat)
  3004.           (progn
  3005.             (re-search-forward retval-pat)
  3006.             (goto-char (match-end 0))))
  3007.           (m3-forward-to-code (point-max))
  3008.           (= (point) save-point)))))))))
  3009.         
  3010.  
  3011.  
  3012.  
  3013.  
  3014. (defun m3-polite-abbrev (pw)
  3015. ;;;  (message "In m3-polite-abbrev") (sit-for 2)
  3016.   (let ((case-fold-search nil))
  3017.     (cond
  3018.      ;; First, if the start of the current keyword is the same as the
  3019.      ;; start of the last keyword we completed, and the user hasn't
  3020.      ;; appended any characters, and m3-cur-keyword-completions is non-nil,
  3021.      ;; try the next completion in the list.
  3022.      ((and
  3023. ;;;     (progn (message "In m3-polite-abbrev (x1)") (sit-for 2) t)
  3024.        (marker-position m3-cur-keyword-completion-start)
  3025. ;;;     (progn (message "In m3-polite-abbrev (x2)") (sit-for 2) t)
  3026.        (> (point) m3-cur-keyword-completion-len)
  3027.        (= m3-cur-keyword-completion-start
  3028.       (save-excursion
  3029.         (forward-char (- m3-cur-keyword-completion-len))
  3030.         (point)))
  3031. ;;;     (progn (message "In m3-polite-abbrev (x3)") (sit-for 2) t)
  3032.        m3-cur-keyword-completions)
  3033.       (let ((cur-completion (car m3-cur-keyword-completions)))
  3034.     (setq m3-cur-keyword-completions
  3035.           (append (cdr m3-cur-keyword-completions) (list cur-completion)))
  3036. ;;;      (progn (message "In m3-polite-abbrev (xx1)") (sit-for 2) t)
  3037.     (forward-word -1)
  3038.     (delete-region m3-cur-keyword-completion-start
  3039.                (+ m3-cur-keyword-completion-start
  3040.               m3-cur-keyword-completion-len))
  3041. ;;;      (progn (message "In m3-polite-abbrev (xx2)") (sit-for 2) t)
  3042.     (insert (car m3-cur-keyword-completions))
  3043.     (setq m3-cur-keyword-completion-len
  3044.           (- (point) m3-cur-keyword-completion-start))
  3045.     (if (> (length m3-cur-keyword-completions) 1)
  3046.         (message "Other matches: %s"
  3047.              (mapconcat '(lambda (x) x)
  3048.                 (cdr m3-cur-keyword-completions) ", ")))))
  3049.  
  3050.      ;; Otherwise, form the list of (<keyword> . <score>) pairs such
  3051.      ;; that pw is a prefix of <keyword>, <score> is the score
  3052.      ;; associated with <keyword> in m3-keyword-completions, and the
  3053.      ;; conditions in m3-keyword-completions are met.
  3054.      (t
  3055. ;;;    (message "In m3-polite-abbrev (t)") (sit-for 2)
  3056.       (let ((keyword-list m3-keyword-completions)
  3057.         matches
  3058.         (on-lm
  3059.          (and
  3060.           (= (save-excursion (forward-word -1) (current-column))
  3061.          0)
  3062.           (let ((continue t) (res nil))
  3063.         (save-excursion
  3064.           (while continue
  3065.             (setq continue nil)
  3066.             (m3-re-search-backward
  3067.              (concat m3-part-starters "\\|" m3-end-matchers "\\|"
  3068.                  "\\bEND\\b")
  3069.              (point-min) 'move-to-limit)
  3070.             (cond
  3071.              ((looking-at "END")
  3072.               (m3-backward-to-end-match (point-min))
  3073.               (setq continue t))
  3074.              ((looking-at (concat "^\\(" m3-part-starters "\\)"))
  3075.               (setq res t))
  3076.              ((= (point) (point-min))
  3077.               (setq res t)))))
  3078. ;;;          (message "After loop, res is %s" res) (sit-for 2)
  3079.         (and res
  3080.              (save-excursion
  3081.                (forward-word -1)
  3082.                (or (= (point) (point-min))
  3083.                (progn
  3084.                  (m3-backward-to-code (point-min))
  3085. ;;;               (message "xxx") (sit-for 2)
  3086.                  (looking-at ";"))))))))
  3087.         (starts-ssl
  3088.          (let ((first-char (save-excursion (forward-word -1) (point))))
  3089.            (save-excursion
  3090.          (forward-word -1)
  3091.          (m3-re-search-backward
  3092.           (concat
  3093.            "\\(;\\|END\\|" m3-keyword-endable-ssl-introducers "\\)")
  3094.           (point-min) 'move-to-limit)
  3095.          (re-search-forward
  3096.           (concat
  3097.            "\\(;\\|END\\|" m3-keyword-endable-ssl-introducers "\\)")
  3098.           first-char t)
  3099.          (goto-char (match-end 0))
  3100. ;;;           (message "In m3-polite-abbrev (zz1)") (sit-for 2)
  3101.          (m3-forward-to-code (point-max))
  3102.          (= (point) first-char)))))
  3103. ;;;      (message "In m3-polite-abbrev, on-lm = %s, starts-ssl = %s"
  3104. ;;;           on-lm starts-ssl)
  3105. ;;;      (sit-for 2)
  3106.  
  3107.     (while keyword-list
  3108.       (let* ((entry (car keyword-list))
  3109.          (kw (car entry)))
  3110. ;;;      (message "In m3-polite-abbrev kw = %s" kw) (sit-for 2)
  3111. ;;;      (message "Foo") (sit-for 2)
  3112.         (if (m3-is-prefix kw pw)
  3113.         (let* ((rest (cdr entry))
  3114.                (score (car rest))
  3115.                (props (car (cdr rest)))
  3116.                (pred (car (cdr (cdr rest)))))
  3117. ;;;        (message "In m3-polite-abbrev, found kw = %s" kw) (sit-for 1)
  3118.           (let ((lm-status
  3119.              (cond
  3120.               ((and (memq 'lm-ok props) (memq 'lm-only props))
  3121.                (error "Bad prop-list in m3-keyword-completions."))
  3122.               ((memq 'lm-ok props) 'lm-ok)
  3123.               ((memq 'lm-only props) 'lm-only)
  3124.               (t 'lm-not)))
  3125.             (ls-status
  3126.              (cond
  3127.               ((and (memq 'ls-ok props) (memq 'ls-only props))
  3128.                (error "Bad prop-list in m3-keyword-completions."))
  3129.               ((memq 'ls-ok props) 'ls-ok)
  3130.               ((memq 'ls-only props) 'ls-only)
  3131.               (t 'ls-not))))
  3132. ;;;            (message
  3133. ;;;             "In m3-polite-abbrev, (2) lm-status = %s ls-status = %s"
  3134. ;;;             lm-status ls-status)
  3135. ;;;          (sit-for 2)
  3136.             (and
  3137.              (or (eq lm-status 'lm-ok)
  3138.              (cond
  3139.               ((eq lm-status 'lm-only) on-lm)
  3140.               ((eq lm-status 'lm-not) (not on-lm))))
  3141.              (or
  3142. ;;;            (progn (message "In m3-polite-abbrev, (3.2)")
  3143. ;;;               (sit-for 2) nil)
  3144.               (eq ls-status 'ls-ok)
  3145.               (cond
  3146.                ((eq ls-status 'ls-only) starts-ssl)
  3147.                ((eq ls-status 'ls-not) (not starts-ssl))))
  3148.  
  3149.              (or 
  3150. ;;;            (progn (message "In m3-polite-abbrev, (5), pred = %s" pred)
  3151. ;;;               (sit-for 2) nil)
  3152.               (not pred)
  3153. ;;;            (progn (message "In m3-polite-abbrev, (5)")
  3154. ;;;               (sit-for 2) nil)
  3155.               (funcall pred on-lm starts-ssl))
  3156. ;;;           (message "In m3-polite abbrev, adding %s to matches" kw)
  3157. ;;;           (sit-for 2)
  3158.              (setq matches (cons (cons kw score) matches)))))))
  3159.       (setq keyword-list (cdr keyword-list)))
  3160.  
  3161. ;;;   (message "In m3-polite-abbrev (after matches): %s" matches) (sit-for 4)
  3162.     ;; If there are any matches, do a completion
  3163.     (and matches
  3164.          (progn
  3165.            ;; Now sort matches according to score.
  3166. ;;;         (message "In m3-polite-abbrev, (10)") (sit-for 2)
  3167.            (setq matches
  3168.              (sort matches '(lambda (e1 e2) (< (cdr e1) (cdr e2)))))
  3169.            ;; And strip off the scores from the result.
  3170. ;;;         (message "In m3-polite-abbrev, (11)") (sit-for 2)
  3171.            (setq matches (mapcar'(lambda (e) (car e)) matches))
  3172. ;;;         (message "In m3-polite-abbrev, (12)") (sit-for 2)
  3173.            (setq m3-cur-keyword-completions matches)
  3174.            (let ((first-match (car matches)))
  3175.          (forward-word -1)
  3176.          (delete-region (point)
  3177.                 (save-excursion (forward-word 1) (point)))
  3178. ;;;           (message "In m3-polite-abbrev, (13)") (sit-for 2)
  3179.          (set-marker m3-cur-keyword-completion-start (point))
  3180.          (insert first-match)
  3181.          (setq m3-cur-keyword-completion-len
  3182.                (- (point) m3-cur-keyword-completion-start))
  3183.          (if (> (length matches) 1)
  3184.              (message
  3185.               "Other matches: %s"
  3186.               (mapconcat '(lambda (x) x) (cdr matches) ", ")))))
  3187.          ))))))
  3188.       
  3189.               
  3190. ;;; The identifiers are the names of
  3191. ;;;   1) imported interfaces
  3192. ;;;   2) variables, types, constants, exceptions and procedures defined at
  3193. ;;;      module scope. 
  3194. ;;;   3) If we are in a procedure body:
  3195. ;;;       variables, constants, and procedures defined in enclosing scopes.
  3196.  
  3197. (defun m3-find-id-list ()
  3198.   (interactive)
  3199.   "Returns a list of the identifiers visible at point."
  3200.   (append
  3201.    (setq m3-mod-names (m3-module-names))
  3202.    (m3-scope-names)
  3203.    ))
  3204.  
  3205. (defun m3-module-names ()
  3206.   (interactive)
  3207.   (let ((names nil))
  3208.     (save-excursion
  3209.       (goto-char (point-min))
  3210.       (while (m3-re-search-forward
  3211.           (concat "^\\(" m3-part-starters "\\)")
  3212.           (point-max) t)
  3213. ;;;    (message "m3-module-names (0.1)") (sit-for 2)
  3214.     (let ((limit
  3215.            (save-excursion
  3216.          (forward-word 1)
  3217. ;;;         (message "m3-module-names (0.2)") (sit-for 2)
  3218.          (if (m3-re-search-forward
  3219.               (concat "^\\(" m3-part-starters "\\)")
  3220.               (point-max) t)
  3221.              (point)
  3222.            (point-max)))))
  3223. ;;;      (message "m3-module-names (1)") (sit-for 2)
  3224.       (cond
  3225.        ((looking-at "INTERFACE\\|MODULE")
  3226.         (forward-word 1))
  3227.        ((looking-at "IMPORT")
  3228. ;;;        (message "m3-mod-names, IMPORT(1)") (sit-for 2)
  3229.         (forward-word 1)
  3230.         (setq names (append (m3-parse-name-list "," nil ";" limit) names)))
  3231.        ((looking-at "FROM")
  3232. ;;;        (message "m3-mod-names, FROM(1)") (sit-for 2)
  3233.         (forward-word 3)
  3234.         (forward-word -1)
  3235. ;;;        (message "m3-mod-names, FROM(2)") (sit-for 2)
  3236.         (if (looking-at "IMPORT")
  3237.         (progn (forward-word 1)
  3238.                (setq names (append
  3239.                     (m3-parse-name-list "," nil ";" limit)
  3240.                     names)))))
  3241.        ((looking-at "TYPE\\|REVEAL")
  3242.         (forward-word 1)
  3243.         (setq names (append (m3-parse-name-list
  3244.                  ";" "\\(=\\|<:\\)" nil limit)
  3245.                 names)))
  3246.        ((looking-at "EXCEPTION")
  3247.         (forward-word 1)
  3248.         (setq names (append (m3-parse-name-list ";" nil nil limit)
  3249.                 names)))
  3250.        ((looking-at "VAR")
  3251.         (forward-word 1)
  3252.         (let ((continue t))
  3253.           (while (and (< (point) (point-max)) continue)
  3254. ;;;        (message "m3-mod-names, VAR(1), limit = %d" limit) (sit-for 2)
  3255.         (setq names (append (m3-parse-name-list "," nil ":" limit)
  3256.                     names))
  3257. ;;;        (message "m3-mod-names, VAR(2)") (sit-for 2)
  3258.         (setq continue
  3259.               (and (m3-re-search-forward ";" limit t)
  3260. ;;;               (progn (message "m3-mod-names, VAR(3)")
  3261. ;;;                  (sit-for 2) t)
  3262.                (progn (forward-char 1)
  3263. ;;;                  (message "m3-mod-names, VAR(4)") (sit-for 2)
  3264.                   (m3-forward-to-code limit)
  3265. ;;;                  (message "m3-mod-names, VAR(5), point = %d"
  3266. ;;;                       (point))
  3267. ;;;                  (sit-for 2)
  3268.                   (< (point) limit)))))))
  3269.        ((looking-at "PROCEDURE")
  3270.         (forward-word 1)
  3271.         (m3-forward-to-code limit)
  3272.         (setq names (cons (buffer-substring (point)
  3273.                         (save-excursion
  3274.                           (forward-word 1)
  3275.                           (point)))
  3276.                   names)))
  3277.        ((looking-at "CONST")
  3278.         (forward-word 1)
  3279.         (setq names (append (m3-parse-name-list ";" "=" nil limit)
  3280.                 names)))))))
  3281. ;;;    (message "names are %s" names)
  3282.     names))
  3283.  
  3284.  
  3285. (defun m3-scope-names ()
  3286.   "If we are not in a procedure scope, return nil.  If we are, return a list
  3287. of all identifiers defined in the current scope."
  3288.   ;; Identifiers can be introduced by VAR, CONST, WITH, or nested PROCEDURE
  3289.   ;; declarations.
  3290.   (interactive)
  3291. ;;;  (message "m3-scope-names") (sit-for 2)
  3292.   (let ((case-fold-search nil) (orig-point (point)))
  3293.     (save-excursion
  3294.       (cond
  3295.        ((save-excursion
  3296.       (m3-re-search-backward (concat "^\\(" m3-part-starters "\\)")
  3297.                  (point-min) t)
  3298. ;;;      (message "m3-scope-names (1)") (sit-for 2)
  3299.       (and
  3300.        (looking-at "^PROCEDURE")
  3301.        (progn
  3302.          (forward-word 1)
  3303.          (m3-re-search-forward "VAR\\|CONST\\|PROCEDURE\\|BEGIN"
  3304.                    (point-max) 'move-to-limit)
  3305.          (while (m3-in-arg-list (point-min))
  3306.            (forward-word 1)
  3307.            (m3-re-search-forward "VAR\\|CONST\\|PROCEDURE\\|BEGIN"
  3308.                      (point-max) 'move-to-limit))
  3309.          (and (looking-at "VAR\\|CONST\\|PROCEDURE\\|BEGIN")
  3310.           (> orig-point (point))))))
  3311.            
  3312. ;;;    (message "m3-scope-names (2)") (sit-for 2)
  3313.     (let ((continue t) (names nil) (orig-point (point)))
  3314.       ;; Set things up to make sure we start with a complete list.
  3315.       (m3-re-search-backward
  3316.        (concat "\\(VAR\\|CONST\\|WITH\\|PROCEDURE\\|END\\|;\\)")
  3317.        (point-min) t)
  3318. ;;;      (message "m3-scope-names (2.2)") (sit-for 2)
  3319.       (while continue
  3320.         (m3-re-search-backward
  3321.          (concat "\\(VAR\\|CONST\\|WITH\\|PROCEDURE\\|END\\)")
  3322.          (point-min) t)
  3323. ;;;        (message "m3-scope-names (3)") (sit-for 2)
  3324.         (cond
  3325.          ((looking-at "^PROCEDURE")
  3326.           (setq continue nil))
  3327.  
  3328.          ((looking-at "END")
  3329.           (m3-backward-to-end-match (point-min))
  3330.           ;; If we're now looking at a BEGIN, skip over any
  3331.           ;; VAR, CONST, or PROCEDURE associated with the BEGIN.
  3332.           (cond
  3333.            ((looking-at "BEGIN")
  3334.         (m3-re-search-backward
  3335.          (concat "\\(BEGIN\\|WITH\\|END\\)")
  3336.          (point-min) t)
  3337.         (forward-word 1))))
  3338.  
  3339.          ((looking-at "VAR")
  3340. ;;;          (message "m3-scope-names (VAR)") (sit-for 2)
  3341.           (let ((save-point (point))
  3342.             (limit
  3343.              (save-excursion
  3344.                (forward-word 1)
  3345.                (m3-re-search-forward
  3346.             (concat "\\(" m3-part-starters "\\|BEGIN\\)")
  3347.             orig-point 'move-to-limit)
  3348. ;;;               (message "m3-scope-names, VAR(0.5)") (sit-for 2)
  3349.                (point))))
  3350.         (forward-word 1)
  3351.         (let ((continue t))
  3352.           (while (and (< (point) (point-max)) continue)
  3353. ;;;          (message "m3-scope-names, VAR(1)") (sit-for 2)
  3354.             (let ((new-names (m3-parse-name-list "," nil ":"
  3355.                              limit)))
  3356. ;;;              (message "m3-scope-names, VAR(2), new-names = %s"
  3357. ;;;                   new-names)
  3358. ;;;              (sit-for 2)
  3359.               (setq names (append names new-names)))
  3360. ;;;          (message "m3-scope-names, VAR(3)") (sit-for 2)
  3361.             (setq continue
  3362.               (and (m3-re-search-forward ";" limit t)
  3363. ;;;                 (progn (message "m3-mod-names, VAR(4)")
  3364. ;;;                    (sit-for 2) t)
  3365.                    (progn
  3366.                  (forward-char 1)
  3367. ;;;                   (message "m3-mod-names, VAR(5)")
  3368. ;;;                   (sit-for 2)
  3369.                  (m3-forward-to-code limit)
  3370. ;;;                   (message "m3-mod-names, VAR(6), point = %d"
  3371. ;;;                    (point))
  3372. ;;;                   (sit-for 2)
  3373.                  (< (point) limit))))))
  3374.         (goto-char save-point)))
  3375.      
  3376.          ((looking-at "CONST")
  3377.           (let ((save-point (point)))
  3378.         (forward-word 1)
  3379.         (setq names (append (m3-parse-name-list ";" "=" nil orig-point)
  3380.                     names))
  3381.         (goto-char save-point)))
  3382.  
  3383.          ((looking-at "WITH")
  3384.           (let ((save-point (point)))
  3385.         (forward-word 1)
  3386.         (let ((new-names (m3-parse-name-list "," "=" "DO" orig-point)))
  3387. ;;;          (message "WITH: %s" new-names) (sit-for 2)
  3388.           (setq names (append names new-names)))          
  3389.         (goto-char save-point)))
  3390.         
  3391.  
  3392.          ((looking-at "PROCEDURE")
  3393.           (let ((save-point (point)))
  3394.         (forward-word 1)
  3395.         (m3-forward-to-code orig-point)
  3396.         (setq names (cons (buffer-substring (point)
  3397.                             (save-excursion
  3398.                               (forward-word 1)
  3399.                               (point)))
  3400.                   names))
  3401.         (goto-char save-point)))))
  3402. ;;;      (message "scope-names returns %s" names) (sit-for 10)
  3403.       names))
  3404.     
  3405.        (t nil)))))
  3406.         
  3407.         
  3408.  
  3409. (defun m3-parse-name-list (between skip end lim)
  3410.   "Assumes point is at the start of a BETWEEN-separated list.  Assumes that
  3411. SKIP, if non-nil is an regexp giving a pattern that ends each element,
  3412. and starts a string that should be ignored up to the next BETWEEN or END.
  3413. END, if non-nil gives the regexp that terminates the list.
  3414.  Alternatively, LIMIT, if non-nil is a character position that bounds the
  3415. parse.  Returns the list of names, leaves point positioned after list."
  3416. ;;;  (message "m3-parse-name-list (1)") (sit-for 2)
  3417.   (let ((names nil) (continue t) (limit (if lim lim (point-max))))
  3418. ;;;    (message "m3-parse-name-list, re = %s" re) (sit-for 2)
  3419.     (while (and (< (point) limit) continue)
  3420. ;;;      (message "m3-parse-name-list (2)") (sit-for 2)
  3421.       (m3-forward-to-code limit)
  3422. ;;;      (message "m3-parse-name-list (3)") (sit-for 2)
  3423.       (cond
  3424.        ((< (point) limit)
  3425. ;;;    (message "m3-parse-name-list (3.5)") (sit-for 2)
  3426.     (let ((start (point)))
  3427.       (setq names (cons (buffer-substring
  3428.                  (point)
  3429.                  (progn (forward-word 1) (point)))
  3430.                 names))
  3431.       (cond
  3432.        ((m3-re-search-forward
  3433.          (concat "\\(" between "[ \t\n]*" m3-identifier-re
  3434.              (if skip (concat "[ \t\n]*" skip)) "\\)"
  3435.              (if end (concat "\\|" end)))
  3436.          limit t)
  3437. ;;;        (message "m3-parse-name-list (4)") (sit-for 2)
  3438.         (cond
  3439.          ((looking-at between)
  3440. ;;;          (message "m3-parse-name-list (6.1)") (sit-for 2)
  3441.           (re-search-forward between limit t)
  3442.           (goto-char (match-end 0)))
  3443.          ((and end (looking-at end))
  3444. ;;;          (message "m3-parse-name-list (6.2)") (sit-for 2)
  3445.           (setq continue nil))))
  3446.        (t
  3447.         (setq continue nil)))))))
  3448. ;;;    (message "Parse-name-list returns: %s" names) (sit-for 2)
  3449.     names))
  3450.  
  3451.  
  3452.  
  3453. (defvar m3-cur-ident-completion-start (make-marker)
  3454.   "A marker indicating the start of the last word that was
  3455. identifier-completed.")
  3456.  
  3457. (defvar m3-cur-ident-completion-len nil
  3458.   "The length of the completed identifier at the time of completion, to allow
  3459. us to determine if the user has entered more text.")
  3460.  
  3461. (defvar m3-cur-ident-completions nil
  3462.   "A list of the strings that matched the originally input identifier text.")
  3463.  
  3464. (defvar m3-cur-ident-completion-done nil
  3465.   "A list of the strings that matched the originally input identifier text.")
  3466.  
  3467. (defvar m3-ident-match-no-case-fold t
  3468.   "If non-nil, case matters in identifier matches.  If nil, case is ignored.")
  3469. ;;;(setq m3-ident-match-no-case-fold nil)
  3470.  
  3471. (defun m3-ident-complete ()
  3472.   "Moves to the end of the current word; then checks if that word is a prefix
  3473. of any of the identifiers in the current file.  If it is a prefix of a
  3474. unique member of the list, completes the word to that prefix.  If it is a
  3475. prefix of multiple elements of the list, completes to the longest prefix
  3476. shared by all those elements, and presents the further completions to
  3477. the user in the minibuffer.  If this command is next executed from at
  3478. the end of the partially completed word, and no changes have been made
  3479. to the word, it will fill in the first element of the set of full
  3480. completions, and subsequent executions will cycle through the list."
  3481.   (interactive)
  3482. ;;;  (message "In m3-ident-complete") (sit-for 2)
  3483.   (m3-ident-complete-work (m3-find-id-list)))
  3484.        
  3485. (defun m3-ident-complete-work (names)
  3486.   "Moves to the end of the current word; then checks if that word is a prefix
  3487. of any of the strings in NAMES.  If it is a prefix of a unique member of the
  3488. list, completes the word to that prefix.  If it is a prefix of multiple
  3489. elements of the list, completes to the longest prefix shared by all those
  3490. elements, and presents the further completions to the user in the minibuffer.
  3491. If this command is next executed from at the end of the partially
  3492. completed word, and no changes have been made to the word, it will fill in
  3493. the first element of the set of full completions, and subsequent executions
  3494. will cycle through the list."
  3495. ;;;  (message "In m3-ident-complete-work (1), names = %s" names) (sit-for 2)
  3496.   (let ((save-point (point)))
  3497.     (cond
  3498.      ((and
  3499. ;;;       (progn (message "In m3-ident-complete (x1)") (sit-for 2) t)
  3500.        (marker-position m3-cur-ident-completion-start)
  3501. ;;;     (progn (message "In m3-ident-complete (x2)") (sit-for 2) t)
  3502.        (> (point) m3-cur-ident-completion-len)
  3503. ;;;     (progn (message "In m3-ident-complete (x2.5)") (sit-for 2) t)
  3504.        (= m3-cur-ident-completion-start
  3505.       (save-excursion
  3506.         (forward-char (- m3-cur-ident-completion-len))
  3507. ;;;      (progn (message "In m3-ident-complete (x2.75)") (sit-for 2) t)
  3508.         (point)))
  3509. ;;;     (progn (message "In m3-ident-complete (x3)") (sit-for 2) t)
  3510.        m3-cur-ident-completions)
  3511.       (let ((cur-completion (car m3-cur-ident-completions)))
  3512.     (if m3-cur-ident-completion-done
  3513.         (setq m3-cur-ident-completions
  3514.           (append (cdr m3-cur-ident-completions)
  3515.               (list cur-completion))))
  3516. ;;;    (progn (message "In m3-ident-complete (xx1)") (sit-for 2) t)
  3517.     (forward-word -1)
  3518.     (delete-region m3-cur-ident-completion-start
  3519.                (+ m3-cur-ident-completion-start
  3520.               m3-cur-ident-completion-len))
  3521. ;;;      (progn (message "In m3-ident-complete (xx2)") (sit-for 2) t)
  3522.     (insert (car m3-cur-ident-completions))
  3523.     (setq m3-cur-ident-completion-len
  3524.           (- (point) m3-cur-ident-completion-start))
  3525.     (setq m3-cur-ident-completion-done t)
  3526.     (if (> (length m3-cur-ident-completions) 1)
  3527.         (message "Other matches: %s"
  3528.              (mapconcat '(lambda (x) x)
  3529.                 (cdr m3-cur-ident-completions) ", ")))))
  3530.    
  3531.      ;; Otherwise, find the current word, and see if it is a prefix of any
  3532.      ;; members of names.
  3533.      (t
  3534. ;;;    (progn (message "In m3-ident-complete-work (1)") (sit-for 2) t)
  3535.       (cond
  3536.        ((and (not (looking-at m3-identifier-char-re))
  3537.          (or (= (point) (point-min))
  3538.          (save-excursion
  3539.            (forward-char -1)
  3540.            (not (looking-at m3-identifier-char-re)))))
  3541. ;;;      (progn (message "In m3-ident-complete-work (2.1)") (sit-for 2) t)
  3542.     (beep)
  3543.     (message "Not in identifier!")
  3544.     (goto-char save-point))
  3545.        (t
  3546. ;;;      (progn (message "In m3-ident-complete-work (2)") (sit-for 2) t)
  3547.     (let ((cur-word
  3548.            (cond
  3549.         ((looking-at (concat "\\b" m3-identifier-char-re))
  3550.          (buffer-substring (point)
  3551.                    (save-excursion (forward-word 1)
  3552.                            (point))))
  3553.         (t
  3554.          (forward-word -1)
  3555.          (buffer-substring (point)
  3556.                    (save-excursion (forward-word 1)
  3557.                            (point))))))
  3558.           (matches nil))
  3559.       ;; Get the matches
  3560.       (mapcar '(lambda (elem)
  3561.              (if (m3-is-prefix elem cur-word
  3562.                        m3-ident-match-no-case-fold)
  3563.              (setq matches (cons elem matches))))
  3564.           names)
  3565.  
  3566. ;;;      (message "In m3-ident-complete-work (3), matches = %s" matches)
  3567. ;;;      (sit-for 2)
  3568.       (cond
  3569.        ((eq (length matches) 0)
  3570.         (goto-char save-point)
  3571.         (message "No matches of current word '%s'." cur-word))
  3572.        ((eq (length matches) 1)
  3573.         (delete-region (point)
  3574.                (save-excursion (forward-word 1) (point)))
  3575.         (insert (car matches)))
  3576.        (t
  3577.         ;; Multiple matches.  Sort them alphabetically.
  3578.         (setq matches (sort matches 'string<))
  3579.         ;; Find the longest common prefix.
  3580.         (let ((lcp (m3-longest-common-prefix matches)))
  3581. ;;;          (message "In m3-ident-complete-work (4), lcp = %s" lcp)
  3582. ;;;          (sit-for 2)
  3583.           (setq m3-cur-ident-completions matches)
  3584.           (setq m3-cur-ident-completion-len (length lcp))
  3585.           ;; This completion is only partial.
  3586.           (setq m3-cur-ident-completion-done nil)
  3587.           (delete-region (point)
  3588.                  (save-excursion (forward-word 1) (point)))
  3589.           (set-marker m3-cur-ident-completion-start (point))
  3590.           (insert lcp)
  3591.           (if (> (length m3-cur-ident-completions) 1)
  3592.           (message
  3593.            "Completions: %s"
  3594.            (mapconcat '(lambda (x) x)
  3595.                   m3-cur-ident-completions ", ")))))))))))))
  3596.  
  3597.  
  3598. (defun m3-longest-common-prefix (names)
  3599.   "Returns the longest string that is a common substring of all the strings
  3600. in NAMES"
  3601.   (m3-longest-common-prefix-work (car names) (cdr names)))
  3602.  
  3603. (defun m3-longest-common-prefix-work (lcp names)
  3604.   "Returns the longest string that is a common substring of lcp and the
  3605. strings in the list NAMES"
  3606.   (cond
  3607.    ((null names) lcp)
  3608.    (t
  3609.     (let ((len (length lcp))
  3610.       (continue nil)
  3611.       (first-name (car names)))
  3612. ;;;      (message "m3-lcp, lcp: %s, fn: %s" lcp first-name) (sit-for 2)
  3613.       (while (and (> len 0) (not (m3-is-prefix first-name
  3614.                            (substring lcp 0 len))))
  3615. ;;;    (message "m3-lcp, len = %d, lcp = %s" len (substring lcp 0 len))
  3616. ;;;    (sit-for 2)
  3617.     (setq len (- len 1)))
  3618. ;;;      (message "m3-lcp (2)") (sit-for 2)
  3619.       (cond
  3620.        ((= len 0) "")
  3621.        (t (m3-longest-common-prefix-work (substring lcp 0 len)
  3622.                      (cdr names))))))))
  3623.           
  3624.     
  3625.         
  3626.  
  3627. ;;;======================================================================
  3628.  
  3629. (defun m3-is-letter (ch)
  3630.   "checks if argument is a letter."
  3631.   (and (>= (upcase ch) ?A) (<= (upcase ch) ?Z)))
  3632.  
  3633. (defun m3-abbrev-or-tab ()
  3634.   "if preceding char in buffer is letter, tries to expand abbrev else tabs."
  3635.   (interactive)
  3636.   (if (and m3-abbrev-enabled (m3-is-letter (preceding-char)))
  3637.     (m3-abbrev)
  3638.     (m3-tab)))
  3639.  
  3640. (defun m3-abbrev-and-or-indent ()
  3641.   "If preceding char in buffer is letter, tries to expand abbrev.
  3642. Otherwise, indents the current line."
  3643.   (interactive)
  3644. ;;;  (message "Foo1") (sit-for 2)
  3645.   (if (and m3-abbrev-enabled
  3646.        (or (m3-is-letter (preceding-char))
  3647.            (save-excursion
  3648.          (and
  3649.           (> (point) 2)
  3650.           (progn
  3651.             (forward-char -2)
  3652.             (and
  3653.              (looking-at "*)")
  3654.              (progn (forward-word -1) (forward-char -3)
  3655.                 (looking-at "(*"))
  3656.              (progn (forward-word -1) (looking-at "END"))))))
  3657.            (save-excursion
  3658.          (and
  3659.           (> (point) 2)
  3660.           (progn
  3661.             (forward-char -1)
  3662.             (and
  3663.              (looking-at ";\\|.")
  3664.              (progn (forward-word -2) (looking-at "END")))))))
  3665.        (or (eq (point) (point-max))
  3666.            (eq (following-char) ?\ )
  3667.            (eq (following-char) ?\t)
  3668.            (eq (following-char) ?\n)))
  3669.       (progn (m3-abbrev)
  3670.          (m3-indent-line))
  3671.     (m3-indent-line)))
  3672.  
  3673.  
  3674. ; Finally a function for those used to M2 style text literals. It checks for
  3675. ; text literals containing single quotes and ensures that they are preceded by
  3676. ; a backslash.
  3677. ; BUG: If a text literal contains an embedded double quote it is ignored
  3678.  
  3679. (defun m3-text-literal-check ()
  3680. "Ensures that single quotes in text literals are preceded by backslash"
  3681.   (interactive)
  3682.   (save-excursion
  3683.     (goto-char (point-min))
  3684.     (while (re-search-forward "[^\\\\]\"\\([^\"]*\\)[^\\\\]" nil t)
  3685.       (save-excursion
  3686.         (save-restriction
  3687.           (narrow-to-region (match-beginning 1) (match-end 1))
  3688.           (goto-char (point-min))
  3689.           (replace-regexp "\\([^\\\\]\\)'" "\\1\\\\'"))))))
  3690.  
  3691.  
  3692. ;;;-------------------------------------------------------- pretty printing ---
  3693.  
  3694. (defvar m3pp-options '("-ZZ")
  3695.   "Command line options that should be passed to m3pp when it is started up.")
  3696.  
  3697. (defvar &m3pp-modunit "\002")
  3698. (defvar &m3pp-defunit "\005")
  3699. (defvar &m3pp-endunit "\001")
  3700.  
  3701. (defvar &m3pp-process nil)
  3702. (defvar &m3pp-in-progress nil)
  3703.  
  3704. (defvar &m3pp-unit-boundary
  3705.       (concat "^[ \t]*\nCONST\\|" 
  3706.               "^[ \t]*\nTYPE\\|"
  3707.               "^[ \t]*\nVAR\\|"
  3708.               "^[ \t]*\nPROCEDURE\\|"
  3709.               "^[ \t]*\nEXCEPTION\\|"
  3710.           "^[ \t]*\n<\*EXTERNAL\*>|"
  3711.           "^[ \t]*\n<\*INLINE\*>|"
  3712.               "^[ \t]*\nMODULE\\|"
  3713.           "^[ \t]*\nINTERFACE\\|"
  3714.           "^[ \t]*\nIMPORT\\|"
  3715.               "^[ \t]*\nBEGIN"))
  3716.  
  3717. (defun &m3pp-startup ()
  3718.   (if (not (and &m3pp-process
  3719.         (process-status (process-name &m3pp-process))))
  3720.       (save-excursion 
  3721.     (get-buffer-create "&m3pp")
  3722.     (set-buffer "&m3pp")
  3723.     (erase-buffer)
  3724.     (setq &m3pp-process 
  3725.           (apply 'start-process "m3pp" nil "m3pp" m3pp-options))
  3726.     (process-kill-without-query &m3pp-process)
  3727.     (set-process-filter &m3pp-process '&m3pp-filter)
  3728.     (process-send-string &m3pp-process 
  3729.                  (concat &m3pp-modunit &m3pp-endunit "\n"))
  3730.     (accept-process-output &m3pp-process))))
  3731.  
  3732. (defun m3pp-unit ()
  3733.   "Pretty prints the 'unit' containing the cursor. 
  3734.    A unit starts with a blank line followed by CONST, TYPE, VAR, 
  3735.    PROCEDURE, EXCEPTION, IMPORT, FROM, MODULE, or BEGIN, and it extends 
  3736.    to the start of the next unit.  If there is no such unit around the
  3737.    cursor, the entire file is pretty printed."
  3738.   (interactive)
  3739.   (save-excursion
  3740.     (let (start)
  3741.       (&m3pp-find-format-unit)
  3742.       (setq start (point-marker))
  3743.       (m3pp-region)
  3744.       (set-mark (point))
  3745.       (goto-char start)
  3746.       (exchange-point-and-mark))))
  3747.  
  3748. (defun m3pp-region ()
  3749.   "Pretty prints the region. 
  3750.    The region should consist of zero or more declarations, definitions, 
  3751.    import statements, or modules."
  3752.   (interactive)
  3753.   (let* ((size (- (point-marker) (mark-marker)))
  3754.      (a (if (< size 0) (- size) size)))
  3755.     (if (> a 32760)
  3756.     (error (concat "Sorry, region too large for emac "
  3757.                (int-to-string a) " > 32760"))))
  3758.   (safe-m3pp-region))
  3759.  
  3760. (defun safe-m3pp-region ()
  3761.   (let ((m3pp-type nil)
  3762.     (m3pp-start nil))
  3763.     (&m3pp-startup)
  3764.     (save-excursion
  3765.       (goto-char (point-min))
  3766.       (if (search-forward &m3pp-endunit (point-max) t)
  3767.       (error "m3pp: file mustn't contain ^A"))
  3768.       (get-buffer-create "&m3pp-output")
  3769.       (set-buffer "&m3pp-output")
  3770.       (erase-buffer))
  3771.     (let* ((len (length (buffer-file-name)))
  3772.        (tail (substring (buffer-file-name) (- len 3) len)))
  3773.       (if (string-equal tail ".m3")
  3774.       (setq m3pp-type &m3pp-modunit))
  3775.       (if (string-equal tail ".i3")
  3776.       (setq m3pp-type &m3pp-defunit))
  3777.       (if (and (not (string-equal tail ".m3")) (not (string-equal tail ".i3")))
  3778.       (error "m3pp: pretty-print only .m3 or .i3 files")))
  3779.     (message "m3pp: working ...")
  3780.     (setq &m3pp-in-progress t)
  3781.     (process-send-string 
  3782.      &m3pp-process
  3783.      (concat m3pp-type 
  3784.          (buffer-substring (min (point) (mark)) (max (point) (mark)))
  3785.          &m3pp-endunit "\n"))
  3786.     (while &m3pp-in-progress
  3787.       (accept-process-output &m3pp-process))
  3788.     (setq m3pp-start (point-marker))
  3789.     (kill-region (point) (mark))
  3790.     (insert-buffer "&m3pp-output")
  3791.     (save-excursion
  3792.       (set-buffer "&m3pp-output")
  3793.       (if (re-search-backward "(\\* SYNTAX ERROR " (point-min) t)
  3794.       (progn
  3795.         (beep)
  3796.         (message "m3pp: syntax error"))
  3797.     (progn ;else
  3798.       (message "m3pp: done"))))
  3799.     (if (not (pos-visible-in-window-p))
  3800.     (let ((dotval (+ (point-marker))))
  3801.       (line-to-bottom-of-window)
  3802.       (goto-char dotval)))))
  3803.  
  3804. (defun &m3pp-filter (&process &str)
  3805.   (save-excursion
  3806.     (get-buffer-create "&m3pp-output")
  3807.     (set-buffer "&m3pp-output")
  3808.     (goto-char (point-max))
  3809.     (insert &str)
  3810.     (if (search-backward &m3pp-endunit (point-min) t) 
  3811.     (progn
  3812.       (delete-char 2)
  3813.       (setq &m3pp-in-progress nil)))))
  3814.  
  3815. (defun &m3pp-find-format-unit ()
  3816.   (if (not (re-search-backward &m3pp-unit-boundary (point-min) t))
  3817.       (goto-char (point-min)))
  3818.   (set-mark (point))
  3819.   (if (bobp)
  3820.       (progn 
  3821.     (goto-char (point-max))
  3822.     (if (bolp) (backward-char)))
  3823.     (progn ;else
  3824.       (forward-line)
  3825.       (beginning-of-line)
  3826.       (set-mark (point))
  3827.       (if (not (re-search-forward &m3pp-unit-boundary (point-max) t)) 
  3828.       (progn 
  3829.         (goto-char (point-max))
  3830.         (if (bolp) (backward-char)))
  3831.         (progn ;else
  3832.       (beginning-of-line)))))
  3833.   (exchange-point-and-mark)
  3834.   nil)
  3835.  
  3836. ;;;------------------------------------------------------------------- epoch ---
  3837.  
  3838. (if (boundp 'epoch::version)
  3839.     (progn
  3840.     (require 'mouse)
  3841.     (require 'scr-pool)))
  3842.  
  3843. (defvar *m3::defpath* '("." "/proj/cra/ultrix/${CPU_TYPE}/pub/m3")
  3844.   "Search path for Modula-3 interfaces")
  3845.  
  3846. (if (boundp 'epoch::version)
  3847.     (progn
  3848.       (defvar *m3::poolsize* 8
  3849.     "Size of the pool of screens for Modula-3 interfaces")
  3850.       (defvar *m3::poolclass* "Modula-3"
  3851.     "Class for the Modula-3 interface screens")))
  3852.  
  3853. ;;; stolen from lib-complete, 
  3854. ;;; Author          : Mike Williams <mike-w@cs.aukuni.ac.nz>
  3855. ;;; Created On      : Sat Apr 20 17:47:21 1991
  3856. ;;; Last Modified By: Mike Williams
  3857. ;;; Last Modified On: Tue Jun 18 12:53:08 1991
  3858.  
  3859. (defun m3::locate-file (FILE SEARCH-PATH &optional SUFFIX-LIST PRED)
  3860.   "Search for FILE on SEARCH-PATH (list).  If optional SUFFIX-LIST is
  3861. provided, allow file to be followed by one of the suffixes.
  3862. Optional second argument PRED restricts the number of files which
  3863. may match.  The default is file-exists-p."
  3864.   (if (not SUFFIX-LIST) (setq SUFFIX-LIST '("")))
  3865.   (if (not PRED) (setq PRED 'file-exists-p))
  3866.   (if (file-name-absolute-p FILE) (setq SEARCH-PATH '(nil)))
  3867.   (if (equal FILE "") (error "Empty filename"))
  3868.   (let ((filelist 
  3869.      (mapcar 
  3870.       (function (lambda (ext) (concat FILE ext)))
  3871.       SUFFIX-LIST)))
  3872.     ;; Search SEARCH-PATH for a readable file in filelist
  3873.     (catch 'found
  3874.       (while SEARCH-PATH
  3875.     (let ((filelist filelist))
  3876.       (while filelist
  3877.         (let ((filepath (substitute-in-file-name 
  3878.                  (expand-file-name (car filelist) (car SEARCH-PATH)))))
  3879.           (if (funcall PRED filepath)
  3880.           (throw 'found filepath)))
  3881.         (setq filelist (cdr filelist))))
  3882.     (setq SEARCH-PATH (cdr SEARCH-PATH))))
  3883.     ))
  3884.  
  3885.  
  3886.  
  3887. (defun m3::show-interface (&optional arg)
  3888.   "Find a Modula-3 interface. 
  3889.    If ARG is a string, it is the name of the interface.  If ARG is nil, 
  3890.    get the name from the text around the point.  Otherwise, ARG should be 
  3891.    an epoch mouse position and the name is found around that position.
  3892.    Using *m3::defpath*, find the file that contains that interface.
  3893.    Under gnuemacs, show the interface in another window. 
  3894.    Under epoch, show the interface in a screen of the Modula-3 pool; the 
  3895.    screens in that pool are in the class *m3::poolclass*. The Modula-3 pool
  3896.    is of size *m3::poolsize*." 
  3897.   (interactive)
  3898.   (let (buffer pos interface filename)
  3899.     (if (stringp arg)
  3900.     (setq interface arg)
  3901.       (save-excursion
  3902.     (if arg
  3903.         (progn
  3904.           (setq buffer (nth 1 arg))
  3905.           (setq pos (car arg)))
  3906.       (progn
  3907.         (setq buffer (current-buffer))
  3908.         (setq pos (point))))
  3909.     (set-buffer buffer)
  3910.     (goto-char pos)
  3911.     (let (end)
  3912.       (re-search-forward "[^A-Za-z0-9]" nil t)
  3913.       (backward-char)
  3914.       (setq end (point))
  3915.       (re-search-backward "[^A-Za-z0-9]" nil t)
  3916.       (forward-char)
  3917.       (setq interface (buffer-substring (point) end)))))
  3918.     (setq filename (locate-file (concat interface ".i3") *m3::defpath*))
  3919.     (if (boundp 'epoch::version)
  3920.     (progn
  3921.       (setq buf (find-file-noselect filename))
  3922.       (let ((screen (pool:get-shrink-wrapped-screen 
  3923.              m3-interfaces-pool buf '(80 80 20 40))))
  3924.         (epoch::select-screen screen)
  3925.         (epoch::mapraised-screen screen))
  3926.       (switch-to-buffer buf))
  3927.       (progn 
  3928.     (find-file-other-window filename)))))
  3929.  
  3930.  
  3931. (if (boundp 'epoch::version)
  3932.     (progn
  3933.       (setq m3-interfaces-pool
  3934.         (pool:create *m3::poolsize* 
  3935.              '(lambda () 
  3936.                 (create-screen nil 
  3937.                        (cons (cons 'class *m3::poolclass*) 
  3938.                          nil)))))
  3939.       (global-set-mouse mouse-left mouse-meta 'm3::show-interface)))
  3940.     
  3941.  
  3942.