home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lifeos2.zip / LIFE-1.02 / EMACSMOD / LIFE-MOD.EL < prev   
Lisp/Scheme  |  1996-06-04  |  13KB  |  459 lines

  1. ;; life-mode.el --- major mode for editing Life under Emacs
  2.  
  3. ;; Author: Bruno Dumant <dumant@prl.dec.com>
  4. ;; Keywords: languages
  5.  
  6. ;; This package provides a major mode for editing Life.  It knows
  7. ;; about Life syntax and comments.
  8.  
  9. ;;; Code:
  10.  
  11.  
  12. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  13. ;;
  14. ;; Variables 
  15. ;;
  16. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  17.  
  18.  
  19. (defvar life-mode-syntax-table nil)
  20. (defvar life-mode-abbrev-table nil)
  21. (defvar life-mode-map (make-sparse-keymap)
  22.   "Keymap used in life-mode.")
  23.  
  24. (defvar life-brace-offset 4)
  25. (defvar life-multiline-offset 2)
  26. (defvar close-position 0)
  27. (defvar small-comments nil)
  28. (defvar life-tab-always-indent t)
  29. (defvar clause-beginning 0)
  30. (defvar sentence-start-col (* 2 life-brace-offset))
  31. (defvar sentence-start-pos 0)
  32. (defvar open-pile nil)
  33.  
  34. (setq max-lisp-eval-depth 500)
  35.  
  36. (if (not life-mode-syntax-table)
  37.     (let ( (table (make-syntax-table)) )
  38.       (modify-syntax-entry ?_ "w" 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 ?\n ">" table)
  47.       (modify-syntax-entry ?< "." table)
  48.       (modify-syntax-entry ?> "." table)
  49.       (modify-syntax-entry ?\' "\"" table)
  50.       (setq life-mode-syntax-table table)))
  51.  
  52.  
  53. (define-abbrev-table 'life-mode-abbrev-table ())
  54.  
  55.  
  56. (defun life-mode-variables ()
  57.   (set-syntax-table life-mode-syntax-table)
  58.   (setq local-abbrev-table life-mode-abbrev-table)
  59.   (make-local-variable 'paragraph-start)
  60.   (setq paragraph-start (concat "^%%%\\|^$\\|" page-delimiter)) ;'%%%..'
  61.   (make-local-variable 'paragraph-separate)
  62.   (setq paragraph-separate paragraph-start)
  63.   (make-local-variable 'paragraph-ignore-fill-prefix)
  64.   (setq paragraph-ignore-fill-prefix t)
  65.   (make-local-variable 'indent-line-function)
  66.   (setq indent-line-function 'life-indent-line-2)
  67.   (make-local-variable 'comment-start)
  68.   (setq comment-start "%")
  69.   (make-local-variable 'comment-start-skip)
  70.   (setq comment-start-skip "%+ *")
  71.   (make-local-variable 'comment-column)
  72.   (setq comment-column 48)
  73.   (make-local-variable 'comment-indent-hook)
  74.   (setq comment-indent-hook 'life-comment-indent)
  75.   (make-local-variable 'require-final-newline)
  76.   (setq require-final-newline t)
  77.   (make-local-variable 'comment-end)
  78.   (setq comment-end "")
  79.   (make-local-variable 'parse-sexp-ignore-comments)
  80.   (setq parse-sexp-ignore-comments nil))
  81.  
  82.  
  83.  
  84. (defvar life-mode-map (make-sparse-keymap)
  85.   "Keymap used in Life mode.")
  86.  
  87. (define-key life-mode-map "\t" 'life-indent-command)
  88. (define-key life-mode-map "\e\C-\\" 'indent-region)
  89. (define-key life-mode-map "\C-x%" 'life-comment-region)
  90. (define-key life-mode-map "\C-x$" 'life-uncomment-region)
  91. (define-key life-mode-map "\C-j" 'reindent-then-newline-and-indent)
  92. (define-key life-mode-map "\e\C-q" 'indent-life-exp)
  93.  
  94.  
  95.  
  96. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  97. ;;
  98. ;; Life mode
  99. ;;
  100. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  101.  
  102.  
  103. ;;;###autoload
  104. (defun life-mode ()
  105.   "Major mode for editing Life code. 
  106. Tab at left margin indents for Life code (see life-tab-always-indent below),
  107. Blank lines and `%%%...' separate paragraphs.  `%'s start comments.
  108. Commands:
  109. \\{life-mode-map}
  110.  
  111.  There are three kinds of comments:
  112.     - large comments start with %%%. They are always indented at column 0.
  113.     - mid-comments start with %%. They are indented as life code, unless there
  114.       is a comment on the line before. In the latter case, the comments are 
  115.       aligned.
  116.     - small comments start with %.
  117.       If small-comments is non-nil, they are idented to comment-column 
  118.       (default value is 48), unless there is a comment on the line before.
  119.       Otherwise, they are idented like mid-comments.
  120.       Default of small-comments is nil.
  121.  
  122.  life-tab-always-indent
  123.     Non-nil means TAB in Life mode should always reindent the current line,
  124.     regardless of where in the line point is when the TAB command is used.
  125.     Default is t.
  126.  life-brace-offset
  127.     Extra indentation for line if it starts with an open brace.
  128.     Default is 4.
  129.  
  130.  life-multiline-offset 
  131.    It is the amount of extra indentation for more than one line long sentences
  132.    (sequence of terms ending with , ; or |). Its default value is 2. 
  133.  
  134. Entry to this mode calls the value of `life-mode-hook'
  135. if that value is non-nil."
  136.   (interactive)
  137.   (kill-all-local-variables)
  138.   (use-local-map life-mode-map)
  139.   (setq major-mode 'life-mode)
  140.   (setq mode-name "Life")
  141.   (life-mode-variables)
  142.   (run-hooks 'life-mode-hook))
  143.  
  144.  
  145. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  146. ;;
  147. ;; Indentation command
  148. ;;
  149. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  150.  
  151.  
  152. (defun life-indent-command (&optional whole-exp)
  153.   (interactive "P")
  154.   "Indent current line as Life code, or in some cases insert a tab character.
  155. If life-tab-always-indent is non-nil (the default), always indent current line.
  156. Otherwise, indent the current line only if point is at the left margin
  157. or in the line's indentation; otherwise insert a tab.
  158.  
  159. A numeric argument, regardless of its value,
  160. means indent rigidly all the lines of the expression starting after point
  161. so that this line becomes properly indented.
  162. The relative indentation among the lines of the expression are preserved."
  163.   (if whole-exp
  164.       ;; If arg, always indent this line as Life
  165.       ;; and shift remaining lines of expression the same amount.
  166.       (let ((shift-amt (life-indent-line))
  167.         beg end)
  168.     (save-excursion
  169.       (if life-tab-always-indent
  170.           (beginning-of-line))
  171.       (setq beg (point))
  172.       (forward-sexp 1)
  173.       (setq end (point))
  174.       (goto-char beg)
  175.       (forward-line 1)
  176.       (setq beg (point)))
  177.     (if (> end beg)
  178.         (indent-code-rigidly beg end shift-amt "#")))
  179.     (if (and (not life-tab-always-indent)
  180.          (save-excursion
  181.            (skip-chars-backward " \t")
  182.            (not (bolp))))
  183.     (insert-tab)
  184.       (life-indent-line))))
  185.  
  186.  
  187. ;; indenting code
  188.  
  189. (defun life-indent-line ()
  190.   "Indent current line as Life code."
  191.   (interactive "p")
  192.   (beginning-of-line)
  193.   (life-real-indent)
  194.   (if (looking-at "[ \t]*\n")
  195.       (skip-chars-forward " \t")
  196.     (end-of-line)
  197.     (skip-chars-backward " \t")))
  198.  
  199. (defun life-indent-line-2 ()
  200.   "Indent current line as Life code."
  201.   (interactive "p")
  202.   (beginning-of-line)
  203.   (life-real-indent)
  204.   (let ((pos (- (point-max) (point))))
  205.     (if (> (- (point-max) pos) (point))
  206.     (goto-char (- (point-max) pos)))))
  207.  
  208.  
  209.  
  210. (defun life-real-indent ()
  211.   (setq clause-beginning (beginning-of-life-clause-pos))
  212.   (if (not (inside-string t))
  213.       (let ((indent (life-indent-level)) beg)
  214.     (setq beg (point))
  215.     (skip-chars-forward " \t")
  216.     (if (zerop (- indent (current-column)))
  217.         nil
  218.       (delete-region beg (point))
  219.       (indent-to indent)))))
  220.  
  221.  
  222.  
  223. (defun life-indent-level ()
  224.   "Return appropriate indentation for current line as Life code.
  225. In usual case returns an integer: the column to indent to."
  226.   (save-excursion
  227.     (beginning-of-line)
  228.     (skip-chars-forward " \t")
  229.     (cond
  230.      ((>= (- clause-beginning (point)) 0) 
  231.       (setq sentence-start-pos 0)
  232.       0)   ; Beginning of clause
  233.      ((looking-at "%") (life-comment-indent))  ; comment
  234.      (t
  235.       (life-indent-level2 (point))))))
  236.  
  237. (defun life-indent-level2 (current-pos)
  238.   (goto-char clause-beginning)
  239.   (init-indent)
  240.   (life-indent-level3 current-pos))
  241.  
  242.   
  243. (defun life-indent-level3 (current-pos)
  244.   "Return appropriate indentation for current line as Life code when it depends on the previous line."
  245.   (while (< (point) current-pos)
  246.     (looking-at "[^]})\"'{(%,;|.?\n[]*" )
  247.     (goto-char (match-end 0))
  248.     (if (< (point) current-pos)
  249.     (cond ((looking-at "[{([]")
  250.            (save-context))
  251.           ((looking-at "[]})]")
  252.            (restore-context))
  253.           ((looking-at "[\"']")
  254.            (skip-string-forward))
  255.           ((looking-at "%")
  256.            (end-of-line))
  257.           ((looking-at "\n")
  258.            (forward-char 1)
  259.            (if (zerop sentence-start-pos)
  260.            (progn
  261.              (skip-void-comments)
  262.              (setq sentence-start-pos (point)))))
  263.           ((looking-at "[,;|]")
  264.            (forward-char 1)
  265.            (skip-void-comments)
  266.            (setq sentence-start-pos (min current-pos (point))))
  267.           ((looking-at "[.?]")
  268.            (forward-char 1)
  269.            (if (looking-at "[ \t\n]")
  270.            (progn
  271.              (skip-void-comments)
  272.              (setq clause-beginning (point))
  273.              (init-indent)))))))
  274.   (goto-char current-pos)
  275.   (cond ((>= (- clause-beginning (point)) 0) 
  276.      (setq sentence-start-pos 0)
  277.      0)
  278.     ((looking-at "[]});,|]")
  279.      (if open-pile
  280.          (car open-pile)
  281.        life-brace-offset))
  282.     ((zerop sentence-start-pos)
  283.      sentence-start-col)
  284.     ((> (point) sentence-start-pos)  
  285.      (+ life-multiline-offset sentence-start-col))
  286.     (t
  287.      sentence-start-col)))
  288.  
  289. ;; indenting comments
  290.  
  291. (defun life-comment-indent ()
  292.   "Compute life comment indentation."
  293.   (save-excursion
  294.     (cond ((looking-at "%%%") 0)                   ; Large comment starts 
  295.       (t                                       ; Other comments
  296.        (let (col)
  297.          (setq col (current-column))
  298.          (forward-line -1)
  299.          (beginning-of-line)
  300.          (if (looking-at "[^%\n]*%")           ; if there are comments on the
  301.                     ; line before, align. 
  302.          (progn
  303.            (goto-char (- (match-end 0) 1))
  304.            (current-column))
  305.            (forward-line 1)
  306.            (skip-chars-forward " \t\n")
  307.            (if (or (looking-at "%%") (not small-comments))
  308.            (life-indent-level2 (point))
  309.          comment-column)))))))
  310.  
  311.  
  312.  
  313. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  314. ;;
  315. ;; Utilities used for indenting
  316. ;;
  317. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  318.  
  319.  
  320. ;; go to the beginning of the current clause
  321.  
  322. (defun beginning-of-clause ()
  323.   (interactive)
  324.   (cond ((bobp)
  325.      t)
  326.     ((re-search-backward "^[^%\n]*[?.][ \t]*\\(%.*\n?\\)?\n" 
  327.                  (bobp) t)
  328.      (goto-char (match-end 0)))
  329.     (t
  330.      (beginning-of-buffer)))
  331.   (skip-void-comments))
  332.  
  333.  
  334. (defun beginning-of-life-clause-pos ()
  335.   (save-excursion
  336.     (beginning-of-clause)
  337.     (point)))
  338.  
  339.  
  340.  
  341. ;; initialization
  342.  
  343. (defun init-indent ()
  344.   (setq sentence-start-pos 0) 
  345.   (setq sentence-start-col (* 2 life-brace-offset))
  346.   (setq open-pile nil))
  347.  
  348.  
  349. ;; Dealing with contexts
  350.  
  351. (defun save-context ()
  352.   (let (indent-after
  353.     (cc (current-column)) )
  354.     (forward-char 1)
  355.     (skip-void-comments-same-line)
  356.     (if (looking-at "\n")
  357.     (setq indent-after (+ life-brace-offset cc))
  358.       (setq indent-after (current-column)))
  359.     (skip-void-comments)
  360.     (setq open-pile (list cc indent-after sentence-start-pos 
  361.               sentence-start-col open-pile))
  362.     (setq sentence-start-pos (point))
  363.     (setq sentence-start-col indent-after)
  364.     ))
  365.  
  366.  
  367. (defun restore-context ()
  368.   (let (context)
  369.     (if open-pile
  370.     (progn
  371.       (setq sentence-start-pos (nth 2 open-pile))
  372.       (setq sentence-start-col (nth 3 open-pile))
  373.       (setq open-pile (nth 4 open-pile)))))
  374.   (forward-char 1))
  375.  
  376.  
  377. ;; checking whether current position is inside a string or a quoted atom
  378.  
  379. (defun inside-string (incr)
  380.   (if (or (bobp) (not incr))
  381.       nil
  382.     (in-string (point))))
  383.  
  384. (defun in-string (end-point)
  385.   (save-excursion
  386.     (goto-char clause-beginning)
  387.     (in-string2 end-point)))
  388.  
  389. (defun in-string2 (end-point)
  390.   (looking-at "[^\"'%]*")
  391.   (goto-char (match-end 0))
  392.   (if (>= (point) end-point)
  393.       nil
  394.     (cond ((looking-at "[\"']")
  395.        (skip-string-forward)
  396.        (if (>= (point) end-point)
  397.            t
  398.          (in-string2 end-point)))
  399.       ((looking-at "%")
  400.        (end-of-line)
  401.        (cond ((>= (point) end-point)
  402.           nil)
  403.          ((eobp)
  404.           nil)
  405.          (t
  406.           (forward-char 1)
  407.           (in-string2 end-point))))
  408.       ((eobp)
  409.        nil))))
  410.  
  411.  
  412. ;; skipping strings and quoted atoms
  413.  
  414. (defun skip-string-forward ()
  415.   "skip strings or atoms forward"
  416.   (while (looking-at "['\"]")
  417.     (cond ((looking-at "\"[^\"]*\"?")
  418.        (goto-char (match-end 0)))
  419.       ((looking-at "'[^']*'?")
  420.        (goto-char (match-end 0))))))
  421.  
  422. (defun skip-void-comments ()
  423.   (skip-chars-forward " \t\n")
  424.   (while (looking-at "%.*\n?")
  425.     (goto-char (match-end 0))
  426.     (skip-chars-forward " \t\n")))
  427.  
  428. (defun skip-void-comments-same-line ()
  429.   (looking-at "[ \t]*\\(%.*\\)*")
  430.   (goto-char (match-end 0)))
  431.  
  432.  
  433. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  434. ;;
  435. ;; Commenting regions
  436. ;;
  437. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  438.               
  439.  
  440. (defun life-comment-region (start end)
  441.   (interactive "r")
  442.   (comment-region start end 3))
  443.  
  444. (defun life-uncomment-region (start end)
  445.   (interactive "r")
  446.   (comment-region start end -3))
  447.  
  448.  
  449.  
  450. ;;; life-mode.el ends here
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.