1 ;;; prolog.el --- major mode for editing and running Prolog under Emacs
3 ;; Copyright (C) 1986, 1987, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
4 ;; 2008, 2009, 2010 Free Software Foundation, Inc.
6 ;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26 ;; This package provides a major mode for editing Prolog. It knows
27 ;; about Prolog syntax and comments, and can send regions to an inferior
28 ;; Prolog interpreter process. Font locking is tuned towards GNU Prolog.
32 (defvar comint-prompt-regexp
)
33 (defvar comint-process-echoes
)
34 (defvar smie-indent-basic
)
37 "Major mode for editing and running Prolog under Emacs."
38 :link
'(custom-group-link :tag
"Font Lock Faces group" font-lock-faces
)
42 (defcustom prolog-program-name
43 (let ((names '("prolog" "gprolog" "swipl")))
45 (not (executable-find (car names
))))
46 (setq names
(cdr names
)))
47 (or (car names
) "prolog"))
48 "Program name for invoking an inferior Prolog with `run-prolog'."
52 (defcustom prolog-consult-string
"reconsult(user).\n"
53 "(Re)Consult mode (for C-Prolog and Quintus Prolog). "
57 (defcustom prolog-compile-string
"compile(user).\n"
58 "Compile mode (for Quintus Prolog)."
62 (defcustom prolog-eof-string
"end_of_file.\n"
63 "String that represents end of file for Prolog.
64 When nil, send actual operating system end of file."
68 (defcustom prolog-indent-width
4
69 "Level of indentation in Prolog buffers."
73 (defvar prolog-font-lock-keywords
74 '(("\\(#[<=]=>\\|:-\\)\\|\\(#=\\)\\|\\(#[#<>\\/][=\\/]*\\|!\\)"
75 0 font-lock-keyword-face
)
76 ("\\<\\(is\\|write\\|nl\\|read_\\sw+\\)\\>"
77 1 font-lock-keyword-face
)
78 ("^\\(\\sw+\\)\\s-*\\((\\(.+\\))\\)*"
79 (1 font-lock-function-name-face
)
80 (3 font-lock-variable-name-face
)))
81 "Font-lock keywords for Prolog mode.")
83 (defvar prolog-mode-syntax-table
84 (let ((table (make-syntax-table)))
85 (modify-syntax-entry ?_
"w" table
)
86 (modify-syntax-entry ?
\\ "\\" table
)
87 (modify-syntax-entry ?
/ ". 14" table
)
88 (modify-syntax-entry ?
* ". 23" 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 ?
\n ">" table
)
94 (modify-syntax-entry ?
< "." table
)
95 (modify-syntax-entry ?
> "." table
)
96 (modify-syntax-entry ?
\' "\"" table
)
99 (defvar prolog-mode-abbrev-table nil
)
100 (define-abbrev-table 'prolog-mode-abbrev-table
())
102 (defconst prolog-smie-op-levels
103 ;; Rather than construct the operator levels table from the BNF,
104 ;; we directly provide the operator precedences from GNU Prolog's
105 ;; manual. The only problem is that GNU Prolog's manual uses
106 ;; precedence levels in the opposite sense (higher numbers bind less
107 ;; tightly) than SMIE, so we use negative numbers.
108 '(("." -
10000 -
10000)
150 "Precedence levels of infix operators.")
152 (defconst prolog-smie-indent-rules
155 "Prolog indentation rules.")
157 (defun prolog-mode-variables ()
158 (make-local-variable 'paragraph-separate
)
159 (setq paragraph-separate
(concat "%%\\|$\\|" page-delimiter
)) ;'%%..'
160 (make-local-variable 'paragraph-ignore-fill-prefix
)
161 (setq paragraph-ignore-fill-prefix t
)
162 (make-local-variable 'imenu-generic-expression
)
163 (setq imenu-generic-expression
'((nil "^\\sw+" 0)))
164 (smie-setup prolog-smie-op-levels prolog-smie-indent-rules
)
165 (set (make-local-variable 'forward-sexp-function
)
166 'smie-forward-sexp-command
)
167 (set (make-local-variable 'smie-indent-basic
) prolog-indent-width
)
168 (make-local-variable 'comment-start
)
169 (setq comment-start
"%")
170 (make-local-variable 'comment-start-skip
)
171 (setq comment-start-skip
"\\(?:%+\\|/\\*+\\)[ \t]*")
172 (make-local-variable 'comment-end-skip
)
173 (setq comment-end-skip
"[ \t]*\\(\n\\|\\*+/\\)")
174 (make-local-variable 'comment-column
)
175 (setq comment-column
48))
177 (defvar prolog-mode-map
178 (let ((map (make-sparse-keymap)))
179 (define-key map
"\e\C-x" 'prolog-consult-region
)
180 (define-key map
"\C-c\C-l" 'inferior-prolog-load-file
)
181 (define-key map
"\C-c\C-z" 'switch-to-prolog
)
184 (easy-menu-define prolog-mode-menu prolog-mode-map
"Menu for Prolog mode."
185 ;; Mostly copied from scheme-mode's menu.
186 ;; Not tremendously useful, but it's a start.
188 ["Indent line" indent-according-to-mode t
]
189 ["Indent region" indent-region t
]
190 ["Comment region" comment-region t
]
191 ["Uncomment region" uncomment-region t
]
193 ["Run interactive Prolog session" run-prolog t
]
197 (define-derived-mode prolog-mode prog-mode
"Prolog"
198 "Major mode for editing Prolog code for Prologs.
199 Blank lines and `%%...' separate paragraphs. `%'s start comments.
202 Entry to this mode calls the value of `prolog-mode-hook'
203 if that value is non-nil."
204 (prolog-mode-variables)
205 (set (make-local-variable 'comment-add
) 1)
206 (setq font-lock-defaults
'(prolog-font-lock-keywords
210 (defun end-of-prolog-clause ()
211 "Go to end of clause in this line."
212 (beginning-of-line 1)
213 (let* ((eolpos (save-excursion (end-of-line) (point))))
214 (if (re-search-forward comment-start-skip eolpos
'move
)
215 (goto-char (match-beginning 0)))
216 (skip-chars-backward " \t")))
219 ;;; Inferior prolog mode
221 (defvar inferior-prolog-mode-map
222 (let ((map (make-sparse-keymap)))
223 ;; This map will inherit from `comint-mode-map' when entering
224 ;; inferior-prolog-mode.
225 (define-key map
[remap self-insert-command
]
226 'inferior-prolog-self-insert-command
)
229 (defvar inferior-prolog-mode-syntax-table prolog-mode-syntax-table
)
230 (defvar inferior-prolog-mode-abbrev-table prolog-mode-abbrev-table
)
232 (defvar inferior-prolog-error-regexp-alist
233 ;; GNU Prolog used to not follow the GNU standard format.
234 '(("^\\(.*?\\):\\([0-9]+\\) error: .*(char:\\([0-9]+\\)" 1 2 3)
237 (declare-function comint-mode
"comint")
238 (declare-function comint-send-string
"comint" (process string
))
239 (declare-function comint-send-region
"comint" (process start end
))
240 (declare-function comint-send-eof
"comint" ())
241 (defvar compilation-error-regexp-alist
)
243 (define-derived-mode inferior-prolog-mode comint-mode
"Inferior Prolog"
244 "Major mode for interacting with an inferior Prolog process.
246 The following commands are available:
247 \\{inferior-prolog-mode-map}
249 Entry to this mode calls the value of `prolog-mode-hook' with no arguments,
250 if that value is non-nil. Likewise with the value of `comint-mode-hook'.
251 `prolog-mode-hook' is called after `comint-mode-hook'.
253 You can send text to the inferior Prolog from other buffers using the commands
254 `process-send-region', `process-send-string' and \\[prolog-consult-region].
257 Tab indents for Prolog; with argument, shifts rest
258 of expression rigidly with the current line.
259 Paragraphs are separated only by blank lines and '%%'.
262 Return at end of buffer sends line as input.
263 Return not at end copies rest of line to end and sends it.
264 \\[comint-kill-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing.
265 \\[comint-interrupt-subjob] interrupts the shell or its current subjob if any.
266 \\[comint-stop-subjob] stops. \\[comint-quit-subjob] sends quit signal."
267 (setq comint-prompt-regexp
"^| [ ?][- ] *")
268 (set (make-local-variable 'compilation-error-regexp-alist
)
269 inferior-prolog-error-regexp-alist
)
270 (compilation-shell-minor-mode)
271 (prolog-mode-variables))
273 (defvar inferior-prolog-buffer nil
)
275 (defvar inferior-prolog-flavor
'unknown
276 "Either a symbol or a buffer position offset by one.
277 If a buffer position, the flavor has not been determined yet and
278 it is expected that the process's output has been or will
279 be inserted at that position plus one.")
281 (defun inferior-prolog-run (&optional name
)
282 (with-current-buffer (make-comint "prolog" (or name prolog-program-name
))
283 (inferior-prolog-mode)
284 (setq-default inferior-prolog-buffer
(current-buffer))
285 (make-local-variable 'inferior-prolog-buffer
)
286 (when (and name
(not (equal name prolog-program-name
)))
287 (set (make-local-variable 'prolog-program-name
) name
))
288 (set (make-local-variable 'inferior-prolog-flavor
)
289 ;; Force re-detection.
290 (let* ((proc (get-buffer-process (current-buffer)))
291 (pmark (and proc
(marker-position (process-mark proc
)))))
293 ((null pmark
) (1- (point-min)))
294 ;; The use of insert-before-markers in comint.el together with
295 ;; the potential use of comint-truncate-buffer in the output
296 ;; filter, means that it's difficult to reliably keep track of
297 ;; the buffer position where the process's output started.
298 ;; If possible we use a marker at "start - 1", so that
299 ;; insert-before-marker at `start' won't shift it. And if not,
300 ;; we fall back on using a plain integer.
301 ((> pmark
(point-min)) (copy-marker (1- pmark
)))
303 (add-hook 'comint-output-filter-functions
304 'inferior-prolog-guess-flavor nil t
)))
306 (defun inferior-prolog-process (&optional dontstart
)
307 (or (and (buffer-live-p inferior-prolog-buffer
)
308 (get-buffer-process inferior-prolog-buffer
))
310 (inferior-prolog-run)
312 (inferior-prolog-process))))
314 (defun inferior-prolog-guess-flavor (&optional ignored
)
316 (goto-char (1+ inferior-prolog-flavor
))
317 (setq inferior-prolog-flavor
319 ((looking-at "GNU Prolog") 'gnu
)
320 ((looking-at "Welcome to SWI-Prolog") 'swi
)
321 ((looking-at ".*\n") 'unknown
) ;There's at least one line.
322 (t inferior-prolog-flavor
))))
323 (when (symbolp inferior-prolog-flavor
)
324 (remove-hook 'comint-output-filter-functions
325 'inferior-prolog-guess-flavor t
)
326 (if (eq inferior-prolog-flavor
'gnu
)
327 (set (make-local-variable 'comint-process-echoes
) t
))))
330 (defalias 'run-prolog
'switch-to-prolog
)
332 (defun switch-to-prolog (&optional name
)
333 "Run an inferior Prolog process, input and output via buffer *prolog*.
334 With prefix argument \\[universal-prefix], prompt for the program to use."
336 (list (when current-prefix-arg
337 (let ((proc (inferior-prolog-process 'dontstart
)))
339 (if (yes-or-no-p "Kill current process before starting new one? ")
342 (read-string "Run Prolog: " prolog-program-name
)))))
343 (unless (inferior-prolog-process 'dontstart
)
344 (inferior-prolog-run name
))
345 (pop-to-buffer inferior-prolog-buffer
))
347 (defun inferior-prolog-self-insert-command ()
348 "Insert the char in the buffer or pass it directly to the process."
350 (let* ((proc (get-buffer-process (current-buffer)))
351 (pmark (and proc
(marker-position (process-mark proc
)))))
352 (if (and (eq inferior-prolog-flavor
'gnu
)
354 (null current-prefix-arg
)
358 (goto-char (- pmark
3))
359 (looking-at " \\? ")))
360 ;; This is GNU prolog waiting to know whether you want more answers
361 ;; or not (or abort, etc...). The answer is a single char, not
362 ;; a line, so pass this char directly rather than wait for RET to
363 ;; send a whole line.
364 (comint-send-string proc
(string last-command-event
))
365 (call-interactively 'self-insert-command
))))
367 (defun prolog-consult-region (compile beg end
)
368 "Send the region to the Prolog process made by \"M-x run-prolog\".
369 If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
371 (let ((proc (inferior-prolog-process)))
372 (comint-send-string proc
373 (if compile prolog-compile-string
374 prolog-consult-string
))
375 (comint-send-region proc beg end
)
376 (comint-send-string proc
"\n") ;May be unnecessary
377 (if prolog-eof-string
378 (comint-send-string proc prolog-eof-string
)
379 (with-current-buffer (process-buffer proc
)
380 (comint-send-eof))))) ;Send eof to prolog process.
382 (defun prolog-consult-region-and-go (compile beg end
)
383 "Send the region to the inferior Prolog, and switch to *prolog* buffer.
384 If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode."
386 (prolog-consult-region compile beg end
)
387 (pop-to-buffer inferior-prolog-buffer
))
389 ;; inferior-prolog-mode uses the autoloaded compilation-shell-minor-mode.
390 (declare-function compilation-forget-errors
"compile" ())
392 (defun inferior-prolog-load-file ()
393 "Pass the current buffer's file to the inferior prolog process."
396 (let ((file buffer-file-name
)
397 (proc (inferior-prolog-process)))
398 (with-current-buffer (process-buffer proc
)
399 (compilation-forget-errors)
400 (comint-send-string proc
(concat "['" (file-relative-name file
) "'].\n"))
401 (pop-to-buffer (current-buffer)))))
405 ;; arch-tag: f3ec6748-1272-4ab6-8826-c50cb1607636
406 ;;; prolog.el ends here