home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / modes / prolog.el < prev    next >
Encoding:
Text File  |  1990-07-22  |  18.3 KB  |  528 lines

  1. ;From utkcs2!emory!swrinde!zaphod.mps.ohio-state.edu!usc!apple!sun-barr!ccut!titcca!etlcom!handa Wed Jul 11 09:07:59 EDT 1990
  2. ;Article 3152 of gnu.emacs:
  3. ;Xref: utkcs2 gnu.emacs:3152 comp.emacs:4594
  4. ;Path: utkcs2!emory!swrinde!zaphod.mps.ohio-state.edu!usc!apple!sun-barr!ccut!titcca!etlcom!handa
  5. ;>From: handa@etlhit.etl.go.jp (Kenichi Handa)
  6. ;Newsgroups: gnu.emacs,comp.emacs
  7. ;Subject: prolog.el -- new version with enhanced indentation facility
  8. ;Message-ID: <HANDA.90Jul10004814@etlhit.etl.go.jp>
  9. ;Date: 9 Jul 90 15:48:14 GMT
  10. ;Sender: news@etl.go.jp
  11. ;Followup-To: gnu.emacs
  12. ;Distribution: gnu
  13. ;Organization: Electrotechnical Lab., Japan.
  14. ;Lines: 510
  15. ;
  16. ;I've modified the original prolog.el to provide richer
  17. ;indentation facility.  Because 'diff -c' has produced a file
  18. ;of almost the same length as whole source codes, I'll post
  19. ;the source.
  20. ;
  21. ;---
  22. ;Ken'ichi HANDA
  23. ;handa@etl.go.jp
  24. ;
  25. ;----------------------------------------------------------------------
  26. ;; Major mode for editing Prolog, and for running Prolog under Emacs
  27. ;; Copyright (C) 1986, 1987 Free Software Foundation, Inc.
  28. ;; Author Masanobu UMEDA (umerin@flab.flab.fujitsu.junet)
  29.  
  30. ;; Modified for rich indentation in Prolog mode inspired by c-mode.el
  31. ;;    Ken'ichi HANDA (handa@etl.go.jp) 1990.6.13
  32.  
  33. ;; This file is part of GNU Emacs.
  34.  
  35. ;; GNU Emacs is distributed in the hope that it will be useful,
  36. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  37. ;; accepts responsibility to anyone for the consequences of using it
  38. ;; or for whether it serves any particular purpose or works at all,
  39. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  40. ;; License for full details.
  41.  
  42. ;; Everyone is granted permission to copy, modify and redistribute
  43. ;; GNU Emacs, but only under the conditions described in the
  44. ;; GNU Emacs General Public License.   A copy of this license is
  45. ;; supposed to have been given to you along with GNU Emacs so you
  46. ;; can know your rights and responsibilities.  It should be in a
  47. ;; file named COPYING.  Among other things, the copyright notice
  48. ;; and this notice must be preserved on all copies.
  49.  
  50. (defvar prolog-mode-syntax-table nil)
  51. (defvar prolog-mode-abbrev-table nil)
  52. (defvar prolog-mode-map nil)
  53.   
  54. (defvar prolog-consult-string "reconsult(user).\n"
  55.   "*(Re)Consult mode (for C-Prolog and Quintus Prolog). ")
  56.  
  57. (defvar prolog-compile-string "compile(user).\n"
  58.   "*Compile mode (for Quintus Prolog).")
  59.  
  60. (defvar prolog-eof-string "end_of_file.\n"
  61.   "*String that represents end of file for prolog.
  62. nil means send actual operating system end of file.")
  63.  
  64. ;;; Customizable variables for indentation
  65. (defvar prolog-indent-level 4
  66.   "*Indentation of Prolog statements with respect to containing block.")
  67. (defvar prolog-paren-offset 0
  68.   "*Extra indentation for parens, compared with other text in same context.")
  69. (defvar prolog-then-else-offset 2
  70.   "*Offset of Prolog '->' or ';' lines relative to start of current block.")
  71. (defvar prolog-continued-statement-offset 4
  72.   "*Extra indent for lines not starting new statements.")
  73. (defvar prolog-first-argument-offset 4
  74.   "*Extra indent for the first argument relative to a head.")
  75. (defvar prolog-term-separator
  76.   ".*\\(\\.\\|,\\|:-\\|;\\|->\\)\\s *\\($\\|%\\)"
  77.   "*Regexp to test if the last term of current line is terminated.")
  78. (defvar prolog-tab-always-indent t
  79.   "*Non-nil means TAB in Prolog mode should always reindent the current line,
  80. regardless of where in the line point is when the TAB command is used.")
  81.  
  82. (if prolog-mode-syntax-table
  83.     ()
  84.   (let ((table (make-syntax-table)))
  85.     (modify-syntax-entry ?_ "w" table)
  86.     (modify-syntax-entry ?\\ "\\" table)
  87.     (modify-syntax-entry ?+ "." table)
  88.     (modify-syntax-entry ?- "." table)
  89.     (modify-syntax-entry ?= "." table)
  90.     (modify-syntax-entry ?% "<" table)
  91.     (modify-syntax-entry ?< "." table)
  92.     (modify-syntax-entry ?> "." table)
  93.     (modify-syntax-entry ?\' "\"" table)
  94.     (modify-syntax-entry ?\n ">" table)
  95.     (modify-syntax-entry ?\f ">" table)
  96.     (modify-syntax-entry ?/ ". 14" table)
  97.     (modify-syntax-entry ?* ". 23" table)
  98.     (setq prolog-mode-syntax-table table)))
  99.  
  100. (define-abbrev-table 'prolog-mode-abbrev-table ())
  101.  
  102. (defun prolog-mode-variables ()
  103.   (set-syntax-table prolog-mode-syntax-table)
  104.   (setq local-abbrev-table prolog-mode-abbrev-table)
  105.   (make-local-variable 'paragraph-start)
  106.   (setq paragraph-start (concat "^%%\\|^$\\|" page-delimiter)) ;'%%..'
  107.   (make-local-variable 'paragraph-separate)
  108.   (setq paragraph-separate paragraph-start)
  109.   (make-local-variable 'paragraph-ignore-fill-prefix)
  110.   (setq paragraph-ignore-fill-prefix t)
  111.   (make-local-variable 'indent-line-function)
  112.   (setq indent-line-function 'prolog-indent-line)
  113.   (make-local-variable 'comment-start)
  114.   (setq comment-start "%")
  115.   (make-local-variable 'comment-start-skip)
  116.   (setq comment-start-skip "\\(\\)\\(%+ *\\|/\\*+ *\\)") 
  117.   (make-local-variable 'comment-column)
  118.   (setq comment-column 48)
  119.   (make-local-variable 'comment-indent-hook)
  120.   (setq comment-indent-hook 'prolog-comment-indent))
  121.  
  122. (defun prolog-mode-commands (map)
  123.   (define-key map "\t" 'prolog-indent-line)
  124.   (define-key map "\e\C-x" 'prolog-consult-region)
  125.   (define-key map "(" 'electric-prolog-paren)
  126.   (define-key map ")" 'electric-prolog-paren)
  127.   (define-key map ";" 'electric-prolog-paren)
  128.   (define-key map ":" 'electric-prolog-paren)
  129.   (define-key map ">" 'electric-prolog-gt)
  130.   (define-key map "\e\C-q" 'prolog-indent-current-clause))
  131.  
  132. (if prolog-mode-map
  133.     nil
  134.   (setq prolog-mode-map (make-sparse-keymap))
  135.   (prolog-mode-commands prolog-mode-map))
  136.  
  137. (defun prolog-mode ()
  138.   "Major mode for editing Prolog code for Prologs.
  139. Blank lines and `%%...' separate paragraphs.  `%'s start comments.
  140. Commands:
  141. \\{prolog-mode-map}
  142. Entry to this mode calls the value of prolog-mode-hook
  143. if that value is non-nil."
  144.   (interactive)
  145.   (kill-all-local-variables)
  146.   (use-local-map prolog-mode-map)
  147.   (setq major-mode 'prolog-mode)
  148.   (setq mode-name "Prolog")
  149.   (prolog-mode-variables)
  150.   (run-hooks 'prolog-mode-hook))
  151.  
  152. (defun electric-prolog-paren (arg)
  153.   "Insert character and correct line's indentation."
  154.   (interactive "P")
  155.   (if (and (not arg)
  156.        (save-excursion
  157.          (skip-chars-backward " \t")
  158.          (bolp)))
  159.       (progn
  160.     (insert last-command-char)
  161.     (prolog-indent-line)
  162.     (delete-char -1)))
  163.   (self-insert-command (prefix-numeric-value arg)))
  164.  
  165. (defun electric-prolog-gt (arg)
  166.   "Insert character and correct line's indentation."
  167.   (interactive "P")
  168.   (if (and (not arg)
  169.        (save-excursion
  170.          (beginning-of-line)
  171.          (looking-at "^[ \t]*->$")))
  172.       (progn
  173.     (insert last-command-char)
  174.     (prolog-indent-line))
  175.     (self-insert-command (prefix-numeric-value arg))))
  176.  
  177. (defun prolog-comment-indent ()
  178.   "Compute Prolog comment indentation."
  179.   (cond ((looking-at "%%%") 0)
  180.     ((or (looking-at "%%") (looking-at "/\\*"))
  181.      (let ((indent (calculate-prolog-indent)))
  182.        (if (consp indent) (car indent) indent)))
  183.     (t
  184.      (save-excursion
  185.            (skip-chars-backward " \t")
  186.            (max (1+ (current-column)) ;Insert one space at least
  187.             comment-column)))
  188.     ))
  189.  
  190. (defun beginning-of-clause ()
  191.   "Move backward to beginning of current or previous clause."
  192.   (interactive)
  193.   (if (re-search-backward "^\\w\\|^\\s_" (point-min) 'mv)
  194.       (let ((p (point)))
  195.     (prolog-backward-to-noncomment (point-min))
  196.     (if (and (not (bobp))
  197.          (or (/= (preceding-char) ?.) (/= (following-char) ?\n)))
  198.         (beginning-of-clause)
  199.       (goto-char p)))))
  200.  
  201. (defun end-of-clause ()
  202.   "Move forward to end of current or next clause."
  203.   (interactive)
  204.   (let ((p (point)))
  205.     (while (and (re-search-forward "\\.\n" nil 'move)
  206.         (/= (1- (point))
  207.            (save-excursion
  208.              (prolog-backward-to-noncomment p)
  209.              (point)))))))
  210.  
  211. (defun prolog-indent-line ()
  212.   "Indent current line as Prolog code.
  213. Return the amount the indentation changed by."
  214.   (interactive)
  215.   (let ((indent (calculate-prolog-indent nil))
  216.     start-of-block
  217.     beg shift-amt
  218.     (case-fold-search nil)
  219.     (pos (- (point-max) (point))))
  220.     (if (listp indent)
  221.     (progn
  222.       (setq start-of-block (cdr indent))
  223.       (setq indent (car indent)))
  224.       (setq start-of-block 0))
  225.     (beginning-of-line)
  226.     (setq beg (point))
  227.     (setq indent
  228.       (cond ((eq indent nil) (current-indentation))
  229.         ((eq indent t) (calculate-prolog-indent-within-comment))
  230.         (t
  231.          (skip-chars-forward " \t")
  232.          (cond ((or (looking-at "->") (looking-at ";"))
  233.             (+ start-of-block prolog-then-else-offset))
  234.                ((looking-at "%%%") 0)
  235.                ((looking-at "%%") indent)
  236.                ((= (following-char) ?%) comment-column)
  237.                ((= (following-char) ?\)) start-of-block)
  238.                ((= (following-char) ?\()
  239.             (+ indent prolog-paren-offset))
  240.                (t indent)))))
  241.     (skip-chars-forward " \t")
  242.     (setq shift-amt (- indent (current-column)))
  243.     (if (zerop shift-amt)
  244.     (if (> (- (point-max) pos) (point))
  245.         (goto-char (- (point-max) pos)))
  246.       (delete-region beg (point))
  247.       (indent-to indent)
  248.       ;; If initial point was within line's indentation,
  249.       ;; position after the indentation.  Else stay at same point in text.
  250.       (if (> (- (point-max) pos) (point))
  251.       (goto-char (- (point-max) pos))))
  252.     shift-amt))
  253.  
  254. (defun calculate-prolog-indent (&optional parse-start)
  255.   "Return appropriate indentation for current line as Prolog code.
  256. In usual case returns an integer: the column to indent to.
  257. Returns nil if line starts inside a string, t if in a comment,
  258. \(indent . start-of-block\) if line is within a paren block."
  259.   (save-excursion
  260.     (beginning-of-line)
  261.     (if (= (following-char) ?%)
  262.     nil
  263.       (let ((indent-point (point))
  264.         (case-fold-search nil)
  265.         state
  266.         containing-sexp
  267.         (following-character
  268.          (save-excursion (skip-chars-forward " \t") (following-char))))
  269.     (if parse-start
  270.         (goto-char parse-start)
  271.       (beginning-of-clause))
  272.     (while (< (point) indent-point)
  273.       (setq parse-start (point))
  274.       (setq state (parse-partial-sexp (point) indent-point 0))
  275.       (setq containing-sexp (car (cdr state))))
  276.     (cond ((or (nth 3 state) (nth 4 state))
  277.            ;; return nil or t if should not change this line
  278.            (nth 4 state))
  279.           ((null containing-sexp)
  280.            ;; Line is at top level.
  281.            ;; Look at previous line that's at column 0
  282.            ;; to determine whether we are in top-level decls
  283.            ;; or within a clause.  Set basic-indent accordingly.
  284.            (goto-char indent-point)
  285.            (prolog-backward-to-noncomment (or parse-start (point-min)))
  286.            (let (basic-indent p1 p2)
  287.          (setq p1 (save-excursion
  288.                 (re-search-backward "\\.$" nil 'mv)
  289.                 (while (save-excursion
  290.                      (beginning-of-line)
  291.                      (and (not (bobp)) (looking-at ".*%.*$")))
  292.                   (re-search-backward "\\.$" nil 'mv))
  293.                 (point)))
  294.          (setq p2 (save-excursion
  295.                 (if (re-search-backward
  296.                  "^\\(\\w\\|\\s_\\)+\\((\\|\\s *:-\\)" nil 'mv)
  297.                 (point)
  298.                   0)))
  299.          (setq basic-indent (if (> p1 p2) 0 prolog-indent-level))
  300.          ;; Now add a little if this is a continuation line.
  301.          (+ basic-indent
  302.             (if (or (bobp)
  303.                 (progn
  304.                   (beginning-of-line)
  305.                   (looking-at prolog-term-separator)))
  306.             0 prolog-continued-statement-offset))))
  307.           ((or (/= (char-after containing-sexp) ?\()
  308.            (= (char-syntax (char-after (1- containing-sexp))) ?w))
  309.            ;; line is argument, not statement.  Return a list.
  310.            (cons
  311.         (if (nth 2 state)
  312.             ;; If not the start of first argument,
  313.             ;; indent the same amount as the first argument
  314.             (progn
  315.               (goto-char (1+ containing-sexp))
  316.               (skip-chars-forward " \t\n" (point-max))
  317.               (+ (current-column)
  318.              (progn (goto-char indent-point)
  319.                 (prolog-backward-to-noncomment containing-sexp)
  320.                 (if (= (preceding-char) ?,) 0
  321.                   prolog-continued-statement-offset))))
  322.           ;; the first argument
  323.           ;; indent to the start of predicate + alpha
  324.           (goto-char (1- containing-sexp))
  325.           (re-search-backward "\\S_\\<" nil 'mv)
  326.           (forward-char 1)
  327.           (+ (current-column) prolog-first-argument-offset))
  328.         (save-excursion
  329.           (goto-char containing-sexp)
  330.           (current-column))))
  331.           (t
  332.            ;; Statement level.  Return a list.
  333.            (let (current-block-indent block-paren)
  334.          (goto-char containing-sexp)
  335.          ;; At first, find indentation of current block
  336.          (setq block-paren
  337.                (car (cdr (parse-partial-sexp parse-start (point) 0))))
  338.          (setq current-block-indent
  339.                (save-excursion
  340.              (if (not block-paren)
  341.                  (current-indentation)
  342.                (goto-char block-paren)
  343.                (prolog-forward-to-noncomment containing-sexp)
  344.                (current-column))))
  345.          (cons
  346.           ;; Is line a first statement after an open-paren?
  347.           (or
  348.            ;; If no, find that first statement and indent like it.
  349.            (save-excursion
  350.              (prolog-forward-to-noncomment indent-point)
  351.              ;; The first following code counts
  352.              ;; if it is before the line we want to indent.
  353.              (and (< (point) indent-point)
  354.               (+ (current-column)
  355.                  (progn
  356.                    (goto-char indent-point)
  357.                    (forward-line -1)
  358.                    (if (looking-at prolog-term-separator) 0
  359.                  prolog-continued-statement-offset)))))
  360.            ;; If no previous statement,
  361.            ;; indent it relative to line paren is on.
  362.            (+ current-block-indent prolog-first-argument-offset))
  363.           current-block-indent))))))))
  364.  
  365. (defun calculate-prolog-indent-within-comment ()
  366.   "Return the indentation amount for line, assuming that
  367. the current line is to be regarded as part of a block comment."
  368.   (let (end star-start)
  369.     (save-excursion
  370.       (beginning-of-line)
  371.       (skip-chars-forward " \t")
  372.       (setq star-start (= (following-char) ?\*))
  373.       (skip-chars-backward " \t\n")
  374.       (setq end (point))
  375.       (beginning-of-line)
  376.       (skip-chars-forward " \t")
  377.       (and (re-search-forward "/\\*[ \t]*" end t)
  378.        star-start
  379.        (goto-char (1+ (match-beginning 0))))
  380.       (current-column))))
  381.  
  382. (defun prolog-backward-to-noncomment (lim)
  383.   (let (opoint stop)
  384.     (while (not stop)
  385.       (skip-chars-backward " \t\n\f" lim)
  386.       (setq opoint (point))
  387.       (if (and (>= (point) (+ 2 lim))
  388.            (= (preceding-char) ?/) (= (char-after (- (point) 2)) ?*))
  389.       (search-backward "/*" lim 'mv)
  390.     (let ((p (max lim (save-excursion (beginning-of-line) (point)))))
  391.       (if (nth 4 (parse-partial-sexp p (point)))
  392.           (search-backward "%" p 'mv)
  393.         (goto-char opoint)
  394.         (setq stop t)))))))
  395.  
  396. (defun prolog-forward-to-noncomment (lim)
  397.   (forward-char 1)
  398.   (while (progn
  399.        (skip-chars-forward " \t\n" lim)
  400.        (looking-at "%\\|/\\*"))
  401.     ;; Skip over comments and labels following openparen.
  402.     (if (= (following-char) ?\%)
  403.     (forward-line 1)
  404.       (forward-char 2)
  405.       (search-forward "*/" lim 'mv))))
  406.  
  407. (defun mark-prolog-clause ()
  408.   "Put mark at end of current prolog clause, point at beginning."
  409.   (interactive)
  410.   (push-mark (point))
  411.   (end-of-clause)
  412.   (push-mark (point))
  413.   (beginning-of-clause))
  414.  
  415. (defun mark-prolog-clauses ()
  416.   "Put mark at end of prolog clause group of the same
  417. predicate, point at beginning."
  418.   (interactive)
  419.   (push-mark (point))
  420.   (if (not (looking-at "^\\(\\sw\\|\\s_\\)+("))
  421.       (re-search-backward "^\\(\\sw\\|\\s_\\)+(" nil t))
  422.   (let ((predicate
  423.      (concat "^" (buffer-substring (match-beginning 0) (match-end 0)))))
  424.     (while (re-search-forward predicate nil t)
  425.       (end-of-clause))
  426.     (push-mark (point))
  427.     (while (re-search-backward predicate nil t))))
  428.  
  429. (defun prolog-indent-current-clause ()
  430.   "Indent all lines in a current Prolog clause."
  431.   (interactive)
  432.   (let (p)
  433.     (save-excursion
  434.       (end-of-clause)
  435.       (setq p (point-marker))
  436.       (beginning-of-clause)
  437.       (while (< (point) p)
  438.     (prolog-indent-line)
  439.     (forward-line 1)))))
  440.  
  441.  
  442. ;;;
  443. ;;; Inferior prolog mode
  444. ;;;
  445. (defvar inferior-prolog-mode-map nil)
  446.  
  447. ;; Moved into inferior-prolog-mode
  448. ;;(if inferior-prolog-mode-map
  449. ;;    nil
  450. ;;  (setq inferior-prolog-mode-map (copy-alist shell-mode-map))
  451. ;;  (prolog-mode-commands inferior-prolog-mode-map))
  452.  
  453. (defun inferior-prolog-mode ()
  454.   "Major mode for interacting with an inferior Prolog process.
  455.  
  456. The following commands are available:
  457. \\{inferior-prolog-mode-map}
  458.  
  459. Entry to this mode calls the value of prolog-mode-hook with no arguments,
  460. if that value is non-nil.  Likewise with the value of shell-mode-hook.
  461. prolog-mode-hook is called after shell-mode-hook.
  462.  
  463. You can send text to the inferior Prolog from other buffers
  464. using the commands send-region, send-string and \\[prolog-consult-region].
  465.  
  466. Commands:
  467. Tab indents for Prolog; with argument, shifts rest
  468.  of expression rigidly with the current line.
  469. Paragraphs are separated only by blank lines and '%%'. '%'s start comments.
  470.  
  471. Return at end of buffer sends line as input.
  472. Return not at end copies rest of line to end and sends it.
  473. \\[shell-send-eof] sends end-of-file as input.
  474. \\[kill-shell-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing.
  475. \\[interrupt-shell-subjob] interrupts the shell or its current subjob if any.
  476. \\[stop-shell-subjob] stops, likewise. \\[quit-shell-subjob] sends quit signal, likewise."
  477.   (interactive)
  478.   (kill-all-local-variables)
  479.   (setq major-mode 'inferior-prolog-mode)
  480.   (setq mode-name "Inferior Prolog")
  481.   (setq mode-line-process '(": %s"))
  482.   (prolog-mode-variables)
  483.   (require 'shell)
  484.   (if inferior-prolog-mode-map
  485.       nil
  486.     (setq inferior-prolog-mode-map (copy-keymap shell-mode-map))
  487.     (prolog-mode-commands inferior-prolog-mode-map))
  488.   (use-local-map inferior-prolog-mode-map)
  489.   (make-local-variable 'last-input-start)
  490.   (setq last-input-start (make-marker))
  491.   (make-local-variable 'last-input-end)
  492.   (setq last-input-end (make-marker))
  493.   (make-variable-buffer-local 'shell-prompt-pattern)
  494.   (setq shell-prompt-pattern "^| [ ?][- ] *") ;Set prolog prompt pattern
  495.   (run-hooks 'shell-mode-hook 'prolog-mode-hook))
  496.  
  497. (defun run-prolog ()
  498.   "Run an inferior Prolog process, input and output via buffer *prolog*."
  499.   (interactive)
  500.   (require 'shell)
  501.   (switch-to-buffer (make-shell "prolog" "prolog"))
  502.   (inferior-prolog-mode))
  503.  
  504. (defun prolog-consult-region (compile beg end)
  505.   "Send the region to the Prolog process made by M-x run-prolog.
  506.  If COMPILE (prefix arg) is not nil,
  507.  use compile mode rather than consult mode."
  508.   (interactive "P\nr")
  509.   (save-excursion
  510.     (if compile
  511.     (send-string "prolog" prolog-compile-string)
  512.       (send-string "prolog" prolog-consult-string))
  513.     (send-region "prolog" beg end)
  514.     (send-string "prolog" "\n")        ;May be unnecessary
  515.     (if prolog-eof-string
  516.     (send-string "prolog" prolog-eof-string)
  517.       (process-send-eof "prolog")))) ;Send eof to prolog process.
  518.  
  519. (defun prolog-consult-region-and-go (compile beg end)
  520.   "Send the region to the inferior Prolog, and switch to *prolog* buffer.
  521.  If COMPILE (prefix arg) is not nil,
  522.  use compile mode rather than consult mode."
  523.   (interactive "P\nr")
  524.   (prolog-consult-region compile beg end)
  525.   (switch-to-buffer "*prolog*"))
  526.  
  527.  
  528.