prolog.el 9.4 KB
Newer Older
Eric S. Raymond's avatar
Eric S. Raymond committed
1 2
;;; prolog.el --- major mode for editing and running Prolog under Emacs

Eric S. Raymond's avatar
Eric S. Raymond committed
3 4
;; Copyright (C) 1986, 1987 Free Software Foundation, Inc.

Richard M. Stallman's avatar
Richard M. Stallman committed
5
;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
Eric S. Raymond's avatar
Eric S. Raymond committed
6
;; Keywords: languages
Eric S. Raymond's avatar
Eric S. Raymond committed
7

root's avatar
root committed
8 9 10 11
;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
Eric S. Raymond's avatar
Eric S. Raymond committed
12
;; the Free Software Foundation; either version 2, or (at your option)
root's avatar
root committed
13 14 15 16 17 18 19 20
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
Erik Naggum's avatar
Erik Naggum committed
21 22 23
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
root's avatar
root committed
24

25 26 27 28 29 30
;;; Commentary:

;; This package provides a major mode for editing Prolog.  It knows
;; about Prolog syntax and comments, and can send regions to an inferior
;; Prolog interpreter process.

Eric S. Raymond's avatar
Eric S. Raymond committed
31 32
;;; Code:

root's avatar
root committed
33 34 35
(defvar prolog-mode-syntax-table nil)
(defvar prolog-mode-abbrev-table nil)
(defvar prolog-mode-map nil)
36 37 38 39 40

(defgroup prolog nil
  "Major mode for editing and running Prolog under Emacs"
  :group 'languages)

root's avatar
root committed
41
  
42 43 44 45
(defcustom prolog-program-name "prolog"
  "*Program name for invoking an inferior Prolog with `run-prolog'."
  :type 'string
  :group 'prolog)
root's avatar
root committed
46

47 48 49 50
(defcustom prolog-consult-string "reconsult(user).\n"
  "*(Re)Consult mode (for C-Prolog and Quintus Prolog). "
  :type 'string
  :group 'prolog)
root's avatar
root committed
51

52 53 54 55
(defcustom prolog-compile-string "compile(user).\n"
  "*Compile mode (for Quintus Prolog)."
  :type 'string
  :group 'prolog)
root's avatar
root committed
56

57
(defcustom prolog-eof-string "end_of_file.\n"
root's avatar
root committed
58
  "*String that represents end of file for prolog.
59 60 61
nil means send actual operating system end of file."
  :type 'string
  :group 'prolog)
root's avatar
root committed
62

63 64 65 66
(defcustom prolog-indent-width 4
  "Level of indentation in Prolog buffers."
  :type 'integer
  :group 'prolog)
root's avatar
root committed
67 68 69 70 71 72 73 74 75 76 77 78

(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)
79
    (modify-syntax-entry ?\n ">" table)
root's avatar
root committed
80 81 82 83 84 85 86 87 88 89 90
    (modify-syntax-entry ?< "." table)
    (modify-syntax-entry ?> "." table)
    (modify-syntax-entry ?\' "\"" 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)
91
  (setq paragraph-start (concat "%%\\|$\\|" page-delimiter)) ;'%%..'
root's avatar
root committed
92 93 94 95
  (make-local-variable 'paragraph-separate)
  (setq paragraph-separate paragraph-start)
  (make-local-variable 'paragraph-ignore-fill-prefix)
  (setq paragraph-ignore-fill-prefix t)
Karl Heuer's avatar
Karl Heuer committed
96 97
  (make-local-variable 'imenu-generic-expression)
  (setq imenu-generic-expression "^[a-z][a-zA-Z0-9_]+")
root's avatar
root committed
98 99 100 101 102 103 104 105
  (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)
106 107
  (make-local-variable 'comment-indent-function)
  (setq comment-indent-function 'prolog-comment-indent))
root's avatar
root committed
108 109 110 111 112 113 114 115 116 117

(defun prolog-mode-commands (map)
  (define-key map "\t" 'prolog-indent-line)
  (define-key map "\e\C-x" 'prolog-consult-region))

(if prolog-mode-map
    nil
  (setq prolog-mode-map (make-sparse-keymap))
  (prolog-mode-commands prolog-mode-map))

Jim Blandy's avatar
Jim Blandy committed
118
;;;###autoload
root's avatar
root committed
119 120 121 122 123
(defun prolog-mode ()
  "Major mode for editing Prolog code for Prologs.
Blank lines and `%%...' separate paragraphs.  `%'s start comments.
Commands:
\\{prolog-mode-map}
124
Entry to this mode calls the value of `prolog-mode-hook'
root's avatar
root committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
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 prolog-indent-line (&optional whole-exp)
  "Indent current line as Prolog code.
With argument, indent any additional lines of the same clause
rigidly along with this one (not yet)."
  (interactive "p")
  (let ((indent (prolog-indent-level))
	(pos (- (point-max) (point))) beg)
    (beginning-of-line)
    (setq beg (point))
    (skip-chars-forward " \t")
    (if (zerop (- indent (current-column)))
	nil
      (delete-region beg (point))
      (indent-to indent))
    (if (> (- (point-max) pos) (point))
	(goto-char (- (point-max) pos)))
    ))

(defun prolog-indent-level ()
  "Compute prolog indentation level."
  (save-excursion
    (beginning-of-line)
    (skip-chars-forward " \t")
    (cond
     ((looking-at "%%%") 0)		;Large comment starts
     ((looking-at "%[^%]") comment-column) ;Small comment starts
     ((bobp) 0)				;Beginning of buffer
     (t
      (let ((empty t) ind more less)
	(if (looking-at ")")
	    (setq less t)		;Find close
	  (setq less nil))
	;; See previous indentation
	(while empty
	  (forward-line -1)
	  (beginning-of-line)
 	  (if (bobp)
 	      (setq empty nil)
 	    (skip-chars-forward " \t")
 	    (if (not (or (looking-at "%[^%]") (looking-at "\n")))
 		(setq empty nil))))
 	(if (bobp)
 	    (setq ind 0)		;Beginning of buffer
	  (setq ind (current-column)))	;Beginning of clause
	;; See its beginning
	(if (looking-at "%%[^%]")
	    ind
	  ;; Real prolog code
	  (if (looking-at "(")
	      (setq more t)		;Find open
	    (setq more nil))
	  ;; See its tail
	  (end-of-prolog-clause)
	  (or (bobp) (forward-char -1))
	  (cond ((looking-at "[,(;>]")
		 (if (and more (looking-at "[^,]"))
		     (+ ind prolog-indent-width) ;More indentation
		   (max tab-width ind))) ;Same indentation
		((looking-at "-") tab-width) ;TAB
		((or less (looking-at "[^.]"))
		 (max (- ind prolog-indent-width) 0)) ;Less indentation
		(t 0))			;No indentation
	  )))
     )))

(defun end-of-prolog-clause ()
  "Go to end of clause in this line."
  (beginning-of-line 1)
  (let* ((eolpos (save-excursion (end-of-line) (point))))
    (if (re-search-forward comment-start-skip eolpos 'move)
	(goto-char (match-beginning 0)))
    (skip-chars-backward " \t")))

(defun prolog-comment-indent ()
  "Compute prolog comment indentation."
  (cond ((looking-at "%%%") 0)
	((looking-at "%%") (prolog-indent-level))
	(t
	 (save-excursion
	       (skip-chars-backward " \t")
	       ;; Insert one space at least, except at left margin.
	       (max (+ (current-column) (if (bolp) 0 1))
		    comment-column)))
	))


;;;
;;; Inferior prolog mode
;;;
(defvar inferior-prolog-mode-map nil)

(defun inferior-prolog-mode ()
  "Major mode for interacting with an inferior Prolog process.

The following commands are available:
\\{inferior-prolog-mode-map}

231 232 233
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 `comint-mode-hook'.
`prolog-mode-hook' is called after `comint-mode-hook'.
root's avatar
root committed
234 235

You can send text to the inferior Prolog from other buffers
236
using the commands `send-region', `send-string' and \\[prolog-consult-region].
root's avatar
root committed
237 238 239 240

Commands:
Tab indents for Prolog; with argument, shifts rest
 of expression rigidly with the current line.
241 242
Paragraphs are separated only by blank lines and '%%'.
'%'s start comments.
root's avatar
root committed
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

Return at end of buffer sends line as input.
Return not at end copies rest of line to end and sends it.
\\[comint-kill-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing.
\\[comint-interrupt-subjob] interrupts the shell or its current subjob if any.
\\[comint-stop-subjob] stops. \\[comint-quit-subjob] sends quit signal."
  (interactive)
  (require 'comint)
  (comint-mode)
  (setq major-mode 'inferior-prolog-mode
	mode-name "Inferior Prolog"
	comint-prompt-regexp "^| [ ?][- ] *")
  (prolog-mode-variables)
  (if inferior-prolog-mode-map nil
    (setq inferior-prolog-mode-map (copy-keymap comint-mode-map))
    (prolog-mode-commands inferior-prolog-mode-map))
  (use-local-map inferior-prolog-mode-map)
  (run-hooks 'prolog-mode-hook))

Jim Blandy's avatar
Jim Blandy committed
262
;;;###autoload
root's avatar
root committed
263 264 265 266 267 268 269 270
(defun run-prolog ()
  "Run an inferior Prolog process, input and output via buffer *prolog*."
  (interactive)
  (require 'comint)
  (switch-to-buffer (make-comint "prolog" prolog-program-name))
  (inferior-prolog-mode))

(defun prolog-consult-region (compile beg end)
271 272
  "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."
root's avatar
root committed
273 274 275 276 277 278 279 280 281 282 283 284 285
  (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.
286
If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
root's avatar
root committed
287 288 289
  (interactive "P\nr")
  (prolog-consult-region compile beg end)
  (switch-to-buffer "*prolog*"))
Eric S. Raymond's avatar
Eric S. Raymond committed
290

Richard M. Stallman's avatar
Richard M. Stallman committed
291 292
(provide 'prolog)

Eric S. Raymond's avatar
Eric S. Raymond committed
293
;;; prolog.el ends here