home *** CD-ROM | disk | FTP | other *** search
- ;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
- ;Article 3152 of gnu.emacs:
- ;Xref: utkcs2 gnu.emacs:3152 comp.emacs:4594
- ;Path: utkcs2!emory!swrinde!zaphod.mps.ohio-state.edu!usc!apple!sun-barr!ccut!titcca!etlcom!handa
- ;>From: handa@etlhit.etl.go.jp (Kenichi Handa)
- ;Newsgroups: gnu.emacs,comp.emacs
- ;Subject: prolog.el -- new version with enhanced indentation facility
- ;Message-ID: <HANDA.90Jul10004814@etlhit.etl.go.jp>
- ;Date: 9 Jul 90 15:48:14 GMT
- ;Sender: news@etl.go.jp
- ;Followup-To: gnu.emacs
- ;Distribution: gnu
- ;Organization: Electrotechnical Lab., Japan.
- ;Lines: 510
- ;
- ;I've modified the original prolog.el to provide richer
- ;indentation facility. Because 'diff -c' has produced a file
- ;of almost the same length as whole source codes, I'll post
- ;the source.
- ;
- ;---
- ;Ken'ichi HANDA
- ;handa@etl.go.jp
- ;
- ;----------------------------------------------------------------------
- ;; Major mode for editing Prolog, and for running Prolog under Emacs
- ;; Copyright (C) 1986, 1987 Free Software Foundation, Inc.
- ;; Author Masanobu UMEDA (umerin@flab.flab.fujitsu.junet)
-
- ;; Modified for rich indentation in Prolog mode inspired by c-mode.el
- ;; Ken'ichi HANDA (handa@etl.go.jp) 1990.6.13
-
- ;; This file is part of GNU Emacs.
-
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY. No author or distributor
- ;; accepts responsibility to anyone for the consequences of using it
- ;; or for whether it serves any particular purpose or works at all,
- ;; unless he says so in writing. Refer to the GNU Emacs General Public
- ;; License for full details.
-
- ;; Everyone is granted permission to copy, modify and redistribute
- ;; GNU Emacs, but only under the conditions described in the
- ;; GNU Emacs General Public License. A copy of this license is
- ;; supposed to have been given to you along with GNU Emacs so you
- ;; can know your rights and responsibilities. It should be in a
- ;; file named COPYING. Among other things, the copyright notice
- ;; and this notice must be preserved on all copies.
-
- (defvar prolog-mode-syntax-table nil)
- (defvar prolog-mode-abbrev-table nil)
- (defvar prolog-mode-map nil)
-
- (defvar prolog-consult-string "reconsult(user).\n"
- "*(Re)Consult mode (for C-Prolog and Quintus Prolog). ")
-
- (defvar prolog-compile-string "compile(user).\n"
- "*Compile mode (for Quintus Prolog).")
-
- (defvar prolog-eof-string "end_of_file.\n"
- "*String that represents end of file for prolog.
- nil means send actual operating system end of file.")
-
- ;;; Customizable variables for indentation
- (defvar prolog-indent-level 4
- "*Indentation of Prolog statements with respect to containing block.")
- (defvar prolog-paren-offset 0
- "*Extra indentation for parens, compared with other text in same context.")
- (defvar prolog-then-else-offset 2
- "*Offset of Prolog '->' or ';' lines relative to start of current block.")
- (defvar prolog-continued-statement-offset 4
- "*Extra indent for lines not starting new statements.")
- (defvar prolog-first-argument-offset 4
- "*Extra indent for the first argument relative to a head.")
- (defvar prolog-term-separator
- ".*\\(\\.\\|,\\|:-\\|;\\|->\\)\\s *\\($\\|%\\)"
- "*Regexp to test if the last term of current line is terminated.")
- (defvar prolog-tab-always-indent t
- "*Non-nil means TAB in Prolog mode should always reindent the current line,
- regardless of where in the line point is when the TAB command is used.")
-
- (if prolog-mode-syntax-table
- ()
- (let ((table (make-syntax-table)))
- (modify-syntax-entry ?_ "w" table)
- (modify-syntax-entry ?\\ "\\" table)
- (modify-syntax-entry ?+ "." table)
- (modify-syntax-entry ?- "." table)
- (modify-syntax-entry ?= "." table)
- (modify-syntax-entry ?% "<" table)
- (modify-syntax-entry ?< "." table)
- (modify-syntax-entry ?> "." table)
- (modify-syntax-entry ?\' "\"" table)
- (modify-syntax-entry ?\n ">" table)
- (modify-syntax-entry ?\f ">" table)
- (modify-syntax-entry ?/ ". 14" table)
- (modify-syntax-entry ?* ". 23" table)
- (setq prolog-mode-syntax-table table)))
-
- (define-abbrev-table 'prolog-mode-abbrev-table ())
-
- (defun prolog-mode-variables ()
- (set-syntax-table prolog-mode-syntax-table)
- (setq local-abbrev-table prolog-mode-abbrev-table)
- (make-local-variable 'paragraph-start)
- (setq paragraph-start (concat "^%%\\|^$\\|" page-delimiter)) ;'%%..'
- (make-local-variable 'paragraph-separate)
- (setq paragraph-separate paragraph-start)
- (make-local-variable 'paragraph-ignore-fill-prefix)
- (setq paragraph-ignore-fill-prefix t)
- (make-local-variable 'indent-line-function)
- (setq indent-line-function 'prolog-indent-line)
- (make-local-variable 'comment-start)
- (setq comment-start "%")
- (make-local-variable 'comment-start-skip)
- (setq comment-start-skip "\\(\\)\\(%+ *\\|/\\*+ *\\)")
- (make-local-variable 'comment-column)
- (setq comment-column 48)
- (make-local-variable 'comment-indent-hook)
- (setq comment-indent-hook 'prolog-comment-indent))
-
- (defun prolog-mode-commands (map)
- (define-key map "\t" 'prolog-indent-line)
- (define-key map "\e\C-x" 'prolog-consult-region)
- (define-key map "(" 'electric-prolog-paren)
- (define-key map ")" 'electric-prolog-paren)
- (define-key map ";" 'electric-prolog-paren)
- (define-key map ":" 'electric-prolog-paren)
- (define-key map ">" 'electric-prolog-gt)
- (define-key map "\e\C-q" 'prolog-indent-current-clause))
-
- (if prolog-mode-map
- nil
- (setq prolog-mode-map (make-sparse-keymap))
- (prolog-mode-commands prolog-mode-map))
-
- (defun prolog-mode ()
- "Major mode for editing Prolog code for Prologs.
- Blank lines and `%%...' separate paragraphs. `%'s start comments.
- Commands:
- \\{prolog-mode-map}
- Entry to this mode calls the value of prolog-mode-hook
- if that value is non-nil."
- (interactive)
- (kill-all-local-variables)
- (use-local-map prolog-mode-map)
- (setq major-mode 'prolog-mode)
- (setq mode-name "Prolog")
- (prolog-mode-variables)
- (run-hooks 'prolog-mode-hook))
-
- (defun electric-prolog-paren (arg)
- "Insert character and correct line's indentation."
- (interactive "P")
- (if (and (not arg)
- (save-excursion
- (skip-chars-backward " \t")
- (bolp)))
- (progn
- (insert last-command-char)
- (prolog-indent-line)
- (delete-char -1)))
- (self-insert-command (prefix-numeric-value arg)))
-
- (defun electric-prolog-gt (arg)
- "Insert character and correct line's indentation."
- (interactive "P")
- (if (and (not arg)
- (save-excursion
- (beginning-of-line)
- (looking-at "^[ \t]*->$")))
- (progn
- (insert last-command-char)
- (prolog-indent-line))
- (self-insert-command (prefix-numeric-value arg))))
-
- (defun prolog-comment-indent ()
- "Compute Prolog comment indentation."
- (cond ((looking-at "%%%") 0)
- ((or (looking-at "%%") (looking-at "/\\*"))
- (let ((indent (calculate-prolog-indent)))
- (if (consp indent) (car indent) indent)))
- (t
- (save-excursion
- (skip-chars-backward " \t")
- (max (1+ (current-column)) ;Insert one space at least
- comment-column)))
- ))
-
- (defun beginning-of-clause ()
- "Move backward to beginning of current or previous clause."
- (interactive)
- (if (re-search-backward "^\\w\\|^\\s_" (point-min) 'mv)
- (let ((p (point)))
- (prolog-backward-to-noncomment (point-min))
- (if (and (not (bobp))
- (or (/= (preceding-char) ?.) (/= (following-char) ?\n)))
- (beginning-of-clause)
- (goto-char p)))))
-
- (defun end-of-clause ()
- "Move forward to end of current or next clause."
- (interactive)
- (let ((p (point)))
- (while (and (re-search-forward "\\.\n" nil 'move)
- (/= (1- (point))
- (save-excursion
- (prolog-backward-to-noncomment p)
- (point)))))))
-
- (defun prolog-indent-line ()
- "Indent current line as Prolog code.
- Return the amount the indentation changed by."
- (interactive)
- (let ((indent (calculate-prolog-indent nil))
- start-of-block
- beg shift-amt
- (case-fold-search nil)
- (pos (- (point-max) (point))))
- (if (listp indent)
- (progn
- (setq start-of-block (cdr indent))
- (setq indent (car indent)))
- (setq start-of-block 0))
- (beginning-of-line)
- (setq beg (point))
- (setq indent
- (cond ((eq indent nil) (current-indentation))
- ((eq indent t) (calculate-prolog-indent-within-comment))
- (t
- (skip-chars-forward " \t")
- (cond ((or (looking-at "->") (looking-at ";"))
- (+ start-of-block prolog-then-else-offset))
- ((looking-at "%%%") 0)
- ((looking-at "%%") indent)
- ((= (following-char) ?%) comment-column)
- ((= (following-char) ?\)) start-of-block)
- ((= (following-char) ?\()
- (+ indent prolog-paren-offset))
- (t indent)))))
- (skip-chars-forward " \t")
- (setq shift-amt (- indent (current-column)))
- (if (zerop shift-amt)
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos)))
- (delete-region beg (point))
- (indent-to indent)
- ;; If initial point was within line's indentation,
- ;; position after the indentation. Else stay at same point in text.
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos))))
- shift-amt))
-
- (defun calculate-prolog-indent (&optional parse-start)
- "Return appropriate indentation for current line as Prolog code.
- In usual case returns an integer: the column to indent to.
- Returns nil if line starts inside a string, t if in a comment,
- \(indent . start-of-block\) if line is within a paren block."
- (save-excursion
- (beginning-of-line)
- (if (= (following-char) ?%)
- nil
- (let ((indent-point (point))
- (case-fold-search nil)
- state
- containing-sexp
- (following-character
- (save-excursion (skip-chars-forward " \t") (following-char))))
- (if parse-start
- (goto-char parse-start)
- (beginning-of-clause))
- (while (< (point) indent-point)
- (setq parse-start (point))
- (setq state (parse-partial-sexp (point) indent-point 0))
- (setq containing-sexp (car (cdr state))))
- (cond ((or (nth 3 state) (nth 4 state))
- ;; return nil or t if should not change this line
- (nth 4 state))
- ((null containing-sexp)
- ;; Line is at top level.
- ;; Look at previous line that's at column 0
- ;; to determine whether we are in top-level decls
- ;; or within a clause. Set basic-indent accordingly.
- (goto-char indent-point)
- (prolog-backward-to-noncomment (or parse-start (point-min)))
- (let (basic-indent p1 p2)
- (setq p1 (save-excursion
- (re-search-backward "\\.$" nil 'mv)
- (while (save-excursion
- (beginning-of-line)
- (and (not (bobp)) (looking-at ".*%.*$")))
- (re-search-backward "\\.$" nil 'mv))
- (point)))
- (setq p2 (save-excursion
- (if (re-search-backward
- "^\\(\\w\\|\\s_\\)+\\((\\|\\s *:-\\)" nil 'mv)
- (point)
- 0)))
- (setq basic-indent (if (> p1 p2) 0 prolog-indent-level))
- ;; Now add a little if this is a continuation line.
- (+ basic-indent
- (if (or (bobp)
- (progn
- (beginning-of-line)
- (looking-at prolog-term-separator)))
- 0 prolog-continued-statement-offset))))
- ((or (/= (char-after containing-sexp) ?\()
- (= (char-syntax (char-after (1- containing-sexp))) ?w))
- ;; line is argument, not statement. Return a list.
- (cons
- (if (nth 2 state)
- ;; If not the start of first argument,
- ;; indent the same amount as the first argument
- (progn
- (goto-char (1+ containing-sexp))
- (skip-chars-forward " \t\n" (point-max))
- (+ (current-column)
- (progn (goto-char indent-point)
- (prolog-backward-to-noncomment containing-sexp)
- (if (= (preceding-char) ?,) 0
- prolog-continued-statement-offset))))
- ;; the first argument
- ;; indent to the start of predicate + alpha
- (goto-char (1- containing-sexp))
- (re-search-backward "\\S_\\<" nil 'mv)
- (forward-char 1)
- (+ (current-column) prolog-first-argument-offset))
- (save-excursion
- (goto-char containing-sexp)
- (current-column))))
- (t
- ;; Statement level. Return a list.
- (let (current-block-indent block-paren)
- (goto-char containing-sexp)
- ;; At first, find indentation of current block
- (setq block-paren
- (car (cdr (parse-partial-sexp parse-start (point) 0))))
- (setq current-block-indent
- (save-excursion
- (if (not block-paren)
- (current-indentation)
- (goto-char block-paren)
- (prolog-forward-to-noncomment containing-sexp)
- (current-column))))
- (cons
- ;; Is line a first statement after an open-paren?
- (or
- ;; If no, find that first statement and indent like it.
- (save-excursion
- (prolog-forward-to-noncomment indent-point)
- ;; The first following code counts
- ;; if it is before the line we want to indent.
- (and (< (point) indent-point)
- (+ (current-column)
- (progn
- (goto-char indent-point)
- (forward-line -1)
- (if (looking-at prolog-term-separator) 0
- prolog-continued-statement-offset)))))
- ;; If no previous statement,
- ;; indent it relative to line paren is on.
- (+ current-block-indent prolog-first-argument-offset))
- current-block-indent))))))))
-
- (defun calculate-prolog-indent-within-comment ()
- "Return the indentation amount for line, assuming that
- the current line is to be regarded as part of a block comment."
- (let (end star-start)
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (setq star-start (= (following-char) ?\*))
- (skip-chars-backward " \t\n")
- (setq end (point))
- (beginning-of-line)
- (skip-chars-forward " \t")
- (and (re-search-forward "/\\*[ \t]*" end t)
- star-start
- (goto-char (1+ (match-beginning 0))))
- (current-column))))
-
- (defun prolog-backward-to-noncomment (lim)
- (let (opoint stop)
- (while (not stop)
- (skip-chars-backward " \t\n\f" lim)
- (setq opoint (point))
- (if (and (>= (point) (+ 2 lim))
- (= (preceding-char) ?/) (= (char-after (- (point) 2)) ?*))
- (search-backward "/*" lim 'mv)
- (let ((p (max lim (save-excursion (beginning-of-line) (point)))))
- (if (nth 4 (parse-partial-sexp p (point)))
- (search-backward "%" p 'mv)
- (goto-char opoint)
- (setq stop t)))))))
-
- (defun prolog-forward-to-noncomment (lim)
- (forward-char 1)
- (while (progn
- (skip-chars-forward " \t\n" lim)
- (looking-at "%\\|/\\*"))
- ;; Skip over comments and labels following openparen.
- (if (= (following-char) ?\%)
- (forward-line 1)
- (forward-char 2)
- (search-forward "*/" lim 'mv))))
-
- (defun mark-prolog-clause ()
- "Put mark at end of current prolog clause, point at beginning."
- (interactive)
- (push-mark (point))
- (end-of-clause)
- (push-mark (point))
- (beginning-of-clause))
-
- (defun mark-prolog-clauses ()
- "Put mark at end of prolog clause group of the same
- predicate, point at beginning."
- (interactive)
- (push-mark (point))
- (if (not (looking-at "^\\(\\sw\\|\\s_\\)+("))
- (re-search-backward "^\\(\\sw\\|\\s_\\)+(" nil t))
- (let ((predicate
- (concat "^" (buffer-substring (match-beginning 0) (match-end 0)))))
- (while (re-search-forward predicate nil t)
- (end-of-clause))
- (push-mark (point))
- (while (re-search-backward predicate nil t))))
-
- (defun prolog-indent-current-clause ()
- "Indent all lines in a current Prolog clause."
- (interactive)
- (let (p)
- (save-excursion
- (end-of-clause)
- (setq p (point-marker))
- (beginning-of-clause)
- (while (< (point) p)
- (prolog-indent-line)
- (forward-line 1)))))
-
-
- ;;;
- ;;; Inferior prolog mode
- ;;;
- (defvar inferior-prolog-mode-map nil)
-
- ;; Moved into inferior-prolog-mode
- ;;(if inferior-prolog-mode-map
- ;; nil
- ;; (setq inferior-prolog-mode-map (copy-alist shell-mode-map))
- ;; (prolog-mode-commands inferior-prolog-mode-map))
-
- (defun inferior-prolog-mode ()
- "Major mode for interacting with an inferior Prolog process.
-
- The following commands are available:
- \\{inferior-prolog-mode-map}
-
- Entry to this mode calls the value of prolog-mode-hook with no arguments,
- if that value is non-nil. Likewise with the value of shell-mode-hook.
- prolog-mode-hook is called after shell-mode-hook.
-
- You can send text to the inferior Prolog from other buffers
- using the commands send-region, send-string and \\[prolog-consult-region].
-
- Commands:
- Tab indents for Prolog; with argument, shifts rest
- of expression rigidly with the current line.
- Paragraphs are separated only by blank lines and '%%'. '%'s start comments.
-
- Return at end of buffer sends line as input.
- Return not at end copies rest of line to end and sends it.
- \\[shell-send-eof] sends end-of-file as input.
- \\[kill-shell-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing.
- \\[interrupt-shell-subjob] interrupts the shell or its current subjob if any.
- \\[stop-shell-subjob] stops, likewise. \\[quit-shell-subjob] sends quit signal, likewise."
- (interactive)
- (kill-all-local-variables)
- (setq major-mode 'inferior-prolog-mode)
- (setq mode-name "Inferior Prolog")
- (setq mode-line-process '(": %s"))
- (prolog-mode-variables)
- (require 'shell)
- (if inferior-prolog-mode-map
- nil
- (setq inferior-prolog-mode-map (copy-keymap shell-mode-map))
- (prolog-mode-commands inferior-prolog-mode-map))
- (use-local-map inferior-prolog-mode-map)
- (make-local-variable 'last-input-start)
- (setq last-input-start (make-marker))
- (make-local-variable 'last-input-end)
- (setq last-input-end (make-marker))
- (make-variable-buffer-local 'shell-prompt-pattern)
- (setq shell-prompt-pattern "^| [ ?][- ] *") ;Set prolog prompt pattern
- (run-hooks 'shell-mode-hook 'prolog-mode-hook))
-
- (defun run-prolog ()
- "Run an inferior Prolog process, input and output via buffer *prolog*."
- (interactive)
- (require 'shell)
- (switch-to-buffer (make-shell "prolog" "prolog"))
- (inferior-prolog-mode))
-
- (defun prolog-consult-region (compile beg end)
- "Send the region to the Prolog process made by M-x run-prolog.
- If COMPILE (prefix arg) is not nil,
- use compile mode rather than consult mode."
- (interactive "P\nr")
- (save-excursion
- (if compile
- (send-string "prolog" prolog-compile-string)
- (send-string "prolog" prolog-consult-string))
- (send-region "prolog" beg end)
- (send-string "prolog" "\n") ;May be unnecessary
- (if prolog-eof-string
- (send-string "prolog" prolog-eof-string)
- (process-send-eof "prolog")))) ;Send eof to prolog process.
-
- (defun prolog-consult-region-and-go (compile beg end)
- "Send the region to the inferior Prolog, and switch to *prolog* buffer.
- If COMPILE (prefix arg) is not nil,
- use compile mode rather than consult mode."
- (interactive "P\nr")
- (prolog-consult-region compile beg end)
- (switch-to-buffer "*prolog*"))
-
-
-