Sync to HEAD
[bpt/emacs.git] / lisp / progmodes / prolog.el
1 ;;; prolog.el --- major mode for editing and running Prolog under Emacs
2
3 ;; Copyright (C) 1986, 1987, 2003, 2004 Free Software Foundation, Inc.
4
5 ;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
6 ;; Keywords: languages
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;; This package provides a major mode for editing Prolog. It knows
28 ;; about Prolog syntax and comments, and can send regions to an inferior
29 ;; Prolog interpreter process. Font locking is tuned towards GNU Prolog.
30
31 ;;; Code:
32
33 (defgroup prolog nil
34 "Major mode for editing and running Prolog under Emacs"
35 :group 'languages)
36
37
38 (defcustom prolog-program-name
39 (let ((names '("prolog" "gprolog")))
40 (while (and names
41 (not (executable-find (car names))))
42 (setq names (cdr names)))
43 (or (car names) "prolog"))
44 "*Program name for invoking an inferior Prolog with `run-prolog'."
45 :type 'string
46 :group 'prolog)
47
48 (defcustom prolog-consult-string "reconsult(user).\n"
49 "*(Re)Consult mode (for C-Prolog and Quintus Prolog). "
50 :type 'string
51 :group 'prolog)
52
53 (defcustom prolog-compile-string "compile(user).\n"
54 "*Compile mode (for Quintus Prolog)."
55 :type 'string
56 :group 'prolog)
57
58 (defcustom prolog-eof-string "end_of_file.\n"
59 "*String that represents end of file for prolog.
60 nil means send actual operating system end of file."
61 :type 'string
62 :group 'prolog)
63
64 (defcustom prolog-indent-width 4
65 "Level of indentation in Prolog buffers."
66 :type 'integer
67 :group 'prolog)
68
69 (defvar prolog-font-lock-keywords
70 '(("\\(#[<=]=>\\|:-\\)\\|\\(#=\\)\\|\\(#[#<>\\/][=\\/]*\\|!\\)"
71 0 font-lock-keyword-face)
72 ("\\<\\(is\\|write\\|nl\\|read_\\sw+\\)\\>"
73 1 font-lock-keyword-face)
74 ("^\\(\\sw+\\)\\s-*\\((\\(.+\\))\\)*"
75 (1 font-lock-function-name-face)
76 (3 font-lock-variable-name-face)))
77 "Font-lock keywords for Prolog mode.")
78
79 (defvar prolog-mode-syntax-table
80 (let ((table (make-syntax-table)))
81 (modify-syntax-entry ?_ "w" table)
82 (modify-syntax-entry ?\\ "\\" table)
83 (modify-syntax-entry ?/ ". 14" table)
84 (modify-syntax-entry ?* ". 23" table)
85 (modify-syntax-entry ?+ "." table)
86 (modify-syntax-entry ?- "." table)
87 (modify-syntax-entry ?= "." table)
88 (modify-syntax-entry ?% "<" table)
89 (modify-syntax-entry ?\n ">" table)
90 (modify-syntax-entry ?< "." table)
91 (modify-syntax-entry ?> "." table)
92 (modify-syntax-entry ?\' "\"" table)
93 table))
94
95 (defvar prolog-mode-abbrev-table nil)
96 (define-abbrev-table 'prolog-mode-abbrev-table ())
97
98 (defun prolog-mode-variables ()
99 (make-local-variable 'paragraph-separate)
100 (setq paragraph-separate (concat "%%\\|$\\|" page-delimiter)) ;'%%..'
101 (make-local-variable 'paragraph-ignore-fill-prefix)
102 (setq paragraph-ignore-fill-prefix t)
103 (make-local-variable 'imenu-generic-expression)
104 (setq imenu-generic-expression "^[a-z][a-zA-Z0-9_]+")
105 (make-local-variable 'indent-line-function)
106 (setq indent-line-function 'prolog-indent-line)
107 (make-local-variable 'comment-start)
108 (setq comment-start "%")
109 (make-local-variable 'comment-start-skip)
110 (setq comment-start-skip "\\(?:%+\\|/\\*+\\)[ \t]*")
111 (make-local-variable 'comment-end-skip)
112 (setq comment-end-skip "[ \t]*\\(\n\\|\\*+/\\)")
113 (make-local-variable 'comment-column)
114 (setq comment-column 48))
115
116 (defvar prolog-mode-map
117 (let ((map (make-sparse-keymap)))
118 (define-key map "\e\C-x" 'prolog-consult-region)
119 map))
120
121 ;;;###autoload
122 (defun prolog-mode ()
123 "Major mode for editing Prolog code for Prologs.
124 Blank lines and `%%...' separate paragraphs. `%'s start comments.
125 Commands:
126 \\{prolog-mode-map}
127 Entry to this mode calls the value of `prolog-mode-hook'
128 if that value is non-nil."
129 (interactive)
130 (kill-all-local-variables)
131 (use-local-map prolog-mode-map)
132 (set-syntax-table prolog-mode-syntax-table)
133 (setq major-mode 'prolog-mode)
134 (setq mode-name "Prolog")
135 (prolog-mode-variables)
136 ;; font lock
137 (setq font-lock-defaults '(prolog-font-lock-keywords
138 nil nil nil
139 beginning-of-line))
140 (run-mode-hooks 'prolog-mode-hook))
141
142 (defun prolog-indent-line (&optional whole-exp)
143 "Indent current line as Prolog code.
144 With argument, indent any additional lines of the same clause
145 rigidly along with this one (not yet)."
146 (interactive "p")
147 (let ((indent (prolog-indent-level))
148 (pos (- (point-max) (point))) beg)
149 (beginning-of-line)
150 (setq beg (point))
151 (skip-chars-forward " \t")
152 (if (zerop (- indent (current-column)))
153 nil
154 (delete-region beg (point))
155 (indent-to indent))
156 (if (> (- (point-max) pos) (point))
157 (goto-char (- (point-max) pos)))
158 ))
159
160 (defun prolog-indent-level ()
161 "Compute prolog indentation level."
162 (save-excursion
163 (beginning-of-line)
164 (skip-chars-forward " \t")
165 (cond
166 ((looking-at "%%%") 0) ;Large comment starts
167 ((looking-at "%[^%]") comment-column) ;Small comment starts
168 ((bobp) 0) ;Beginning of buffer
169 (t
170 (let ((empty t) ind more less)
171 (if (looking-at ")")
172 (setq less t) ;Find close
173 (setq less nil))
174 ;; See previous indentation
175 (while empty
176 (forward-line -1)
177 (beginning-of-line)
178 (if (bobp)
179 (setq empty nil)
180 (skip-chars-forward " \t")
181 (if (not (or (looking-at "%[^%]") (looking-at "\n")))
182 (setq empty nil))))
183 (if (bobp)
184 (setq ind 0) ;Beginning of buffer
185 (setq ind (current-column))) ;Beginning of clause
186 ;; See its beginning
187 (if (looking-at "%%[^%]")
188 ind
189 ;; Real prolog code
190 (if (looking-at "(")
191 (setq more t) ;Find open
192 (setq more nil))
193 ;; See its tail
194 (end-of-prolog-clause)
195 (or (bobp) (forward-char -1))
196 (cond ((looking-at "[,(;>]")
197 (if (and more (looking-at "[^,]"))
198 (+ ind prolog-indent-width) ;More indentation
199 (max tab-width ind))) ;Same indentation
200 ((looking-at "-") tab-width) ;TAB
201 ((or less (looking-at "[^.]"))
202 (max (- ind prolog-indent-width) 0)) ;Less indentation
203 (t 0)) ;No indentation
204 )))
205 )))
206
207 (defun end-of-prolog-clause ()
208 "Go to end of clause in this line."
209 (beginning-of-line 1)
210 (let* ((eolpos (save-excursion (end-of-line) (point))))
211 (if (re-search-forward comment-start-skip eolpos 'move)
212 (goto-char (match-beginning 0)))
213 (skip-chars-backward " \t")))
214 \f
215 ;;;
216 ;;; Inferior prolog mode
217 ;;;
218 (defvar inferior-prolog-mode-map
219 (let ((map (make-sparse-keymap)))
220 ;; This map will inherit from `comint-mode-map' when entering
221 ;; inferior-prolog-mode.
222 map))
223
224 (defvar inferior-prolog-mode-syntax-table prolog-mode-syntax-table)
225 (defvar inferior-prolog-mode-abbrev-table prolog-mode-abbrev-table)
226
227 (define-derived-mode inferior-prolog-mode comint-mode "Inferior Prolog"
228 "Major mode for interacting with an inferior Prolog process.
229
230 The following commands are available:
231 \\{inferior-prolog-mode-map}
232
233 Entry to this mode calls the value of `prolog-mode-hook' with no arguments,
234 if that value is non-nil. Likewise with the value of `comint-mode-hook'.
235 `prolog-mode-hook' is called after `comint-mode-hook'.
236
237 You can send text to the inferior Prolog from other buffers
238 using the commands `send-region', `send-string' and \\[prolog-consult-region].
239
240 Commands:
241 Tab indents for Prolog; with argument, shifts rest
242 of expression rigidly with the current line.
243 Paragraphs are separated only by blank lines and '%%'.
244 '%'s start comments.
245
246 Return at end of buffer sends line as input.
247 Return not at end copies rest of line to end and sends it.
248 \\[comint-kill-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing.
249 \\[comint-interrupt-subjob] interrupts the shell or its current subjob if any.
250 \\[comint-stop-subjob] stops. \\[comint-quit-subjob] sends quit signal."
251 (setq comint-prompt-regexp "^| [ ?][- ] *")
252 (prolog-mode-variables))
253
254 ;;;###autoload
255 (defun run-prolog ()
256 "Run an inferior Prolog process, input and output via buffer *prolog*."
257 (interactive)
258 (require 'comint)
259 (pop-to-buffer (make-comint "prolog" prolog-program-name))
260 (inferior-prolog-mode))
261
262 (defun prolog-consult-region (compile beg end)
263 "Send the region to the Prolog process made by \"M-x run-prolog\".
264 If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
265 (interactive "P\nr")
266 (save-excursion
267 (if compile
268 (send-string "prolog" prolog-compile-string)
269 (send-string "prolog" prolog-consult-string))
270 (send-region "prolog" beg end)
271 (send-string "prolog" "\n") ;May be unnecessary
272 (if prolog-eof-string
273 (send-string "prolog" prolog-eof-string)
274 (process-send-eof "prolog")))) ;Send eof to prolog process.
275
276 (defun prolog-consult-region-and-go (compile beg end)
277 "Send the region to the inferior Prolog, and switch to *prolog* buffer.
278 If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
279 (interactive "P\nr")
280 (prolog-consult-region compile beg end)
281 (switch-to-buffer "*prolog*"))
282
283 (provide 'prolog)
284
285 ;;; arch-tag: f3ec6748-1272-4ab6-8826-c50cb1607636
286 ;;; prolog.el ends here