home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / modula-3 / m3-3.5 / m3-3 / usr / local / modula3-3.5.4-B / lib / elisp / modula3.el < prev   
Encoding:
Text File  |  1995-11-15  |  114.7 KB  |  3,462 lines

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