prolog.el 10 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
;;; Commentary:

;; This package provides a major mode for editing Prolog.  It knows
;; about Prolog syntax and comments, and can send regions to an inferior
29
;; Prolog interpreter process.  Font locking is tuned towards GNU Prolog.
30

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)

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
(defvar prolog-font-lock-keywords
  '(("\\(#[<=]=>\\|:-\\)\\|\\(#=\\)\\|\\(#[#<>\\/][=\\/]*\\|!\\)"
     0 font-lock-keyword-face)
    ("\\<\\(is\\|write\\|nl\\|read_\\sw+\\)\\>"
     1 font-lock-keyword-face)
    ("^\\(\\sw+\\)\\s-*\\((\\(.+\\))\\)*"
     (1 font-lock-function-name-face)
     (3 font-lock-variable-name-face)))
  "Font-lock keywords for Prolog mode.")

root's avatar
root committed
78 79 80 81 82
(if prolog-mode-syntax-table
    ()
  (let ((table (make-syntax-table)))
    (modify-syntax-entry ?_ "w" table)
    (modify-syntax-entry ?\\ "\\" table)
83 84
    (modify-syntax-entry ?/ ". 14" table)
    (modify-syntax-entry ?* ". 23" table)
root's avatar
root committed
85 86 87 88
    (modify-syntax-entry ?+ "." table)
    (modify-syntax-entry ?- "." table)
    (modify-syntax-entry ?= "." table)
    (modify-syntax-entry ?% "<" table)
89
    (modify-syntax-entry ?\n ">" table)
root's avatar
root committed
90 91 92 93 94 95 96 97 98 99 100
    (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)
101
  (setq paragraph-start (concat "%%\\|$\\|" page-delimiter)) ;'%%..'
root's avatar
root committed
102 103 104 105
  (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
106 107
  (make-local-variable 'imenu-generic-expression)
  (setq imenu-generic-expression "^[a-z][a-zA-Z0-9_]+")
root's avatar
root committed
108 109 110 111 112 113 114 115
  (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)
116 117
  (make-local-variable 'comment-indent-function)
  (setq comment-indent-function 'prolog-comment-indent))
root's avatar
root committed
118 119 120 121 122 123 124 125 126 127

(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
128
;;;###autoload
root's avatar
root committed
129 130 131 132 133
(defun prolog-mode ()
  "Major mode for editing Prolog code for Prologs.
Blank lines and `%%...' separate paragraphs.  `%'s start comments.
Commands:
\\{prolog-mode-map}
134
Entry to this mode calls the value of `prolog-mode-hook'
root's avatar
root committed
135 136 137 138 139 140 141
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)
142 143 144 145
  ;; font lock
  (setq font-lock-defaults '(prolog-font-lock-keywords
                             nil nil nil
                             beginning-of-line))
root's avatar
root committed
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 231 232 233 234 235 236 237 238 239 240 241 242 243 244
  (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}

245 246 247
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
248 249

You can send text to the inferior Prolog from other buffers
250
using the commands `send-region', `send-string' and \\[prolog-consult-region].
root's avatar
root committed
251 252 253 254

Commands:
Tab indents for Prolog; with argument, shifts rest
 of expression rigidly with the current line.
255 256
Paragraphs are separated only by blank lines and '%%'.
'%'s start comments.
root's avatar
root committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

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
276
;;;###autoload
root's avatar
root committed
277 278 279 280 281 282 283 284
(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)
285 286
  "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
287 288 289 290 291 292 293 294 295 296 297 298 299
  (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.
300
If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
root's avatar
root committed
301 302 303
  (interactive "P\nr")
  (prolog-consult-region compile beg end)
  (switch-to-buffer "*prolog*"))
Eric S. Raymond's avatar
Eric S. Raymond committed
304

Richard M. Stallman's avatar
Richard M. Stallman committed
305 306
(provide 'prolog)

Miles Bader's avatar
Miles Bader committed
307
;;; arch-tag: f3ec6748-1272-4ab6-8826-c50cb1607636
Eric S. Raymond's avatar
Eric S. Raymond committed
308
;;; prolog.el ends here